From 550ebc9ab199b2dbd63e4c7e9c0bb539775246a2 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Wed, 24 Sep 2008 17:14:29 +0000 Subject: [PATCH] Add hash and rbtree delete callback, cleanup the code and improve performance (hash as a new internal structure). We still need a hash function for removing a node from the hash and destroying it at the same time. SVN revision: 36222 --- legacy/eina/src/include/eina_hash.h | 7 +- legacy/eina/src/include/eina_rbtree.h | 4 +- legacy/eina/src/include/eina_types.h | 2 + legacy/eina/src/lib/eina_hash.c | 336 ++++++++++++++------- legacy/eina/src/lib/eina_mempool.c | 2 +- legacy/eina/src/lib/eina_rbtree.c | 8 +- legacy/eina/src/lib/eina_stringshare.c | 4 +- legacy/eina/src/tests/eina_bench_hash.c | 79 ++--- legacy/eina/src/tests/eina_test_hash.c | 20 +- legacy/eina/src/tests/eina_test_iterator.c | 2 +- 10 files changed, 286 insertions(+), 178 deletions(-) diff --git a/legacy/eina/src/include/eina_hash.h b/legacy/eina/src/include/eina_hash.h index 392f701bc9..cc0ae0c29d 100644 --- a/legacy/eina/src/include/eina_hash.h +++ b/legacy/eina/src/include/eina_hash.h @@ -64,9 +64,10 @@ EAPI int eina_hash_shutdown(void); EAPI Eina_Hash * eina_hash_new(Eina_Key_Length key_length_cb, Eina_Key_Cmp key_cmp_cb, - Eina_Key_Hash key_hash_cb); -EAPI Eina_Hash * eina_hash_string_djb2_new(void); -EAPI Eina_Hash * eina_hash_string_superfast_new(void); + Eina_Key_Hash key_hash_cb, + Eina_Free_Cb data_free_cb); +EAPI Eina_Hash * eina_hash_string_djb2_new(Eina_Free_Cb data_free_cb); +EAPI Eina_Hash * eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb); EAPI Eina_Bool eina_hash_add(Eina_Hash *hash, const void *key, const void *data); EAPI Eina_Bool eina_hash_direct_add(Eina_Hash *hash, const void *key, const void *data); diff --git a/legacy/eina/src/include/eina_rbtree.h b/legacy/eina/src/include/eina_rbtree.h index 35ac33751d..a8199a5f84 100644 --- a/legacy/eina/src/include/eina_rbtree.h +++ b/legacy/eina/src/include/eina_rbtree.h @@ -50,12 +50,12 @@ typedef Eina_Rbtree_Direction (*Eina_Rbtree_Cmp_Node_Cb)(const Eina_Rbtree *left typedef int (*Eina_Rbtree_Cmp_Key_Cb)(const Eina_Rbtree *node, const void *key, int length, void *data); #define EINA_RBTREE_CMP_KEY_CB(Function) ((Eina_Rbtree_Cmp_Key_Cb) Function) -typedef void (*Eina_Rbtree_Free_Cb)(Eina_Rbtree *node); +typedef void (*Eina_Rbtree_Free_Cb)(Eina_Rbtree *node, void *data); #define EINA_RBTREE_FREE_CB(Function) ((Eina_Rbtree_Free_Cb) Function) EAPI Eina_Rbtree *eina_rbtree_inline_insert(Eina_Rbtree *root, Eina_Rbtree *node, Eina_Rbtree_Cmp_Node_Cb cmp, const void *data); EAPI Eina_Rbtree *eina_rbtree_inline_remove(Eina_Rbtree *root, Eina_Rbtree *node, Eina_Rbtree_Cmp_Node_Cb cmp, const void *data); -EAPI void eina_rbtree_delete(Eina_Rbtree *root, Eina_Rbtree_Free_Cb func); +EAPI void eina_rbtree_delete(Eina_Rbtree *root, Eina_Rbtree_Free_Cb func, void *data); static inline Eina_Rbtree *eina_rbtree_inline_lookup(Eina_Rbtree *root, const void *key, int length, Eina_Rbtree_Cmp_Key_Cb cmp, const void *data); diff --git a/legacy/eina/src/include/eina_types.h b/legacy/eina/src/include/eina_types.h index 61ee053e27..49c12b3c33 100644 --- a/legacy/eina/src/include/eina_types.h +++ b/legacy/eina/src/include/eina_types.h @@ -79,5 +79,7 @@ typedef Eina_Bool (*Eina_Each)(const void *container, void *fdata); #define EINA_EACH(Function) ((Eina_Each)Function) +typedef void (*Eina_Free_Cb)(void *data); +#define EINA_FREE_CB(Function) ((Eina_Free_Cb)Function) #endif /* EINA_TYPES_H_ */ diff --git a/legacy/eina/src/lib/eina_hash.c b/legacy/eina/src/lib/eina_hash.c index 162a6f1dfc..de071c386c 100644 --- a/legacy/eina/src/lib/eina_hash.c +++ b/legacy/eina/src/lib/eina_hash.c @@ -38,6 +38,11 @@ * @cond LOCAL */ +#define EINA_HASH_BUCKET_SIZE 256 +#define EINA_HASH_BUCKET_MASK 0xFF +#define EINA_HASH_RBTREE_MASK 0xFFF + +typedef struct _Eina_Hash_Head Eina_Hash_Head; typedef struct _Eina_Hash_El Eina_Hash_El; typedef struct _Eina_Hash_Foreach Eina_Hash_Foreach; typedef struct _Eina_Iterator_Hash Eina_Iterator_Hash; @@ -48,15 +53,25 @@ struct _Eina_Hash Eina_Key_Length key_length_cb; Eina_Key_Cmp key_cmp_cb; Eina_Key_Hash key_hash_cb; + Eina_Free_Cb data_free_cb; - Eina_Rbtree *buckets[256]; + Eina_Rbtree *buckets[EINA_HASH_BUCKET_SIZE]; int population; }; +struct _Eina_Hash_Head +{ + EINA_RBTREE; + int hash; + + Eina_Rbtree *head; +}; + struct _Eina_Hash_El { - Eina_Rbtree _node_data; + EINA_RBTREE; Eina_Hash_Tuple tuple; + Eina_Bool begin : 1; }; struct _Eina_Hash_Foreach @@ -76,6 +91,8 @@ struct _Eina_Iterator_Hash const Eina_Hash *hash; Eina_Iterator *current; + Eina_Iterator *list; + Eina_Hash_Head *eh; Eina_Hash_El *el; int bucket; @@ -84,10 +101,13 @@ struct _Eina_Iterator_Hash struct _Eina_Hash_Each { + Eina_Hash_Head *eh; const Eina_Hash_El *el; const void *data; }; +static int _eina_hash_init_count = 0; + #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) @@ -100,49 +120,162 @@ struct _Eina_Hash_Each #endif static inline int -_eina_hash_rbtree_key(const Eina_Hash_El *el, const Eina_Hash_Tuple *tuple, __UNUSED__ int key_length, Eina_Key_Cmp cmp) +_eina_hash_hash_rbtree_cmp_hash(const Eina_Hash_Head *eh, const int *hash, __UNUSED__ int key_length, __UNUSED__ void *data) { - int result; - - result = cmp(el->tuple.key, el->tuple.key_length, tuple->key, tuple->key_length); - if (result == 0) - if (tuple->data && el->tuple.data != tuple->data) - return 1; - return result; + return eh->hash - *hash; } static Eina_Rbtree_Direction -_eina_hash_rbtree_node(const Eina_Hash_El *left, const Eina_Hash_El *right, Eina_Key_Cmp cmp) +_eina_hash_hash_rbtree_cmp_node(const Eina_Hash_Head *left, const Eina_Hash_Head *right, __UNUSED__ void *data) { - if (cmp(left->tuple.key, left->tuple.key_length, right->tuple.key, right->tuple.key_length) < 0) + if (left->hash - right->hash < 0) return EINA_RBTREE_LEFT; return EINA_RBTREE_RIGHT; } -static Eina_Bool -_eina_hash_rbtree_each(__UNUSED__ const Eina_Rbtree *container, const Eina_Hash_El *el, Eina_Hash_Each *data) +static inline int +_eina_hash_key_rbtree_cmp_key_data(const Eina_Hash_El *el, const Eina_Hash_Tuple *tuple, __UNUSED__ unsigned int key_length, Eina_Key_Cmp cmp) { - if (el->tuple.data == data->data) + int result; + + result = cmp(el->tuple.key, el->tuple.key_length, tuple->key, tuple->key_length); + + if (result == 0 && tuple->data && tuple->data != el->tuple.data) + return 1; + return result; +} + +static Eina_Rbtree_Direction +_eina_hash_key_rbtree_cmp_node(const Eina_Hash_El *left, const Eina_Hash_El *right, Eina_Key_Cmp cmp) +{ + int result; + + result = cmp(left->tuple.key, left->tuple.key_length, + right->tuple.key, right->tuple.key_length); + + if (result < 0) + return EINA_RBTREE_LEFT; + return EINA_RBTREE_RIGHT; +} + +static inline Eina_Bool +eina_hash_add_alloc_by_hash(Eina_Hash *hash, + const void *key, int key_length, int alloc_length, + int key_hash, + const void *data) +{ + Eina_Hash_El *el = NULL; + Eina_Hash_Head *eh; + Eina_Error error = 0; + int hash_num; + + if ((!hash) || (!key) || (!data)) goto on_error; + error = EINA_ERROR_OUT_OF_MEMORY; + + /* Apply eina mask to hash. */ + hash_num = key_hash & EINA_HASH_BUCKET_MASK; + key_hash &= EINA_HASH_RBTREE_MASK; + + /* Look up for head node. */ + eh = (Eina_Hash_Head*) eina_rbtree_inline_lookup(hash->buckets[hash_num], + &key_hash, 0, + EINA_RBTREE_CMP_KEY_CB(_eina_hash_hash_rbtree_cmp_hash), NULL); + + if (!eh) { - data->el = el; - return EINA_FALSE; + /* If not found allocate it and a element. */ + eh = malloc(sizeof (Eina_Hash_Head) + sizeof (Eina_Hash_El) + alloc_length); + if (!eh) goto on_error; + eh->hash = key_hash; + eh->head = NULL; + + hash->buckets[hash_num] = eina_rbtree_inline_insert(hash->buckets[hash_num], EINA_RBTREE_GET(eh), + EINA_RBTREE_CMP_NODE_CB(_eina_hash_hash_rbtree_cmp_node), NULL); + + el = (Eina_Hash_El*) (eh + 1); + el->begin = EINA_TRUE; } + + if (!el) + { + /* + Alloc every needed things + (No more lookup as we expect to support more than one item for one key). + */ + el = malloc(sizeof (Eina_Hash_El) + alloc_length); + if (!el) goto on_error; + el->begin = EINA_FALSE; + } + + /* Setup the element */ + el->tuple.key_length = key_length; + el->tuple.data = (void *) data; + if (alloc_length > 0) + { + el->tuple.key = (char *) (el + 1); + memcpy((char *) el->tuple.key, key, alloc_length); + } + else + { + el->tuple.key = key; + } + + /* add the new element to the hash. */ + eh->head = eina_rbtree_inline_insert(eh->head, EINA_RBTREE_GET(el), + EINA_RBTREE_CMP_NODE_CB(_eina_hash_key_rbtree_cmp_node), hash->key_cmp_cb); + hash->population++; return EINA_TRUE; + + on_error: + eina_error_set(error); + return EINA_FALSE; +} + +static Eina_Bool +_eina_hash_rbtree_each(__UNUSED__ const Eina_Rbtree *container, const Eina_Hash_Head *eh, Eina_Hash_Each *data) +{ + Eina_Iterator *it; + Eina_Hash_El *el; + Eina_Bool found = EINA_TRUE; + + it = eina_rbtree_iterator_prefix(eh->head); + while (eina_iterator_next(it, (void**) &el)) + { + if (el->tuple.data == data->data) + { + data->el = el; + data->eh = (Eina_Hash_Head*) eh; + found = EINA_FALSE; + break ; + } + } + + eina_iterator_free(it); + return found; } static inline Eina_Hash_El * -_eina_hash_find_by_hash(const Eina_Hash *hash, Eina_Hash_Tuple *tuple, int key_hash) +_eina_hash_find_by_hash(const Eina_Hash *hash, Eina_Hash_Tuple *tuple, int key_hash, Eina_Hash_Head **eh) { Eina_Hash_El *el; + int rb_hash = key_hash & EINA_HASH_RBTREE_MASK; - key_hash &= 0xFF; + key_hash &= EINA_HASH_BUCKET_MASK; + + *eh = (Eina_Hash_Head*) eina_rbtree_inline_lookup(hash->buckets[key_hash], + &rb_hash, 0, + EINA_RBTREE_CMP_KEY_CB(_eina_hash_hash_rbtree_cmp_hash), NULL); + if (!*eh) return NULL; + + el = (Eina_Hash_El*) eina_rbtree_inline_lookup((*eh)->head, + tuple, 0, + EINA_RBTREE_CMP_KEY_CB(_eina_hash_key_rbtree_cmp_key_data), hash->key_cmp_cb); - el = (Eina_Hash_El*) eina_rbtree_inline_lookup(hash->buckets[key_hash], tuple, sizeof (Eina_Hash_Tuple), EINA_RBTREE_CMP_KEY_CB(_eina_hash_rbtree_key), hash->key_cmp_cb); return el; } static inline Eina_Hash_El * -_eina_hash_find_by_data(const Eina_Hash *hash, const void *data, int *key_hash) +_eina_hash_find_by_data(const Eina_Hash *hash, const void *data, int *key_hash, Eina_Hash_Head **eh) { Eina_Hash_Each each; Eina_Iterator *it; @@ -151,7 +284,7 @@ _eina_hash_find_by_data(const Eina_Hash *hash, const void *data, int *key_hash) each.el = NULL; each.data = data; - for (hash_num = 0; hash_num < 256; hash_num++) + for (hash_num = 0; hash_num < EINA_HASH_BUCKET_SIZE; hash_num++) { it = eina_rbtree_iterator_prefix(hash->buckets[hash_num]); eina_iterator_foreach(it, EINA_EACH(_eina_hash_rbtree_each), &each); @@ -160,6 +293,7 @@ _eina_hash_find_by_data(const Eina_Hash *hash, const void *data, int *key_hash) if (each.el) { *key_hash = hash_num; + *eh = each.eh; return (Eina_Hash_El*) each.el; } } @@ -167,6 +301,21 @@ _eina_hash_find_by_data(const Eina_Hash *hash, const void *data, int *key_hash) return NULL; } +static void +_eina_hash_el_free(Eina_Hash_El *el, Eina_Hash *hash) +{ + if (el->begin == EINA_FALSE) free(el); + if (hash->data_free_cb) + hash->data_free_cb(el->tuple.data); +} + +static void +_eina_hash_head_free(Eina_Hash_Head *eh, Eina_Hash *hash) +{ + eina_rbtree_delete(eh->head, EINA_RBTREE_FREE_CB(_eina_hash_el_free), hash); + free(eh); +} + static unsigned int _eina_string_key_length(const char *key) { @@ -229,11 +378,23 @@ _eina_hash_iterator_next(Eina_Iterator_Hash *it, void **data) } else { - ok = eina_iterator_next(it->current, (void**) &it->el); + ok = eina_iterator_next(it->list, (void**) &it->el); if (!ok) { - eina_iterator_free(it->current); - it->current = NULL; + eina_iterator_free(it->list); + it->list = NULL; + + ok = eina_iterator_next(it->current, (void**) &it->eh); + if (!ok) + { + eina_iterator_free(it->current); + it->current = NULL; + } + else + { + it->list = eina_rbtree_iterator_prefix(it->eh->head); + ok = eina_iterator_next(it->list, (void**) &it->el); + } } bucket = it->bucket; @@ -241,18 +402,20 @@ _eina_hash_iterator_next(Eina_Iterator_Hash *it, void **data) if (ok == EINA_FALSE) { - while (bucket < 256) + while (bucket < EINA_HASH_BUCKET_SIZE) { if (it->hash->buckets[bucket] != NULL) { it->current = eina_rbtree_iterator_prefix(it->hash->buckets[bucket]); - ok = eina_iterator_next(it->current, (void**) &it->el); + ok = eina_iterator_next(it->current, (void**) &it->eh); if (ok) break ; eina_iterator_free(it->current); it->current = NULL; } ++bucket; } + it->list = eina_rbtree_iterator_prefix(it->eh->head); + ok = eina_iterator_next(it->list, (void**) &it->el); } it->index++; @@ -339,7 +502,10 @@ _eina_hash_iterator_free(Eina_Iterator_Hash *it) EAPI int eina_hash_init(void) { - return eina_error_init(); + if (!_eina_hash_init_count) + eina_error_init(); + + return ++_eina_hash_init_count; } /** @@ -356,13 +522,16 @@ eina_hash_init(void) EAPI int eina_hash_shutdown(void) { - return eina_error_shutdown(); + if (_eina_hash_init_count == 1) + eina_error_shutdown(); + return --_eina_hash_init_count; } EAPI Eina_Hash * eina_hash_new(Eina_Key_Length key_length_cb, Eina_Key_Cmp key_cmp_cb, - Eina_Key_Hash key_hash_cb) + Eina_Key_Hash key_hash_cb, + Eina_Free_Cb data_free_cb) { /* FIXME: Use mempool. */ Eina_Hash *new; @@ -370,12 +539,16 @@ eina_hash_new(Eina_Key_Length key_length_cb, eina_error_set(0); if (!key_length_cb || !key_cmp_cb) return NULL; - new = calloc(1, sizeof (Eina_Hash)); + new = malloc(sizeof (Eina_Hash)); if (!new) goto on_error; new->key_length_cb = key_length_cb; new->key_cmp_cb = key_cmp_cb; new->key_hash_cb = key_hash_cb; + new->data_free_cb = data_free_cb; + new->population = 0; + + memset(new->buckets, 0, sizeof (new->buckets)); return new; @@ -385,19 +558,21 @@ eina_hash_new(Eina_Key_Length key_length_cb, } EAPI Eina_Hash * -eina_hash_string_djb2_new(void) +eina_hash_string_djb2_new(Eina_Free_Cb data_free_cb) { return eina_hash_new(EINA_KEY_LENGTH(_eina_string_key_length), EINA_KEY_CMP(_eina_string_key_cmp), - EINA_KEY_HASH(eina_hash_djb2)); + EINA_KEY_HASH(eina_hash_djb2), + data_free_cb); } EAPI Eina_Hash * -eina_hash_string_superfast_new(void) +eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb) { return eina_hash_new(EINA_KEY_LENGTH(_eina_string_key_length), EINA_KEY_CMP(_eina_string_key_cmp), - EINA_KEY_HASH(eina_hash_superfast)); + EINA_KEY_HASH(eina_hash_superfast), + data_free_cb); } /** @@ -437,18 +612,8 @@ eina_hash_free(Eina_Hash *hash) if (!hash) return; - /* FIXME: Should have used an iterator. */ - for (i = 0; i < 256; i++) - { - while (hash->buckets[i]) - { - Eina_Rbtree *el; - - el = hash->buckets[i]; - hash->buckets[i] = eina_rbtree_inline_remove(hash->buckets[i], el, EINA_RBTREE_CMP_NODE_CB(_eina_hash_rbtree_node), hash->key_cmp_cb); - free(el); - } - } + for (i = 0; i < EINA_HASH_BUCKET_SIZE; i++) + eina_rbtree_delete(hash->buckets[i], EINA_RBTREE_FREE_CB(_eina_hash_head_free), hash); free(hash); } @@ -481,32 +646,7 @@ eina_hash_add_by_hash(Eina_Hash *hash, const void *key, int key_length, int key_hash, const void *data) { - Eina_Hash_El *el; - - eina_error_set(0); - if ((!hash) || (!key) || (!data)) return EINA_FALSE; - - /* Alloc every needed thing.*/ - el = malloc(sizeof (Eina_Hash_El) + key_length); - if (!el) goto on_error; - - /* Setup the element */ - el->tuple.key_length = key_length; - el->tuple.data = (void *) data; - el->tuple.key = (char *) (el + 1); - memcpy((char *) el->tuple.key, key, key_length); - - /* eina hash have 256 buckets. */ - key_hash &= 0xFF; - - /* add the new element to the hash. */ - hash->buckets[key_hash] = eina_rbtree_inline_insert(hash->buckets[key_hash], &el->_node_data, EINA_RBTREE_CMP_NODE_CB(_eina_hash_rbtree_node), hash->key_cmp_cb); - hash->population++; - return EINA_TRUE; - - on_error: - eina_error_set(EINA_ERROR_OUT_OF_MEMORY); - return EINA_FALSE; + return eina_hash_add_alloc_by_hash(hash, key, key_length, key_length, key_hash, data); } /** @@ -539,31 +679,7 @@ eina_hash_direct_add_by_hash(Eina_Hash *hash, const void *key, int key_length, int key_hash, const void *data) { - Eina_Hash_El *el; - - eina_error_set(0); - if ((!hash) || (!key) || (!data)) return EINA_FALSE; - - /* Alloc every needed thing.*/ - el = malloc(sizeof (Eina_Hash_El)); - if (!el) goto on_error; - - /* Setup the element */ - el->tuple.key_length = key_length; - el->tuple.data = (void *) data; - el->tuple.key = key; - - /* eina hash have 256 buckets. */ - key_hash &= 0xFF; - - /* add the new element to the hash. */ - hash->buckets[key_hash] = eina_rbtree_inline_insert(hash->buckets[key_hash], &el->_node_data, EINA_RBTREE_CMP_NODE_CB(_eina_hash_rbtree_node), hash->key_cmp_cb); - hash->population++; - return EINA_TRUE; - - on_error: - eina_error_set(EINA_ERROR_OUT_OF_MEMORY); - return EINA_FALSE; + return eina_hash_add_alloc_by_hash(hash, key, key_length, 0, key_hash, data); } /** @@ -653,6 +769,7 @@ EAPI Eina_Bool eina_hash_del_by_hash(Eina_Hash *hash, const void *key, int key_length, int key_hash, const void *data) { Eina_Hash_El *el = NULL; + Eina_Hash_Head *eh; Eina_Hash_Tuple tuple; tuple.key = (void *) key; @@ -660,16 +777,23 @@ eina_hash_del_by_hash(Eina_Hash *hash, const void *key, int key_length, int key_ tuple.data = (void *) data; if (!hash) return EINA_FALSE; - if (!key) el = _eina_hash_find_by_data(hash, data, &key_hash); - else el = _eina_hash_find_by_hash(hash, &tuple, key_hash); + if (!key) el = _eina_hash_find_by_data(hash, data, &key_hash, &eh); + else el = _eina_hash_find_by_hash(hash, &tuple, key_hash, &eh); if (!el) return EINA_FALSE; if (data && el->tuple.data != data) return EINA_FALSE; - key_hash &= 0xFF; + eh->head = eina_rbtree_inline_remove(eh->head, EINA_RBTREE_GET(el), EINA_RBTREE_CMP_NODE_CB(_eina_hash_key_rbtree_cmp_node), hash->key_cmp_cb); + if (el->begin == EINA_FALSE) free(el); + + if (!eh->head) + { + key_hash &= EINA_HASH_BUCKET_MASK; + + hash->buckets[key_hash] = eina_rbtree_inline_remove(hash->buckets[key_hash], EINA_RBTREE_GET(eh), EINA_RBTREE_CMP_NODE_CB(_eina_hash_hash_rbtree_cmp_node), NULL); + free(eh); + } - hash->buckets[key_hash] = eina_rbtree_inline_remove(hash->buckets[key_hash], &el->_node_data, EINA_RBTREE_CMP_NODE_CB(_eina_hash_rbtree_node), hash->key_cmp_cb); - free(el); hash->population--; return EINA_TRUE; @@ -717,6 +841,7 @@ eina_hash_del(Eina_Hash *hash, const void *key, const void *data) EAPI void * eina_hash_find_by_hash(const Eina_Hash *hash, const void *key, int key_length, int key_hash) { + Eina_Hash_Head *eh; Eina_Hash_El *el; Eina_Hash_Tuple tuple; @@ -726,7 +851,7 @@ eina_hash_find_by_hash(const Eina_Hash *hash, const void *key, int key_length, i tuple.key_length = key_length; tuple.data = NULL; - el = _eina_hash_find_by_hash(hash, &tuple, key_hash); + el = _eina_hash_find_by_hash(hash, &tuple, key_hash, &eh); if (el) return el->tuple.data; return NULL; } @@ -766,6 +891,7 @@ eina_hash_find(const Eina_Hash *hash, const void *key) EAPI void * eina_hash_modify_by_hash(Eina_Hash *hash, const void *key, int key_length, int key_hash, const void *data) { + Eina_Hash_Head *eh; Eina_Hash_El *el; void *old_data = NULL; Eina_Hash_Tuple tuple; @@ -776,7 +902,7 @@ eina_hash_modify_by_hash(Eina_Hash *hash, const void *key, int key_length, int k tuple.key_length = key_length; tuple.data = NULL; - el = _eina_hash_find_by_hash(hash, &tuple, key_hash); + el = _eina_hash_find_by_hash(hash, &tuple, key_hash, &eh); if (el) { old_data = el->tuple.data; diff --git a/legacy/eina/src/lib/eina_mempool.c b/legacy/eina/src/lib/eina_mempool.c index bf5e967636..10f74abf8f 100644 --- a/legacy/eina/src/lib/eina_mempool.c +++ b/legacy/eina/src/lib/eina_mempool.c @@ -113,7 +113,7 @@ eina_mempool_init(void) eina_module_init(); EINA_ERROR_NOT_MEMPOOL_MODULE = eina_error_msg_register("Not a memory pool module."); - _backends = eina_hash_string_superfast_new(); + _backends = eina_hash_string_superfast_new(NULL); /* dynamic backends */ _modules = eina_module_list_get(PACKAGE_LIB_DIR "/eina/mp/", 0, NULL, NULL); eina_module_list_load(_modules); diff --git a/legacy/eina/src/lib/eina_rbtree.c b/legacy/eina/src/lib/eina_rbtree.c index 2b5b05a92b..078074d462 100644 --- a/legacy/eina/src/lib/eina_rbtree.c +++ b/legacy/eina/src/lib/eina_rbtree.c @@ -448,12 +448,12 @@ eina_rbtree_iterator_postfix(const Eina_Rbtree *root) } EAPI void -eina_rbtree_delete(Eina_Rbtree *root, Eina_Rbtree_Free_Cb func) +eina_rbtree_delete(Eina_Rbtree *root, Eina_Rbtree_Free_Cb func, void *data) { if (!root) return ; - eina_rbtree_delete(root->son[0], func); - eina_rbtree_delete(root->son[1], func); - func(root); + eina_rbtree_delete(root->son[0], func, data); + eina_rbtree_delete(root->son[1], func, data); + func(root, data); } diff --git a/legacy/eina/src/lib/eina_stringshare.c b/legacy/eina/src/lib/eina_stringshare.c index 3c7d08a6f1..91a7b87f12 100644 --- a/legacy/eina/src/lib/eina_stringshare.c +++ b/legacy/eina/src/lib/eina_stringshare.c @@ -129,7 +129,7 @@ _eina_stringshare_node(const Eina_Stringshare_Head *left, const Eina_Stringshare } static void -_eina_stringshare_head_free(Eina_Stringshare_Head *ed) +_eina_stringshare_head_free(Eina_Stringshare_Head *ed, __UNUSED__ void *data) { while (ed->head) { @@ -234,7 +234,7 @@ eina_stringshare_shutdown() /* remove any string still in the table */ for (i = 0; i < EINA_STRINGSHARE_BUCKETS; i++) { - eina_rbtree_delete(EINA_RBTREE_GET(share->buckets[i]), EINA_RBTREE_FREE_CB(_eina_stringshare_head_free)); + eina_rbtree_delete(EINA_RBTREE_GET(share->buckets[i]), EINA_RBTREE_FREE_CB(_eina_stringshare_head_free), NULL); share->buckets[i] = NULL; } free(share); diff --git a/legacy/eina/src/tests/eina_bench_hash.c b/legacy/eina/src/tests/eina_bench_hash.c index af2ea6032e..ee98ae0e34 100644 --- a/legacy/eina/src/tests/eina_bench_hash.c +++ b/legacy/eina/src/tests/eina_bench_hash.c @@ -66,6 +66,12 @@ _eina_bench_rbtree_key(const Eina_Bench_Rbtree *node, const char *key, int lengt return strncmp(node->key, key, length); } +static void +_eina_bench_rbtree_free(Eina_Rbtree *node, __UNUSED__ void *data) +{ + free(node); +} + static void eina_bench_lookup_rbtree(int request) { @@ -97,26 +103,17 @@ eina_bench_lookup_rbtree(int request) tmp = eina_rbtree_inline_lookup(root, tmp_key, 10, EINA_RBTREE_CMP_KEY_CB(_eina_bench_rbtree_key), NULL); } - while (root) - { - tmp = root; - root = eina_rbtree_inline_remove(root, root, EINA_RBTREE_CMP_NODE_CB(_eina_bench_rbtree_cmp), NULL); - free(tmp); - } + eina_rbtree_delete(root, EINA_RBTREE_FREE_CB(_eina_bench_rbtree_free), NULL); } static void eina_bench_lookup_superfast(int request) { Eina_Hash *hash = NULL; - Eina_Array *array = NULL; int *tmp_val; - Eina_Array_Iterator it; unsigned int i; - array = eina_array_new(1000); - - hash = eina_hash_string_superfast_new(); + hash = eina_hash_string_superfast_new(free); for (i = 0; i < (unsigned int) request; ++i) { @@ -130,8 +127,6 @@ eina_bench_lookup_superfast(int request) *tmp_val = i; eina_hash_add(hash, tmp_key, tmp_val); - - eina_array_push(array, tmp_val); } srand(time(NULL)); @@ -146,25 +141,16 @@ eina_bench_lookup_superfast(int request) } eina_hash_free(hash); - - EINA_ARRAY_ITER_NEXT(array, i, tmp_val, it) - free(tmp_val); - - eina_array_free(array); } static void eina_bench_lookup_djb2(int request) { Eina_Hash *hash = NULL; - Eina_Array *array = NULL; int *tmp_val; - Eina_Array_Iterator it; unsigned int i; - array = eina_array_new(1000); - - hash = eina_hash_string_djb2_new(); + hash = eina_hash_string_djb2_new(free); for (i = 0; i < (unsigned int) request; ++i) { @@ -178,8 +164,6 @@ eina_bench_lookup_djb2(int request) *tmp_val = i; eina_hash_add(hash, tmp_key, tmp_val); - - eina_array_push(array, tmp_val); } srand(time(NULL)); @@ -194,41 +178,37 @@ eina_bench_lookup_djb2(int request) } eina_hash_free(hash); - - EINA_ARRAY_ITER_NEXT(array, i, tmp_val, it) - free(tmp_val); - - eina_array_free(array); } +typedef struct _Eina_Bench_DJB2 Eina_Bench_DJB2; +struct _Eina_Bench_DJB2 +{ + char *key; + int value; +}; + static void eina_bench_lookup_djb2_inline(int request) { Eina_Hash *hash = NULL; - Eina_Array *array = NULL; - int *tmp_val; - Eina_Array_Iterator it; + Eina_Bench_DJB2 *elm; unsigned int i; - array = eina_array_new(1000); - - hash = eina_hash_string_djb2_new(); + hash = eina_hash_string_djb2_new(free); for (i = 0; i < (unsigned int) request; ++i) { - char tmp_key[10]; int length; - tmp_val = malloc(sizeof (int)); + elm = malloc(sizeof (Eina_Bench_DJB2) + 10); + if (!elm) continue ; - if (!tmp_key || !tmp_val) continue ; + elm->key = (char*) (elm + 1); - length = eina_convert_itoa(i, tmp_key) + 1; - *tmp_val = i; + length = eina_convert_itoa(i, elm->key) + 1; + elm->value = i; - eina_hash_add_by_hash(hash, tmp_key, length, eina_hash_djb2(tmp_key, length), tmp_val); - - eina_array_push(array, tmp_val); + eina_hash_direct_add_by_hash(hash, elm->key, length, eina_hash_superfast(elm->key, length), elm); } srand(time(NULL)); @@ -236,19 +216,14 @@ eina_bench_lookup_djb2_inline(int request) for (i = 0; i < (unsigned int) request; ++i) { char tmp_key[10]; - int length; + int length = 6; length = eina_convert_itoa(rand() % request, tmp_key) + 1; - tmp_val = eina_hash_find_by_hash(hash, tmp_key, length, eina_hash_djb2(tmp_key, length)); + elm = eina_hash_find_by_hash(hash, tmp_key, length, eina_hash_superfast(tmp_key, length)); } eina_hash_free(hash); - - EINA_ARRAY_ITER_NEXT(array, i, tmp_val, it) - free(tmp_val); - - eina_array_free(array); } #ifdef EINA_BENCH_HAVE_GLIB @@ -401,8 +376,10 @@ void eina_bench_hash(Eina_Benchmark *bench) eina_benchmark_register(bench, "ghash-lookup", EINA_BENCHMARK(eina_bench_lookup_ghash), 1000, 180000, 2500); #endif #ifdef EINA_BENCH_HAVE_EVAS +#if 0 eina_benchmark_register(bench, "evas-lookup", EINA_BENCHMARK(eina_bench_lookup_evas), 1000, 180000, 2500); #endif +#endif #ifdef EINA_BENCH_HAVE_ECORE eina_benchmark_register(bench, "ecore-lookup", EINA_BENCHMARK(eina_bench_lookup_ecore), 1000, 180000, 2500); #endif diff --git a/legacy/eina/src/tests/eina_test_hash.c b/legacy/eina/src/tests/eina_test_hash.c index 2de244ed27..ca4d3bebf9 100644 --- a/legacy/eina/src/tests/eina_test_hash.c +++ b/legacy/eina/src/tests/eina_test_hash.c @@ -60,9 +60,10 @@ START_TEST(eina_hash_simple) int *test; int array[] = { 1, 42, 4, 5, 6 }; - fail_if(eina_hash_init() <= 0); + /* As mempool is already initialized and it use hash, we should have 2 init. */ + fail_if(eina_hash_init() != 2); - hash = eina_hash_string_superfast_new(); + hash = eina_hash_string_superfast_new(NULL); fail_if(hash == NULL); fail_if(eina_hash_add(hash, "1", &array[0]) != EINA_TRUE); @@ -106,7 +107,8 @@ START_TEST(eina_hash_simple) eina_hash_free(hash); - fail_if(eina_hash_shutdown() > 0); + /* Same comment as eina_hash_init */ + fail_if(eina_hash_shutdown() != 1); } END_TEST @@ -115,9 +117,9 @@ START_TEST(eina_hash_extended) Eina_Hash *hash = NULL; int i; - fail_if(eina_hash_init() <= 0); + fail_if(eina_hash_init() != 2); - hash = eina_hash_string_djb2_new(); + hash = eina_hash_string_djb2_new(NULL); fail_if(hash == NULL); fail_if(eina_hash_direct_add(hash, "42", "42") != EINA_TRUE); @@ -134,7 +136,7 @@ START_TEST(eina_hash_extended) eina_hash_free(hash); - fail_if(eina_hash_shutdown() > 0); + fail_if(eina_hash_shutdown() != 1); } END_TEST @@ -144,9 +146,9 @@ START_TEST(eina_hash_double_item) int i[] = { 7, 7 }; int *test; - fail_if(eina_hash_init() <= 0); + fail_if(eina_hash_init() != 2); - hash = eina_hash_string_superfast_new(); + hash = eina_hash_string_superfast_new(NULL); fail_if(hash == NULL); fail_if(eina_hash_add(hash, "7", &i[0]) != EINA_TRUE); @@ -158,7 +160,7 @@ START_TEST(eina_hash_double_item) eina_hash_free(hash); - fail_if(eina_hash_shutdown() > 0); + fail_if(eina_hash_shutdown() != 1); } END_TEST diff --git a/legacy/eina/src/tests/eina_test_iterator.c b/legacy/eina/src/tests/eina_test_iterator.c index 679f728f2d..2a511f5a2d 100644 --- a/legacy/eina/src/tests/eina_test_iterator.c +++ b/legacy/eina/src/tests/eina_test_iterator.c @@ -112,7 +112,7 @@ START_TEST(eina_iterator_hash_simple) eina_hash_init(); - hash = eina_hash_string_superfast_new(); + hash = eina_hash_string_superfast_new(NULL); fail_if(hash == NULL); fail_if(eina_hash_add(hash, "1", &array[0]) != EINA_TRUE);