1 #include "ecore_private.h"
3 #include "Ecore_Data.h"
5 #define PRIME_TABLE_MAX 21
7 #define PRIME_MAX 16777213
9 #define ECORE_HASH_CHAIN_MAX 3
11 #define ECORE_COMPUTE_HASH(hash, key) hash->hash_func(key) % \
12 ecore_prime_table[hash->size];
14 #define ECORE_HASH_INCREASE(hash) ((hash && ecore_prime_table[hash->size] < PRIME_MAX) ? \
15 (hash->nodes / ecore_prime_table[hash->size]) > \
16 ECORE_HASH_CHAIN_MAX : FALSE)
17 #define ECORE_HASH_REDUCE(hash) ((hash && ecore_prime_table[hash->size] > PRIME_MIN) ? \
18 (double)hash->nodes / (double)ecore_prime_table[hash->size-1] \
19 < ((double)ECORE_HASH_CHAIN_MAX * 0.375) : FALSE)
21 /* Private hash manipulation functions */
22 static int _ecore_hash_node_add(Ecore_Hash *hash, Ecore_Hash_Node *node);
23 static Ecore_Hash_Node * _ecore_hash_node_get(Ecore_Hash *hash, const void *key);
24 static int _ecore_hash_increase(Ecore_Hash *hash);
25 static int _ecore_hash_decrease(Ecore_Hash *hash);
26 inline int _ecore_hash_rehash(Ecore_Hash *hash, Ecore_Hash_Node **old_table, int old_size);
27 static int _ecore_hash_bucket_destroy(Ecore_Hash_Node *list, Ecore_Free_Cb keyd,
28 Ecore_Free_Cb valued);
29 inline Ecore_Hash_Node * _ecore_hash_bucket_get(Ecore_Hash *hash,
30 Ecore_Hash_Node *bucket, const void *key);
32 static Ecore_Hash_Node *_ecore_hash_node_new(void *key, void *value);
33 static int _ecore_hash_node_init(Ecore_Hash_Node *node, void *key, void *value);
34 static int _ecore_hash_node_destroy(Ecore_Hash_Node *node, Ecore_Free_Cb keyd,
35 Ecore_Free_Cb valued);
38 * @defgroup Ecore_Data_Hash_ADT_Creation_Group Hash Creation Functions
40 * Functions that create hash tables.
44 * Creates and initializes a new hash
45 * @param hash_func The function for determining hash position.
46 * @param compare The function for comparing node keys.
47 * @return @c NULL on error, a new hash on success.
48 * @ingroup Ecore_Data_Hash_ADT_Creation_Group
51 ecore_hash_new(Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare)
53 Ecore_Hash *new_hash = (Ecore_Hash *)malloc(sizeof(Ecore_Hash));
57 if (!ecore_hash_init(new_hash, hash_func, compare))
67 * Initializes the given hash.
68 * @param hash The given hash.
69 * @param hash_func The function used for hashing node keys.
70 * @param compare The function used for comparing node keys.
71 * @return @c TRUE on success, @c FALSE on an error.
72 * @ingroup Ecore_Data_Hash_ADT_Creation_Group
75 ecore_hash_init(Ecore_Hash *hash, Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare)
77 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
79 memset(hash, 0, sizeof(Ecore_Hash));
81 hash->hash_func = hash_func;
82 hash->compare = compare;
84 hash->buckets = (Ecore_Hash_Node **)calloc(ecore_prime_table[0],
85 sizeof(Ecore_Hash_Node *));
91 * @defgroup Ecore_Data_Hash_ADT_Destruction_Group Hash Destruction Functions
93 * Functions that destroy hash tables and their contents.
97 * Sets the function to destroy the keys of the given hash.
98 * @param hash The given hash.
99 * @param function The function used to free the node keys. NULL is a
100 * valid value and means that no function will be called.
101 * @return @c TRUE on success, @c FALSE on error.
102 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
105 ecore_hash_free_key_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function)
107 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
109 hash->free_key = function;
115 * Sets the function to destroy the values in the given hash.
116 * @param hash The given hash.
117 * @param function The function that will free the node values. NULL is a
118 * valid value and means that no function will be called.
119 * @return @c TRUE on success, @c FALSE on error
120 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
123 ecore_hash_free_value_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function)
125 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
127 hash->free_value = function;
133 * @defgroup Ecore_Data_Hash_ADT_Data_Group Hash Data Functions
135 * Functions that set, access and delete values from the hash tables.
139 * Sets a key-value pair in the given hash table.
140 * @param hash The given hash table.
141 * @param key The key.
142 * @param value The value.
143 * @return @c TRUE if successful, @c FALSE if not.
144 * @ingroup Ecore_Data_Hash_ADT_Data_Group
147 ecore_hash_set(Ecore_Hash *hash, void *key, void *value)
150 Ecore_Hash_Node *node;
152 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
154 node = _ecore_hash_node_get(hash, key);
157 if (hash->free_key) hash->free_key(key);
158 if (node->value && hash->free_value) hash->free_value(node->value);
164 node = _ecore_hash_node_new(key, value);
166 ret = _ecore_hash_node_add(hash, node);
173 * Sets all key-value pairs from set in the given hash table.
174 * @param hash The given hash table.
175 * @param set The hash table to import.
176 * @return @c TRUE if successful, @c FALSE if not.
177 * @ingroup Ecore_Data_Hash_ADT_Data_Group
180 ecore_hash_hash_set(Ecore_Hash *hash, Ecore_Hash *set)
183 Ecore_Hash_Node *node, *old;
185 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
186 CHECK_PARAM_POINTER_RETURN("set", set, FALSE);
188 for (i = 0; i < ecore_prime_table[set->size]; i++)
190 /* Hash into a new list to avoid loops of rehashing the same nodes */
191 while ((old = set->buckets[i]))
193 set->buckets[i] = old->next;
195 node = _ecore_hash_node_get(hash, old->key);
198 /* This key already exists. Delete the old and add the new
200 if (hash->free_key) hash->free_key(node->key);
201 if (hash->free_value) hash->free_key(node->value);
202 node->key = old->key;
203 node->value = old->value;
207 _ecore_hash_node_add(hash, old);
211 ecore_hash_init(set, set->hash_func, set->compare);
216 * Frees the hash table and the data contained inside it.
217 * @param hash The hash table to destroy.
218 * @return @c TRUE on success, @c FALSE on error.
219 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
222 ecore_hash_destroy(Ecore_Hash *hash)
226 CHECK_PARAM_POINTER("hash", hash);
230 while (i < ecore_prime_table[hash->size])
232 if (hash->buckets[i])
234 Ecore_Hash_Node *bucket;
237 * Remove the bucket list to avoid possible recursion
238 * on the free callbacks.
240 bucket = hash->buckets[i];
241 hash->buckets[i] = NULL;
242 _ecore_hash_bucket_destroy(bucket,
257 * @defgroup Ecore_Data_Hash_ADT_Traverse_Group Hash Traverse Functions
259 * Functions that iterate through hash tables.
263 * Counts the number of nodes in a hash table.
264 * @param hash The hash table to count current nodes.
265 * @return The number of nodes in the hash.
266 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
269 ecore_hash_count(Ecore_Hash *hash)
271 CHECK_PARAM_POINTER_RETURN("hash", hash, 0);
277 * Runs the @p for_each_func function on each entry in the given hash.
278 * @param hash The given hash.
279 * @param for_each_func The function that each entry is passed to.
280 * @param user_data a pointer passed to calls of for_each_func
281 * @return TRUE on success, FALSE otherwise.
282 * @ingroup Ecore_Data_Hash_ADT_Traverse_Group
285 ecore_hash_for_each_node(Ecore_Hash *hash, Ecore_For_Each for_each_func, void *user_data)
289 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
290 CHECK_PARAM_POINTER_RETURN("for_each_func", for_each_func, FALSE);
292 while (i < ecore_prime_table[hash->size])
294 if (hash->buckets[i])
296 Ecore_Hash_Node *node;
298 for (node = hash->buckets[i]; node; node = node->next)
300 for_each_func(node, user_data);
310 * Retrieves an ecore_list of all keys in the given hash.
311 * @param hash The given hash.
312 * @return new ecore_list on success, NULL otherwise
313 * @ingroup Ecore_Data_Hash_ADT_Traverse_Group
316 ecore_hash_keys(Ecore_Hash *hash)
321 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
323 keys = ecore_list_new();
324 while (i < ecore_prime_table[hash->size])
326 if (hash->buckets[i])
328 Ecore_Hash_Node *node;
330 for (node = hash->buckets[i]; node; node = node->next)
332 ecore_list_append(keys, node->key);
337 ecore_list_first_goto(keys);
343 * Prints the distribution of the given hash table for graphing.
344 * @param hash The given hash table.
347 ecore_hash_dump_graph(Ecore_Hash *hash)
351 for (i = 0; i < ecore_prime_table[hash->size]; i++)
352 if (hash->buckets[i])
355 Ecore_Hash_Node *node;
356 for (node = hash->buckets[i]; node; node = node->next)
358 printf("%d\t%u\n", i, n);
361 printf("%d\t0\n", i);
365 * Prints the distribution of the given hash table for graphing.
366 * @param hash The given hash table.
369 ecore_hash_dump_stats(Ecore_Hash *hash)
372 double variance, sum_n_2 = 0, sum_n = 0;
374 for (i = 0; i < ecore_prime_table[hash->size]; i++)
376 if (hash->buckets[i])
379 Ecore_Hash_Node *node;
380 for (node = hash->buckets[i]; node; node = node->next)
382 sum_n_2 += ((double)n * (double)n);
386 variance = (sum_n_2 - ((sum_n * sum_n) / (double)i)) / (double)i;
387 printf("Average length: %f\n\tvariance^2: %f\n", (sum_n / (double)i),
392 _ecore_hash_bucket_destroy(Ecore_Hash_Node *list, Ecore_Free_Cb keyd, Ecore_Free_Cb valued)
394 Ecore_Hash_Node *node;
396 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
398 for (node = list; node; node = list)
401 _ecore_hash_node_destroy(node, keyd, valued);
408 * @brief Add the node to the hash table
409 * @param hash: the hash table to add the key
410 * @param node: the node to add to the hash table
411 * @return Returns FALSE on error, TRUE on success
414 _ecore_hash_node_add(Ecore_Hash *hash, Ecore_Hash_Node *node)
416 unsigned int hash_val;
418 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
419 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
421 /* Check to see if the hash needs to be resized */
422 if (ECORE_HASH_INCREASE(hash))
423 _ecore_hash_increase(hash);
425 /* Compute the position in the table */
426 if (!hash->hash_func)
427 hash_val = (unsigned int)node->key % ecore_prime_table[hash->size];
429 hash_val = ECORE_COMPUTE_HASH(hash, node->key);
431 /* Prepend the node to the list at the index position */
432 node->next = hash->buckets[hash_val];
433 hash->buckets[hash_val] = node;
440 * Retrieves the value associated with the given key from the given hash
442 * @param hash The given hash table.
443 * @param key The key to search for.
444 * @return The value corresponding to key on success, @c NULL otherwise.
445 * @ingroup Ecore_Data_Hash_ADT_Data_Group
448 ecore_hash_get(Ecore_Hash *hash, const void *key)
451 Ecore_Hash_Node *node;
453 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
455 node = _ecore_hash_node_get(hash, key);
465 * Removes the value associated with the given key in the given hash
467 * @param hash The given hash table.
468 * @param key The key to search for.
469 * @return The value corresponding to the key on success. @c NULL is
470 * returned if there is an error.
471 * @ingroup Ecore_Data_Hash_ADT_Data_Group
474 ecore_hash_remove(Ecore_Hash *hash, const void *key)
476 Ecore_Hash_Node *node = NULL;
477 Ecore_Hash_Node *list;
478 unsigned int hash_val;
481 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
483 /* Compute the position in the table */
484 if (!hash->hash_func)
485 hash_val = (unsigned int )key % ecore_prime_table[hash->size];
487 hash_val = ECORE_COMPUTE_HASH(hash, key);
490 * If their is a list that could possibly hold the key/value pair
491 * traverse it and remove the hash node.
493 if (hash->buckets[hash_val])
495 list = hash->buckets[hash_val];
498 * Traverse the list to find the specified key
503 while ((node) && (hash->compare(node->key, key) != 0))
511 while ((node) && (node->key != key))
519 * Remove the node with the matching key and free it's memory
524 hash->buckets[hash_val] = node->next;
526 list->next = node->next;
529 _ecore_hash_node_destroy(node, hash->free_key, NULL);
534 if (ECORE_HASH_REDUCE(hash))
535 _ecore_hash_decrease(hash);
541 * Retrieves the first value that matches
543 * @param hash The given hash table.
544 * @param key The key to search for.
545 * @return The value corresponding to key on success, @c NULL otherwise.
546 * @ingroup Ecore_Data_Hash_ADT_Data_Group
549 ecore_hash_find(Ecore_Hash *hash, Ecore_Compare_Cb compare, const void *value)
553 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
554 CHECK_PARAM_POINTER_RETURN("compare", compare, NULL);
555 CHECK_PARAM_POINTER_RETURN("value", value, NULL);
557 while (i < ecore_prime_table[hash->size])
559 if (hash->buckets[i])
561 Ecore_Hash_Node *node;
563 for (node = hash->buckets[i]; node; node = node->next)
565 if (!compare(node->value, value)) return node->value;
575 * @brief Retrieve the node associated with key
576 * @param hash: the hash table to search for the key
577 * @param key: the key to search for in the hash table
578 * @return Returns NULL on error, node corresponding to key on success
580 static Ecore_Hash_Node *
581 _ecore_hash_node_get(Ecore_Hash *hash, const void *key)
583 unsigned int hash_val;
584 Ecore_Hash_Node *node = NULL;
586 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
593 /* Compute the position in the table */
594 if (!hash->hash_func)
595 hash_val = (unsigned int )key % ecore_prime_table[hash->size];
597 hash_val = ECORE_COMPUTE_HASH(hash, key);
599 /* Grab the bucket at the specified position */
600 if (hash->buckets[hash_val])
602 node = _ecore_hash_bucket_get(hash, hash->buckets[hash_val], key);
604 * Move matched node to the front of the list as it's likely
605 * to be searched for again soon.
607 if (node && node != hash->buckets[hash_val])
609 node->next = hash->buckets[hash_val];
610 hash->buckets[hash_val] = node;
618 * @brief Search the hash bucket for a specified key
619 * @param hash: the hash table to retrieve the comparison function
620 * @param bucket: the list to search for the key
621 * @param key: the key to search for in the list
622 * @return Returns NULL on error or not found, the found node on success
624 inline Ecore_Hash_Node *
625 _ecore_hash_bucket_get(Ecore_Hash *hash, Ecore_Hash_Node *bucket, const void *key)
627 Ecore_Hash_Node *prev = NULL;
628 Ecore_Hash_Node *node = NULL;
631 * Traverse the list to find the desired node, if the node is in the
632 * list, then return the node.
636 for (node = bucket; node; node = node->next)
638 if (hash->compare(node->key, key) == 0)
645 for (node = bucket; node; node = node->next)
647 if (node->key == key)
654 * Remove node from the list to replace it at the beginning.
658 prev->next = node->next;
666 * @brief Increase the size of the hash table by approx. 2 * current size
667 * @param hash: the hash table to increase the size of
668 * @return Returns TRUE on success, FALSE on error
671 _ecore_hash_increase(Ecore_Hash *hash)
675 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
677 /* Max size reached so return FALSE */
678 if ((ecore_prime_table[hash->size] == PRIME_MAX) || (hash->size == PRIME_TABLE_MAX))
682 * Increase the size of the hash and save a pointer to the old data
688 * Allocate a new bucket area, of the new larger size
690 hash->buckets = calloc(ecore_prime_table[hash->size], sizeof(Ecore_Hash_Node *));
693 * Make sure the allocation succeeded, if not replace the old data and
705 * Now move all of the old data into the new bucket area
707 if (_ecore_hash_rehash(hash, old, hash->size - 1))
714 * Free the old buckets regardless of success.
722 * @brief Decrease the size of the hash table by < 1/2 * current size
723 * @param hash: the hash table to decrease the size of
724 * @return Returns TRUE on success, FALSE on error
727 _ecore_hash_decrease(Ecore_Hash *hash)
729 Ecore_Hash_Node **old;
731 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
733 if (ecore_prime_table[hash->size] == PRIME_MIN)
737 * Decrease the hash size and store a pointer to the old data
743 * Allocate a new area to store the data
745 hash->buckets = (Ecore_Hash_Node **)calloc(ecore_prime_table[hash->size],
746 sizeof(Ecore_Hash_Node *));
749 * Make sure allocation succeeded otherwise rreturn to the previous
761 if (_ecore_hash_rehash(hash, old, hash->size + 1))
771 * @brief Rehash the nodes of a table into the hash table
772 * @param hash: the hash to place the nodes of the table
773 * @param table: the table to remove the nodes from and place in hash
774 * @return Returns TRUE on success, FALSE on error
777 _ecore_hash_rehash(Ecore_Hash *hash, Ecore_Hash_Node **old_table, int old_size)
780 Ecore_Hash_Node *old;
782 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
783 CHECK_PARAM_POINTER_RETURN("old_table", old_table, FALSE);
785 for (i = 0; i < ecore_prime_table[old_size]; i++)
787 /* Hash into a new list to avoid loops of rehashing the same nodes */
788 while ((old = old_table[i]))
790 old_table[i] = old->next;
792 _ecore_hash_node_add(hash, old);
800 * @brief Create a new hash node for key and value storage
801 * @param key: the key for this node
802 * @param value: the value that the key references
803 * @return Returns NULL on error, a new hash node on success
805 static Ecore_Hash_Node *
806 _ecore_hash_node_new(void *key, void *value)
808 Ecore_Hash_Node *node;
810 node = (Ecore_Hash_Node *)malloc(sizeof(Ecore_Hash_Node));
814 if (!_ecore_hash_node_init(node, key, value))
824 * @brief Initialize a hash node to some sane default values
825 * @param node: the node to set the values
826 * @param key: the key to reference this node
827 * @param value: the value that key refers to
828 * @return Returns TRUE on success, FALSE on error
831 _ecore_hash_node_init(Ecore_Hash_Node *node, void *key, void *value)
833 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
842 * @brief Destroy a node and call the specified callbacks to free data
843 * @param node: the node to be destroyed
844 * @param keyd: the function to free the key
845 * @param valued: the function to free the value
846 * @return Returns TRUE on success, FALSE on error
849 _ecore_hash_node_destroy(Ecore_Hash_Node *node, Ecore_Free_Cb keyd, Ecore_Free_Cb valued)
851 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);