Support tpl_objet_set_user_data() by key 87/59487/3
authorSangjin Lee <lsj119@samsung.com>
Tue, 16 Feb 2016 05:00:51 +0000 (14:00 +0900)
committerGwan-gyeong Mun <kk.moon@samsung.com>
Tue, 16 Feb 2016 08:27:48 +0000 (00:27 -0800)
- add utils apis for map
tpl_map support int32, int64 and pointer data type to hash key.
and tpl_object use the pointer type map, key is treated as
a normal variable. Thus, tpl_object_set/get_user_data() is
modified to use the pointer value itself as a key.

Change-Id: I0bffd9dba61aeeedcb498eaff1f8099c628aca8d

Makefile
src/tpl.h
src/tpl_internal.h
src/tpl_object.c
src/tpl_utils.h
src/tpl_utils_map.c [new file with mode: 0644]

index 4529297..ee9b725 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -64,6 +64,7 @@ TPL_SRCS += $(SRC_DIR)/tpl_object.c
 TPL_SRCS += $(SRC_DIR)/tpl_region.c
 TPL_SRCS += $(SRC_DIR)/tpl_surface.c
 TPL_SRCS += $(SRC_DIR)/tpl_utils_hlist.c
+TPL_SRCS += $(SRC_DIR)/tpl_utils_map.c
 
 ifneq ($(call is-feature-enabled,winsys_wl),)
 TPL_SRCS += $(SRC_DIR)/tpl_wayland.c
index 6d41edc..4d6d46c 100644 (file)
--- a/src/tpl.h
+++ b/src/tpl.h
@@ -244,8 +244,10 @@ tpl_object_type_t tpl_object_get_type(tpl_object_t *object);
  * Users want to relate some data with a TPL object. This function provides
  * registering a pointer to such data which can be retrieved later using
  * tpl_object_get_user_data().
+ * key should the pointer value itself as a key
  *
  * @param object object to set user data to.
+ * @param key pointer to the key.
  * @param data pointer to the user data.
  * @param free_func free function which is used for freeing the user data when the object is destroyed.
  * @return TPL_TRUE on success, TPL_FALSE on error.
@@ -253,6 +255,7 @@ tpl_object_type_t tpl_object_get_type(tpl_object_t *object);
  * @see tpl_object_get_user_data()
  */
 tpl_bool_t tpl_object_set_user_data(tpl_object_t *object,
+                             void *key,
                              void *data,
                              tpl_free_func_t free_func);
 
@@ -260,11 +263,12 @@ tpl_bool_t tpl_object_set_user_data(tpl_object_t *object,
  * Get registered user data of a TPL object.
  *
  * @param object object to get user data.
+ * @param key pointer to the key.
  * @return pointer to the registered user data on success, NULL on error.
  *
  * @see tpl_object_set_user_data()
  */
-void * tpl_object_get_user_data(tpl_object_t *object);
+void * tpl_object_get_user_data(tpl_object_t *object, void *key);
 
 /**
  * Create TPL display object for the given native display.
index ae3259b..009ca71 100644 (file)
@@ -15,6 +15,8 @@
 #include <tbm_surface.h>
 #include <tbm_surface_internal.h>
 
+#define TPL_OBJECT_BUCKET_BITS       5
+
 #define TPL_OBJECT_LOCK(object)                __tpl_object_lock((tpl_object_t *)(object))
 #define TPL_OBJECT_UNLOCK(object)      __tpl_object_unlock((tpl_object_t *)(object))
 
@@ -70,10 +72,8 @@ struct _tpl_object
        tpl_free_func_t         free;
        pthread_mutex_t         mutex;
 
-       struct {
-               void            *data;
-               tpl_free_func_t free;
-       } user_data;
+       tpl_util_map_t user_data_map;
+       tpl_util_map_entry_t     *buckets[1 << TPL_OBJECT_BUCKET_BITS];
 };
 
 struct _tpl_display
index 418146b..3558908 100644 (file)
@@ -18,6 +18,7 @@ __tpl_object_init(tpl_object_t *object, tpl_object_type_t type, tpl_free_func_t
 
        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);
 
@@ -35,8 +36,7 @@ __tpl_object_fini(tpl_object_t *object)
        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;
 }
@@ -119,7 +119,7 @@ tpl_object_get_type(tpl_object_t *object)
 }
 
 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))
        {
@@ -128,15 +128,14 @@ tpl_object_set_user_data(tpl_object_t *object, void *data, tpl_free_func_t free_
        }
 
        __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;
 
@@ -147,7 +146,7 @@ tpl_object_get_user_data(tpl_object_t *object)
        }
 
        __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;
index 28cbd55..02a3eed 100644 (file)
@@ -7,6 +7,11 @@
 #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
@@ -849,4 +854,70 @@ tpl_list_pop_back(tpl_list_t *list, tpl_free_func_t func)
        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 */
diff --git a/src/tpl_utils_map.c b/src/tpl_utils_map.c
new file mode 100644 (file)
index 0000000..e42ef31
--- /dev/null
@@ -0,0 +1,305 @@
+#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;
+}