Annotation of gpl/axl/src/axl_hash.c, revision 1.1.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>