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
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
27 * For commercial support on build XML enabled solutions contact us:
30 * Advanced Software Production Line, S.L.
31 * C/ Dr. Michavila NÂș 14
32 * Coslada 28820 Madrid
36 * info@aspl.es - http://fact.aspl.es
39 #include <axl_factory.h>
42 #define LOG_DOMAIN "axl-hash"
45 * \defgroup axl_hash_module Axl Hash: A hash table used by Axl Library
49 * \addtogroup axl_hash_module
53 typedef struct _axlHashNode axlHashNode
;
56 /* the key stored and the destroy function */
58 axlDestroyFunc key_destroy
;
60 /* the data stored and the destroy function */
62 axlDestroyFunc data_destroy
;
64 /* a pointer to the next item */
69 /* the hash function */
73 /* the hash table, implemented using chaining for collition
77 /* factory to allocate nodes */
80 /* stored items in the hash */
86 /* steps: how many slots are allocated when the hash is
92 * @internal Implementation of the axl hash cursor.
94 struct _axlHashCursor
{
95 /* a pointer to the hash */
98 /* a pointer to the node inside the hash (current value) */
101 /* the value if the index being accessed by the node
102 * pointed (current value) */
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
120 /* hashing taken from the Red Dragon book!! */
123 if ((g
= h
& 0xF0000000) != 0) {
131 /* return the value */
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
147 int axl_hash_equal_string (axlPointer keya
,
154 while (_keya
[i
] != 0 && _keyb
[i
] != 0) {
157 if (_keya
[i
] != _keyb
[i
])
160 /* update the iterator */
164 /* check that both string ends at the same point */
165 if (_keya
[i
] != 0 || _keyb
[i
] != 0)
168 /* both keys are equal */
173 * @brief Convenience hashing function to store keys that are
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
;
189 * @brief Convenience hash function to compare two keys that holds
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
,
200 /* return if both keys containing int values are equal */
201 return (PTR_TO_INT (keya
) == PTR_TO_INT(keyb
)) ? 0 : 1;
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
)
218 axl_return_val_if_fail (hash
, NULL
);
220 /* get the node at the provided position */
221 if (hash
->hash_size
== 0)
223 node
= hash
->table
[hash
->hash (key
) % hash
->hash_size
];
229 /* check for equal keys */
230 if (hash
->equal (node
->key
, key
) == 0)
233 while (node
->next
!= NULL
) {
234 /* seems we have more nodes */
237 /* check for equal keys */
238 if (hash
->equal (node
->key
, key
) == 0)
247 * @brief Creates a new hash table using the function provided as
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
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.
270 * // create a string indexed hash
271 * axlHash * hash = axl_hash_new (axl_hash_string, axl_hash_equal_string);
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
280 * - \ref axl_hash_insert
281 * - \ref axl_hash_insert_full
283 * Then, use the following function to get data associated to the
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);
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
325 * @return A newly created hash table that is deallocated by using \ref axl_hash_free.
327 axlHash
* axl_hash_new_full (axlHashFunc hash
,
331 /* create the hash */
334 result
= axl_new (axlHash
, 1);
335 result
->factory
= axl_factory_create (sizeof (axlHashNode
));
337 result
->equal
= equal
;
340 /* return the hash table created */
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
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
363 * @param data The data to store associated to the provided key.
365 void axl_hash_insert (axlHash
* hash
,
369 /* call to the full implementation */
370 axl_hash_insert_full (hash
, key
, NULL
, data
, NULL
);
372 /* nothing more to do */
377 * @internal Function used to create the node that will be stored in
380 #define __axl_hash_create_node(factory, node, key, key_destroy, data, data_destroy)\
381 node = axl_factory_get (factory);\
383 node->key_destroy = key_destroy;\
385 node->data_destroy = data_destroy;
388 * @internal Function that performs the hash insertion for the
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;\
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
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
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
,
424 axlDestroyFunc key_destroy
,
426 axlDestroyFunc data_destroy
)
429 axlHashNode
* node
= NULL
;
430 axlHashNode
* aux
= NULL
;
433 /* check incoming data */
434 axl_return_if_fail (hash
);
436 /* check the really basic case where the hash has no data
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);
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
460 /* before allocating more memory, extract all items to
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 */
471 /* configure init node position */
472 node
= hash
->table
[iterator
];
474 /* and last aux position */
476 while (aux
->next
!= NULL
) {
477 /* update reference */
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 */
495 /* update the 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 */
512 /* insert the node into the hash */
513 __axl_hash_insert_node (pos
, hash
, node
->key
, node
, false);
515 /* update the reference */
519 /* clear node reference */
521 } /* rehashing if end */
523 /* we have enough space to store the item create the
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);
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 */
542 node
->key_destroy
= key_destroy
;
544 node
->data_destroy
= data_destroy
;
547 /* nothing more man!! */
552 * @internal Function that supports axl_hash_remove and
555 void __axl_hash_remove_common (axlHash
* hash
,
563 axl_return_if_fail (hash
);
565 /* do not perform any operation if the hash is empty */
566 if (hash
->hash_size
== 0)
569 /* get the node at the provided position */
570 pos
= (hash
->hash (key
)) % hash
->hash_size
;
571 node
= hash
->table
[pos
];
577 /* check for equal keys */
578 if (hash
->equal (node
->key
, key
) == 0) {
579 /* set that no items are available at the provided
581 hash
->table
[pos
] = node
->next
;
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 */
595 /* delete the node */
596 /* axl_free (node); */
598 /* element destroyed, nothing more to do around
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) */
609 /* update the reference to the next node */
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
;
622 /* no item was found on the hash */
627 * @brief Allows to remove the selected pair key/value on the provided
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
639 * @param key The key to lookup to be removed.
641 void axl_hash_remove (axlHash
* hash
,
644 /* call common implementation deleting data with destroy
645 * functions defined */
646 __axl_hash_remove_common (hash
, key
, true);
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
663 * @param key The key to lookup to be removed.
665 void axl_hash_delete (axlHash
* hash
,
668 /* call common implementation, without calling destroy
669 * functions defined */
670 __axl_hash_remove_common (hash
, key
, false);
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
,
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 */
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
)
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
];
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 */
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 */
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 */
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 */
762 /* next item inside the same collition
766 /* while the next item is not null,
767 * keep on iterating */
768 } while (node
!= NULL
);
772 /* update the iterator */
781 * @brief Performs a foreach operation over all items stored in the
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
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
);
815 * @brief Allows to perform a foreach operation providing two user
816 * defined pointer to be passed to the foreach function for each item
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
831 * @param user_data2 Second User defined data to be passed to the
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
);
851 * @brief Three user defined pointers foreach function over a hash.
853 * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
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
861 * @param user_data The user defined pointer to be configured in the
864 * @param user_data2 Second user defined pointer to be configured in
867 * @param user_data3 Third user defined pointer to be configured in
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
);
885 * @brief Four user defined pointers foreach function over a hash.
887 * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
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
895 * @param user_data The user defined pointer to be configured in the
898 * @param user_data2 Second user defined pointer to be configured in
901 * @param user_data3 Third user defined pointer to be configured in
904 * @param user_data4 Forth user defined pointer to be configured in
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
);
923 * @brief Allows to check if the provided key is found on the given
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:
929 * // just compare if the provided key returns some value
930 * bool value = (axl_hash_get (hash, "key2") != NULL);
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
,
947 /* check if the hash is provided without loggin an error */
948 return (__axl_hash_internal_lookup (hash
, key
) != NULL
);
952 * @internal function for axl_hash_copy.
954 bool __axl_hash_copy_foreach (axlPointer key
,
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 */
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)
979 /* it isn't the node looked up */
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 */
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
)
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
,
1032 /* make initial step to be equal
1033 * to the current hash size copied
1034 * to avoid resizing operations
1035 * during the foreach. */
1038 result
->step
= hash
->step
;
1040 /* check empty hash value */
1041 if (hash
->hash_size
== 0)
1044 /* copy all items */
1045 axl_hash_foreach4 (hash
, __axl_hash_copy_foreach
, hash
, result
, key_copy
, value_copy
);
1048 /* return created hash */
1053 * @brief Returns the number of items already stored on the provided
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 */
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
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
);
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
)
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 */
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
);
1115 /* update iterator */
1118 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "number of empty cells: %d", count
);
1120 /* get the number properly used cells (no collitions) */
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
);
1130 if (show_item
!= NULL
) {
1131 show_item (node
->key
, node
->data
);
1135 /* update 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 */
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
);
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 */
1161 /* update iterator */
1164 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "number of collitioned cells: %d", count
);
1172 * @brief Allows to deallocate the hash provided.
1174 * @param hash The hash to deallocate.
1176 void axl_hash_free (axlHash
* hash
)
1182 /* do not perform any operation if a null reference is
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
];
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
);
1207 /* while more nodes */
1208 } while (node
!= NULL
);
1211 /* update the iterator */
1215 /* now release the table */
1216 axl_free (hash
->table
);
1220 axl_factory_free (hash
->factory
);
1222 /* now release the hash itself */
1225 /* nothing more to free */
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
;
1242 /* configure first */
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
];
1250 /* first node found, store it */
1251 cursor
->node
= node
;
1255 /* node not found, go next position */
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
];
1266 /* find last entry filled, now find
1267 * last entry in the same index */
1268 while (node
->next
!= NULL
)
1272 cursor
->node
= node
;
1276 /* node not found, go next position */
1281 /* if the node wasn't found, reset index */
1285 /* cursor initialized */
1290 * \addtogroup axl_hash_cursor_module
1295 * @brief Allows to get a cursor to iterate the hash in a linear and
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:
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);
1334 * axl_hash_cursor_next (cursor);
1338 * // free the cursor
1339 * axl_hash_cursor_free (cursor);
1342 * @param hash The hash that the new cursor (\ref axlHashCursor) will
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);
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);
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
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
1396 __axl_hash_cursor_init (cursor
, false);
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
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
1416 if (cursor
->node
== NULL
) {
1417 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "no nodes found....");
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
;
1430 /* node not found, go next position */
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
;
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! */
1452 /* node not found, go next position */
1456 /* nothing to be done */
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
1467 * @return \ref true if more items are found, otherwise \ref false is
1470 bool axl_hash_cursor_has_next (axlHashCursor
* cursor
)
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..");
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
)
1488 /* node not found, go next position */
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
);
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
1520 * @param cursor The cursor pointing to the item inside the hash that
1523 void axl_hash_cursor_remove (axlHashCursor
* cursor
)
1527 axl_return_if_fail (cursor
);
1529 /* if current cursor is pointing nowhere, just do nothing */
1530 if (cursor
->node
== NULL
)
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
];
1550 /* node not found, go next position */
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
)
1573 return cursor
->node
->data
;
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
)
1590 /* return key pointer */
1591 return cursor
->node
->key
;
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
;
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 */