object->type = type;
object->free = free_func;
+ tpl_util_map_pointer_init(&object->user_data_map, TPL_OBJECT_BUCKET_BITS, &object->buckets[0]);
__tpl_util_atomic_set(&object->reference, 1);
if (0 != pthread_mutex_destroy(&object->mutex))
return TPL_FALSE;
- if (object->user_data.free)
- object->user_data.free(object->user_data.data);
+ tpl_util_map_fini(&object->user_data_map);
return TPL_TRUE;
}
}
tpl_bool_t
-tpl_object_set_user_data(tpl_object_t *object, void *data, tpl_free_func_t free_func)
+tpl_object_set_user_data(tpl_object_t *object, void *key, void *data, tpl_free_func_t free_func)
{
if (TPL_TRUE != __tpl_object_is_valid(object))
{
}
__tpl_object_lock(object);
- object->user_data.data = data;
- object->user_data.free = free_func;
+ tpl_util_map_set(&object->user_data_map, key, data, free_func);
__tpl_object_unlock(object);
return TPL_TRUE;
}
void *
-tpl_object_get_user_data(tpl_object_t *object)
+tpl_object_get_user_data(tpl_object_t *object, void *key)
{
void *data;
}
__tpl_object_lock(object);
- data = object->user_data.data;
+ data = tpl_util_map_get(&object->user_data_map, key);
__tpl_object_unlock(object);
return data;
#include <pthread.h>
#define TPL_MIN_REGION_RECTS 16
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define TPL_API __attribute__ ((visibility("default")))
+#else
+# define TPL_API
+#endif
#define TPL_ASSERT(expr) assert(expr)
#define TPL_INLINE __inline__
#define TPL_IGNORE(x) (void)x
return data;
}
+typedef struct tpl_util_map_entry tpl_util_map_entry_t;
+typedef struct tpl_util_map tpl_util_map_t;
+
+typedef int (*tpl_util_hash_func_t)(const void *key, int key_length);
+typedef int (*tpl_util_key_length_func_t)(const void *key);
+typedef int (*tpl_util_key_compare_func_t)(const void *key0, int key0_length,
+ const void *key1, int key1_length);
+
+struct tpl_util_map
+{
+ tpl_util_hash_func_t hash_func;
+ tpl_util_key_length_func_t key_length_func;
+ tpl_util_key_compare_func_t key_compare_func;
+
+ int bucket_bits;
+ int bucket_size;
+ int bucket_mask;
+ tpl_util_map_entry_t **buckets;
+};
+
+void
+tpl_util_map_init(tpl_util_map_t *map,
+ int bucket_bits,
+ tpl_util_hash_func_t hash_func,
+ tpl_util_key_length_func_t key_length_func,
+ tpl_util_key_compare_func_t key_compare_func,
+ void *buckets);
+
+void
+tpl_util_map_int32_init(tpl_util_map_t *map, int bucket_bits, void *buckets);
+
+void
+tpl_util_map_int64_init(tpl_util_map_t *map, int bucket_bits, void *buckets);
+
+void
+tpl_util_map_pointer_init(tpl_util_map_t *map, int bucket_bits, void *buckets);
+
+void
+tpl_util_map_fini(tpl_util_map_t *map);
+
+tpl_util_map_t *
+tpl_util_map_create(int bucket_bits,
+ tpl_util_hash_func_t hash_func,
+ tpl_util_key_length_func_t key_length_func,
+ tpl_util_key_compare_func_t key_compare_func);
+
+tpl_util_map_t *
+tpl_util_map_int32_create(int bucket_bits);
+
+tpl_util_map_t *
+tpl_util_map_int64_create(int bucket_bits);
+
+tpl_util_map_t *
+tpl_util_map_pointer_create(int bucket_bits);
+
+void
+tpl_util_map_destroy(tpl_util_map_t *map);
+
+void
+tpl_util_map_clear(tpl_util_map_t *map);
+
+void *
+tpl_util_map_get(tpl_util_map_t *map, const void *key);
+
+void
+tpl_util_map_set(tpl_util_map_t *map, const void *key, void *data, tpl_free_func_t free_func);
#endif /* TPL_UTILS_H */
--- /dev/null
+#include "tpl_internal.h"
+
+struct tpl_util_map_entry
+{
+ const void *key;
+ void *data;
+ tpl_free_func_t free_func;
+ tpl_util_map_entry_t *next;
+};
+
+static inline int
+__get_bucket_index(tpl_util_map_t *map, const void *key)
+{
+ int key_length = 0;
+ int hash;
+
+ if (map->key_length_func)
+ key_length = map->key_length_func(key);
+
+ hash = map->hash_func(key, key_length);
+ return hash & map->bucket_mask;
+}
+
+static inline tpl_util_map_entry_t **
+__get_bucket(tpl_util_map_t *map, const void *key)
+{
+ return &map->buckets[__get_bucket_index(map, key)];
+}
+
+static int
+__int64_hash(const void *key, int key_length)
+{
+ uint64_t _key = (uint64_t)key;
+
+ /* Hash functions from Thomas Wang https://gist.github.com/badboy/6267743 */
+ _key = ~_key + (_key << 15);
+ _key ^= _key >> 12;
+ _key += _key << 2;
+ _key ^= _key >> 4;
+ _key *= 2057;
+ _key ^= _key >> 16;
+
+ return (int)_key;
+}
+
+static int
+__int64_key_compare(const void *key0, int key0_length,
+ const void *key1, int key1_length)
+{
+ return (int)(key0 - key1);
+}
+
+static int
+__int32_hash(const void *key, int key_length)
+{
+ uint32_t _key = (uint32_t)key;
+
+ /* Hash functions from Thomas Wang https://gist.github.com/badboy/6267743 */
+ _key = ~_key + (_key << 15);
+ _key ^= _key >> 12;
+ _key += _key << 2;
+ _key ^= _key >> 4;
+ _key *= 2057;
+ _key ^= _key >> 16;
+
+ return _key;
+}
+
+static int
+__int32_key_compare(const void *key0, int key0_length,
+ const void *key1, int key1_length)
+{
+ return (int)(key0 - key1);
+}
+
+void
+tpl_util_map_init(tpl_util_map_t *map,
+ int bucket_bits,
+ tpl_util_hash_func_t hash_func,
+ tpl_util_key_length_func_t key_length_func,
+ tpl_util_key_compare_func_t key_compare_func,
+ void *buckets)
+{
+ map->hash_func = hash_func;
+ map->key_length_func = key_length_func;
+ map->key_compare_func = key_compare_func;
+
+ map->bucket_bits = bucket_bits;
+ map->bucket_size = 1 << bucket_bits;
+ map->bucket_mask = map->bucket_size - 1;
+
+ map->buckets = buckets;
+}
+
+void
+tpl_util_map_int32_init(tpl_util_map_t *map, int bucket_bits, void *buckets)
+{
+ tpl_util_map_init(map, bucket_bits, __int32_hash, NULL, __int32_key_compare, buckets);
+}
+
+void
+tpl_util_map_int64_init(tpl_util_map_t *map, int bucket_bits, void *buckets)
+{
+ tpl_util_map_init(map, bucket_bits, __int64_hash, NULL, __int64_key_compare, buckets);
+}
+
+void
+tpl_util_map_pointer_init(tpl_util_map_t *map, int bucket_bits, void *buckets)
+{
+#if INTPTR_MAX == INT32_MAX
+ tpl_util_map_init(map, bucket_bits, __int32_hash, NULL, __int32_key_compare, buckets);
+#elif INTPTR_MAX == INT64_MAX
+ tpl_util_map_init(map, bucket_bits, __int64_hash, NULL, __int64_key_compare, buckets);
+#else
+ #error "Not 32 or 64bit system"
+#endif
+}
+
+ void
+tpl_util_map_fini(tpl_util_map_t *map)
+{
+ tpl_util_map_clear(map);
+}
+
+ tpl_util_map_t *
+tpl_util_map_create(int bucket_bits,
+ tpl_util_hash_func_t hash_func,
+ tpl_util_key_length_func_t key_length_func,
+ tpl_util_key_compare_func_t key_compare_func)
+{
+ tpl_util_map_t *map;
+ int bucket_size = 1 << bucket_bits;
+
+ map = calloc(1, sizeof(tpl_util_map_t) + bucket_size * sizeof(tpl_util_map_entry_t *));
+ TPL_CHECK_ON_FALSE_RETURN_VAL(map, NULL);
+
+ tpl_util_map_init(map, bucket_bits, hash_func, key_length_func, key_compare_func, map + 1);
+ return map;
+}
+
+ tpl_util_map_t *
+tpl_util_map_int32_create(int bucket_bits)
+{
+ return tpl_util_map_create(bucket_bits, __int32_hash, NULL, __int32_key_compare);
+}
+
+ tpl_util_map_t *
+tpl_util_map_int64_create(int bucket_bits)
+{
+ return tpl_util_map_create(bucket_bits, __int64_hash, NULL, __int64_key_compare);
+}
+
+ tpl_util_map_t *
+tpl_util_map_pointer_create(int bucket_bits)
+{
+#if INTPTR_MAX == INT32_MAX
+ return tpl_util_map_create(bucket_bits, __int32_hash, NULL, __int32_key_compare);
+#elif INTPTR_MAX == INT64_MAX
+ return tpl_util_map_create(bucket_bits, __int64_hash, NULL, __int64_key_compare);
+#else
+ #error "Not 32 or 64bit system"
+#endif
+
+ return NULL;
+}
+
+ void
+tpl_util_map_destroy(tpl_util_map_t *map)
+{
+ tpl_util_map_fini(map);
+ free(map);
+}
+
+ void
+tpl_util_map_clear(tpl_util_map_t *map)
+{
+ int i;
+
+ if (!map->buckets)
+ return;
+
+ for (i = 0; i < map->bucket_size; i++)
+ {
+ tpl_util_map_entry_t *curr = map->buckets[i];
+
+ while (curr)
+ {
+ tpl_util_map_entry_t *next = curr->next;
+
+ if (curr->free_func)
+ curr->free_func(curr->data);
+
+ free(curr);
+ curr = next;
+ }
+ }
+
+ memset(map->buckets, 0x00, map->bucket_size * sizeof(tpl_util_map_entry_t *));
+}
+
+ void *
+tpl_util_map_get(tpl_util_map_t *map, const void *key)
+{
+ tpl_util_map_entry_t *curr = *__get_bucket(map, key);
+
+ while (curr)
+ {
+ int len0 = 0;
+ int len1 = 0;
+
+ if (map->key_length_func)
+ {
+ len0 = map->key_length_func(curr->key);
+ len1 = map->key_length_func(key);
+ }
+
+ if (map->key_compare_func(curr->key, len0, key, len1) == 0)
+ return curr->data;
+
+ curr = curr->next;
+ }
+
+ return NULL;
+}
+
+ void
+tpl_util_map_set(tpl_util_map_t *map, const void *key, void *data, tpl_free_func_t free_func)
+{
+ tpl_util_map_entry_t **bucket = __get_bucket(map, key);
+ tpl_util_map_entry_t *curr = *bucket;
+ tpl_util_map_entry_t *prev = NULL;
+ int key_length = 0;
+
+ /* Find existing entry for the key. */
+ while (curr)
+ {
+ int len0 = 0;
+ int len1 = 0;
+
+ if (map->key_length_func)
+ {
+ len0 = map->key_length_func(curr->key);
+ len1 = map->key_length_func(key);
+ }
+
+ if (map->key_compare_func(curr->key, len0, key, len1) == 0)
+ {
+ /* Free previous data. */
+ if (curr->free_func)
+ curr->free_func(curr->data);
+
+ if (data)
+ {
+ /* Set new data. */
+ curr->data = data;
+ curr->free_func = free_func;
+ }
+ else
+ {
+ /* Delete entry. */
+ if (prev)
+ prev->next = curr->next;
+ else
+ *bucket = curr->next;
+
+ free(curr);
+ }
+
+ return;
+ }
+
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (data == NULL)
+ {
+ /* Nothing to delete. */
+ return;
+ }
+
+ /* Allocate a new entry. */
+ if (map->key_length_func)
+ key_length = map->key_length_func(key);
+
+ curr = malloc(sizeof(tpl_util_map_entry_t) + key_length);
+ TPL_CHECK_ON_FALSE_RETURN(curr);
+
+ if (key_length > 0)
+ {
+ memcpy(curr + 1, key, key_length);
+ curr->key = (const void *)(curr + 1);
+ }
+ else
+ {
+ curr->key = key;
+ }
+
+ curr->data = data;
+ curr->free_func = free_func;
+
+ /* Insert at the head of the bucket. */
+ curr->next = *bucket;
+ *bucket = curr;
+}