Annotation of gpl/axl/src/axl_hash.c, revision 1.1.1.2
1.1 misho 1: /*
1.1.1.2 ! misho 2: * Libaxl: Another XML library
1.1 misho 3: * Copyright (C) 2006 Advanced Software Production Line, S.L.
4: *
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.
9: *
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.
14: *
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
19: *
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.
26: *
27: * For commercial support on build XML enabled solutions contact us:
28: *
29: * Postal address:
30: * Advanced Software Production Line, S.L.
31: * Edificio Alius A, Oficina 102,
32: * C/ Antonio Suarez Nº 10,
33: * Alcalá de Henares 28802 Madrid
34: * Spain
35: *
36: * Email address:
37: * info@aspl.es - http://www.aspl.es/xml
38: */
39: #include <axl_hash.h>
40: #include <axl_factory.h>
41: #include <axl_log.h>
42:
43: #define LOG_DOMAIN "axl-hash"
44:
45: /**
46: * \defgroup axl_hash_module Axl Hash: A hash table used by Axl Library
47: */
48:
49: /**
50: * \addtogroup axl_hash_module
51: * @{
52: */
53:
54: typedef struct _axlHashNode axlHashNode;
55:
56: struct _axlHashNode {
57: /* the key stored and the destroy function */
58: axlPointer key;
59: axlDestroyFunc key_destroy;
60:
61: /* the data stored and the destroy function */
62: axlPointer data;
63: axlDestroyFunc data_destroy;
64:
65: /* a pointer to the next item */
66: axlHashNode * next;
67: };
68:
69: struct _axlHash {
70: /* the hash function */
71: axlHashFunc hash;
72: axlEqualFunc equal;
73:
74: /* the hash table, implemented using chaining for collition
75: * resolution. */
76: axlHashNode ** table;
77:
78: /* factory to allocate nodes */
79: axlFactory * factory;
80:
81: /* stored items in the hash */
82: int items;
83:
84: /* the hash size */
85: int hash_size;
86:
87: /* steps: how many slots are allocated when the hash is
88: * resized */
89: int step;
90: };
91:
92: /**
93: * @internal Implementation of the axl hash cursor.
94: */
95: struct _axlHashCursor {
96: /* a pointer to the hash */
97: axlHash * hash;
98:
99: /* a pointer to the node inside the hash (current value) */
100: axlHashNode * node;
101:
102: /* the value if the index being accessed by the node
103: * pointed (current value) */
104: int index;
105: };
106:
107: /**
108: * @brief Public hash implementation for keys that are strings.
109: *
110: * @param _key The string key to hash.
111: *
112: * @return A value associated to the key.
113: */
114: unsigned int axl_hash_string (axlPointer _key)
115: {
116: /* never is received a NULL value at this function, so, don't
117: * check it */
118: int g, h = 0;
119: char * key = _key;
120:
121: /* hashing taken from the Red Dragon book!! */
122: while (*key) {
123: h = (h << 4) + *key;
124: if ((g = h & 0xF0000000) != 0) {
125: h ^= g >> 24;
126: h ^= g;
127: }
128:
129: ++ key;
130: } /* end while */
131:
132: /* return the value */
133: return h;
134: }
135:
136: /**
137: * @brief Common equal hash function associated to \ref
138: * axl_hash_string that allows to check two keys to be equal,
139: * conforming to the results expected by the hash (\ref axlHash).
140: *
141: * @param keya The key to compare.
142: *
143: * @param keyb The other key to compare.
144: *
145: * @return 0 if both strings are equal and any other else value when
146: * they differs.
147: */
148: int axl_hash_equal_string (axlPointer keya,
149: axlPointer keyb)
150: {
151: char * _keya = keya;
152: char * _keyb = keyb;
153: int i = 0;
154:
155: while (_keya [i] != 0 && _keyb [i] != 0) {
156:
157: /* check values */
158: if (_keya [i] != _keyb [i])
159: return 1;
160:
161: /* update the iterator */
162: i++;
163: } /* end while */
164:
165: /* check that both string ends at the same point */
166: if (_keya [i] != 0 || _keyb [i] != 0)
167: return 1;
168:
169: /* both keys are equal */
170: return 0;
171: }
172:
173: /**
174: * @brief Convenience hashing function to store keys that are
175: * integers.
176: *
177: * @param key The key that is supported to contain a int value stored
178: * using \ref INT_TO_PTR.
179: *
180: * @return The index in the hash where is located the associated data.
181: */
182: unsigned int axl_hash_int (axlPointer key)
183: {
184: int value = PTR_TO_INT (key);
185:
186: return (unsigned int) value;
187: }
188:
189: /**
190: * @brief Convenience hash function to compare two keys that holds
191: * integers values.
192: *
193: * @param keya The first key to compare.
194: * @param keyb The second key to compare.
195: *
196: * @return 0 if both keys are equal, 1 if not.
197: */
198: int axl_hash_equal_int (axlPointer keya,
199: axlPointer keyb)
200: {
201: /* return if both keys containing int values are equal */
202: return (PTR_TO_INT (keya) == PTR_TO_INT(keyb)) ? 0 : 1;
203: }
204:
205:
206: /**
207: * @internal Internal lookup function, returns the hole hash node.
208: *
209: * @param hash The hash where the lookup will be performed.
210: *
211: * @param key The key that is being looked up.
212: *
213: * @return The axlHashNode reference or NULL if not found.
214: */
215: axlHashNode * __axl_hash_internal_lookup (axlHash * hash, axlPointer key)
216: {
217: axlHashNode * node;
218:
219: axl_return_val_if_fail (hash, NULL);
220:
221: /* get the node at the provided position */
222: if (hash->hash_size == 0)
223: return NULL;
224: node = hash->table [hash->hash (key) % hash->hash_size];
225:
226: /* node not found */
227: if (node == NULL)
228: return NULL;
229:
230: /* check for equal keys */
231: if (hash->equal (node->key, key) == 0)
232: return node;
233:
234: while (node->next != NULL) {
235: /* seems we have more nodes */
236: node = node->next;
237:
238: /* check for equal keys */
239: if (hash->equal (node->key, key) == 0)
240: return node;
241: } /* end */
242:
243: /* node not found */
244: return NULL;
245: }
246:
247: /**
248: * @brief Creates a new hash table using the function provided as
249: * hashing function.
250: *
251: * The hash function (\ref axlHashFunc) allows the hash table to
252: * distribute values across the table while performing inserts
253: * operation but it is also used while getting data from the table.
254: *
255: * A second function is required (\ref axlEqualFunc) to resolve
256: * internal table conflicts while placing data that are indexed using
257: * the same value generated by \ref axlHashFunc. This hash
258: * implementation store items at the giving position using a linked
259: * list (Chaining collition resolution). Knowing this, an external
260: * function is required to compare items to ensure they are selected
261: * properly.
262: *
263: * This hash accept any kind of key and values to be stored as long as
264: * the provided functions returns different identifiers to store
265: * items. However, because the common use of a hash is to store data
266: * using strings as keys two functions are provided by default to
267: * create a string index hash table: \ref axl_hash_equal_string and
268: * \ref axl_hash_string.
269: *
270: * \code
271: * // create a string indexed hash
272: * axlHash * hash = axl_hash_new (axl_hash_string, axl_hash_equal_string);
273: * \endcode
274: *
275: * Additionally, two functions are provided to create hash containing
276: * integer values as keys: \ref axl_hash_int and \ref axl_hash_equal_int.
277: *
278: * Once the hash is created the following functions must be used to
279: * store data:
280: *
281: * - \ref axl_hash_insert
282: * - \ref axl_hash_insert_full
283: *
284: * Then, use the following function to get data associated to the
285: * provided key.
286: *
287: * - \ref axl_hash_get
288: *
289: * Finally, you can use the following functions to either remove items
290: * from the hash and to completely deallocate the memory used by the
291: * hash and all of its data:
292: *
293: * - \ref axl_hash_remove
294: * - \ref axl_hash_free
295: *
296: *
297: * @param hash The hashing function to be used for this table.
298: *
299: * @param equal The equal function used by the hash to actually check
300: * that two stored items are equal (using the key value)
301: *
302: * @return A newly created hash table that is deallocated by using \ref axl_hash_free.
303: */
304: axlHash * axl_hash_new (axlHashFunc hash, axlEqualFunc equal)
305: {
306: /* call to full implementation */
307: return axl_hash_new_full (hash, equal, 10);
308: }
309:
310: /**
311: * @brief The function works the same way like \ref axl_hash_new, but
312: * provides a way to configure how many unit are allocated on hash
313: * resizing operations.
314: *
315: * See \ref axl_hash_new for more information. That function uses a
316: * default step value equal to 10.
317: *
318: * @param hash The hashing function to be used for this table.
319: *
320: * @param equal The equal function used by the hash to actually check
321: * that two stored items are equal (using the key value)
322: *
323: * @param step The number of empty new slots to allocate once the hash
324: * must be resized.
325: *
326: * @return A newly created hash table that is deallocated by using \ref axl_hash_free.
327: */
328: axlHash * axl_hash_new_full (axlHashFunc hash,
329: axlEqualFunc equal,
330: int step)
331: {
332: /* create the hash */
333: axlHash * result;
334:
335: result = axl_new (axlHash, 1);
1.1.1.2 ! misho 336: /* check allocated node */
! 337: if (result == NULL)
! 338: return NULL;
! 339:
1.1 misho 340: result->factory = axl_factory_create (sizeof (axlHashNode));
1.1.1.2 ! misho 341: /* check allocated node */
! 342: if (result->factory == NULL) {
! 343: /* release allocated node */
! 344: axl_free (result);
! 345: return NULL;
! 346: }
! 347:
1.1 misho 348: result->hash = hash;
349: result->equal = equal;
350: result->step = step;
351:
352: /* return the hash table created */
353: return result;
354: }
355:
356: /**
357: * @brief Inserts a key index value into the provided hash table.
358: *
359: * The function will store the data provided on the hash setting no
360: * destroy function for the key and the data stored. See \ref
361: * axl_hash_insert_full for more details.
362: *
363: * <b>NOTE:</b> The insert operation will replace a previously
364: * inserted item with the same key. If no item is found, and insert
365: * will take place, otherwise previous item is replaced calling to the
366: * key destroy and data destroy defined.
367: *
368: * @param hash The hash table where the insert operation will be
369: * produced.
370: *
371: * @param key The key to store in the hash table. If the key is found,
372: * previous data is replaced, storing this new key and the value
373: * provided.
374: *
375: * @param data The data to store associated to the provided key.
376: */
377: void axl_hash_insert (axlHash * hash,
378: axlPointer key,
379: axlPointer data)
380: {
381: /* call to the full implementation */
382: axl_hash_insert_full (hash, key, NULL, data, NULL);
383:
384: /* nothing more to do */
385: return;
386: }
387:
388: /**
389: * @internal Function used to create the node that will be stored in
390: * the hash.
391: */
392: #define __axl_hash_create_node(factory, node, key, key_destroy, data, data_destroy)\
393: node = axl_factory_get (factory);\
1.1.1.2 ! misho 394: if (node != NULL) { \
! 395: node->key = key; \
! 396: node->key_destroy = key_destroy; \
! 397: node->data = data; \
! 398: node->data_destroy = data_destroy; \
! 399: }
1.1 misho 400:
401: /**
402: * @internal Function that performs the hash insertion for the
403: * selected node.
404: */
405: #define __axl_hash_insert_node(_pos,_hash,_key,_node,_increase)\
406: _pos = (_hash->hash (_key)) % _hash->hash_size;\
407: _node->next = _hash->table [_pos];\
408: _hash->table [pos] = _node;\
409: if (_increase)\
410: _hash->items++;
411:
412: /**
413: * @brief Inserts a key value into the provided hash table, allowing
414: * to provide deallocation functions for the key and the data to be
415: * stored.
416: *
417: * <b>NOTE:</b> The insert operation will replace a previously
418: * inserted item with the same key. If no item is found, an insert
419: * will take place, otherwise previous item is replaced calling to the
420: * key destroy and data destroy functions defined.
421: *
422: * @param hash The hash table where the data will be added.
423: *
424: * @param key The key to store in the hash table. If the key is found,
425: * previous data is replaced, storing this new key and the value
426: * provided.
427: *
428: * @param key_destroy An optional destroy function that will be called
429: * to deallocate the key provided.
430: *
431: * @param data The data to store associated to the provided key.
432: *
433: * @param data_destroy An optional destroy function that will be
434: * called to deallocate the data provided.
435: */
436: void axl_hash_insert_full (axlHash * hash,
437: axlPointer key,
438: axlDestroyFunc key_destroy,
439: axlPointer data,
440: axlDestroyFunc data_destroy)
441: {
1.1.1.2 ! misho 442: int pos = 0;
! 443: axlHashNode * node = NULL;
! 444: axlHashNode * aux = NULL;
! 445: int iterator = 0;
! 446: axlHashNode ** temp;
1.1 misho 447:
448: /* check incoming data */
449: axl_return_if_fail (hash);
450:
451: /* check the really basic case where the hash has no data
452: * stored yet. */
453: if (hash->hash_size == 0) {
454: /* allocate memory for the hash */
455: hash->table = axl_new (axlHashNode *, hash->step);
1.1.1.2 ! misho 456: /* check allocated value */
! 457: if (hash->table == NULL)
! 458: return;
1.1 misho 459: hash->hash_size = hash->step;
460:
461: /* create the node to store */
462: __axl_hash_create_node (hash->factory, node, key, key_destroy, data, data_destroy);
1.1.1.2 ! misho 463: /* check allocated value and cleanup on failure */
! 464: if (node == NULL) {
! 465: hash->hash_size = 0;
! 466: axl_free (hash->table);
! 467: hash->table = NULL;
! 468: return;
! 469: } /* end if */
1.1 misho 470:
471: /* insert the node into the hash */
472: __axl_hash_insert_node (pos, hash, key, node, axl_true);
473:
474: return;
475: }
476:
477: /* now check for a more complex case */
478: node = __axl_hash_internal_lookup (hash, key);
479:
480: /* if the node is not found and the hash size can't hold more items, expand it and rehash */
481: if ((hash->hash_size == hash->items) && (node == NULL)) {
482: /* seems we need to rehash items, reallocating enough
483: * memory */
484:
485: /* before allocating more memory, extract all items to
486: * be reallocated */
487: iterator = 0;
488: node = NULL;
489: while (iterator < hash->hash_size) {
490:
491: /* check for content */
492: if (hash->table[iterator] != NULL) {
493: /* check if node has been initialized,
494: * and set it to the first position */
495: if (node == NULL) {
496: /* configure init node position */
497: node = hash->table[iterator];
498:
499: /* and last aux position */
500: aux = node;
501: while (aux->next != NULL) {
502: /* update reference */
503: aux = aux->next;
504: }
505:
506: } else {
507: /* make aux to point to the next list */
508: aux->next = hash->table[iterator];
509:
510: /* and while the last item is not
511: * reached, move aux to point to the
512: * last item of the chain */
513: while (aux->next != NULL) {
514: /* update reference */
515: aux = aux->next;
516: }
517: }
518: } /* end if */
519:
520: /* update the iterator */
521: iterator++;
522: }
523:
524: /* now we have in node a complete list of items
525: * stored, allocate more memory and rehash */
526: hash->hash_size += hash->step;
1.1.1.2 ! misho 527: temp = hash->table;
1.1 misho 528: hash->table = realloc (hash->table, sizeof (axlHashNode *) * (hash->hash_size));
529:
1.1.1.2 ! misho 530: /* check realloc operation */
! 531: if (hash->table == NULL) {
! 532: /* alloc failed, restore and cleanup */
! 533: hash->table = temp;
! 534: hash->hash_size -= hash->step;
! 535: return;
! 536: } /* end if */
! 537:
1.1 misho 538: /* clear the table */
539: memset (hash->table, 0, sizeof (axlHashNode*) * (hash->hash_size));
540:
541: /* for each item inside the list rehash it */
542: while (node != NULL) {
543: /* store next item to rehash in aux */
544: aux = node->next;
545:
546: /* insert the node into the hash */
547: __axl_hash_insert_node (pos, hash, node->key, node, axl_false);
548:
549: /* update the reference */
550: node = aux;
551: } /* end while */
552:
553: /* clear node reference */
554: node = NULL;
555: } /* rehashing if end */
556:
557: /* we have enough space to store the item create the
558: node to store */
559: if (node == NULL) {
560: /* create a new node */
561: __axl_hash_create_node (hash->factory, node, key, key_destroy, data, data_destroy);
1.1.1.2 ! misho 562: /* check allocated value and cleanup on failure */
! 563: if (node == NULL) {
! 564: return;
! 565: } /* end if */
1.1 misho 566:
567: /* insert the node into the hash as usual */
568: __axl_hash_insert_node (pos, hash, key, node, axl_true);
569: } else {
570: /* don't create a node, replace previous content and use new content */
571: if (node->key_destroy != NULL) {
572: node->key_destroy (node->key);
573: }
574: if (node->data_destroy != NULL) {
575: node->data_destroy (node->data);
576: }
577:
578: /* now use new data */
579: node->key = key;
580: node->key_destroy = key_destroy;
581: node->data = data;
582: node->data_destroy = data_destroy;
583: }
584:
585: /* nothing more man!! */
586: return;
587: }
588:
589: /**
590: * @internal Function that supports axl_hash_remove and
591: * axl_hash_delete.
592: *
593: * The function returns axl_true if an item was removed due to the call
594: * done.
595: */
596: axl_bool __axl_hash_remove_common (axlHash * hash,
597: axlPointer key,
598: axl_bool remove)
599: {
600: axlHashNode * node;
601: axlHashNode * aux;
602: int pos;
603:
604: axl_return_val_if_fail (hash, axl_false);
605:
606: /* do not perform any operation if the hash is empty */
607: if (hash->hash_size == 0)
608: return axl_false;
609:
610: /* get the node at the provided position */
611: pos = (hash->hash (key)) % hash->hash_size;
612: node = hash->table [pos];
613:
614: /* node not found */
615: if (node == NULL)
616: return axl_false;
617:
618: /* check for equal keys */
619: if (hash->equal (node->key, key) == 0) {
620: /* set that no items are available at the provided
621: * position */
622: hash->table [pos] = node->next;
623:
624: remove_element:
1.1.1.2 ! misho 625:
! 626: /* decreases elements found */
! 627: hash->items--;
! 628:
1.1 misho 629: /* key destruction is defined */
630: if (node->key_destroy != NULL && remove)
631: node->key_destroy (node->key);
632:
633: /* if data destruction is defined */
634: if (node->data_destroy != NULL && remove)
635: node->data_destroy (node->data);
636:
637: /* delete the node */
638: axl_factory_release_spare (hash->factory, node);
639: /* axl_free (node); */
640:
641: /* element destroyed, nothing more to do around
642: * here */
643: return axl_true;
644: }
645:
646: /* seems we have more nodes */
647: while (node->next != NULL) {
648: /* store a reference to the current node (which will
649: * be the previous on next sentences) */
650: aux = node;
651:
652: /* update the reference to the next node */
653: node = node->next;
654:
655: /* check for equal keys */
656: if (hash->equal (node->key, key) == 0) {
657: /* make previous node to point to the next
658: * element of the following node */
659: aux->next = node->next;
660:
661: goto remove_element;
662: }
663: } /* end */
664:
665: /* no item was found on the hash */
666: return axl_false;
667: }
668:
669: /**
670: * @brief Allows to remove the selected pair key/value on the provided
671: * hash table.
672: *
673: * The function will remevo the item but it will not resize the table
674: * due to it. The function will call to the key destroy and data
675: * destroy function if they were defined at the insertion time (\ref
676: * axl_hash_insert_full).
677: *
678: *
679: * @param hash The hash table where the removal operation will be
680: * performed.
681: *
682: * @param key The key to lookup to be removed.
683: *
684: * @return The function returns axl_true if the item was removed,
685: * otherwise axl_false is returned. If the function returns axl_true, it means
686: * the object was stored in the hash before calling to remove it.
687: */
688: axl_bool axl_hash_remove (axlHash * hash,
689: axlPointer key)
690: {
691: /* call common implementation deleting data with destroy
692: * functions defined */
693: return __axl_hash_remove_common (hash, key, axl_true);
694: }
695:
696: /**
697: * @brief Allows to remove the selected pair key/value on the provided
698: * hash table, without calling to destroy functions.
699: *
700: * The function will remove the item but it will not resize the table
701: * due to it. The function will NOT call to the key destroy and data
702: * destroy function if they were defined at the insertion time (\ref
703: * axl_hash_insert_full).
704: *
705: *
706: * @param hash The hash table where the removal operation will be
707: * performed.
708: *
709: * @param key The key to lookup to be removed.
710: *
711: * @return The function returns axl_true if the item was removed
712: * (deallocation functions aren't called), otherwise axl_false is
713: * returned. If the function returns axl_true, it means the object was
714: * stored in the hash before calling to remove.
715: */
716: axl_bool axl_hash_delete (axlHash * hash,
717: axlPointer key)
718: {
719: /* call common implementation, without calling destroy
720: * functions defined */
721: return __axl_hash_remove_common (hash, key, axl_false);
722: }
723:
724: /**
725: * @brief Allows to get the content associated to the key provided
726: * inside the hash provided.
727: *
728: * @param hash The hash table where the lookup will be performed.
729: *
730: * @param key The key to use to retrieve the information.
731: *
732: * @return NULL or the associated data to the key provided. The
733: * function will also return a NULL value if provided a NULL hash
734: * reference or a NULL key reference.
735: */
736: axlPointer axl_hash_get (axlHash * hash,
737: axlPointer key)
738: {
739: axlHashNode * node;
740:
741: axl_return_val_if_fail (hash, NULL);
742:
743: /* check for empty hash to return NULL directly */
744: if (hash->items == 0)
745: return NULL;
746:
747: /* lookup using internal function */
748: node = __axl_hash_internal_lookup (hash, key);
749:
750: /* return the content or NULL if not defined the node */
751: if (node != NULL)
752: return node->data;
753: return NULL;
754: }
755:
756: /**
757: * @internal
758: *
759: * Common implementation for both foreach functions: axl_hash_foreach
760: * and axl_hash_foreach2.
761: */
762: void __axl_hash_foreach (axlHash * hash,
763: axlHashForeachFunc func,
764: axlHashForeachFunc2 func2,
765: axlHashForeachFunc3 func3,
766: axlHashForeachFunc4 func4,
767: axlPointer user_data,
768: axlPointer user_data2,
769: axlPointer user_data3,
770: axlPointer user_data4)
771: {
772:
773: int iterator = 0;
774: axlHashNode * node;
775:
776: /* perform some basic checks */
777: axl_return_if_fail (hash);
778:
779: /* foreach item row inside the hash table */
780: while (iterator < hash->hash_size) {
781:
782: /* check for content */
783: if (hash->table[iterator] != NULL) {
784: /* get the first item inside the table */
785: node = hash->table[iterator];
786:
787: do {
788: /* check for one user defined pointer
789: * foreach: notify the item found */
790: if (func != NULL && func (node->key, node->data, user_data)) {
791: /* user have decided to stop */
792: return;
793: } /* end if */
794:
795: /* check for two user defined pointers
796: * notify the item found */
797: if (func2 != NULL && func2 (node->key, node->data, user_data, user_data2)) {
798: /* user have decided to stop */
799: return;
800: } /* end if */
801:
802: /* check for three user defined pointers
803: * notify the item found */
804: if (func3 != NULL && func3 (node->key, node->data, user_data, user_data2, user_data3)) {
805: /* user have decided to stop */
806: return;
807: } /* end if */
808:
809: /* check for four user defined
810: * pointers notify the item found */
811: if (func4 != NULL && func4 (node->key, node->data, user_data, user_data2, user_data3, user_data4)) {
812: /* user have decided to stop */
813: return;
814: } /* end if */
815:
816: /* next item inside the same collition
817: * position */
818: node = node->next;
819:
820: /* while the next item is not null,
821: * keep on iterating */
822: } while (node != NULL);
823:
824: } /* end if */
825:
826: /* update the iterator */
827: iterator++;
828:
829: } /* end while */
830:
831: return;
832: }
833:
834: /**
835: * @brief Performs a foreach operation over all items stored in the
836: * hash provided.
837: *
838: * The function provided (<b>func</b>) will be called passing in the
839: * item found, and the data provided (third argument).
840: *
841: * Because the \ref axlHashForeachFunc function is used, \ref axl_true must be
842: * returned to stop the foreach process. In the case all items must be
843: * visited, \ref axl_false must be returned in any case.
844: *
845: * @param hash The hash table where the iteration process will take
846: * place.
847: *
848: * @param func The function to call for each item found.
849: *
850: * @param user_data User defined data to be passed in to the function callback along with the item found.
851: */
852: void axl_hash_foreach (axlHash * hash,
853: axlHashForeachFunc func,
854: axlPointer user_data)
855:
856: {
857:
858: /* perform the foreach operation using common support */
859: __axl_hash_foreach (hash,
860: /* foreach function */
861: func, NULL, NULL, NULL,
862: /* user defined data */
863: user_data, NULL, NULL, NULL);
864:
865: return;
866: }
867:
868: /**
869: * @brief Allows to perform a foreach operation providing two user
870: * defined pointer to be passed to the foreach function for each item
871: * found.
872: *
873: * This function works like \ref axl_hash_foreach function but support
874: * two user defined pointers. See \ref axl_hash_foreach for more information.
875: *
876: * @param hash The hash where the iteration will be performed.
877: *
878: * @param func The foreach function that will be called for all nodes
879: * found passed in both pointers defined along with the key value and
880: * the value associated.
881: *
882: * @param user_data User defined data to be passed to the foreach
883: * function.
884: *
885: * @param user_data2 Second User defined data to be passed to the
886: * foreach function.
887: */
888: void axl_hash_foreach2 (axlHash * hash,
889: axlHashForeachFunc2 func,
890: axlPointer user_data,
891: axlPointer user_data2)
892:
893: {
894: /* perform the foreach operation using common support */
895: __axl_hash_foreach (hash,
896: /* foreach function */
897: NULL, func, NULL, NULL,
898: /* user defined data */
899: user_data, user_data2, NULL, NULL);
900:
901: return;
902: }
903:
904: /**
905: * @brief Three user defined pointers foreach function over a hash.
906: *
907: * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
908: * information.
909: *
910: * @param hash The hash where the foreach operation will take place.
911: *
912: * @param func The function to be called for each item found in the
913: * hash.
914: *
915: * @param user_data The user defined pointer to be configured in the
916: * hash.
917: *
918: * @param user_data2 Second user defined pointer to be configured in
919: * the hash.
920: *
921: * @param user_data3 Third user defined pointer to be configured in
922: * the hash.
923: */
924: void axl_hash_foreach3 (axlHash * hash,
925: axlHashForeachFunc3 func,
926: axlPointer user_data,
927: axlPointer user_data2,
928: axlPointer user_data3)
929: {
930: /* perform the foreach operation using common support */
931: __axl_hash_foreach (hash,
932: /* foreach function */
933: NULL, NULL, func, NULL,
934: /* user defined data */
935: user_data, user_data2, user_data3, NULL);
936: }
937:
938: /**
939: * @brief Four user defined pointers foreach function over a hash.
940: *
941: * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
942: * information.
943: *
944: * @param hash The hash where the foreach operation will take place.
945: *
946: * @param func The function to be called for each item found in the
947: * hash.
948: *
949: * @param user_data The user defined pointer to be configured in the
950: * hash.
951: *
952: * @param user_data2 Second user defined pointer to be configured in
953: * the hash.
954: *
955: * @param user_data3 Third user defined pointer to be configured in
956: * the hash.
957: *
958: * @param user_data4 Forth user defined pointer to be configured in
959: * the hash.
960: */
961: void axl_hash_foreach4 (axlHash * hash,
962: axlHashForeachFunc4 func,
963: axlPointer user_data,
964: axlPointer user_data2,
965: axlPointer user_data3,
966: axlPointer user_data4)
967: {
968: /* perform the foreach operation using common support */
969: __axl_hash_foreach (hash,
970: /* foreach functions */
971: NULL, NULL, NULL, func,
972: /* user defined data */
973: user_data, user_data2, user_data3, user_data4);
974: }
975:
976: /**
977: * @brief Allows to check if the provided key is found on the given
978: * hash table.
979: *
980: * The function allows to get if the key is found on the table pretty
981: * much the behaviour that we could get using the following:
982: * \code
983: * // just compare if the provided key returns some value
984: * axl_bool value = (axl_hash_get (hash, "key2") != NULL);
985: * \endcode
986: *
987: * However it could happen that the value associated to the key, which
988: * already exists, is a NULL pointer, making previous comparation to
989: * not work in all cases. This function allows to check for the
990: * existance of a key and its associated data no mather what is the
991: * value of the associated data.
992: *
993: * @param hash The hash table to check for a key value.
994: * @param key The key to check for its existance.
995: *
996: * @return axl_true if the key is found, otherwise axl_false is returned.
997: */
998: axl_bool axl_hash_exists (axlHash * hash,
999: axlPointer key)
1000: {
1001: /* check if the hash is provided without loggin an error */
1002: return (__axl_hash_internal_lookup (hash, key) != NULL);
1003: }
1004:
1005: /**
1006: * @internal function for axl_hash_copy.
1007: */
1008: axl_bool __axl_hash_copy_foreach (axlPointer key,
1009: axlPointer data,
1010: /* user defined pointers */
1011: axlPointer user_data, /* hash */
1012: axlPointer user_data2, /* result */
1013: axlPointer user_data3, /* key_copy */
1014: axlPointer user_data4) /* value_copy */
1015: {
1016: /* get a reference to the received data */
1017: axlHash * hash = user_data;
1018: axlHash * result = user_data2;
1019: axlHashItemCopy key_copy = user_data3;
1020: axlHashItemCopy value_copy = user_data4;
1021:
1022: /* additional variables */
1023: axlHashNode * node;
1024:
1025: /* get node to copy */
1026: node = hash->table [(hash->hash (key)) % hash->hash_size];
1027:
1028: /* check this is the node to copy */
1029: while (node != NULL) {
1030: if (hash->equal (node->key, key) == 0)
1031: break;
1032:
1033: /* it isn't the node looked up */
1034: node = node->next;
1035: } /* end while */
1036:
1037: /* copy */
1038: axl_hash_insert_full (result,
1039: /* insert the key and its destroy function. */
1040: key_copy (node->key, node->key_destroy, node->data, node->data_destroy), node->key_destroy,
1041: /* insert data and its destroy function. */
1042: value_copy (node->key, node->key_destroy, node->data, node->data_destroy), node->data_destroy);
1043:
1044: /* make the foreach process to continue until the last element */
1045: return axl_false;
1046: }
1047:
1048: /**
1049: * @brief Allows to copy the provided hash, providing the copy
1050: * function used to duplicate key and value items stored.
1051: *
1052: * The function are optional, so, if they are null, the same value is
1053: * stored in the hash (for the key and the value). In this case, if
1054: * the source hash has defined destroy function for either key or
1055: * values, they will not be configured in the returning hash.
1056: *
1057: * If function are provided, \ref axl_hash_copy will use it to get a
1058: * duplicated version for either the key or the value. In this case,
1059: * if the source hash has defined the destroy function either for the
1060: * key or the value, it will be configured in the returning hash.
1061: *
1062: * @param hash The \ref axlHash that will work as data source.
1063: *
1064: * @param key_copy The function to be used to duplicate keys.
1065: *
1066: * @param value_copy The function used to duplicate values.
1067: *
1068: * @return A newly allocated reference to a \ref axlHash containing
1069: * all values from the source hash. The function will fail if the hash
1070: * provided is a null reference or copy functions aren't provided.
1071: */
1072: axlHash * axl_hash_copy (axlHash * hash,
1073: axlHashItemCopy key_copy,
1074: axlHashItemCopy value_copy)
1075: {
1076: axlHash * result;
1077:
1078: /* return if the hash reference is null */
1079: axl_return_val_if_fail (hash, NULL);
1080: axl_return_val_if_fail (key_copy, NULL);
1081: axl_return_val_if_fail (value_copy, NULL);
1082:
1083: /* create the hash */
1084: result = axl_hash_new_full (hash->hash,
1085: hash->equal,
1086: /* make initial step to be equal
1087: * to the current hash size copied
1088: * to avoid resizing operations
1089: * during the foreach. */
1090: hash->items);
1091: /* restore step */
1092: result->step = hash->step;
1093:
1094: /* check empty hash value */
1095: if (hash->hash_size == 0)
1096: return result;
1097:
1098: /* copy all items */
1099: axl_hash_foreach4 (hash, __axl_hash_copy_foreach, hash, result, key_copy, value_copy);
1100:
1101:
1102: /* return created hash */
1103: return result;
1104: }
1105:
1106: /**
1107: * @brief Returns the number of items already stored on the provided
1108: * hash.
1109: *
1110: * @param hash The hash that is being requested for the number of
1111: * indexed data items.
1112: *
1113: * @return The number of items or -1 if it fails.
1114: */
1115: int axl_hash_items (axlHash * hash)
1116: {
1117: axl_return_val_if_fail (hash, -1);
1118:
1119: /* return current items stored */
1120: return hash->items;
1121: }
1122:
1123: /**
1124: * @brief Allows to get the amount of items that could store the hash
1125: * without allocating more additional memory.
1126: *
1127: * @param hash The hash that is being requested to return its items
1128: * capacity (key + value) pair.
1129: *
1130: * @return The capacity or -1 if the reference received is null.
1131: */
1132: int axl_hash_capacity (axlHash * hash)
1133: {
1134: axl_return_val_if_fail (hash, -1);
1135: /* return current capacity */
1136: return hash->hash_size;
1137: }
1138:
1139: /**
1140: * @internal Shows current hash status to the console.
1141: *
1142: * The function is only useful for internal hash module purposes. It
1143: * shows the numbers of items stored, the table size, the number of
1144: * collitions, etc.
1145: *
1146: * @param hash The hash where the status is requested.
1147: */
1148: void axl_hash_show_status (axlHash * hash)
1149: {
1150: /* use full implementation */
1151: axl_hash_show_status_full (hash, NULL);
1152:
1153: return;
1154: }
1155:
1156: /**
1157: * @internal Shows current hash content to the console using the
1158: * provided function to show the hash content.
1159: *
1160: * @param hash The hash that is requested to show its content.
1161: *
1162: * @param show_item The function to be used to show the content.
1163: */
1164: void axl_hash_show_status_full (axlHash * hash,
1165: axlHashPrintKeyData show_item)
1166: {
1167: axlHashNode * node;
1168: int iterator;
1169: int count;
1170: axl_return_if_fail (hash);
1171:
1172: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl hash table status:");
1173: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "table size: %d items: %d step: %d",
1174: hash->hash_size, hash->items, hash->step);
1175: /* get the number of empty blocks */
1176: iterator = 0;
1177: count = 0;
1178: while (iterator < hash->hash_size) {
1179: /* empty item found */
1180: if (hash->table[iterator] == NULL) {
1181: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "empty cell at: %d", iterator);
1182: count++;
1183: }
1184:
1185: /* update iterator */
1186: iterator++;
1187: }
1188: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of empty cells: %d", count);
1189:
1190: /* get the number properly used cells (no collitions) */
1191: iterator = 0;
1192: count = 0;
1193: while (iterator < hash->hash_size) {
1194: /* empty item found */
1195: node = hash->table[iterator];
1196: if (node != NULL && node->next == NULL) {
1197: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "properly used cell at: %d", iterator);
1198: count++;
1199:
1200: if (show_item != NULL) {
1201: show_item (node->key, node->data);
1202: }
1203: }
1204:
1205: /* update iterator */
1206: iterator++;
1207: }
1208: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of properly used cells (no collition): %d", count);
1209:
1210: /* get the number of collitioned cells */
1211: iterator = 0;
1212: count = 0;
1213: while (iterator < hash->hash_size) {
1214: /* empty item found */
1215: node = hash->table[iterator];
1216: if (node != NULL && node->next != NULL) {
1217: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "collitioned cell at: %d", iterator);
1218: count++;
1219: }
1220:
1221: /* for each node show the content */
1222: while ((show_item) != NULL && (node != NULL)) {
1223: if (show_item != NULL) {
1224: show_item (node->key, node->data);
1225: }
1226:
1227: /* update to the next node */
1228: node = node->next;
1229: }
1230:
1231: /* update iterator */
1232: iterator++;
1233: }
1234: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of collitioned cells: %d", count);
1235:
1236:
1237:
1238: return;
1239: }
1240:
1241: /**
1242: * @brief Allows to deallocate the hash provided.
1243: *
1244: * @param hash The hash to deallocate.
1245: */
1246: void axl_hash_free (axlHash * hash)
1247: {
1248: int iterator = 0;
1249: axlHashNode * node;
1250:
1251: /* do not perform any operation if a null reference is
1252: * received */
1253: if (hash == NULL)
1254: return;
1255:
1256: /* release the hash table */
1257: if (hash->table != NULL) {
1258:
1259: /* first release all nodes inside */
1260: while (iterator < hash->hash_size) {
1261: node = hash->table[iterator];
1262: if (node != NULL) {
1263: do {
1264: /* key destruction is defined */
1265: if (node->key_destroy != NULL)
1266: node->key_destroy (node->key);
1267:
1268: /* if data destruction is defined */
1269: if (node->data_destroy != NULL)
1270: node->data_destroy (node->data);
1271:
1272: /* check data */
1273: node = node->next;
1274:
1275: /* while more nodes */
1276: } while (node != NULL);
1277: } /* end if */
1278:
1279: /* update the iterator */
1280: iterator++;
1281: } /* end while */
1282:
1283: /* now release the table */
1284: axl_free (hash->table);
1285: } /* end if */
1286:
1287: /* free factory */
1288: axl_factory_free (hash->factory);
1289:
1290: /* now release the hash itself */
1291: axl_free (hash);
1292:
1293: /* nothing more to free */
1294: return;
1295: }
1296:
1297: /**
1298: * @internal Function that allows to get how many spare internal hash
1299: * nodes we can store.
1300: */
1301: int __axl_hash_spare_max (axlHash * hash)
1302: {
1303: return axl_factory_spare_max (hash->factory);
1304: }
1305:
1306: /**
1307: * @internal Function that allows to get how many spare internal hash
1308: * nodes are actually stored.
1309: */
1310: int __axl_hash_spare_next (axlHash * hash)
1311: {
1312: return axl_factory_spare_next (hash->factory);
1313: }
1314:
1315: /* @} */
1316:
1317: /**
1318: * \defgroup axl_hash_cursor_module Axl Hash Cursor: Iterator support for the Axl Hash
1319: */
1320:
1321: /* init the cursor */
1322: void __axl_hash_cursor_init (axlHashCursor * cursor, axl_bool first)
1323: {
1324: /* pointer to a hash node (basic atom holding key and value) */
1325: axlHashNode * node = NULL;
1326:
1327: if (first) {
1328: /* configure first */
1329: cursor->index = 0;
1330:
1331: /* foreach element inside the hash, check the first value */
1332: while (cursor->index < cursor->hash->hash_size) {
1333: /* check the table at the current position */
1334: node = cursor->hash->table[cursor->index];
1335: if (node != NULL) {
1336: /* first node found, store it */
1337: cursor->node = node;
1338: break;
1339: } /* end if */
1340:
1341: /* node not found, go next position */
1342: cursor->index++;
1343: } /* end while */
1344: } else {
1345: /* find last value */
1346: cursor->index = cursor->hash->hash_size - 1;
1347: cursor->node = NULL;
1348: while (cursor->index > 0) {
1349: /* check the table at the current position */
1350: node = cursor->hash->table[cursor->index];
1351: if (node != NULL) {
1352: /* find last entry filled, now find
1353: * last entry in the same index */
1354: while (node->next != NULL)
1355: node = node->next;
1356:
1357: /* configure it */
1358: cursor->node = node;
1359: break;
1360: } /* end if */
1361:
1362: /* node not found, go next position */
1363: cursor->index--;
1364: } /* end while */
1365: } /* end if */
1366:
1367: /* if the node wasn't found, reset index */
1368: if (node == NULL)
1369: cursor->index = 0;
1370:
1371: /* cursor initialized */
1372: return;
1373: }
1374:
1375: /**
1376: * \addtogroup axl_hash_cursor_module
1377: * @{
1378: */
1379:
1380: /**
1381: * @brief Allows to get a cursor to iterate the hash in a linear and
1382: * efficient way.
1383: *
1384: * The \ref axlHashCursor could be used to iterate an \ref axlHash in
1385: * an efficient way because it stores current state (position), hiding
1386: * all module details. Then using the following functions you can
1387: * modify the state (current position to get):
1388: *
1389: * - \ref axl_hash_cursor_first
1390: * - \ref axl_hash_cursor_last
1391: * - \ref axl_hash_cursor_next
1392: *
1393: * Finally, the following functions are provided to get the data stored at a
1394: * particular position, pointed by the current status of the cursor:
1395: *
1396: * - \ref axl_hash_cursor_get_key (returns the key of the current position)
1397: * - \ref axl_hash_cursor_get_value (returns the value of the current position)
1398: *
1399: * You are allowed to remove elements from the hash (\ref axlHash)
1400: * having a cursor created (\ref axlHashCursor), using \ref
1401: * axl_hash_cursor_remove.
1402: *
1403: * Here is an example:
1404: * \code
1405: * axlPointer key;
1406: * axlPointer value;
1407: * axlHashCursor * cursor;
1408: *
1409: * // create the cursor
1410: * cursor = axl_hash_cursor_new (hash);
1411: *
1412: * // while there are more elements
1413: * while (axl_hash_cursor_has_item (cursor)) {
1414: *
1415: * // get the value and key
1416: * value = axl_hash_cursor_get_key (cursor);
1417: * value = axl_hash_cursor_get_value (cursor);
1418: *
1419: * // get the next
1420: * axl_hash_cursor_next (cursor);
1421: *
1422: * }
1423: *
1424: * // free the cursor
1425: * axl_hash_cursor_free (cursor);
1426: * \endcode
1427: *
1428: * @param hash The hash that the new cursor (\ref axlHashCursor) will
1429: * provide access.
1430: *
1431: * @return A newly created \ref axlHashCursor used to iterate the
1432: * hash. Once finished you must call to \ref axl_hash_cursor_free.
1433: */
1434: axlHashCursor * axl_hash_cursor_new (axlHash * hash)
1435: {
1436: axlHashCursor * cursor;
1437:
1438: axl_return_val_if_fail (hash, NULL);
1439:
1440: /* create the cursor */
1441: cursor = axl_new (axlHashCursor, 1);
1.1.1.2 ! misho 1442: /* check allocated value */
! 1443: if (cursor == NULL)
! 1444: return NULL;
1.1 misho 1445:
1446: /* initial configuration */
1447: cursor->hash = hash;
1448:
1449: /* init the cursor */
1450: __axl_hash_cursor_init (cursor, axl_true);
1451:
1452: /* return cursor */
1453: return cursor;
1454: }
1455:
1456: /**
1457: * @brief Allows to configure the cursor to point to the first item of
1458: * the hash (if there are any).
1459: *
1460: * @param cursor The cursor that is required to be configured to point the first item.
1461: */
1462: void axl_hash_cursor_first (axlHashCursor * cursor)
1463: {
1464: axl_return_if_fail (cursor);
1465:
1466: /* init the cursor at the initial state */
1467: __axl_hash_cursor_init (cursor, axl_true);
1468:
1469: return;
1470: }
1471:
1472: /**
1473: * @brief Allows to configure the cursor to point to the last item of
1474: * the hash (if there are any).
1475: *
1476: * @param cursor The cursor that is required to be configured to point
1477: * to the last item.
1478: */
1479: void axl_hash_cursor_last (axlHashCursor * cursor)
1480: {
1481: axl_return_if_fail (cursor);
1482:
1483: /* init the cursor at the initial state, selecting the last
1484: * node */
1485: __axl_hash_cursor_init (cursor, axl_false);
1486:
1487: return;
1488: }
1489:
1490: /**
1491: * @brief Allows to configure the cursor to point to the next item of
1492: * the hash (if there are any).
1493: *
1494: * @param cursor The cursor that is required to be configured to point
1495: * to the next item.
1496: */
1497: void axl_hash_cursor_next (axlHashCursor * cursor)
1498: {
1499: axl_return_if_fail (cursor);
1500:
1501: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next element at the cursor");
1502:
1503: /* check if the current node is null and do nothing if nothing
1504: * is found */
1505: if (cursor->node == NULL) {
1506: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "no nodes found....");
1507: return;
1508: }
1509:
1510: /* basic case, the item is found in the same level */
1511: if (cursor->node->next != NULL) {
1512: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node....");
1513: /* configure new current node */
1514: cursor->node = cursor->node->next;
1515:
1516: return;
1517: } /* end if */
1518:
1519: /* node not found, go next position */
1520: cursor->index++;
1521:
1522: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "updating and checking next index: %d (hash: %d)....",
1523: cursor->index, cursor->hash->hash_size);
1524:
1525: /* check if we have reached the phisical limit of the hash */
1526: if (cursor->index >= cursor->hash->hash_size) {
1527: cursor->node = NULL;
1528: return;
1529: }
1530:
1531: /* seems next is null, see in other positions */
1532: while (cursor->index < cursor->hash->hash_size) {
1533:
1534: /* check the table at the current position */
1535: cursor->node = cursor->hash->table[cursor->index];
1536: if (cursor->node != NULL) {
1537: /* node found, stop! */
1538: break;
1539: } /* end if */
1540:
1541: /* node not found, go next position */
1542: cursor->index++;
1543: } /* end while */
1544:
1545: /* nothing to be done */
1546: return;
1547: }
1548:
1549: /**
1550: * @brief Allows to check if there are more elements next to the
1551: * current element pointed by the cursor.
1552: *
1553: * @param cursor The cursor that is required to return if there are
1554: * next items.
1555: *
1556: * @return \ref axl_true if more items are found, otherwise \ref axl_false is
1557: * returned.
1558: */
1559: axl_bool axl_hash_cursor_has_next (axlHashCursor * cursor)
1560: {
1561: int iterator;
1562: axl_return_val_if_fail (cursor, axl_false);
1563:
1564: /* check basic case */
1565: if (cursor->node != NULL && cursor->node->next != NULL) {
1566: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "next is defined..");
1567: return axl_true;
1568: }
1569:
1570: /* seems next is null, see in other positions */
1571: iterator = cursor->index + 1;
1572: while (iterator < cursor->hash->hash_size) {
1573: /* check the table at the current position */
1574: if (cursor->hash->table[iterator] != NULL)
1575: return axl_true;
1576:
1577: /* node not found, go next position */
1578: iterator++;
1579: } /* end while */
1580:
1581: return axl_false;
1582: }
1583:
1584: /**
1585: * @brief Allows to know if the current position has items.
1586: *
1587: * @param cursor The cursor pointing to a particular element inside
1588: * the hash (or not).
1589: *
1590: * @return \ref axl_true if the hash that is iterated can return data at
1591: * the current position, otherwise \ref axl_false is returned.
1592: */
1593: axl_bool axl_hash_cursor_has_item (axlHashCursor * cursor)
1594: {
1595: axl_return_val_if_fail (cursor, axl_false);
1596:
1597: /* return axl_true if there are a item selected */
1598: return (cursor->node != NULL);
1599: }
1600:
1601: /**
1602: * @brief Allows to remove current element pointed by the cursor,
1603: * maintainig internal state of the cursor, calling to the destroy
1604: * function associated in the hash.
1605: *
1606: * The function will call to the destroy function asociated to the
1607: * hash.
1608: *
1609: * @param cursor The cursor pointing to the item inside the hash that
1610: * must be removed.
1611: */
1612: void axl_hash_cursor_remove (axlHashCursor * cursor)
1613: {
1614: axlHashNode * node;
1615:
1616: axl_return_if_fail (cursor);
1617:
1618: /* if current cursor is pointing nowhere, just do nothing */
1619: if (cursor->node == NULL)
1620: return;
1621:
1622: /* remember node */
1623: node = cursor->node->next;
1624:
1625: /* remove node selected */
1626: axl_hash_remove (cursor->hash, cursor->node->key);
1627:
1628: /* configure next item */
1629: cursor->node = node;
1630: if (cursor->node == NULL) {
1631: while (cursor->index < cursor->hash->hash_size) {
1632: /* check the table at the current position */
1633: if (cursor->hash->table[cursor->index] != NULL) {
1634: /* configure the next node */
1635: cursor->node = cursor->hash->table[cursor->index];
1636: return;
1637: }
1638:
1639: /* node not found, go next position */
1640: cursor->index++;
1641: } /* end while */
1642: } /* end if */
1643:
1644: return;
1645: }
1646:
1647: /**
1648: * @brief Allows to get current value at the current cursor state.
1649: *
1650: * @param cursor The cursor that will be used to return the data
1651: * located at the hash, using cursor current state.
1652: */
1653: axlPointer axl_hash_cursor_get_value (axlHashCursor * cursor)
1654: {
1655: axl_return_val_if_fail (cursor, NULL);
1656:
1657: /* nothing to return if current is NULL */
1658: if (cursor->node == NULL)
1659: return NULL;
1660:
1661: /* return data */
1662: return cursor->node->data;
1663: }
1664:
1665: /**
1666: * @brief Allows to get current key at the current cursor state.
1667: *
1668: * @param cursor The cursor that will be used to return the data
1669: * located at the hash, using cursor current state.
1670: */
1671: axlPointer axl_hash_cursor_get_key (axlHashCursor * cursor)
1672: {
1673: axl_return_val_if_fail (cursor, NULL);
1674:
1675: /* nothing to return if current is NULL */
1676: if (cursor->node == NULL)
1677: return NULL;
1678:
1679: /* return key pointer */
1680: return cursor->node->key;
1681: }
1682:
1683: /**
1684: * @brief Allows to get the reference to the hash that is associated
1685: * to the cursor received.
1686: *
1687: * @param cursor The cursor that is required to return the hash associated.
1688: *
1689: * @return A reference to the hash being iterated or NULL if fails.
1690: */
1691: axlHash * axl_hash_cursor_hash (axlHashCursor * cursor)
1692: {
1693: /* check incoming cursor */
1694: axl_return_val_if_fail (cursor, NULL);
1695:
1696: /* return the hash */
1697: return cursor->hash;
1698: }
1699:
1700: /**
1701: * @brief Deallocates memory used by the cursor.
1702: *
1703: * @param cursor The cursor to be deallocated.
1704: */
1705: void axl_hash_cursor_free (axlHashCursor * cursor)
1706: {
1707: axl_return_if_fail (cursor);
1708:
1709: /* free the cursor */
1710: axl_free (cursor);
1711:
1712: return;
1713: }
1714:
1715:
1716: /* @} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>