Annotation of gpl/axl/src/axl_hash.c, revision 1.1
1.1 ! misho 1: /*
! 2: * LibAxl: Another XML library
! 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);
! 336: result->factory = axl_factory_create (sizeof (axlHashNode));
! 337: result->hash = hash;
! 338: result->equal = equal;
! 339: result->step = step;
! 340:
! 341: /* return the hash table created */
! 342: return result;
! 343: }
! 344:
! 345: /**
! 346: * @brief Inserts a key index value into the provided hash table.
! 347: *
! 348: * The function will store the data provided on the hash setting no
! 349: * destroy function for the key and the data stored. See \ref
! 350: * axl_hash_insert_full for more details.
! 351: *
! 352: * <b>NOTE:</b> The insert operation will replace a previously
! 353: * inserted item with the same key. If no item is found, and insert
! 354: * will take place, otherwise previous item is replaced calling to the
! 355: * key destroy and data destroy defined.
! 356: *
! 357: * @param hash The hash table where the insert operation will be
! 358: * produced.
! 359: *
! 360: * @param key The key to store in the hash table. If the key is found,
! 361: * previous data is replaced, storing this new key and the value
! 362: * provided.
! 363: *
! 364: * @param data The data to store associated to the provided key.
! 365: */
! 366: void axl_hash_insert (axlHash * hash,
! 367: axlPointer key,
! 368: axlPointer data)
! 369: {
! 370: /* call to the full implementation */
! 371: axl_hash_insert_full (hash, key, NULL, data, NULL);
! 372:
! 373: /* nothing more to do */
! 374: return;
! 375: }
! 376:
! 377: /**
! 378: * @internal Function used to create the node that will be stored in
! 379: * the hash.
! 380: */
! 381: #define __axl_hash_create_node(factory, node, key, key_destroy, data, data_destroy)\
! 382: node = axl_factory_get (factory);\
! 383: node->key = key;\
! 384: node->key_destroy = key_destroy;\
! 385: node->data = data;\
! 386: node->data_destroy = data_destroy;
! 387:
! 388: /**
! 389: * @internal Function that performs the hash insertion for the
! 390: * selected node.
! 391: */
! 392: #define __axl_hash_insert_node(_pos,_hash,_key,_node,_increase)\
! 393: _pos = (_hash->hash (_key)) % _hash->hash_size;\
! 394: _node->next = _hash->table [_pos];\
! 395: _hash->table [pos] = _node;\
! 396: if (_increase)\
! 397: _hash->items++;
! 398:
! 399: /**
! 400: * @brief Inserts a key value into the provided hash table, allowing
! 401: * to provide deallocation functions for the key and the data to be
! 402: * stored.
! 403: *
! 404: * <b>NOTE:</b> The insert operation will replace a previously
! 405: * inserted item with the same key. If no item is found, an insert
! 406: * will take place, otherwise previous item is replaced calling to the
! 407: * key destroy and data destroy functions defined.
! 408: *
! 409: * @param hash The hash table where the data will be added.
! 410: *
! 411: * @param key The key to store in the hash table. If the key is found,
! 412: * previous data is replaced, storing this new key and the value
! 413: * provided.
! 414: *
! 415: * @param key_destroy An optional destroy function that will be called
! 416: * to deallocate the key provided.
! 417: *
! 418: * @param data The data to store associated to the provided key.
! 419: *
! 420: * @param data_destroy An optional destroy function that will be
! 421: * called to deallocate the data provided.
! 422: */
! 423: void axl_hash_insert_full (axlHash * hash,
! 424: axlPointer key,
! 425: axlDestroyFunc key_destroy,
! 426: axlPointer data,
! 427: axlDestroyFunc data_destroy)
! 428: {
! 429: int pos = 0;
! 430: axlHashNode * node = NULL;
! 431: axlHashNode * aux = NULL;
! 432: int iterator = 0;
! 433:
! 434: /* check incoming data */
! 435: axl_return_if_fail (hash);
! 436:
! 437: /* check the really basic case where the hash has no data
! 438: * stored yet. */
! 439: if (hash->hash_size == 0) {
! 440: /* allocate memory for the hash */
! 441: hash->table = axl_new (axlHashNode *, hash->step);
! 442: hash->hash_size = hash->step;
! 443:
! 444: /* create the node to store */
! 445: __axl_hash_create_node (hash->factory, node, key, key_destroy, data, data_destroy);
! 446:
! 447: /* insert the node into the hash */
! 448: __axl_hash_insert_node (pos, hash, key, node, axl_true);
! 449:
! 450: return;
! 451: }
! 452:
! 453: /* now check for a more complex case */
! 454: node = __axl_hash_internal_lookup (hash, key);
! 455:
! 456: /* if the node is not found and the hash size can't hold more items, expand it and rehash */
! 457: if ((hash->hash_size == hash->items) && (node == NULL)) {
! 458: /* seems we need to rehash items, reallocating enough
! 459: * memory */
! 460:
! 461: /* before allocating more memory, extract all items to
! 462: * be reallocated */
! 463: iterator = 0;
! 464: node = NULL;
! 465: while (iterator < hash->hash_size) {
! 466:
! 467: /* check for content */
! 468: if (hash->table[iterator] != NULL) {
! 469: /* check if node has been initialized,
! 470: * and set it to the first position */
! 471: if (node == NULL) {
! 472: /* configure init node position */
! 473: node = hash->table[iterator];
! 474:
! 475: /* and last aux position */
! 476: aux = node;
! 477: while (aux->next != NULL) {
! 478: /* update reference */
! 479: aux = aux->next;
! 480: }
! 481:
! 482: } else {
! 483: /* make aux to point to the next list */
! 484: aux->next = hash->table[iterator];
! 485:
! 486: /* and while the last item is not
! 487: * reached, move aux to point to the
! 488: * last item of the chain */
! 489: while (aux->next != NULL) {
! 490: /* update reference */
! 491: aux = aux->next;
! 492: }
! 493: }
! 494: } /* end if */
! 495:
! 496: /* update the iterator */
! 497: iterator++;
! 498: }
! 499:
! 500: /* now we have in node a complete list of items
! 501: * stored, allocate more memory and rehash */
! 502: hash->hash_size += hash->step;
! 503: hash->table = realloc (hash->table, sizeof (axlHashNode *) * (hash->hash_size));
! 504:
! 505: /* clear the table */
! 506: memset (hash->table, 0, sizeof (axlHashNode*) * (hash->hash_size));
! 507:
! 508: /* for each item inside the list rehash it */
! 509: while (node != NULL) {
! 510: /* store next item to rehash in aux */
! 511: aux = node->next;
! 512:
! 513: /* insert the node into the hash */
! 514: __axl_hash_insert_node (pos, hash, node->key, node, axl_false);
! 515:
! 516: /* update the reference */
! 517: node = aux;
! 518: } /* end while */
! 519:
! 520: /* clear node reference */
! 521: node = NULL;
! 522: } /* rehashing if end */
! 523:
! 524: /* we have enough space to store the item create the
! 525: node to store */
! 526: if (node == NULL) {
! 527: /* create a new node */
! 528: __axl_hash_create_node (hash->factory, node, key, key_destroy, data, data_destroy);
! 529:
! 530: /* insert the node into the hash as usual */
! 531: __axl_hash_insert_node (pos, hash, key, node, axl_true);
! 532: } else {
! 533: /* don't create a node, replace previous content and use new content */
! 534: if (node->key_destroy != NULL) {
! 535: node->key_destroy (node->key);
! 536: }
! 537: if (node->data_destroy != NULL) {
! 538: node->data_destroy (node->data);
! 539: }
! 540:
! 541: /* now use new data */
! 542: node->key = key;
! 543: node->key_destroy = key_destroy;
! 544: node->data = data;
! 545: node->data_destroy = data_destroy;
! 546: }
! 547:
! 548: /* nothing more man!! */
! 549: return;
! 550: }
! 551:
! 552: /**
! 553: * @internal Function that supports axl_hash_remove and
! 554: * axl_hash_delete.
! 555: *
! 556: * The function returns axl_true if an item was removed due to the call
! 557: * done.
! 558: */
! 559: axl_bool __axl_hash_remove_common (axlHash * hash,
! 560: axlPointer key,
! 561: axl_bool remove)
! 562: {
! 563: axlHashNode * node;
! 564: axlHashNode * aux;
! 565: int pos;
! 566:
! 567: axl_return_val_if_fail (hash, axl_false);
! 568:
! 569: /* do not perform any operation if the hash is empty */
! 570: if (hash->hash_size == 0)
! 571: return axl_false;
! 572:
! 573: /* get the node at the provided position */
! 574: pos = (hash->hash (key)) % hash->hash_size;
! 575: node = hash->table [pos];
! 576:
! 577: /* node not found */
! 578: if (node == NULL)
! 579: return axl_false;
! 580:
! 581: /* check for equal keys */
! 582: if (hash->equal (node->key, key) == 0) {
! 583: /* set that no items are available at the provided
! 584: * position */
! 585: hash->table [pos] = node->next;
! 586:
! 587: remove_element:
! 588: /* key destruction is defined */
! 589: if (node->key_destroy != NULL && remove)
! 590: node->key_destroy (node->key);
! 591:
! 592: /* if data destruction is defined */
! 593: if (node->data_destroy != NULL && remove)
! 594: node->data_destroy (node->data);
! 595:
! 596: /* decreases elements found */
! 597: hash->items--;
! 598:
! 599: /* delete the node */
! 600: axl_factory_release_spare (hash->factory, node);
! 601: /* axl_free (node); */
! 602:
! 603: /* element destroyed, nothing more to do around
! 604: * here */
! 605: return axl_true;
! 606: }
! 607:
! 608: /* seems we have more nodes */
! 609: while (node->next != NULL) {
! 610: /* store a reference to the current node (which will
! 611: * be the previous on next sentences) */
! 612: aux = node;
! 613:
! 614: /* update the reference to the next node */
! 615: node = node->next;
! 616:
! 617: /* check for equal keys */
! 618: if (hash->equal (node->key, key) == 0) {
! 619: /* make previous node to point to the next
! 620: * element of the following node */
! 621: aux->next = node->next;
! 622:
! 623: goto remove_element;
! 624: }
! 625: } /* end */
! 626:
! 627: /* no item was found on the hash */
! 628: return axl_false;
! 629: }
! 630:
! 631: /**
! 632: * @brief Allows to remove the selected pair key/value on the provided
! 633: * hash table.
! 634: *
! 635: * The function will remevo the item but it will not resize the table
! 636: * due to it. The function will call to the key destroy and data
! 637: * destroy function if they were defined at the insertion time (\ref
! 638: * axl_hash_insert_full).
! 639: *
! 640: *
! 641: * @param hash The hash table where the removal operation will be
! 642: * performed.
! 643: *
! 644: * @param key The key to lookup to be removed.
! 645: *
! 646: * @return The function returns axl_true if the item was removed,
! 647: * otherwise axl_false is returned. If the function returns axl_true, it means
! 648: * the object was stored in the hash before calling to remove it.
! 649: */
! 650: axl_bool axl_hash_remove (axlHash * hash,
! 651: axlPointer key)
! 652: {
! 653: /* call common implementation deleting data with destroy
! 654: * functions defined */
! 655: return __axl_hash_remove_common (hash, key, axl_true);
! 656: }
! 657:
! 658: /**
! 659: * @brief Allows to remove the selected pair key/value on the provided
! 660: * hash table, without calling to destroy functions.
! 661: *
! 662: * The function will remove the item but it will not resize the table
! 663: * due to it. The function will NOT call to the key destroy and data
! 664: * destroy function if they were defined at the insertion time (\ref
! 665: * axl_hash_insert_full).
! 666: *
! 667: *
! 668: * @param hash The hash table where the removal operation will be
! 669: * performed.
! 670: *
! 671: * @param key The key to lookup to be removed.
! 672: *
! 673: * @return The function returns axl_true if the item was removed
! 674: * (deallocation functions aren't called), otherwise axl_false is
! 675: * returned. If the function returns axl_true, it means the object was
! 676: * stored in the hash before calling to remove.
! 677: */
! 678: axl_bool axl_hash_delete (axlHash * hash,
! 679: axlPointer key)
! 680: {
! 681: /* call common implementation, without calling destroy
! 682: * functions defined */
! 683: return __axl_hash_remove_common (hash, key, axl_false);
! 684: }
! 685:
! 686: /**
! 687: * @brief Allows to get the content associated to the key provided
! 688: * inside the hash provided.
! 689: *
! 690: * @param hash The hash table where the lookup will be performed.
! 691: *
! 692: * @param key The key to use to retrieve the information.
! 693: *
! 694: * @return NULL or the associated data to the key provided. The
! 695: * function will also return a NULL value if provided a NULL hash
! 696: * reference or a NULL key reference.
! 697: */
! 698: axlPointer axl_hash_get (axlHash * hash,
! 699: axlPointer key)
! 700: {
! 701: axlHashNode * node;
! 702:
! 703: axl_return_val_if_fail (hash, NULL);
! 704:
! 705: /* check for empty hash to return NULL directly */
! 706: if (hash->items == 0)
! 707: return NULL;
! 708:
! 709: /* lookup using internal function */
! 710: node = __axl_hash_internal_lookup (hash, key);
! 711:
! 712: /* return the content or NULL if not defined the node */
! 713: if (node != NULL)
! 714: return node->data;
! 715: return NULL;
! 716: }
! 717:
! 718: /**
! 719: * @internal
! 720: *
! 721: * Common implementation for both foreach functions: axl_hash_foreach
! 722: * and axl_hash_foreach2.
! 723: */
! 724: void __axl_hash_foreach (axlHash * hash,
! 725: axlHashForeachFunc func,
! 726: axlHashForeachFunc2 func2,
! 727: axlHashForeachFunc3 func3,
! 728: axlHashForeachFunc4 func4,
! 729: axlPointer user_data,
! 730: axlPointer user_data2,
! 731: axlPointer user_data3,
! 732: axlPointer user_data4)
! 733: {
! 734:
! 735: int iterator = 0;
! 736: axlHashNode * node;
! 737:
! 738: /* perform some basic checks */
! 739: axl_return_if_fail (hash);
! 740:
! 741: /* foreach item row inside the hash table */
! 742: while (iterator < hash->hash_size) {
! 743:
! 744: /* check for content */
! 745: if (hash->table[iterator] != NULL) {
! 746: /* get the first item inside the table */
! 747: node = hash->table[iterator];
! 748:
! 749: do {
! 750: /* check for one user defined pointer
! 751: * foreach: notify the item found */
! 752: if (func != NULL && func (node->key, node->data, user_data)) {
! 753: /* user have decided to stop */
! 754: return;
! 755: } /* end if */
! 756:
! 757: /* check for two user defined pointers
! 758: * notify the item found */
! 759: if (func2 != NULL && func2 (node->key, node->data, user_data, user_data2)) {
! 760: /* user have decided to stop */
! 761: return;
! 762: } /* end if */
! 763:
! 764: /* check for three user defined pointers
! 765: * notify the item found */
! 766: if (func3 != NULL && func3 (node->key, node->data, user_data, user_data2, user_data3)) {
! 767: /* user have decided to stop */
! 768: return;
! 769: } /* end if */
! 770:
! 771: /* check for four user defined
! 772: * pointers notify the item found */
! 773: if (func4 != NULL && func4 (node->key, node->data, user_data, user_data2, user_data3, user_data4)) {
! 774: /* user have decided to stop */
! 775: return;
! 776: } /* end if */
! 777:
! 778: /* next item inside the same collition
! 779: * position */
! 780: node = node->next;
! 781:
! 782: /* while the next item is not null,
! 783: * keep on iterating */
! 784: } while (node != NULL);
! 785:
! 786: } /* end if */
! 787:
! 788: /* update the iterator */
! 789: iterator++;
! 790:
! 791: } /* end while */
! 792:
! 793: return;
! 794: }
! 795:
! 796: /**
! 797: * @brief Performs a foreach operation over all items stored in the
! 798: * hash provided.
! 799: *
! 800: * The function provided (<b>func</b>) will be called passing in the
! 801: * item found, and the data provided (third argument).
! 802: *
! 803: * Because the \ref axlHashForeachFunc function is used, \ref axl_true must be
! 804: * returned to stop the foreach process. In the case all items must be
! 805: * visited, \ref axl_false must be returned in any case.
! 806: *
! 807: * @param hash The hash table where the iteration process will take
! 808: * place.
! 809: *
! 810: * @param func The function to call for each item found.
! 811: *
! 812: * @param user_data User defined data to be passed in to the function callback along with the item found.
! 813: */
! 814: void axl_hash_foreach (axlHash * hash,
! 815: axlHashForeachFunc func,
! 816: axlPointer user_data)
! 817:
! 818: {
! 819:
! 820: /* perform the foreach operation using common support */
! 821: __axl_hash_foreach (hash,
! 822: /* foreach function */
! 823: func, NULL, NULL, NULL,
! 824: /* user defined data */
! 825: user_data, NULL, NULL, NULL);
! 826:
! 827: return;
! 828: }
! 829:
! 830: /**
! 831: * @brief Allows to perform a foreach operation providing two user
! 832: * defined pointer to be passed to the foreach function for each item
! 833: * found.
! 834: *
! 835: * This function works like \ref axl_hash_foreach function but support
! 836: * two user defined pointers. See \ref axl_hash_foreach for more information.
! 837: *
! 838: * @param hash The hash where the iteration will be performed.
! 839: *
! 840: * @param func The foreach function that will be called for all nodes
! 841: * found passed in both pointers defined along with the key value and
! 842: * the value associated.
! 843: *
! 844: * @param user_data User defined data to be passed to the foreach
! 845: * function.
! 846: *
! 847: * @param user_data2 Second User defined data to be passed to the
! 848: * foreach function.
! 849: */
! 850: void axl_hash_foreach2 (axlHash * hash,
! 851: axlHashForeachFunc2 func,
! 852: axlPointer user_data,
! 853: axlPointer user_data2)
! 854:
! 855: {
! 856: /* perform the foreach operation using common support */
! 857: __axl_hash_foreach (hash,
! 858: /* foreach function */
! 859: NULL, func, NULL, NULL,
! 860: /* user defined data */
! 861: user_data, user_data2, NULL, NULL);
! 862:
! 863: return;
! 864: }
! 865:
! 866: /**
! 867: * @brief Three user defined pointers foreach function over a hash.
! 868: *
! 869: * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
! 870: * information.
! 871: *
! 872: * @param hash The hash where the foreach operation will take place.
! 873: *
! 874: * @param func The function to be called for each item found in the
! 875: * hash.
! 876: *
! 877: * @param user_data The user defined pointer to be configured in the
! 878: * hash.
! 879: *
! 880: * @param user_data2 Second user defined pointer to be configured in
! 881: * the hash.
! 882: *
! 883: * @param user_data3 Third user defined pointer to be configured in
! 884: * the hash.
! 885: */
! 886: void axl_hash_foreach3 (axlHash * hash,
! 887: axlHashForeachFunc3 func,
! 888: axlPointer user_data,
! 889: axlPointer user_data2,
! 890: axlPointer user_data3)
! 891: {
! 892: /* perform the foreach operation using common support */
! 893: __axl_hash_foreach (hash,
! 894: /* foreach function */
! 895: NULL, NULL, func, NULL,
! 896: /* user defined data */
! 897: user_data, user_data2, user_data3, NULL);
! 898: }
! 899:
! 900: /**
! 901: * @brief Four user defined pointers foreach function over a hash.
! 902: *
! 903: * See \ref axl_hash_foreach2 and \ref axl_hash_foreach3 for more
! 904: * information.
! 905: *
! 906: * @param hash The hash where the foreach operation will take place.
! 907: *
! 908: * @param func The function to be called for each item found in the
! 909: * hash.
! 910: *
! 911: * @param user_data The user defined pointer to be configured in the
! 912: * hash.
! 913: *
! 914: * @param user_data2 Second user defined pointer to be configured in
! 915: * the hash.
! 916: *
! 917: * @param user_data3 Third user defined pointer to be configured in
! 918: * the hash.
! 919: *
! 920: * @param user_data4 Forth user defined pointer to be configured in
! 921: * the hash.
! 922: */
! 923: void axl_hash_foreach4 (axlHash * hash,
! 924: axlHashForeachFunc4 func,
! 925: axlPointer user_data,
! 926: axlPointer user_data2,
! 927: axlPointer user_data3,
! 928: axlPointer user_data4)
! 929: {
! 930: /* perform the foreach operation using common support */
! 931: __axl_hash_foreach (hash,
! 932: /* foreach functions */
! 933: NULL, NULL, NULL, func,
! 934: /* user defined data */
! 935: user_data, user_data2, user_data3, user_data4);
! 936: }
! 937:
! 938: /**
! 939: * @brief Allows to check if the provided key is found on the given
! 940: * hash table.
! 941: *
! 942: * The function allows to get if the key is found on the table pretty
! 943: * much the behaviour that we could get using the following:
! 944: * \code
! 945: * // just compare if the provided key returns some value
! 946: * axl_bool value = (axl_hash_get (hash, "key2") != NULL);
! 947: * \endcode
! 948: *
! 949: * However it could happen that the value associated to the key, which
! 950: * already exists, is a NULL pointer, making previous comparation to
! 951: * not work in all cases. This function allows to check for the
! 952: * existance of a key and its associated data no mather what is the
! 953: * value of the associated data.
! 954: *
! 955: * @param hash The hash table to check for a key value.
! 956: * @param key The key to check for its existance.
! 957: *
! 958: * @return axl_true if the key is found, otherwise axl_false is returned.
! 959: */
! 960: axl_bool axl_hash_exists (axlHash * hash,
! 961: axlPointer key)
! 962: {
! 963: /* check if the hash is provided without loggin an error */
! 964: return (__axl_hash_internal_lookup (hash, key) != NULL);
! 965: }
! 966:
! 967: /**
! 968: * @internal function for axl_hash_copy.
! 969: */
! 970: axl_bool __axl_hash_copy_foreach (axlPointer key,
! 971: axlPointer data,
! 972: /* user defined pointers */
! 973: axlPointer user_data, /* hash */
! 974: axlPointer user_data2, /* result */
! 975: axlPointer user_data3, /* key_copy */
! 976: axlPointer user_data4) /* value_copy */
! 977: {
! 978: /* get a reference to the received data */
! 979: axlHash * hash = user_data;
! 980: axlHash * result = user_data2;
! 981: axlHashItemCopy key_copy = user_data3;
! 982: axlHashItemCopy value_copy = user_data4;
! 983:
! 984: /* additional variables */
! 985: axlHashNode * node;
! 986:
! 987: /* get node to copy */
! 988: node = hash->table [(hash->hash (key)) % hash->hash_size];
! 989:
! 990: /* check this is the node to copy */
! 991: while (node != NULL) {
! 992: if (hash->equal (node->key, key) == 0)
! 993: break;
! 994:
! 995: /* it isn't the node looked up */
! 996: node = node->next;
! 997: } /* end while */
! 998:
! 999: /* copy */
! 1000: axl_hash_insert_full (result,
! 1001: /* insert the key and its destroy function. */
! 1002: key_copy (node->key, node->key_destroy, node->data, node->data_destroy), node->key_destroy,
! 1003: /* insert data and its destroy function. */
! 1004: value_copy (node->key, node->key_destroy, node->data, node->data_destroy), node->data_destroy);
! 1005:
! 1006: /* make the foreach process to continue until the last element */
! 1007: return axl_false;
! 1008: }
! 1009:
! 1010: /**
! 1011: * @brief Allows to copy the provided hash, providing the copy
! 1012: * function used to duplicate key and value items stored.
! 1013: *
! 1014: * The function are optional, so, if they are null, the same value is
! 1015: * stored in the hash (for the key and the value). In this case, if
! 1016: * the source hash has defined destroy function for either key or
! 1017: * values, they will not be configured in the returning hash.
! 1018: *
! 1019: * If function are provided, \ref axl_hash_copy will use it to get a
! 1020: * duplicated version for either the key or the value. In this case,
! 1021: * if the source hash has defined the destroy function either for the
! 1022: * key or the value, it will be configured in the returning hash.
! 1023: *
! 1024: * @param hash The \ref axlHash that will work as data source.
! 1025: *
! 1026: * @param key_copy The function to be used to duplicate keys.
! 1027: *
! 1028: * @param value_copy The function used to duplicate values.
! 1029: *
! 1030: * @return A newly allocated reference to a \ref axlHash containing
! 1031: * all values from the source hash. The function will fail if the hash
! 1032: * provided is a null reference or copy functions aren't provided.
! 1033: */
! 1034: axlHash * axl_hash_copy (axlHash * hash,
! 1035: axlHashItemCopy key_copy,
! 1036: axlHashItemCopy value_copy)
! 1037: {
! 1038: axlHash * result;
! 1039:
! 1040: /* return if the hash reference is null */
! 1041: axl_return_val_if_fail (hash, NULL);
! 1042: axl_return_val_if_fail (key_copy, NULL);
! 1043: axl_return_val_if_fail (value_copy, NULL);
! 1044:
! 1045: /* create the hash */
! 1046: result = axl_hash_new_full (hash->hash,
! 1047: hash->equal,
! 1048: /* make initial step to be equal
! 1049: * to the current hash size copied
! 1050: * to avoid resizing operations
! 1051: * during the foreach. */
! 1052: hash->items);
! 1053: /* restore step */
! 1054: result->step = hash->step;
! 1055:
! 1056: /* check empty hash value */
! 1057: if (hash->hash_size == 0)
! 1058: return result;
! 1059:
! 1060: /* copy all items */
! 1061: axl_hash_foreach4 (hash, __axl_hash_copy_foreach, hash, result, key_copy, value_copy);
! 1062:
! 1063:
! 1064: /* return created hash */
! 1065: return result;
! 1066: }
! 1067:
! 1068: /**
! 1069: * @brief Returns the number of items already stored on the provided
! 1070: * hash.
! 1071: *
! 1072: * @param hash The hash that is being requested for the number of
! 1073: * indexed data items.
! 1074: *
! 1075: * @return The number of items or -1 if it fails.
! 1076: */
! 1077: int axl_hash_items (axlHash * hash)
! 1078: {
! 1079: axl_return_val_if_fail (hash, -1);
! 1080:
! 1081: /* return current items stored */
! 1082: return hash->items;
! 1083: }
! 1084:
! 1085: /**
! 1086: * @brief Allows to get the amount of items that could store the hash
! 1087: * without allocating more additional memory.
! 1088: *
! 1089: * @param hash The hash that is being requested to return its items
! 1090: * capacity (key + value) pair.
! 1091: *
! 1092: * @return The capacity or -1 if the reference received is null.
! 1093: */
! 1094: int axl_hash_capacity (axlHash * hash)
! 1095: {
! 1096: axl_return_val_if_fail (hash, -1);
! 1097: /* return current capacity */
! 1098: return hash->hash_size;
! 1099: }
! 1100:
! 1101: /**
! 1102: * @internal Shows current hash status to the console.
! 1103: *
! 1104: * The function is only useful for internal hash module purposes. It
! 1105: * shows the numbers of items stored, the table size, the number of
! 1106: * collitions, etc.
! 1107: *
! 1108: * @param hash The hash where the status is requested.
! 1109: */
! 1110: void axl_hash_show_status (axlHash * hash)
! 1111: {
! 1112: /* use full implementation */
! 1113: axl_hash_show_status_full (hash, NULL);
! 1114:
! 1115: return;
! 1116: }
! 1117:
! 1118: /**
! 1119: * @internal Shows current hash content to the console using the
! 1120: * provided function to show the hash content.
! 1121: *
! 1122: * @param hash The hash that is requested to show its content.
! 1123: *
! 1124: * @param show_item The function to be used to show the content.
! 1125: */
! 1126: void axl_hash_show_status_full (axlHash * hash,
! 1127: axlHashPrintKeyData show_item)
! 1128: {
! 1129: axlHashNode * node;
! 1130: int iterator;
! 1131: int count;
! 1132: axl_return_if_fail (hash);
! 1133:
! 1134: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl hash table status:");
! 1135: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "table size: %d items: %d step: %d",
! 1136: hash->hash_size, hash->items, hash->step);
! 1137: /* get the number of empty blocks */
! 1138: iterator = 0;
! 1139: count = 0;
! 1140: while (iterator < hash->hash_size) {
! 1141: /* empty item found */
! 1142: if (hash->table[iterator] == NULL) {
! 1143: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "empty cell at: %d", iterator);
! 1144: count++;
! 1145: }
! 1146:
! 1147: /* update iterator */
! 1148: iterator++;
! 1149: }
! 1150: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of empty cells: %d", count);
! 1151:
! 1152: /* get the number properly used cells (no collitions) */
! 1153: iterator = 0;
! 1154: count = 0;
! 1155: while (iterator < hash->hash_size) {
! 1156: /* empty item found */
! 1157: node = hash->table[iterator];
! 1158: if (node != NULL && node->next == NULL) {
! 1159: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "properly used cell at: %d", iterator);
! 1160: count++;
! 1161:
! 1162: if (show_item != NULL) {
! 1163: show_item (node->key, node->data);
! 1164: }
! 1165: }
! 1166:
! 1167: /* update iterator */
! 1168: iterator++;
! 1169: }
! 1170: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of properly used cells (no collition): %d", count);
! 1171:
! 1172: /* get the number of collitioned cells */
! 1173: iterator = 0;
! 1174: count = 0;
! 1175: while (iterator < hash->hash_size) {
! 1176: /* empty item found */
! 1177: node = hash->table[iterator];
! 1178: if (node != NULL && node->next != NULL) {
! 1179: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "collitioned cell at: %d", iterator);
! 1180: count++;
! 1181: }
! 1182:
! 1183: /* for each node show the content */
! 1184: while ((show_item) != NULL && (node != NULL)) {
! 1185: if (show_item != NULL) {
! 1186: show_item (node->key, node->data);
! 1187: }
! 1188:
! 1189: /* update to the next node */
! 1190: node = node->next;
! 1191: }
! 1192:
! 1193: /* update iterator */
! 1194: iterator++;
! 1195: }
! 1196: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "number of collitioned cells: %d", count);
! 1197:
! 1198:
! 1199:
! 1200: return;
! 1201: }
! 1202:
! 1203: /**
! 1204: * @brief Allows to deallocate the hash provided.
! 1205: *
! 1206: * @param hash The hash to deallocate.
! 1207: */
! 1208: void axl_hash_free (axlHash * hash)
! 1209: {
! 1210: int iterator = 0;
! 1211: axlHashNode * node;
! 1212: axlHashNode * aux;
! 1213:
! 1214: /* do not perform any operation if a null reference is
! 1215: * received */
! 1216: if (hash == NULL)
! 1217: return;
! 1218:
! 1219: /* release the hash table */
! 1220: if (hash->table != NULL) {
! 1221:
! 1222: /* first release all nodes inside */
! 1223: while (iterator < hash->hash_size) {
! 1224: node = hash->table[iterator];
! 1225: if (node != NULL) {
! 1226: do {
! 1227: /* key destruction is defined */
! 1228: if (node->key_destroy != NULL)
! 1229: node->key_destroy (node->key);
! 1230:
! 1231: /* if data destruction is defined */
! 1232: if (node->data_destroy != NULL)
! 1233: node->data_destroy (node->data);
! 1234:
! 1235: /* check data */
! 1236: aux = node;
! 1237: node = node->next;
! 1238:
! 1239: /* while more nodes */
! 1240: } while (node != NULL);
! 1241: } /* end if */
! 1242:
! 1243: /* update the iterator */
! 1244: iterator++;
! 1245: } /* end while */
! 1246:
! 1247: /* now release the table */
! 1248: axl_free (hash->table);
! 1249: } /* end if */
! 1250:
! 1251: /* free factory */
! 1252: axl_factory_free (hash->factory);
! 1253:
! 1254: /* now release the hash itself */
! 1255: axl_free (hash);
! 1256:
! 1257: /* nothing more to free */
! 1258: return;
! 1259: }
! 1260:
! 1261: /**
! 1262: * @internal Function that allows to get how many spare internal hash
! 1263: * nodes we can store.
! 1264: */
! 1265: int __axl_hash_spare_max (axlHash * hash)
! 1266: {
! 1267: return axl_factory_spare_max (hash->factory);
! 1268: }
! 1269:
! 1270: /**
! 1271: * @internal Function that allows to get how many spare internal hash
! 1272: * nodes are actually stored.
! 1273: */
! 1274: int __axl_hash_spare_next (axlHash * hash)
! 1275: {
! 1276: return axl_factory_spare_next (hash->factory);
! 1277: }
! 1278:
! 1279: /* @} */
! 1280:
! 1281: /**
! 1282: * \defgroup axl_hash_cursor_module Axl Hash Cursor: Iterator support for the Axl Hash
! 1283: */
! 1284:
! 1285: /* init the cursor */
! 1286: void __axl_hash_cursor_init (axlHashCursor * cursor, axl_bool first)
! 1287: {
! 1288: /* pointer to a hash node (basic atom holding key and value) */
! 1289: axlHashNode * node = NULL;
! 1290:
! 1291: if (first) {
! 1292: /* configure first */
! 1293: cursor->index = 0;
! 1294:
! 1295: /* foreach element inside the hash, check the first value */
! 1296: while (cursor->index < cursor->hash->hash_size) {
! 1297: /* check the table at the current position */
! 1298: node = cursor->hash->table[cursor->index];
! 1299: if (node != NULL) {
! 1300: /* first node found, store it */
! 1301: cursor->node = node;
! 1302: break;
! 1303: } /* end if */
! 1304:
! 1305: /* node not found, go next position */
! 1306: cursor->index++;
! 1307: } /* end while */
! 1308: } else {
! 1309: /* find last value */
! 1310: cursor->index = cursor->hash->hash_size - 1;
! 1311: cursor->node = NULL;
! 1312: while (cursor->index > 0) {
! 1313: /* check the table at the current position */
! 1314: node = cursor->hash->table[cursor->index];
! 1315: if (node != NULL) {
! 1316: /* find last entry filled, now find
! 1317: * last entry in the same index */
! 1318: while (node->next != NULL)
! 1319: node = node->next;
! 1320:
! 1321: /* configure it */
! 1322: cursor->node = node;
! 1323: break;
! 1324: } /* end if */
! 1325:
! 1326: /* node not found, go next position */
! 1327: cursor->index--;
! 1328: } /* end while */
! 1329: } /* end if */
! 1330:
! 1331: /* if the node wasn't found, reset index */
! 1332: if (node == NULL)
! 1333: cursor->index = 0;
! 1334:
! 1335: /* cursor initialized */
! 1336: return;
! 1337: }
! 1338:
! 1339: /**
! 1340: * \addtogroup axl_hash_cursor_module
! 1341: * @{
! 1342: */
! 1343:
! 1344: /**
! 1345: * @brief Allows to get a cursor to iterate the hash in a linear and
! 1346: * efficient way.
! 1347: *
! 1348: * The \ref axlHashCursor could be used to iterate an \ref axlHash in
! 1349: * an efficient way because it stores current state (position), hiding
! 1350: * all module details. Then using the following functions you can
! 1351: * modify the state (current position to get):
! 1352: *
! 1353: * - \ref axl_hash_cursor_first
! 1354: * - \ref axl_hash_cursor_last
! 1355: * - \ref axl_hash_cursor_next
! 1356: *
! 1357: * Finally, the following functions are provided to get the data stored at a
! 1358: * particular position, pointed by the current status of the cursor:
! 1359: *
! 1360: * - \ref axl_hash_cursor_get_key (returns the key of the current position)
! 1361: * - \ref axl_hash_cursor_get_value (returns the value of the current position)
! 1362: *
! 1363: * You are allowed to remove elements from the hash (\ref axlHash)
! 1364: * having a cursor created (\ref axlHashCursor), using \ref
! 1365: * axl_hash_cursor_remove.
! 1366: *
! 1367: * Here is an example:
! 1368: * \code
! 1369: * axlPointer key;
! 1370: * axlPointer value;
! 1371: * axlHashCursor * cursor;
! 1372: *
! 1373: * // create the cursor
! 1374: * cursor = axl_hash_cursor_new (hash);
! 1375: *
! 1376: * // while there are more elements
! 1377: * while (axl_hash_cursor_has_item (cursor)) {
! 1378: *
! 1379: * // get the value and key
! 1380: * value = axl_hash_cursor_get_key (cursor);
! 1381: * value = axl_hash_cursor_get_value (cursor);
! 1382: *
! 1383: * // get the next
! 1384: * axl_hash_cursor_next (cursor);
! 1385: *
! 1386: * }
! 1387: *
! 1388: * // free the cursor
! 1389: * axl_hash_cursor_free (cursor);
! 1390: * \endcode
! 1391: *
! 1392: * @param hash The hash that the new cursor (\ref axlHashCursor) will
! 1393: * provide access.
! 1394: *
! 1395: * @return A newly created \ref axlHashCursor used to iterate the
! 1396: * hash. Once finished you must call to \ref axl_hash_cursor_free.
! 1397: */
! 1398: axlHashCursor * axl_hash_cursor_new (axlHash * hash)
! 1399: {
! 1400: axlHashCursor * cursor;
! 1401:
! 1402: axl_return_val_if_fail (hash, NULL);
! 1403:
! 1404: /* create the cursor */
! 1405: cursor = axl_new (axlHashCursor, 1);
! 1406:
! 1407: /* initial configuration */
! 1408: cursor->hash = hash;
! 1409:
! 1410: /* init the cursor */
! 1411: __axl_hash_cursor_init (cursor, axl_true);
! 1412:
! 1413: /* return cursor */
! 1414: return cursor;
! 1415: }
! 1416:
! 1417: /**
! 1418: * @brief Allows to configure the cursor to point to the first item of
! 1419: * the hash (if there are any).
! 1420: *
! 1421: * @param cursor The cursor that is required to be configured to point the first item.
! 1422: */
! 1423: void axl_hash_cursor_first (axlHashCursor * cursor)
! 1424: {
! 1425: axl_return_if_fail (cursor);
! 1426:
! 1427: /* init the cursor at the initial state */
! 1428: __axl_hash_cursor_init (cursor, axl_true);
! 1429:
! 1430: return;
! 1431: }
! 1432:
! 1433: /**
! 1434: * @brief Allows to configure the cursor to point to the last item of
! 1435: * the hash (if there are any).
! 1436: *
! 1437: * @param cursor The cursor that is required to be configured to point
! 1438: * to the last item.
! 1439: */
! 1440: void axl_hash_cursor_last (axlHashCursor * cursor)
! 1441: {
! 1442: axl_return_if_fail (cursor);
! 1443:
! 1444: /* init the cursor at the initial state, selecting the last
! 1445: * node */
! 1446: __axl_hash_cursor_init (cursor, axl_false);
! 1447:
! 1448: return;
! 1449: }
! 1450:
! 1451: /**
! 1452: * @brief Allows to configure the cursor to point to the next item of
! 1453: * the hash (if there are any).
! 1454: *
! 1455: * @param cursor The cursor that is required to be configured to point
! 1456: * to the next item.
! 1457: */
! 1458: void axl_hash_cursor_next (axlHashCursor * cursor)
! 1459: {
! 1460: axl_return_if_fail (cursor);
! 1461:
! 1462: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next element at the cursor");
! 1463:
! 1464: /* check if the current node is null and do nothing if nothing
! 1465: * is found */
! 1466: if (cursor->node == NULL) {
! 1467: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "no nodes found....");
! 1468: return;
! 1469: }
! 1470:
! 1471: /* basic case, the item is found in the same level */
! 1472: if (cursor->node->next != NULL) {
! 1473: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node....");
! 1474: /* configure new current node */
! 1475: cursor->node = cursor->node->next;
! 1476:
! 1477: return;
! 1478: } /* end if */
! 1479:
! 1480: /* node not found, go next position */
! 1481: cursor->index++;
! 1482:
! 1483: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "updating and checking next index: %d (hash: %d)....",
! 1484: cursor->index, cursor->hash->hash_size);
! 1485:
! 1486: /* check if we have reached the phisical limit of the hash */
! 1487: if (cursor->index >= cursor->hash->hash_size) {
! 1488: cursor->node = NULL;
! 1489: return;
! 1490: }
! 1491:
! 1492: /* seems next is null, see in other positions */
! 1493: while (cursor->index < cursor->hash->hash_size) {
! 1494:
! 1495: /* check the table at the current position */
! 1496: cursor->node = cursor->hash->table[cursor->index];
! 1497: if (cursor->node != NULL) {
! 1498: /* node found, stop! */
! 1499: break;
! 1500: } /* end if */
! 1501:
! 1502: /* node not found, go next position */
! 1503: cursor->index++;
! 1504: } /* end while */
! 1505:
! 1506: /* nothing to be done */
! 1507: return;
! 1508: }
! 1509:
! 1510: /**
! 1511: * @brief Allows to check if there are more elements next to the
! 1512: * current element pointed by the cursor.
! 1513: *
! 1514: * @param cursor The cursor that is required to return if there are
! 1515: * next items.
! 1516: *
! 1517: * @return \ref axl_true if more items are found, otherwise \ref axl_false is
! 1518: * returned.
! 1519: */
! 1520: axl_bool axl_hash_cursor_has_next (axlHashCursor * cursor)
! 1521: {
! 1522: int iterator;
! 1523: axl_return_val_if_fail (cursor, axl_false);
! 1524:
! 1525: /* check basic case */
! 1526: if (cursor->node != NULL && cursor->node->next != NULL) {
! 1527: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "next is defined..");
! 1528: return axl_true;
! 1529: }
! 1530:
! 1531: /* seems next is null, see in other positions */
! 1532: iterator = cursor->index + 1;
! 1533: while (iterator < cursor->hash->hash_size) {
! 1534: /* check the table at the current position */
! 1535: if (cursor->hash->table[iterator] != NULL)
! 1536: return axl_true;
! 1537:
! 1538: /* node not found, go next position */
! 1539: iterator++;
! 1540: } /* end while */
! 1541:
! 1542: return axl_false;
! 1543: }
! 1544:
! 1545: /**
! 1546: * @brief Allows to know if the current position has items.
! 1547: *
! 1548: * @param cursor The cursor pointing to a particular element inside
! 1549: * the hash (or not).
! 1550: *
! 1551: * @return \ref axl_true if the hash that is iterated can return data at
! 1552: * the current position, otherwise \ref axl_false is returned.
! 1553: */
! 1554: axl_bool axl_hash_cursor_has_item (axlHashCursor * cursor)
! 1555: {
! 1556: axl_return_val_if_fail (cursor, axl_false);
! 1557:
! 1558: /* return axl_true if there are a item selected */
! 1559: return (cursor->node != NULL);
! 1560: }
! 1561:
! 1562: /**
! 1563: * @brief Allows to remove current element pointed by the cursor,
! 1564: * maintainig internal state of the cursor, calling to the destroy
! 1565: * function associated in the hash.
! 1566: *
! 1567: * The function will call to the destroy function asociated to the
! 1568: * hash.
! 1569: *
! 1570: * @param cursor The cursor pointing to the item inside the hash that
! 1571: * must be removed.
! 1572: */
! 1573: void axl_hash_cursor_remove (axlHashCursor * cursor)
! 1574: {
! 1575: axlHashNode * node;
! 1576:
! 1577: axl_return_if_fail (cursor);
! 1578:
! 1579: /* if current cursor is pointing nowhere, just do nothing */
! 1580: if (cursor->node == NULL)
! 1581: return;
! 1582:
! 1583: /* remember node */
! 1584: node = cursor->node->next;
! 1585:
! 1586: /* remove node selected */
! 1587: axl_hash_remove (cursor->hash, cursor->node->key);
! 1588:
! 1589: /* configure next item */
! 1590: cursor->node = node;
! 1591: if (cursor->node == NULL) {
! 1592: while (cursor->index < cursor->hash->hash_size) {
! 1593: /* check the table at the current position */
! 1594: if (cursor->hash->table[cursor->index] != NULL) {
! 1595: /* configure the next node */
! 1596: cursor->node = cursor->hash->table[cursor->index];
! 1597: return;
! 1598: }
! 1599:
! 1600: /* node not found, go next position */
! 1601: cursor->index++;
! 1602: } /* end while */
! 1603: } /* end if */
! 1604:
! 1605: return;
! 1606: }
! 1607:
! 1608: /**
! 1609: * @brief Allows to get current value at the current cursor state.
! 1610: *
! 1611: * @param cursor The cursor that will be used to return the data
! 1612: * located at the hash, using cursor current state.
! 1613: */
! 1614: axlPointer axl_hash_cursor_get_value (axlHashCursor * cursor)
! 1615: {
! 1616: axl_return_val_if_fail (cursor, NULL);
! 1617:
! 1618: /* nothing to return if current is NULL */
! 1619: if (cursor->node == NULL)
! 1620: return NULL;
! 1621:
! 1622: /* return data */
! 1623: return cursor->node->data;
! 1624: }
! 1625:
! 1626: /**
! 1627: * @brief Allows to get current key at the current cursor state.
! 1628: *
! 1629: * @param cursor The cursor that will be used to return the data
! 1630: * located at the hash, using cursor current state.
! 1631: */
! 1632: axlPointer axl_hash_cursor_get_key (axlHashCursor * cursor)
! 1633: {
! 1634: axl_return_val_if_fail (cursor, NULL);
! 1635:
! 1636: /* nothing to return if current is NULL */
! 1637: if (cursor->node == NULL)
! 1638: return NULL;
! 1639:
! 1640: /* return key pointer */
! 1641: return cursor->node->key;
! 1642: }
! 1643:
! 1644: /**
! 1645: * @brief Allows to get the reference to the hash that is associated
! 1646: * to the cursor received.
! 1647: *
! 1648: * @param cursor The cursor that is required to return the hash associated.
! 1649: *
! 1650: * @return A reference to the hash being iterated or NULL if fails.
! 1651: */
! 1652: axlHash * axl_hash_cursor_hash (axlHashCursor * cursor)
! 1653: {
! 1654: /* check incoming cursor */
! 1655: axl_return_val_if_fail (cursor, NULL);
! 1656:
! 1657: /* return the hash */
! 1658: return cursor->hash;
! 1659: }
! 1660:
! 1661: /**
! 1662: * @brief Deallocates memory used by the cursor.
! 1663: *
! 1664: * @param cursor The cursor to be deallocated.
! 1665: */
! 1666: void axl_hash_cursor_free (axlHashCursor * cursor)
! 1667: {
! 1668: axl_return_if_fail (cursor);
! 1669:
! 1670: /* free the cursor */
! 1671: axl_free (cursor);
! 1672:
! 1673: return;
! 1674: }
! 1675:
! 1676:
! 1677: /* @} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>