9 #include "Ecore_Data.h"
11 #define PRIME_TABLE_MAX 21
13 #define PRIME_MAX 16777213
15 #define ECORE_HASH_CHAIN_MAX 3
17 #define ECORE_COMPUTE_HASH(hash, key) hash->hash_func(key) % \
18 ecore_prime_table[hash->size];
20 #define ECORE_HASH_INCREASE(hash) ((hash && ecore_prime_table[hash->size] < \
23 ecore_prime_table[hash->size]) > \
24 ECORE_HASH_CHAIN_MAX : FALSE)
25 #define ECORE_HASH_REDUCE(hash) ((hash && ecore_prime_table[hash->size] > \
27 (double)hash->nodes / \
28 (double)ecore_prime_table[hash->size - 1] \
29 < ((double)ECORE_HASH_CHAIN_MAX * \
33 static const unsigned int ecore_prime_table[] =
35 17, 31, 61, 127, 257, 509, 1021,
36 2053, 4093, 8191, 16381, 32771, 65537, 131071, 262147, 524287, 1048573,
37 2097143, 4194301, 8388617, 16777213
41 /* Private hash manipulation functions */
42 static int _ecore_hash_node_add(Ecore_Hash *hash,
43 Ecore_Hash_Node *node);
44 static Ecore_Hash_Node * _ecore_hash_node_get(Ecore_Hash *hash,
46 static int _ecore_hash_increase(Ecore_Hash *hash);
47 static int _ecore_hash_decrease(Ecore_Hash *hash);
48 static inline int _ecore_hash_rehash(Ecore_Hash *hash,
49 Ecore_Hash_Node **old_table,
51 static int _ecore_hash_bucket_destroy(Ecore_Hash_Node *list,
53 Ecore_Free_Cb valued);
54 static inline Ecore_Hash_Node *_ecore_hash_bucket_get(Ecore_Hash *hash,
55 Ecore_Hash_Node *bucket,
58 static Ecore_Hash_Node * _ecore_hash_node_new(void *key, void *value);
59 static int _ecore_hash_node_init(Ecore_Hash_Node *node,
62 static int _ecore_hash_node_destroy(Ecore_Hash_Node *node,
64 Ecore_Free_Cb valued);
67 * @defgroup Ecore_Data_Hash_ADT_Creation_Group Hash Creation Functions
69 * Functions that create hash tables.
73 * Creates and initializes a new hash
74 * @param hash_func The function for determining hash position.
75 * @param compare The function for comparing node keys.
76 * @return @c NULL on error, a new hash on success.
77 * @ingroup Ecore_Data_Hash_ADT_Creation_Group
80 ecore_hash_new(Ecore_Hash_Cb hash_func, Ecore_Compare_Cb compare)
82 Ecore_Hash *new_hash = (Ecore_Hash *)malloc(sizeof(Ecore_Hash));
86 if (!ecore_hash_init(new_hash, hash_func, compare))
96 * Initializes the given hash.
97 * @param hash The given hash.
98 * @param hash_func The function used for hashing node keys.
99 * @param compare The function used for comparing node keys.
100 * @return @c TRUE on success, @c FALSE on an error.
101 * @ingroup Ecore_Data_Hash_ADT_Creation_Group
104 ecore_hash_init(Ecore_Hash *hash,
105 Ecore_Hash_Cb hash_func,
106 Ecore_Compare_Cb compare)
108 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
110 memset(hash, 0, sizeof(Ecore_Hash));
112 hash->hash_func = hash_func;
113 hash->compare = compare;
115 hash->buckets = (Ecore_Hash_Node **)calloc(ecore_prime_table[0],
116 sizeof(Ecore_Hash_Node *));
122 * @defgroup Ecore_Data_Hash_ADT_Destruction_Group Hash Destruction Functions
124 * Functions that destroy hash tables and their contents.
128 * Sets the function to destroy the keys of the given hash.
129 * @param hash The given hash.
130 * @param function The function used to free the node keys. NULL is a
131 * valid value and means that no function will be called.
132 * @return @c TRUE on success, @c FALSE on error.
133 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
136 ecore_hash_free_key_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function)
138 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
140 hash->free_key = function;
146 * Sets the function to destroy the values in the given hash.
147 * @param hash The given hash.
148 * @param function The function that will free the node values. NULL is a
149 * valid value and means that no function will be called.
150 * @return @c TRUE on success, @c FALSE on error
151 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
154 ecore_hash_free_value_cb_set(Ecore_Hash *hash, Ecore_Free_Cb function)
156 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
158 hash->free_value = function;
164 * @defgroup Ecore_Data_Hash_ADT_Data_Group Hash Data Functions
166 * Functions that set, access and delete values from the hash tables.
170 * Sets a key-value pair in the given hash table.
171 * @param hash The given hash table.
172 * @param key The key.
173 * @param value The value.
174 * @return @c TRUE if successful, @c FALSE if not.
175 * @ingroup Ecore_Data_Hash_ADT_Data_Group
178 ecore_hash_set(Ecore_Hash *hash, void *key, void *value)
181 Ecore_Hash_Node *node;
183 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
185 node = _ecore_hash_node_get(hash, key);
191 if (node->value && hash->free_value)
192 hash->free_value(node->value);
199 node = _ecore_hash_node_new(key, value);
201 ret = _ecore_hash_node_add(hash, node);
208 * Sets all key-value pairs from set in the given hash table.
209 * @param hash The given hash table.
210 * @param set The hash table to import.
211 * @return @c TRUE if successful, @c FALSE if not.
212 * @ingroup Ecore_Data_Hash_ADT_Data_Group
215 ecore_hash_hash_set(Ecore_Hash *hash, Ecore_Hash *set)
218 Ecore_Hash_Node *node, *old;
220 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
221 CHECK_PARAM_POINTER_RETURN("set", set, FALSE);
223 for (i = 0; i < ecore_prime_table[set->size]; i++)
225 /* Hash into a new list to avoid loops of rehashing the same nodes */
226 while ((old = set->buckets[i]))
228 set->buckets[i] = old->next;
230 node = _ecore_hash_node_get(hash, old->key);
233 /* This key already exists. Delete the old and add the new
236 hash->free_key(node->key);
238 if (hash->free_value)
239 hash->free_key(node->value);
241 node->key = old->key;
242 node->value = old->value;
246 _ecore_hash_node_add(hash, old);
250 ecore_hash_init(set, set->hash_func, set->compare);
255 * Frees the hash table and the data contained inside it.
256 * @param hash The hash table to destroy.
257 * @return @c TRUE on success, @c FALSE on error.
258 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
261 ecore_hash_destroy(Ecore_Hash *hash)
265 CHECK_PARAM_POINTER("hash", hash);
269 while (i < ecore_prime_table[hash->size])
271 if (hash->buckets[i])
273 Ecore_Hash_Node *bucket;
276 * Remove the bucket list to avoid possible recursion
277 * on the free callbacks.
279 bucket = hash->buckets[i];
280 hash->buckets[i] = NULL;
281 _ecore_hash_bucket_destroy(bucket,
298 * @defgroup Ecore_Data_Hash_ADT_Traverse_Group Hash Traverse Functions
300 * Functions that iterate through hash tables.
304 * Counts the number of nodes in a hash table.
305 * @param hash The hash table to count current nodes.
306 * @return The number of nodes in the hash.
307 * @ingroup Ecore_Data_Hash_ADT_Destruction_Group
310 ecore_hash_count(Ecore_Hash *hash)
312 CHECK_PARAM_POINTER_RETURN("hash", hash, 0);
318 * Runs the @p for_each_func function on each entry in the given hash.
319 * @param hash The given hash.
320 * @param for_each_func The function that each entry is passed to.
321 * @param user_data a pointer passed to calls of for_each_func
322 * @return TRUE on success, FALSE otherwise.
323 * @ingroup Ecore_Data_Hash_ADT_Traverse_Group
326 ecore_hash_for_each_node(Ecore_Hash *hash,
327 Ecore_For_Each for_each_func,
332 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
333 CHECK_PARAM_POINTER_RETURN("for_each_func", for_each_func, FALSE);
335 while (i < ecore_prime_table[hash->size])
337 if (hash->buckets[i])
339 Ecore_Hash_Node *node;
341 for (node = hash->buckets[i]; node; node = node->next)
343 for_each_func(node, user_data);
354 * Retrieves an ecore_list of all keys in the given hash.
355 * @param hash The given hash.
356 * @return new ecore_list on success, NULL otherwise
357 * @ingroup Ecore_Data_Hash_ADT_Traverse_Group
360 ecore_hash_keys(Ecore_Hash *hash)
365 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
367 keys = ecore_list_new();
368 while (i < ecore_prime_table[hash->size])
370 if (hash->buckets[i])
372 Ecore_Hash_Node *node;
374 for (node = hash->buckets[i]; node; node = node->next)
376 ecore_list_append(keys, node->key);
382 ecore_list_first_goto(keys);
388 * Prints the distribution of the given hash table for graphing.
389 * @param hash The given hash table.
392 ecore_hash_dump_graph(Ecore_Hash *hash)
396 for (i = 0; i < ecore_prime_table[hash->size]; i++)
397 if (hash->buckets[i])
400 Ecore_Hash_Node *node;
401 for (node = hash->buckets[i]; node; node = node->next)
403 printf("%d\t%u", i, n);
411 * Prints the distribution of the given hash table for graphing.
412 * @param hash The given hash table.
415 ecore_hash_dump_stats(Ecore_Hash *hash)
418 double variance, sum_n_2 = 0, sum_n = 0;
420 for (i = 0; i < ecore_prime_table[hash->size]; i++)
422 if (hash->buckets[i])
425 Ecore_Hash_Node *node;
426 for (node = hash->buckets[i]; node; node = node->next)
428 sum_n_2 += ((double)n * (double)n);
432 variance = (sum_n_2 - ((sum_n * sum_n) / (double)i)) / (double)i;
433 printf("Average length: %f\n\tvariance^2: %f", (sum_n / (double)i),
438 _ecore_hash_bucket_destroy(Ecore_Hash_Node *list,
440 Ecore_Free_Cb valued)
442 Ecore_Hash_Node *node;
444 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
446 for (node = list; node; node = list)
449 _ecore_hash_node_destroy(node, keyd, valued);
456 * @brief Add the node to the hash table
457 * @param hash: the hash table to add the key
458 * @param node: the node to add to the hash table
459 * @return Returns FALSE on error, TRUE on success
462 _ecore_hash_node_add(Ecore_Hash *hash, Ecore_Hash_Node *node)
464 unsigned long hash_val;
466 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
467 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
469 /* Check to see if the hash needs to be resized */
470 if (ECORE_HASH_INCREASE(hash))
471 _ecore_hash_increase(hash);
473 /* Compute the position in the table */
474 if (!hash->hash_func)
475 hash_val = (unsigned long)node->key % ecore_prime_table[hash->size];
477 hash_val = ECORE_COMPUTE_HASH(hash, node->key);
479 /* Prepend the node to the list at the index position */
480 node->next = hash->buckets[hash_val];
481 hash->buckets[hash_val] = node;
488 * Retrieves the value associated with the given key from the given hash
490 * @param hash The given hash table.
491 * @param key The key to search for.
492 * @return The value corresponding to key on success, @c NULL otherwise.
493 * @ingroup Ecore_Data_Hash_ADT_Data_Group
496 ecore_hash_get(Ecore_Hash *hash, const void *key)
499 Ecore_Hash_Node *node;
501 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
503 node = _ecore_hash_node_get(hash, key);
513 * Removes the value associated with the given key in the given hash
515 * @param hash The given hash table.
516 * @param key The key to search for.
517 * @return The value corresponding to the key on success. @c NULL is
518 * returned if there is an error.
519 * @ingroup Ecore_Data_Hash_ADT_Data_Group
522 ecore_hash_remove(Ecore_Hash *hash, const void *key)
524 Ecore_Hash_Node *node = NULL;
525 Ecore_Hash_Node *list;
526 unsigned long hash_val;
529 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
531 /* Compute the position in the table */
532 if (!hash->hash_func)
533 hash_val = (unsigned long )key % ecore_prime_table[hash->size];
535 hash_val = ECORE_COMPUTE_HASH(hash, key);
538 * If their is a list that could possibly hold the key/value pair
539 * traverse it and remove the hash node.
541 if (hash->buckets[hash_val])
543 list = hash->buckets[hash_val];
546 * Traverse the list to find the specified key
550 while ((node) && (hash->compare(node->key, key) != 0))
556 while ((node) && (node->key != key))
563 * Remove the node with the matching key and free it's memory
568 hash->buckets[hash_val] = node->next;
570 list->next = node->next;
574 _ecore_hash_node_destroy(node, hash->free_key, NULL);
579 if (ECORE_HASH_REDUCE(hash))
580 _ecore_hash_decrease(hash);
586 * Retrieves the first value that matches
588 * @param hash The given hash table.
589 * @param key The key to search for.
590 * @return The value corresponding to key on success, @c NULL otherwise.
591 * @ingroup Ecore_Data_Hash_ADT_Data_Group
594 ecore_hash_find(Ecore_Hash *hash, Ecore_Compare_Cb compare, const void *value)
598 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
599 CHECK_PARAM_POINTER_RETURN("compare", compare, NULL);
600 CHECK_PARAM_POINTER_RETURN("value", value, NULL);
602 while (i < ecore_prime_table[hash->size])
604 if (hash->buckets[i])
606 Ecore_Hash_Node *node;
608 for (node = hash->buckets[i]; node; node = node->next)
610 if (!compare(node->value, value))
622 * @brief Retrieve the node associated with key
623 * @param hash: the hash table to search for the key
624 * @param key: the key to search for in the hash table
625 * @return Returns NULL on error, node corresponding to key on success
627 static Ecore_Hash_Node *
628 _ecore_hash_node_get(Ecore_Hash *hash, const void *key)
630 unsigned long hash_val;
631 Ecore_Hash_Node *node = NULL;
633 CHECK_PARAM_POINTER_RETURN("hash", hash, NULL);
638 /* Compute the position in the table */
639 if (!hash->hash_func)
640 hash_val = (unsigned long)key % ecore_prime_table[hash->size];
642 hash_val = ECORE_COMPUTE_HASH(hash, key);
644 /* Grab the bucket at the specified position */
645 if (hash->buckets[hash_val])
647 node = _ecore_hash_bucket_get(hash, hash->buckets[hash_val], key);
649 * Move matched node to the front of the list as it's likely
650 * to be searched for again soon.
652 if (node && node != hash->buckets[hash_val])
654 node->next = hash->buckets[hash_val];
655 hash->buckets[hash_val] = node;
663 * @brief Search the hash bucket for a specified key
664 * @param hash: the hash table to retrieve the comparison function
665 * @param bucket: the list to search for the key
666 * @param key: the key to search for in the list
667 * @return Returns NULL on error or not found, the found node on success
669 static inline Ecore_Hash_Node *
670 _ecore_hash_bucket_get(Ecore_Hash *hash,
671 Ecore_Hash_Node *bucket,
674 Ecore_Hash_Node *prev = NULL;
675 Ecore_Hash_Node *node = NULL;
678 * Traverse the list to find the desired node, if the node is in the
679 * list, then return the node.
682 for (node = bucket; node; node = node->next)
684 if (hash->compare(node->key, key) == 0)
690 for (node = bucket; node; node = node->next)
692 if (node->key == key)
699 * Remove node from the list to replace it at the beginning.
703 prev->next = node->next;
711 * @brief Increase the size of the hash table by approx. 2 * current size
712 * @param hash: the hash table to increase the size of
713 * @return Returns TRUE on success, FALSE on error
716 _ecore_hash_increase(Ecore_Hash *hash)
720 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
722 /* Max size reached so return FALSE */
723 if ((ecore_prime_table[hash->size] == PRIME_MAX) ||
724 (hash->size == PRIME_TABLE_MAX))
728 * Increase the size of the hash and save a pointer to the old data
734 * Allocate a new bucket area, of the new larger size
737 calloc(ecore_prime_table[hash->size], sizeof(Ecore_Hash_Node *));
740 * Make sure the allocation succeeded, if not replace the old data and
753 * Now move all of the old data into the new bucket area
755 if (_ecore_hash_rehash(hash, old, hash->size - 1))
762 * Free the old buckets regardless of success.
770 * @brief Decrease the size of the hash table by < 1/2 * current size
771 * @param hash: the hash table to decrease the size of
772 * @return Returns TRUE on success, FALSE on error
775 _ecore_hash_decrease(Ecore_Hash *hash)
777 Ecore_Hash_Node **old;
779 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
781 if (ecore_prime_table[hash->size] == PRIME_MIN)
785 * Decrease the hash size and store a pointer to the old data
791 * Allocate a new area to store the data
793 hash->buckets = (Ecore_Hash_Node **)calloc(ecore_prime_table[hash->size],
794 sizeof(Ecore_Hash_Node *));
797 * Make sure allocation succeeded otherwise rreturn to the previous
809 if (_ecore_hash_rehash(hash, old, hash->size + 1))
819 * @brief Rehash the nodes of a table into the hash table
820 * @param hash: the hash to place the nodes of the table
821 * @param table: the table to remove the nodes from and place in hash
822 * @return Returns TRUE on success, FALSE on error
825 _ecore_hash_rehash(Ecore_Hash *hash, Ecore_Hash_Node **old_table, int old_size)
828 Ecore_Hash_Node *old;
830 CHECK_PARAM_POINTER_RETURN("hash", hash, FALSE);
831 CHECK_PARAM_POINTER_RETURN("old_table", old_table, FALSE);
833 for (i = 0; i < ecore_prime_table[old_size]; i++)
835 /* Hash into a new list to avoid loops of rehashing the same nodes */
836 while ((old = old_table[i]))
838 old_table[i] = old->next;
840 _ecore_hash_node_add(hash, old);
848 * @brief Create a new hash node for key and value storage
849 * @param key: the key for this node
850 * @param value: the value that the key references
851 * @return Returns NULL on error, a new hash node on success
853 static Ecore_Hash_Node *
854 _ecore_hash_node_new(void *key, void *value)
856 Ecore_Hash_Node *node;
858 node = (Ecore_Hash_Node *)malloc(sizeof(Ecore_Hash_Node));
862 if (!_ecore_hash_node_init(node, key, value))
872 * @brief Initialize a hash node to some sane default values
873 * @param node: the node to set the values
874 * @param key: the key to reference this node
875 * @param value: the value that key refers to
876 * @return Returns TRUE on success, FALSE on error
879 _ecore_hash_node_init(Ecore_Hash_Node *node, void *key, void *value)
881 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
890 * @brief Destroy a node and call the specified callbacks to free data
891 * @param node: the node to be destroyed
892 * @param keyd: the function to free the key
893 * @param valued: the function to free the value
894 * @return Returns TRUE on success, FALSE on error
897 _ecore_hash_node_destroy(Ecore_Hash_Node *node,
899 Ecore_Free_Cb valued)
901 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
915 ecore_str_compare(const void *key1, const void *key2)
920 return ecore_direct_compare(key1, key2);
921 else if (key1 == key2)
927 return strcmp(k1, k2);
931 ecore_str_hash(const void *key)
935 unsigned int value = 0;
941 mask = (sizeof(unsigned int) * 8) - 1;
943 for (i = 0; k[i] != '\0'; i++)
945 value ^= ((unsigned int)k[i] << ((i * 5) & mask));