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>