File:  [ELWIX - Embedded LightWeight unIX -] / gpl / axl / src / axl_hash.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 12:50:03 2012 UTC (12 years, 4 months ago) by misho
Branches: axl, MAIN
CVS tags: HEAD, AXL0_6_7
version 0.6.7

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>