Add missing files
[gmpc-magnatune.git] / src / axl / axl_hash.c
blobf65e060e6e05a1826f0b5c13e270eb72e8a3ac3b
1 /*
2 * LibAxl: Another XML library
3 * Copyright (C) 2006 Advanced Software Production Line, S.L.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 * 02111-1307 USA
20 * You may find a copy of the license under this software is released
21 * at COPYING file. This is LGPL software: you are welcome to
22 * develop proprietary applications using this library without any
23 * royalty or fee but returning back any change, improvement or
24 * addition in the form of source code, project image, documentation
25 * patches, etc.
27 * For commercial support on build XML enabled solutions contact us:
29 * Postal address:
30 * Advanced Software Production Line, S.L.
31 * C/ Dr. Michavila NÂș 14
32 * Coslada 28820 Madrid
33 * Spain
35 * Email address:
36 * info@aspl.es - http://fact.aspl.es
38 #include <axl_hash.h>
39 #include <axl_factory.h>
40 #include <axl_log.h>
42 #define LOG_DOMAIN "axl-hash"
44 /**
45 * \defgroup axl_hash_module Axl Hash: A hash table used by Axl Library
48 /**
49 * \addtogroup axl_hash_module
50 * @{
53 typedef struct _axlHashNode axlHashNode;
55 struct _axlHashNode {
56 /* the key stored and the destroy function */
57 axlPointer key;
58 axlDestroyFunc key_destroy;
60 /* the data stored and the destroy function */
61 axlPointer data;
62 axlDestroyFunc data_destroy;
64 /* a pointer to the next item */
65 axlHashNode * next;
68 struct _axlHash {
69 /* the hash function */
70 axlHashFunc hash;
71 axlEqualFunc equal;
73 /* the hash table, implemented using chaining for collition
74 * resolution. */
75 axlHashNode ** table;
77 /* factory to allocate nodes */
78 axlFactory * factory;
80 /* stored items in the hash */
81 int items;
83 /* the hash size */
84 int hash_size;
86 /* steps: how many slots are allocated when the hash is
87 * resized */
88 int step;
91 /**
92 * @internal Implementation of the axl hash cursor.
94 struct _axlHashCursor {
95 /* a pointer to the hash */
96 axlHash * hash;
98 /* a pointer to the node inside the hash (current value) */
99 axlHashNode * node;
101 /* the value if the index being accessed by the node
102 * pointed (current value) */
103 int index;
106 /**
107 * @brief Public hash implementation for keys that are strings.
109 * @param _key The string key to hash.
111 * @return A value associated to the key.
113 unsigned int axl_hash_string (axlPointer _key)
115 /* never is received a NULL value at this function, so, don't
116 * check it */
117 int g, h = 0;
118 char * key = _key;
120 /* hashing taken from the Red Dragon book!! */
121 while (*key) {
122 h = (h << 4) + *key;
123 if ((g = h & 0xF0000000) != 0) {
124 h ^= g >> 24;
125 h ^= g;
128 ++ key;
129 } /* end while */
131 /* return the value */
132 return h;
135 /**
136 * @brief Common equal hash function associated to \ref
137 * axl_hash_string that allows to check two keys to be equal,
138 * conforming to the results expected by the hash (\ref axlHash).
140 * @param keya The key to compare.
142 * @param keyb The other key to compare.
144 * @return 0 if both strings are equal and any other else value when
145 * they differs.
147 int axl_hash_equal_string (axlPointer keya,
148 axlPointer keyb)
150 char * _keya = keya;
151 char * _keyb = keyb;
152 int i = 0;
154 while (_keya [i] != 0 && _keyb [i] != 0) {
156 /* check values */
157 if (_keya [i] != _keyb [i])
158 return 1;
160 /* update the iterator */
161 i++;
162 } /* end while */
164 /* check that both string ends at the same point */
165 if (_keya [i] != 0 || _keyb [i] != 0)
166 return 1;
168 /* both keys are equal */
169 return 0;
172 /**
173 * @brief Convenience hashing function to store keys that are
174 * integers.
176 * @param key The key that is supported to contain a int value stored
177 * using \ref INT_TO_PTR.
179 * @return The index in the hash where is located the associated data.
181 unsigned int axl_hash_int (axlPointer key)
183 int value = PTR_TO_INT (key);
185 return (unsigned int) value;
188 /**
189 * @brief Convenience hash function to compare two keys that holds
190 * integers values.
192 * @param keya The first key to compare.
193 * @param keyb The second key to compare.
195 * @return 0 if both keys are equal, 1 if not.
197 int axl_hash_equal_int (axlPointer keya,
198 axlPointer keyb)
200 /* return if both keys containing int values are equal */
201 return (PTR_TO_INT (keya) == PTR_TO_INT(keyb)) ? 0 : 1;
205 /**
206 * @internal Internal lookup function, returns the hole hash node.
208 * @param hash The hash where the lookup will be performed.
210 * @param key The key that is being looked up.
212 * @return The axlHashNode reference or NULL if not found.
214 axlHashNode * __axl_hash_internal_lookup (axlHash * hash, axlPointer key)
216 axlHashNode * node;
218 axl_return_val_if_fail (hash, NULL);
220 /* get the node at the provided position */
221 if (hash->hash_size == 0)
222 return NULL;
223 node = hash->table [hash->hash (key) % hash->hash_size];
225 /* node not found */
226 if (node == NULL)
227 return NULL;
229 /* check for equal keys */
230 if (hash->equal (node->key, key) == 0)
231 return node;
233 while (node->next != NULL) {
234 /* seems we have more nodes */
235 node = node->next;
237 /* check for equal keys */
238 if (hash->equal (node->key, key) == 0)
239 return node;
240 } /* end */
242 /* node not found */
243 return NULL;
246 /**
247 * @brief Creates a new hash table using the function provided as
248 * hashing function.
250 * The hash function (\ref axlHashFunc) allows the hash table to
251 * distribute values across the table while performing inserts
252 * operation but it is also used while getting data from the table.
254 * A second function is required (\ref axlEqualFunc) to resolve
255 * internal table conflicts while placing data that are indexed using
256 * the same value generated by \ref axlHashFunc. This hash
257 * implementation store items at the giving position using a linked
258 * list (Chaining collition resolution). Knowing this, an external
259 * function is required to compare items to ensure they are selected
260 * properly.
262 * This hash accept any kind of key and values to be stored as long as
263 * the provided functions returns different identifiers to store
264 * items. However, because the common use of a hash is to store data
265 * using strings as keys two functions are provided by default to
266 * create a string index hash table: \ref axl_hash_equal_string and
267 * \ref axl_hash_string.
269 * \code
270 * // create a string indexed hash
271 * axlHash * hash = axl_hash_new (axl_hash_string, axl_hash_equal_string);
272 * \endcode
274 * Additionally, two functions are provided to create hash containing
275 * integer values as keys: \ref axl_hash_int and \ref axl_hash_equal_int.
277 * Once the hash is created the following functions must be used to
278 * store data:
280 * - \ref axl_hash_insert
281 * - \ref axl_hash_insert_full
283 * Then, use the following function to get data associated to the
284 * provided key.
286 * - \ref axl_hash_get
288 * Finally, you can use the following functions to either remove items
289 * from the hash and to completely deallocate the memory used by the
290 * hash and all of its data:
292 * - \ref axl_hash_remove
293 * - \ref axl_hash_free
296 * @param hash The hashing function to be used for this table.
298 * @param equal The equal function used by the hash to actually check
299 * that two stored items are equal (using the key value)
301 * @return A newly created hash table that is deallocated by using \ref axl_hash_free.
303 axlHash * axl_hash_new (axlHashFunc hash, axlEqualFunc equal)
305 /* call to full implementation */
306 return axl_hash_new_full (hash, equal, 10);
309 /**
310 * @brief The function works the same way like \ref axl_hash_new, but
311 * provides a way to configure how many unit are allocated on hash
312 * resizing operations.
314 * See \ref axl_hash_new for more information. That function uses a
315 * default step value equal to 10.
317 * @param hash The hashing function to be used for this table.
319 * @param equal The equal function used by the hash to actually check
320 * that two stored items are equal (using the key value)
322 * @param step The number of empty new slots to allocate once the hash
323 * must be resized.
325 * @return A newly created hash table that is deallocated by using \ref axl_hash_free.
327 axlHash * axl_hash_new_full (axlHashFunc hash,
328 axlEqualFunc equal,
329 int step)
331 /* create the hash */
332 axlHash * result;
334 result = axl_new (axlHash, 1);
335 result->factory = axl_factory_create (sizeof (axlHashNode));
336 result->hash = hash;
337 result->equal = equal;
338 result->step = step;
340 /* return the hash table created */
341 return result;
344 /**
345 * @brief Inserts a key index value into the provided hash table.
347 * The function will store the data provided on the hash setting no
348 * destroy function for the key and the data stored. See \ref
349 * axl_hash_insert_full for more details.
351 * <b>NOTE:</b> The insert operation will replace a previously
352 * inserted item with the same key. If no item is found, and insert
353 * will take place, otherwise previous item is replaced calling to the
354 * key destroy and data destroy defined.
356 * @param hash The hash table where the insert operation will be
357 * produced.
359 * @param key The key to store in the hash table. If the key is found,
360 * previous data is replaced, storing this new key and the value
361 * provided.
363 * @param data The data to store associated to the provided key.
365 void axl_hash_insert (axlHash * hash,
366 axlPointer key,
367 axlPointer data)
369 /* call to the full implementation */
370 axl_hash_insert_full (hash, key, NULL, data, NULL);
372 /* nothing more to do */
373 return;
376 /**
377 * @internal Function used to create the node that will be stored in
378 * the hash.
380 #define __axl_hash_create_node(factory, node, key, key_destroy, data, data_destroy)\
381 node = axl_factory_get (factory);\
382 node->key = key;\
383 node->key_destroy = key_destroy;\
384 node->data = data;\
385 node->data_destroy = data_destroy;
387 /**
388 * @internal Function that performs the hash insertion for the
389 * selected node.
391 #define __axl_hash_insert_node(_pos,_hash,_key,_node,_increase)\
392 _pos = (_hash->hash (_key)) % _hash->hash_size;\
393 _node->next = _hash->table [_pos];\
394 _hash->table [pos] = _node;\
395 if (_increase)\
396 _hash->items++;
398 /**
399 * @brief Inserts a key value into the provided hash table, allowing
400 * to provide deallocation functions for the key and the data to be
401 * stored.
403 * <b>NOTE:</b> The insert operation will replace a previously
404 * inserted item with the same key. If no item is found, and insert
405 * will take place, otherwise previous item is replaced calling to the
406 * key destroy and data destroy defined.
408 * @param hash The hash table where the data will be added.
410 * @param key The key to store in the hash table. If the key is found,
411 * previous data is replaced, storing this new key and the value
412 * provided.
414 * @param key_destroy An optional destroy function that will be called
415 * to deallocate the key provided.
417 * @param data The data to store associated to the provided key.
419 * @param data_destroy An optional destroy function that will be
420 * called to deallocate the data provided.
422 void axl_hash_insert_full (axlHash * hash,
423 axlPointer key,
424 axlDestroyFunc key_destroy,
425 axlPointer data,
426 axlDestroyFunc data_destroy)
428 int pos = 0;
429 axlHashNode * node = NULL;
430 axlHashNode * aux = NULL;
431 int iterator = 0;
433 /* check incoming data */
434 axl_return_if_fail (hash);
436 /* check the really basic case where the hash has no data
437 * stored yet. */
438 if (hash->hash_size == 0) {
439 /* allocate memory for the hash */
440 hash->table = axl_new (axlHashNode *, hash->step);
441 hash->hash_size = hash->step;
443 /* create the node to store */
444 __axl_hash_create_node (hash->factory, node, key, key_destroy, data, data_destroy);
446 /* insert the node into the hash */
447 __axl_hash_insert_node (pos, hash, key, node, true);
449 return;
452 /* now check for a more complex case */
453 node = __axl_hash_internal_lookup (hash, key);
455 /* if the node is not found and the hash size can't hold more items, expand it and rehash */
456 if ((hash->hash_size == hash->items) && (node == NULL)) {
457 /* seems we need to rehash items, reallocating enough
458 * memory */
460 /* before allocating more memory, extract all items to
461 * be reallocated */
462 iterator = 0;
463 node = NULL;
464 while (iterator < hash->hash_size) {
466 /* check for content */
467 if (hash->table[iterator] != NULL) {
468 /* check if node has been initialized,
469 * and set it to the first position */
470 if (node == NULL) {
471 /* configure init node position */
472 node = hash->table[iterator];
474 /* and last aux position */
475 aux = node;
476 while (aux->next != NULL) {
477 /* update reference */
478 aux = aux->next;
481 } else {
482 /* make aux to point to the next list */
483 aux->next = hash->table[iterator];
485 /* and while the last item is not
486 * reached, move aux to point to the
487 * last item of the chain */
488 while (aux->next != NULL) {
489 /* update reference */
490 aux = aux->next;
493 } /* end if */
495 /* update the iterator */
496 iterator++;
499 /* now we have in node a complete list of items
500 * stored, allocate more memory and rehash */
501 hash->hash_size += hash->step;
502 hash->table = realloc (hash->table, sizeof (axlHashNode *) * (hash->hash_size));
504 /* clear the table */
505 memset (hash->table, 0, sizeof (axlHashNode*) * (hash->hash_size));
507 /* for each item inside the list rehash it */
508 while (node != NULL) {
509 /* store next item to rehash in aux */
510 aux = node->next;
512 /* insert the node into the hash */
513 __axl_hash_insert_node (pos, hash, node->key, node, false);
515 /* update the reference */
516 node = aux;
517 } /* end while */
519 /* clear node reference */
520 node = NULL;
521 } /* rehashing if end */
523 /* we have enough space to store the item create the
524 node to store */
525 if (node == NULL) {
526 /* create a new node */
527 __axl_hash_create_node (hash->factory, node, key, key_destroy, data, data_destroy);
529 /* insert the node into the hash as usual */
530 __axl_hash_insert_node (pos, hash, key, node, true);
531 } else {
532 /* don't create a node, replace previous content and use new content */
533 if (node->key_destroy != NULL) {
534 node->key_destroy (node->key);
536 if (node->data_destroy != NULL) {
537 node->data_destroy (node->data);
540 /* now use new data */
541 node->key = key;
542 node->key_destroy = key_destroy;
543 node->data = data;
544 node->data_destroy = data_destroy;
547 /* nothing more man!! */
548 return;
552 * @internal Function that supports axl_hash_remove and
553 * axl_hash_delete.
555 void __axl_hash_remove_common (axlHash * hash,
556 axlPointer key,
557 bool remove)
559 axlHashNode * node;
560 axlHashNode * aux;
561 int pos;
563 axl_return_if_fail (hash);
565 /* do not perform any operation if the hash is empty */
566 if (hash->hash_size == 0)
567 return;
569 /* get the node at the provided position */
570 pos = (hash->hash (key)) % hash->hash_size;
571 node = hash->table [pos];
573 /* node not found */
574 if (node == NULL)
575 return;
577 /* check for equal keys */
578 if (hash->equal (node->key, key) == 0) {
579 /* set that no items are available at the provided
580 * position */
581 hash->table [pos] = node->next;
583 remove_element:
584 /* key destruction is defined */
585 if (node->key_destroy != NULL && remove)
586 node->key_destroy (node->key);
588 /* if data destruction is defined */
589 if (node->data_destroy != NULL && remove)
590 node->data_destroy (node->data);
592 /* decreases elements found */
593 hash->items--;
595 /* delete the node */
596 /* axl_free (node); */
598 /* element destroyed, nothing more to do around
599 * here */
600 return;
603 /* seems we have more nodes */
604 while (node->next != NULL) {
605 /* store a reference to the current node (which will
606 * be the previous on next sentences) */
607 aux = node;
609 /* update the reference to the next node */
610 node = node->next;
612 /* check for equal keys */
613 if (hash->equal (node->key, key) == 0) {
614 /* make previous node to point to the next
615 * element of the following node */
616 aux->next = node->next;
618 goto remove_element;
620 } /* end */
622 /* no item was found on the hash */
623 return;
626 /**
627 * @brief Allows to remove the selected pair key/value on the provided
628 * hash table.
630 * The function will remevo the item but it will not resize the table
631 * due to it. The function will call to the key destroy and data
632 * destroy function if they were defined at the insertion time (\ref
633 * axl_hash_insert_full).
636 * @param hash The hash table where the removal operation will be
637 * performed.
639 * @param key The key to lookup to be removed.
641 void axl_hash_remove (axlHash * hash,
642 axlPointer key)
644 /* call common implementation deleting data with destroy
645 * functions defined */
646 __axl_hash_remove_common (hash, key, true);
647 return;
650 /**
651 * @brief Allows to remove the selected pair key/value on the provided
652 * hash table, without calling to destroy functions.
654 * The function will remove the item but it will not resize the table
655 * due to it. The function will NOT call to the key destroy and data
656 * destroy function if they were defined at the insertion time (\ref
657 * axl_hash_insert_full).
660 * @param hash The hash table where the removal operation will be
661 * performed.
663 * @param key The key to lookup to be removed.
665 void axl_hash_delete (axlHash * hash,
666 axlPointer key)
668 /* call common implementation, without calling destroy
669 * functions defined */
670 __axl_hash_remove_common (hash, key, false);
671 return;
674 /**
675 * @brief Allows to get the content associated to the key provided
676 * inside the hash provided.
678 * @param hash The hash table where the lookup will be performed.
680 * @param key The key to use to retrieve the information.
682 * @return NULL or the associated data to the key provided. The
683 * function will also return a NULL value if provided a NULL hash
684 * reference or a NULL key reference.
686 axlPointer axl_hash_get (axlHash * hash,
687 axlPointer key)
689 axlHashNode * node;
691 axl_return_val_if_fail (hash, NULL);
693 /* lookup using internal function */
694 node = __axl_hash_internal_lookup (hash, key);
696 /* return the content or NULL if not defined the node */
697 if (node != NULL)
698 return node->data;
699 return NULL;
702 /**
703 * @internal
705 * Common implementation for both foreach functions: axl_hash_foreach
706 * and axl_hash_foreach2.
708 void __axl_hash_foreach (axlHash * hash,
709 axlHashForeachFunc func,
710 axlHashForeachFunc2 func2,
711 axlHashForeachFunc3 func3,
712 axlHashForeachFunc4 func4,
713 axlPointer user_data,
714 axlPointer user_data2,
715 axlPointer user_data3,
716 axlPointer user_data4)
719 int iterator = 0;
720 axlHashNode * node;
722 /* perform some basic checks */
723 axl_return_if_fail (hash);
725 /* foreach item row inside the hash table */
726 while (iterator < hash->hash_size) {
728 /* check for content */
729 if (hash->table[iterator] != NULL) {
730 /* get the first item inside the table */
731 node = hash->table[iterator];
733 do {
734 /* check for one user defined pointer
735 * foreach: notify the item found */
736 if (func != NULL && func (node->key, node->data, user_data)) {
737 /* user have decided to stop */
738 return;
739 } /* end if */
741 /* check for two user defined pointers
742 * notify the item found */
743 if (func2 != NULL && func2 (node->key, node->data, user_data, user_data2)) {
744 /* user have decided to stop */
745 return;
746 } /* end if */
748 /* check for three user defined pointers
749 * notify the item found */
750 if (func3 != NULL && func3 (node->key, node->data, user_data, user_data2, user_data3)) {
751 /* user have decided to stop */
752 return;
753 } /* end if */
755 /* check for four user defined
756 * pointers notify the item found */
757 if (func4 != NULL && func4 (node->key, node->data, user_data, user_data2, user_data3, user_data4)) {
758 /* user have decided to stop */
759 return;
760 } /* end if */
762 /* next item inside the same collition
763 * position */
764 node = node->next;
766 /* while the next item is not null,
767 * keep on iterating */
768 } while (node != NULL);
770 } /* end if */
772 /* update the iterator */
773 iterator++;
775 } /* end while */
777 return;
780 /**
781 * @brief Performs a foreach operation over all items stored in the
782 * hash provided.
784 * The function provided (<b>func</b>) will be called passing in the
785 * item found, and the data provided (third argument).
787 * Because the \ref axlHashForeachFunc function is used, \ref true must be
788 * returned to stop the foreach process. In the case all items must be
789 * visited, \ref false must be returned in any case.
791 * @param hash The hash table where the iteration process will take
792 * place.
794 * @param func The function to call for each item found.
796 * @param user_data User defined data to be passed in to the function callback along with the item found.
798 void axl_hash_foreach (axlHash * hash,
799 axlHashForeachFunc func,
800 axlPointer user_data)
804 /* perform the foreach operation using common support */
805 __axl_hash_foreach (hash,
806 /* foreach function */
807 func, NULL, NULL, NULL,
808 /* user defined data */
809 user_data, NULL, NULL, NULL);
811 return;
814 /**
815 * @brief Allows to perform a foreach operation providing two user
816 * defined pointer to be passed to the foreach function for each item
817 * found.
819 * This function works like \ref axl_hash_foreach function but support
820 * two user defined pointers. See \ref axl_hash_foreach for more information.
822 * @param hash The hash where the iteration will be performed.
824 * @param func The foreach function that will be called for all nodes
825 * found passed in both pointers defined along with the key value and
826 * the value associated.
828 * @param user_data User defined data to be passed to the foreach
829 * function.
831 * @param user_data2 Second User defined data to be passed to the
832 * foreach function.
834 void axl_hash_foreach2 (axlHash * hash,
835 axlHashForeachFunc2 func,
836 axlPointer user_data,
837 axlPointer user_data2)
840 /* perform the foreach operation using common support */
841 __axl_hash_foreach (hash,
842 /* foreach function */
843 NULL, func, NULL, NULL,
844 /* user defined data */
845 user_data, user_data2, NULL, NULL);
847 return;
850 /**
851 * @brief Three user defined pointers foreach function over a hash.
853 * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
854 * information.
856 * @param hash The hash where the foreach operation will take place.
858 * @param func The function to be called for each item found in the
859 * hash.
861 * @param user_data The user defined pointer to be configured in the
862 * hash.
864 * @param user_data2 Second user defined pointer to be configured in
865 * the hash.
867 * @param user_data3 Third user defined pointer to be configured in
868 * the hash.
870 void axl_hash_foreach3 (axlHash * hash,
871 axlHashForeachFunc3 func,
872 axlPointer user_data,
873 axlPointer user_data2,
874 axlPointer user_data3)
876 /* perform the foreach operation using common support */
877 __axl_hash_foreach (hash,
878 /* foreach function */
879 NULL, NULL, func, NULL,
880 /* user defined data */
881 user_data, user_data2, user_data3, NULL);
884 /**
885 * @brief Four user defined pointers foreach function over a hash.
887 * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
888 * information.
890 * @param hash The hash where the foreach operation will take place.
892 * @param func The function to be called for each item found in the
893 * hash.
895 * @param user_data The user defined pointer to be configured in the
896 * hash.
898 * @param user_data2 Second user defined pointer to be configured in
899 * the hash.
901 * @param user_data3 Third user defined pointer to be configured in
902 * the hash.
904 * @param user_data4 Forth user defined pointer to be configured in
905 * the hash.
907 void axl_hash_foreach4 (axlHash * hash,
908 axlHashForeachFunc4 func,
909 axlPointer user_data,
910 axlPointer user_data2,
911 axlPointer user_data3,
912 axlPointer user_data4)
914 /* perform the foreach operation using common support */
915 __axl_hash_foreach (hash,
916 /* foreach functions */
917 NULL, NULL, NULL, func,
918 /* user defined data */
919 user_data, user_data2, user_data3, user_data4);
922 /**
923 * @brief Allows to check if the provided key is found on the given
924 * hash table.
926 * The function allows to get if the key is found on the table pretty
927 * much the behaviour that we could get using the following:
928 * \code
929 * // just compare if the provided key returns some value
930 * bool value = (axl_hash_get (hash, "key2") != NULL);
931 * \endcode
933 * However it could happen that the value associated to the key, which
934 * already exists, is a NULL pointer, making previous comparation to
935 * not work in all cases. This function allows to check for the
936 * existance of a key and its associated data no mather what is the
937 * value of the associated data.
939 * @param hash The hash table to check for a key value.
940 * @param key The key to check for its existance.
942 * @return true if the key is found, otherwise false is returned.
944 bool axl_hash_exists (axlHash * hash,
945 axlPointer key)
947 /* check if the hash is provided without loggin an error */
948 return (__axl_hash_internal_lookup (hash, key) != NULL);
951 /**
952 * @internal function for axl_hash_copy.
954 bool __axl_hash_copy_foreach (axlPointer key,
955 axlPointer data,
956 /* user defined pointers */
957 axlPointer user_data, /* hash */
958 axlPointer user_data2, /* result */
959 axlPointer user_data3, /* key_copy */
960 axlPointer user_data4) /* value_copy */
962 /* get a reference to the received data */
963 axlHash * hash = user_data;
964 axlHash * result = user_data2;
965 axlHashItemCopy key_copy = user_data3;
966 axlHashItemCopy value_copy = user_data4;
968 /* additional variables */
969 axlHashNode * node;
971 /* get node to copy */
972 node = hash->table [(hash->hash (key)) % hash->hash_size];
974 /* check this is the node to copy */
975 while (node != NULL) {
976 if (hash->equal (node->key, key) == 0)
977 break;
979 /* it isn't the node looked up */
980 node = node->next;
981 } /* end while */
983 /* copy */
984 axl_hash_insert_full (result,
985 /* insert the key and its destroy function. */
986 key_copy (node->key, node->key_destroy, node->data, node->data_destroy), node->key_destroy,
987 /* insert data and its destroy function. */
988 value_copy (node->key, node->key_destroy, node->data, node->data_destroy), node->data_destroy);
990 /* make the foreach process to continue until the last element */
991 return false;
994 /**
995 * @brief Allows to copy the provided hash, providing the copy
996 * function used to duplicate key and value items stored.
998 * The function are optional, so, if they are null, the same value is
999 * stored in the hash (for the key and the value). In this case, if
1000 * the source hash has defined destroy function for either key or
1001 * values, they will not be configured in the returning hash.
1003 * If function are provided, \ref axl_hash_copy will use it to get a
1004 * duplicated version for either the key or the value. In this case,
1005 * if the source hash has defined the destroy function either for the
1006 * key or the value, it will be configured in the returning hash.
1008 * @param hash The \ref axlHash that will work as data source.
1010 * @param key_copy The function to be used to duplicate keys.
1012 * @param value_copy The function used to duplicate values.
1014 * @return A newly allocated reference to a \ref axlHash containing
1015 * all values from the source hash. The function will fail if the hash
1016 * provided is a null reference or copy functions aren't provided.
1018 axlHash * axl_hash_copy (axlHash * hash,
1019 axlHashItemCopy key_copy,
1020 axlHashItemCopy value_copy)
1022 axlHash * result;
1024 /* return if the hash reference is null */
1025 axl_return_val_if_fail (hash, NULL);
1026 axl_return_val_if_fail (key_copy, NULL);
1027 axl_return_val_if_fail (value_copy, NULL);
1029 /* create the hash */
1030 result = axl_hash_new_full (hash->hash,
1031 hash->equal,
1032 /* make initial step to be equal
1033 * to the current hash size copied
1034 * to avoid resizing operations
1035 * during the foreach. */
1036 hash->items);
1037 /* restore step */
1038 result->step = hash->step;
1040 /* check empty hash value */
1041 if (hash->hash_size == 0)
1042 return result;
1044 /* copy all items */
1045 axl_hash_foreach4 (hash, __axl_hash_copy_foreach, hash, result, key_copy, value_copy);
1048 /* return created hash */
1049 return result;
1052 /**
1053 * @brief Returns the number of items already stored on the provided
1054 * hash.
1056 * @param hash The hash that is being requested for the number of
1057 * indexed data items.
1059 * @return The number of items or -1 if it fails.
1061 int axl_hash_items (axlHash * hash)
1063 axl_return_val_if_fail (hash, -1);
1065 /* return current items stored */
1066 return hash->items;
1069 /**
1070 * @internal Shows current hash status to the console.
1072 * The function is only useful for internal hash module purposes. It
1073 * shows the numbers of items stored, the table size, the number of
1074 * collitions, etc.
1076 * @param hash The hash where the status is requested.
1078 void axl_hash_show_status (axlHash * hash)
1080 /* use full implementation */
1081 axl_hash_show_status_full (hash, NULL);
1083 return;
1086 /**
1087 * @internal Shows current hash content to the console using the
1088 * provided function to show the hash content.
1090 * @param hash The hash that is requested to show its content.
1092 * @param show_item The function to be used to show the content.
1094 void axl_hash_show_status_full (axlHash * hash,
1095 axlHashPrintKeyData show_item)
1097 axlHashNode * node;
1098 int iterator;
1099 int count;
1100 axl_return_if_fail (hash);
1102 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl hash table status:");
1103 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "table size: %d items: %d step: %d",
1104 hash->hash_size, hash->items, hash->step);
1105 /* get the number of empty blocks */
1106 iterator = 0;
1107 count = 0;
1108 while (iterator < hash->hash_size) {
1109 /* empty item found */
1110 if (hash->table[iterator] == NULL) {
1111 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "empty cell at: %d", iterator);
1112 count++;
1115 /* update iterator */
1116 iterator++;
1118 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of empty cells: %d", count);
1120 /* get the number properly used cells (no collitions) */
1121 iterator = 0;
1122 count = 0;
1123 while (iterator < hash->hash_size) {
1124 /* empty item found */
1125 node = hash->table[iterator];
1126 if (node != NULL && node->next == NULL) {
1127 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "properly used cell at: %d", iterator);
1128 count++;
1130 if (show_item != NULL) {
1131 show_item (node->key, node->data);
1135 /* update iterator */
1136 iterator++;
1138 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of properly used cells (no collition): %d", count);
1140 /* get the number of collitioned cells */
1141 iterator = 0;
1142 count = 0;
1143 while (iterator < hash->hash_size) {
1144 /* empty item found */
1145 node = hash->table[iterator];
1146 if (node != NULL && node->next != NULL) {
1147 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "collitioned cell at: %d", iterator);
1148 count++;
1151 /* for each node show the content */
1152 while ((show_item) != NULL && (node != NULL)) {
1153 if (show_item != NULL) {
1154 show_item (node->key, node->data);
1157 /* update to the next node */
1158 node = node->next;
1161 /* update iterator */
1162 iterator++;
1164 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of collitioned cells: %d", count);
1168 return;
1171 /**
1172 * @brief Allows to deallocate the hash provided.
1174 * @param hash The hash to deallocate.
1176 void axl_hash_free (axlHash * hash)
1178 int iterator = 0;
1179 axlHashNode * node;
1180 axlHashNode * aux;
1182 /* do not perform any operation if a null reference is
1183 * received */
1184 if (hash == NULL)
1185 return;
1187 /* release the hash table */
1188 if (hash->table != NULL) {
1190 /* first release all nodes inside */
1191 while (iterator < hash->hash_size) {
1192 node = hash->table[iterator];
1193 if (node != NULL) {
1194 do {
1195 /* key destruction is defined */
1196 if (node->key_destroy != NULL)
1197 node->key_destroy (node->key);
1199 /* if data destruction is defined */
1200 if (node->data_destroy != NULL)
1201 node->data_destroy (node->data);
1203 /* check data */
1204 aux = node;
1205 node = node->next;
1207 /* while more nodes */
1208 } while (node != NULL);
1209 } /* end if */
1211 /* update the iterator */
1212 iterator++;
1213 } /* end while */
1215 /* now release the table */
1216 axl_free (hash->table);
1217 } /* end if */
1219 /* free factory */
1220 axl_factory_free (hash->factory);
1222 /* now release the hash itself */
1223 axl_free (hash);
1225 /* nothing more to free */
1226 return;
1229 /* @} */
1232 * \defgroup axl_hash_cursor_module Axl Hash Cursor: Iterator support for the Axl Hash
1235 /* init the cursor */
1236 void __axl_hash_cursor_init (axlHashCursor * cursor, bool first)
1238 /* pointer to a hash node (basic atom holding key and value) */
1239 axlHashNode * node = NULL;
1241 if (first) {
1242 /* configure first */
1243 cursor->index = 0;
1245 /* foreach element inside the hash, check the first value */
1246 while (cursor->index < cursor->hash->hash_size) {
1247 /* check the table at the current position */
1248 node = cursor->hash->table[cursor->index];
1249 if (node != NULL) {
1250 /* first node found, store it */
1251 cursor->node = node;
1252 break;
1253 } /* end if */
1255 /* node not found, go next position */
1256 cursor->index++;
1257 } /* end while */
1258 } else {
1259 /* find last value */
1260 cursor->index = cursor->hash->hash_size - 1;
1261 cursor->node = NULL;
1262 while (cursor->index > 0) {
1263 /* check the table at the current position */
1264 node = cursor->hash->table[cursor->index];
1265 if (node != NULL) {
1266 /* find last entry filled, now find
1267 * last entry in the same index */
1268 while (node->next != NULL)
1269 node = node->next;
1271 /* configure it */
1272 cursor->node = node;
1273 break;
1274 } /* end if */
1276 /* node not found, go next position */
1277 cursor->index--;
1278 } /* end while */
1279 } /* end if */
1281 /* if the node wasn't found, reset index */
1282 if (node == NULL)
1283 cursor->index = 0;
1285 /* cursor initialized */
1286 return;
1289 /**
1290 * \addtogroup axl_hash_cursor_module
1291 * @{
1294 /**
1295 * @brief Allows to get a cursor to iterate the hash in a linear and
1296 * efficient way.
1298 * The \ref axlHashCursor could be used to iterate an \ref axlHash in
1299 * an efficient way because it stores current state (position), hiding
1300 * all module details. Then using the following functions you can
1301 * modify the state (current position to get):
1303 * - \ref axl_hash_cursor_first
1304 * - \ref axl_hash_cursor_last
1305 * - \ref axl_hash_cursor_next
1307 * Finally, the following functions are provided to get the data stored at a
1308 * particular position, pointed by the current status of the cursor:
1310 * - \ref axl_hash_cursor_get_key (returns the key of the current position)
1311 * - \ref axl_hash_cursor_get_value (returns the value of the current position)
1313 * You are allowed to remove elements from the hash (\ref axlHash)
1314 * having a cursor created (\ref axlHashCursor), using \ref
1315 * axl_hash_cursor_remove.
1317 * Here is an example:
1318 * \code
1319 * axlPointer key;
1320 * axlPointer value;
1321 * axlHashCursor * cursor;
1323 * // create the cursor
1324 * cursor = axl_hash_cursor_new (hash);
1326 * // while there are more elements
1327 * while (axl_hash_cursor_has_item (cursor)) {
1329 * // get the value and key
1330 * value = axl_hash_cursor_get_key (cursor);
1331 * value = axl_hash_cursor_get_value (cursor);
1333 * // get the next
1334 * axl_hash_cursor_next (cursor);
1336 * }
1338 * // free the cursor
1339 * axl_hash_cursor_free (cursor);
1340 * \endcode
1342 * @param hash The hash that the new cursor (\ref axlHashCursor) will
1343 * provide access.
1345 * @return A newly created \ref axlHashCursor used to iterate the
1346 * hash. Once finished you must call to \ref axl_hash_cursor_free.
1348 axlHashCursor * axl_hash_cursor_new (axlHash * hash)
1350 axlHashCursor * cursor;
1352 axl_return_val_if_fail (hash, NULL);
1354 /* create the cursor */
1355 cursor = axl_new (axlHashCursor, 1);
1357 /* initial configuration */
1358 cursor->hash = hash;
1360 /* init the cursor */
1361 __axl_hash_cursor_init (cursor, true);
1363 /* return cursor */
1364 return cursor;
1367 /**
1368 * @brief Allows to configure the cursor to point to the first item of
1369 * the hash (if there are any).
1371 * @param cursor The cursor that is required to be configured to point the first item.
1373 void axl_hash_cursor_first (axlHashCursor * cursor)
1375 axl_return_if_fail (cursor);
1377 /* init the cursor at the initial state */
1378 __axl_hash_cursor_init (cursor, true);
1380 return;
1383 /**
1384 * @brief Allows to configure the cursor to point to the last item of
1385 * the hash (if there are any).
1387 * @param cursor The cursor that is required to be configured to point
1388 * to the last item.
1390 void axl_hash_cursor_last (axlHashCursor * cursor)
1392 axl_return_if_fail (cursor);
1394 /* init the cursor at the initial state, selecting the last
1395 * node */
1396 __axl_hash_cursor_init (cursor, false);
1398 return;
1401 /**
1402 * @brief Allows to configure the cursor to point to the next item of
1403 * the hash (if there are any).
1405 * @param cursor The cursor that is required to be configured to point
1406 * to the next item.
1408 void axl_hash_cursor_next (axlHashCursor * cursor)
1410 axl_return_if_fail (cursor);
1412 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next element at the cursor");
1414 /* check if the current node is null and do nothing if nothing
1415 * is found */
1416 if (cursor->node == NULL) {
1417 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "no nodes found....");
1418 return;
1421 /* basic case, the item is found in the same level */
1422 if (cursor->node->next != NULL) {
1423 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node....");
1424 /* configure new current node */
1425 cursor->node = cursor->node->next;
1427 return;
1428 } /* end if */
1430 /* node not found, go next position */
1431 cursor->index++;
1433 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "updating and checking next index: %d (hash: %d)....",
1434 cursor->index, cursor->hash->hash_size);
1436 /* check if we have reached the phisical limit of the hash */
1437 if (cursor->index >= cursor->hash->hash_size) {
1438 cursor->node = NULL;
1439 return;
1442 /* seems next is null, see in other positions */
1443 while (cursor->index < cursor->hash->hash_size) {
1445 /* check the table at the current position */
1446 cursor->node = cursor->hash->table[cursor->index];
1447 if (cursor->node != NULL) {
1448 /* node found, stop! */
1449 break;
1450 } /* end if */
1452 /* node not found, go next position */
1453 cursor->index++;
1454 } /* end while */
1456 /* nothing to be done */
1457 return;
1460 /**
1461 * @brief Allows to check if there are more elements next to the
1462 * current element pointed by the cursor.
1464 * @param cursor The cursor that is required to return if there are
1465 * next items.
1467 * @return \ref true if more items are found, otherwise \ref false is
1468 * returned.
1470 bool axl_hash_cursor_has_next (axlHashCursor * cursor)
1472 int iterator;
1473 axl_return_val_if_fail (cursor, false);
1475 /* check basic case */
1476 if (cursor->node != NULL && cursor->node->next != NULL) {
1477 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "next is defined..");
1478 return true;
1481 /* seems next is null, see in other positions */
1482 iterator = cursor->index + 1;
1483 while (iterator < cursor->hash->hash_size) {
1484 /* check the table at the current position */
1485 if (cursor->hash->table[iterator] != NULL)
1486 return true;
1488 /* node not found, go next position */
1489 iterator++;
1490 } /* end while */
1492 return false;
1495 /**
1496 * @brief Allows to know if the current position has items.
1498 * @param cursor The cursor pointing to a particular element inside
1499 * the hash (or not).
1501 * @return \ref true if the hash that is iterated can return data at
1502 * the current position, otherwise \ref false is returned.
1504 bool axl_hash_cursor_has_item (axlHashCursor * cursor)
1506 axl_return_val_if_fail (cursor, false);
1508 /* return true if there are a item selected */
1509 return (cursor->node != NULL);
1512 /**
1513 * @brief Allows to remove current element pointed by the cursor,
1514 * maintainig internal state of the cursor, calling to the destroy
1515 * function associated in the hash.
1517 * The function will call to the destroy function asociated to the
1518 * hash.
1520 * @param cursor The cursor pointing to the item inside the hash that
1521 * must be removed.
1523 void axl_hash_cursor_remove (axlHashCursor * cursor)
1525 axlHashNode * node;
1527 axl_return_if_fail (cursor);
1529 /* if current cursor is pointing nowhere, just do nothing */
1530 if (cursor->node == NULL)
1531 return;
1533 /* remember node */
1534 node = cursor->node->next;
1536 /* remove node selected */
1537 axl_hash_remove (cursor->hash, cursor->node->key);
1539 /* configure next item */
1540 cursor->node = node;
1541 if (cursor->node == NULL) {
1542 while (cursor->index < cursor->hash->hash_size) {
1543 /* check the table at the current position */
1544 if (cursor->hash->table[cursor->index] != NULL) {
1545 /* configure the next node */
1546 cursor->node = cursor->hash->table[cursor->index];
1547 return;
1550 /* node not found, go next position */
1551 cursor->index++;
1552 } /* end while */
1553 } /* end if */
1555 return;
1558 /**
1559 * @brief Allows to get current value at the current cursor state.
1561 * @param cursor The cursor that will be used to return the data
1562 * located at the hash, using cursor current state.
1564 axlPointer axl_hash_cursor_get_value (axlHashCursor * cursor)
1566 axl_return_val_if_fail (cursor, NULL);
1568 /* nothing to return if current is NULL */
1569 if (cursor->node == NULL)
1570 return NULL;
1572 /* return data */
1573 return cursor->node->data;
1576 /**
1577 * @brief Allows to get current key at the current cursor state.
1579 * @param cursor The cursor that will be used to return the data
1580 * located at the hash, using cursor current state.
1582 axlPointer axl_hash_cursor_get_key (axlHashCursor * cursor)
1584 axl_return_val_if_fail (cursor, NULL);
1586 /* nothing to return if current is NULL */
1587 if (cursor->node == NULL)
1588 return NULL;
1590 /* return key pointer */
1591 return cursor->node->key;
1594 /**
1595 * @brief Allows to get the reference to the hash that is associated
1596 * to the cursor received.
1598 * @param cursor The cursor that is required to return the hash associated.
1600 * @return A reference to the hash being iterated or NULL if fails.
1602 axlHash * axl_hash_cursor_hash (axlHashCursor * cursor)
1604 /* check incoming cursor */
1605 axl_return_val_if_fail (cursor, NULL);
1607 /* return the hash */
1608 return cursor->hash;
1611 /**
1612 * @brief Deallocates memory used by the cursor.
1614 * @param cursor The cursor to be deallocated.
1616 void axl_hash_cursor_free (axlHashCursor * cursor)
1618 axl_return_if_fail (cursor);
1620 /* free the cursor */
1621 axl_free (cursor);
1623 return;
1627 /* @} */