Annotation of gpl/axl/src/axl_list.c, revision 1.1.1.2
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:
40: #include <axl_decl.h>
41: #include <axl_list.h>
42: #include <axl_log.h>
43: #include <axl_stream.h>
44:
45: #define LOG_DOMAIN "axl-list"
46:
47: typedef struct _axlListNode axlListNode;
48:
49: struct _axlList {
50: /* functions used by the list to properly order elements
51: * inside it and how they are destroyed */
52: axlEqualFunc are_equal;
53: axlDestroyFunc destroy_data;
54:
55: /* pointers to the list content */
56: axlListNode * first_node;
57: axlListNode * last_node;
58:
59: /* list length */
60: int length;
61:
62: /* memory management functions */
63: axlListNode ** preallocated;
64: int available;
65: int allocated;
66: };
67:
68: struct _axlListNode {
69: axlListNode * previous;
70: axlListNode * next;
71: axlPointer data;
72: };
73:
74: struct _axlListCursor {
75: axlList * list;
76: axlListNode * current;
77: };
78:
79: /**
80: * \defgroup axl_list_module Axl List: A configurable double-linked list used across the library.
81: */
82:
83: /**
84: * \addtogroup axl_list_module
85: * @{
86: */
87:
88: /**
89: * @internal
90: *
91: * Internal are equal handler implementation for the axl list module
92: * that always return 0.
93: */
94: int __axl_list_always_true (axlPointer a, axlPointer b)
95: {
96: return 0;
97: }
98:
99: /**
100: * @internal
101: *
102: * Preallocates nodes to be used to store data on the lists.
103: *
104: * @param list The list where the preallocation operation will be
105: * performed.
106: */
107: void __axl_list_allocate_nodes (axlList * list)
108: {
1.1.1.2 ! misho 109: int iterator;
! 110: axlListNode ** temp;
! 111: int available;
1.1 misho 112:
113: list->available = 1;
114: list->allocated += list->available;
115:
116: /* allocate enough memory to hold all nodes already
117: * allocated */
1.1.1.2 ! misho 118: if (list->preallocated == NULL) {
1.1 misho 119: list->preallocated = axl_new (axlListNode *, list->allocated);
1.1.1.2 ! misho 120: if (list->preallocated == NULL) {
! 121: /* reduce noddes available */
! 122: list->available = 0;
! 123: list->allocated--;
! 124: return;
! 125: }
! 126: } else {
! 127: /* realloc for the list */
! 128: temp = list->preallocated;
1.1 misho 129: list->preallocated = realloc (list->preallocated, (sizeof (axlListNode *)) * list->allocated);
130:
1.1.1.2 ! misho 131: /* check alloc operation */
! 132: if (list->preallocated == NULL) {
! 133: /* alloc failed, restore to previous pointer */
! 134: list->preallocated = temp;
! 135:
! 136: /* reduce noddes available */
! 137: list->available = 0;
! 138: list->allocated--;
! 139:
! 140: return;
! 141: }
! 142: } /* end */
! 143:
! 144: /* reached this point, alloc operation worked */
! 145:
1.1 misho 146: /* allocate a node for each available position */
1.1.1.2 ! misho 147: available = list->available;
1.1 misho 148: for (iterator = 0; iterator < list->available; iterator++) {
1.1.1.2 ! misho 149: /* alloc node */
1.1 misho 150: list->preallocated[iterator] = axl_new (axlListNode, 1);
1.1.1.2 ! misho 151:
! 152: /* check alloc operation */
! 153: if (list->preallocated[iterator] == NULL) {
! 154: available--;
! 155: } /* end if */
! 156: } /* end if */
! 157:
! 158: /* update list of available nodes */
! 159: list->available = available;
1.1 misho 160:
161: return;
162: }
163:
164: /**
165: * @internal
166: *
167: * Disposes the node provided, reusing on the next operation
168: * requested.
169: */
170: void __axl_list_dispose_node (axlList * list, axlListNode * node)
171: {
172: /* store the node to be usable again */
173: list->preallocated [list->available] = node;
174:
175: /* increase current available nodes */
176: list->available++;
177:
178: return;
179: }
180:
181: /**
182: * @internal
183: *
184: * Returns a reference to an list node to be used.
185: */
186: axlListNode * __axl_list_get_next_node_available (axlList * list)
187: {
188: axlListNode * node;
189:
190: /* check that there are nodes available */
1.1.1.2 ! misho 191: if (list->available == 0) {
! 192: /* alloc nodes */
1.1 misho 193: __axl_list_allocate_nodes (list);
1.1.1.2 ! misho 194:
! 195: /* check if there are available nodes */
! 196: if (list->available == 0)
! 197: return NULL;
! 198: } /* end if */
1.1 misho 199:
200: /* get the next node available */
201: node = list->preallocated[list->available - 1];
202: list->available--;
203:
204: /* clean node */
205: node->next = NULL;
206: node->previous = NULL;
207: node->data = NULL;
208:
209: return node;
210: }
211:
212:
213: /**
214: * @brief Creates a new \ref axlList, using provided handlers.
215: *
216: * An \ref axlList is a double linked list, with the hability to
217: * recognize elements inside its list by providing the \ref
218: * axlEqualFunc "are_equal" function and the ability to release
219: * memory allocated by the data stored by providing a \ref
220: * axlDestroyFunc "destroy_data" handler.
221: *
222: * The destroy handler is a optional value. If not provided, any
223: * automatic deallocation function will not provided.
224: *
225: * The "are equal" handler is not optinal. You must provide it to make
226: * the list work. In the case you don't like a ordering feature you
227: * can provide an are equal that just return 0 when elements are equal
228: * and always -1 for the rest of the cases if element should be
229: * appended or 1 if the element should be prepended.
230: *
231: * The list is not prepared to be managed at the same type by several
232: * threads. If the list is created and then used by several threads it
233: * will work properly. However, if several threads add and removes
234: * elements at the same time rainy days will come and you'll get funny
235: * behaviours.
236: *
237: * To create the list you must provide two function that performs some
238: * minimal functions required by the list o properly order the data
239: * inside the list and how this data is deallocated (this is
240: * optional).
241: *
242: * For example, to create a list that will hold strings dinamically
243: * allocated you can use:
244: * \code
245: * axlList * list = axl_list_new (axl_list_equal_string, axl_free);
246: * \endcode
247: *
248: * For a list that will holds integer values you can use: \ref
249: * axl_list_equal_int.
250: *
251: * Previous list will cause all strings inside to be deallocated once
252: * called to \ref axl_list_free. If you don't like this, do not
253: * provide the deallocation function.
254: *
255: * You can always use the following function to make the list to allways
256: * add all data at the end of the list: \ref axl_list_always_return_1,
257: * which, as its names indicates, allways return 1, causing the item
258: * to be added at the end of the list. See \ref axlEqualFunc
259: * documentation to know more about creating ordenation functions.
260: *
261: * Now you have your list created, you can use the following functions
262: * to add items:
263: *
264: * - \ref axl_list_add
265: * - \ref axl_list_add_at
266: * - \ref axl_list_prepend
267: * - \ref axl_list_append
268: *
269: * Once you have inserted some data, you can use the following piece
270: * of code to perform an iteration:
271: *
272: * \code
273: * int iterator = 0;
274: * while (iterator < axl_list_length (list)) {
275: * // get the data at the given position
276: * data = axl_list_get_nth (list, iterator);
277: *
278: * // update the iterator
279: * iterator++;
280: * }
281: * \endcode
282: *
283: * However, it is preferred to use the \ref axlListCursor, which is
284: * far more efficient. See the following function to get more
285: * information: \ref axl_list_cursor_new.
286: *
287: * In general, if you are going to perform a lookup for a single item
288: * you can use \ref axl_list_lookup (by providing a handler) or \ref
289: * axl_list_get_nth if you know the position.
290: *
291: *
292: * @param are_equal The equal function to be used by the list to find
293: * and order elements inside the list.
294: *
295: * @param destroy_data An optional handler to destroy nodes in the
296: * case the list is unrefered.
297: *
298: * @return A newly allocated list, that must be destroy by calling to
299: * \ref axl_list_free.
300: */
301: axlList * axl_list_new (axlEqualFunc are_equal, axlDestroyFunc destroy_data)
302: {
303: axlList * result;
304:
305: axl_return_val_if_fail (are_equal, NULL);
306:
1.1.1.2 ! misho 307: /* alloc node */
1.1 misho 308: result = axl_new (axlList, 1);
1.1.1.2 ! misho 309: /* check alloc operation */
! 310: if (result == NULL)
! 311: return NULL;
1.1 misho 312: result->are_equal = are_equal;
313: result->destroy_data = destroy_data;
314:
315: /* preallocate memory for nodes */
316: /* __axl_list_allocate_nodes (result); */
317:
318: return result;
319: }
320:
321: /**
322: * @brief Allows to reconfigure the destroy function to be used on
323: * this list. This function can be useful to disable the destroy
324: * function associated to the list.
325: *
326: * @param list The list to reconfigure or disable (NULL) the destroy function.
327: *
328: * @param destroy_data The reference to the destroy function to be
329: * used or NULL to disable it.
330: */
331: void axl_list_set_destroy_func (axlList * list, axlDestroyFunc destroy_data)
332: {
333: axl_return_if_fail (list);
334: list->destroy_data = destroy_data;
335: return;
336: }
337:
338: /**
339: * @brief Allows to copy the provided list, returning a newly
340: * allocated structure.
341: *
342: * The copy process can also perform a deep copy for all data stored
343: * inside the \ref axlList. However, for this purpose it is required
344: * to provide a duplication function that is able to implement the
345: * duplication operation over the data received.
346: *
347: * This handler is optional, and in the case it is not provided, the
348: * list returned will be a copy having reference to the content
349: * stored.
350: *
351: * NOTE: the function also copy the destroy and equal function
352: * configured at \ref axl_list_new. If you want to disable destroy
353: * function on the copy returned you must use \ref
354: * axl_list_set_destroy_func, passing NULL as destroy handler.
355: *
356: * @param list The list to copy.
357: * @param func The duplication function used to perform a deep copy (optional handler).
358: *
359: * @return A newly allocated \ref axlList with the same configuration
360: * as the one provided.
361: */
362: axlList * axl_list_copy (axlList * list, axlDuplicateFunc func)
363: {
364: axlList * result;
365: int iterator;
366: axlPointer data;
367:
368: axl_return_val_if_fail (list, NULL);
369:
370: /* create a new axl list */
371: result = axl_list_new (list->are_equal, list->destroy_data);
372:
373: /* if the duplicate function is NULL, remove the destroy
374: * function */
375: if (func == NULL)
376: result->destroy_data = NULL;
377:
378: /* add all elements */
379: iterator = 0;
380: while (iterator < axl_list_length (list)) {
381: /* get data pointer from the list */
382: data = axl_list_get_nth (list, iterator);
383:
384: /* try to make a copy */
385: if (func != NULL)
386: data = func (data);
387:
388: /* add the data to the new list */
389: axl_list_add (result, data);
390:
391: /* update index */
392: iterator++;
393: }
394:
395: return result;
396: }
397:
398: /**
399: * @brief Equal function that is prepared to receive two strings a
400: * return if they are equal.
401: *
402: * This function is provided as a convenience implementation for the
403: * \ref axl_list_new function, allowing to store strings inside the
404: * given list.
405: *
406: * The function will return 0 if the string are equal and 1 if
407: * not. This will cause strings to be append at the end of the list.
408: *
409: * @param a The first string to compare.
410: * @param b The second string to compare.
411: */
412: int axl_list_equal_string (axlPointer a, axlPointer b)
413: {
414: int length;
415:
416: axl_return_val_if_fail (a, 1);
417: axl_return_val_if_fail (b, 1);
418:
419: /* get length */
420: length = strlen (a);
421:
422: /* check first that both strings have the same length */
423: if (length != strlen (b))
424: return 1;
425:
426: if (axl_stream_cmp (a, b, length))
427: return 0;
428: /* differs */
429: return 1;
430: }
431:
432: /**
1.1.1.2 ! misho 433: * @brief Works like \ref axl_list_equal_string but ordering strings
! 434: * stored.
! 435: *
! 436: * @param a The first string to compare.
! 437: * @param b The second string to compare.
! 438: *
! 439: * @return 0 if both are equal, -1 if a shold go before b and 1 if a
! 440: * should go after b.
! 441: */
! 442: int axl_list_order_string (axlPointer a, axlPointer b)
! 443: {
! 444: int value;
! 445:
! 446: value = strcmp (a, b);
! 447: if (value == 0)
! 448: return value;
! 449: if (value > 0)
! 450: return -1;
! 451: return 1;
! 452: }
! 453:
! 454: /**
! 455: * @brief Equal function that is prepared to receive to integers and
1.1 misho 456: * return if they are equal.
457: *
458: * It is assumed that integers are stored in the list using the
459: * following:
460: * \code
461: * axl_list_add (list, INT_TO_PTR (integer));
462: * \endcode
463: *
464: * You can use this function to create an \ref axlList that stores
465: * integer values as follows:
466: * \code
467: * list = axl_list_new (axl_list_equal_int, NULL);
468: * \endcode
469: *
470: * The list created with this function will order data from litter to
471: * greater values.
472: *
473: *
474: * @param a A reference to the first integer.
475: * @param b A reference to the second integer.
476: *
477: * @return 0 if values received are equal, and 1 if b is greater than
478: * b. Otherwise -1 is returned.
479: */
480: int axl_list_equal_int (axlPointer a, axlPointer b)
481: {
482: /* especial case where a 0 is stored */
483: if (PTR_TO_INT (a) == PTR_TO_INT (b))
484: return 0;
485: else if (PTR_TO_INT (a) < PTR_TO_INT (b))
486: return -1;
487: else
488: return 1;
489: }
490:
491: /**
492: * @brief An equal function that could be used to make elements to be
493: * stored inside an \ref axlList at the end as the are added, without
494: * replacing any previously added item.
495: *
496: *
497: * If it is needed to create a list that stores elements at the end as
498: * they are added, this function could be used as the \ref
499: * axlEqualFunc, while calling to axl_list_new.
500: *
501: * @param a First item.
502: * @param b Second item.
503: *
504: * @return The function always return 1.
505: *
506: * NOTE: If you use this function and your intention is to remove
507: * items (without calling to axl_list_free) you must use \ref
508: * axl_list_remove_ptr or \ref axl_list_unlink_ptr since \ref
509: * axl_list_remove and \ref axl_list_unlink relays on the equal
510: * function to find and remove the item. Because this function never
511: * return 0, the item is never removed.
512: */
513: int axl_list_always_return_1 (axlPointer a, axlPointer b)
514: {
515: return 1;
516: }
517:
518: /**
519: * @brief Allows to store a new element inside the list, using the
520: * provided data.
521: *
522: * The function will fail to perform any action if a null reference is
523: * provided to the function.
524: *
525: * @param list The list where the element will be added.
526: *
527: * @param pointer The pointer to store.
528: *
529: * NOTE: The function uses the equal function defined at \ref
530: * axl_list_new. If the function shows that the item to be added is
531: * already added (because the equal function returns 0, then the item
532: * won't be added.
533: *
534: */
535: void axl_list_add (axlList * list, axlPointer pointer)
536: {
537: axlListNode * new_node;
538: axlListNode * node;
539: axlListNode * node2;
540:
541:
542: /* perform some environment checkings */
543: axl_return_if_fail (list);
544:
545: new_node = __axl_list_get_next_node_available (list);
1.1.1.2 ! misho 546: /* check returned node */
! 547: if (new_node == NULL)
! 548: return;
1.1 misho 549: new_node->data = pointer;
550:
551: /* check basic case */
552: if (list->first_node == NULL) {
553: list->first_node = new_node;
554: list->last_node = new_node;
555: list->length = 1;
556: return;
557: }
558:
559: /* complex case */
560: node = list->first_node;
561: node2 = list->last_node;
562:
563: /* lookup */
564: while ((node != NULL) || (node2 != NULL)) {
565: /* lookup the head */
566: if (node != NULL) {
567: switch (list->are_equal (node->data, pointer)) {
568: case -1:
569: /* the node should be added before node */
570: new_node->next = node;
571: new_node->previous = node->previous;
572: node->previous = new_node;
573:
574: /* if new previous is null do not update it */
575: if (new_node->previous != NULL)
576: new_node->previous->next = new_node;
577: else
578: list->first_node = new_node;
579:
580: /* update list length */
581: list->length ++;
582: return;
583: case 0:
584: /* the node found is equal, do not perform any operation */
585: return;
586: case 1:
587: default:
588: /* the node should be added after */
589: node = node->next;
590: break;
591: }
592: } /* end if */
593:
594: /* lookup from the tail */
595: if (node2 != NULL) {
596: switch (list->are_equal (node2->data, pointer)) {
597: case -1:
598: default:
599: /* the node should be added before node */
600: node2 = node2->previous;
601: break;
602: case 0:
603:
604: /* the node found is equal, do not perform any operation */
605: return;
606: case 1:
607: /* the node should be added after */
608: new_node->previous = node2;
609: new_node->next = node2->next;
610: node2->next = new_node;
611:
612: /* do not update if next is NULL */
613: if (new_node->next != NULL)
614: new_node->next->previous = new_node;
615: else
616: list->last_node = new_node;
617:
618: /* update length size */
619: list->length ++;
620: return;
621: }
622: } /* end if */
623: } /* end while */
624:
625: /* nothing more to do */
626: return;
627: }
628:
629: /**
630: * @brief Allows to adds the provided item to the given list at the
631: * selected position.
632: *
633: * The function will perform an indexed addition, using the value
634: * <b>position</b>, by-passing current list configuration (\ref
635: * axl_list_new).
636: *
637: * If the position is greater than the length of the list, the item is
638: * added at the end of the list. If the position is 0, the item is
639: * added at the begin (equivalent to call \ref axl_list_prepend).
640: *
641: * If an item is found at the provided position, the element is added
642: * before the already found.
643: *
644: * @param list The list where the addition operation will be performed.
645: *
646: * @param pointer The item to add to the list.
647: *
648: * @param position Position where the addition operation will be
649: * performed. Values allowed ranges from 0 up to list length - 1.
650: */
651: void axl_list_add_at (axlList * list, axlPointer pointer, int position)
652: {
653: int iterator;
654: axlListNode * node;
655: axlListNode * new_node;
656:
657: /* check incoming values */
658: axl_return_if_fail (list);
659:
660: /* check if we have a prepend operation */
661: if (position <= 0) {
662: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item using prepend");
663: /* prepend */
664: axl_list_prepend (list, pointer);
665:
666: return;
667: }
668: /* check if we have an append operation */
669: if (position >= list->length) {
670: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item using append (position=%d >= length=%d)",
671: position, list->length);
672: /* append */
673: axl_list_append (list, pointer);
674:
675: return;
676: }
677:
678: /* allocate a new node */
679: new_node = __axl_list_get_next_node_available (list);
1.1.1.2 ! misho 680: /* check returned node */
! 681: if (new_node == NULL)
! 682: return;
1.1 misho 683: new_node->data = pointer;
684:
685:
686: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "looking node position: %d", position);
687:
688: /* basic case isn't reached here (remove first and last
689: * cases) */
690: iterator = 1;
691: node = list->first_node->next;
692: while (iterator < position) {
693:
694: /* get the next element */
695: node = node->next;
696:
697: /* update the iterator */
698: iterator++;
699: }
700:
701: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item at: %d", iterator);
702:
703: /* add the element */
704: new_node->previous = node->previous;
705: if (node->previous != NULL)
706: node->previous->next = new_node;
707:
708: new_node->next = node;
709: node->previous = new_node;
710:
711: /* update number of items inside */
712: list->length++;
713: return;
714: }
715:
716: /**
717: * @brief Allows to add a node to the provided list, at the first
718: * position, without taking into consideration current \ref axlList
719: * configuration (\ref axlEqualFunc at \ref axl_list_new).
720: *
721: * @param list The list where the data will be added at the first
722: * position.
723: *
724: * @param pointer The pointer to add.
725: */
726: void axl_list_prepend (axlList * list, axlPointer pointer)
727: {
728: axlListNode * new_node;
729:
730: axl_return_if_fail (list);
731:
732: /* simulate adding the node at the first position */
733: new_node = __axl_list_get_next_node_available (list);
1.1.1.2 ! misho 734: /* check returned node */
! 735: if (new_node == NULL)
! 736: return;
1.1 misho 737: new_node->data = pointer;
738:
739: /* make the new node the be the first one */
740: if (list->first_node == NULL) {
741: list->first_node = new_node;
742: list->last_node = new_node;
743: }else {
744: list->first_node->previous = new_node;
745: new_node->next = list->first_node;
746: list->first_node = new_node;
747: }
748:
749: /* update number of items inside */
750: list->length++;
751:
752: return;
753: }
754:
755:
756: /**
757: * @brief Allows to add a node to the provided list, at the last
758: * position, without taking into consideration current \ref axlList
759: * configuration (\ref axlEqualFunc at \ref axl_list_new).
760: *
761: * @param list The list where the data will be added at the last
762: * position.
763: *
764: * @param pointer The pointer to add.
765: */
766: void axl_list_append (axlList * list, axlPointer pointer)
767: {
768: axlListNode * new_node;
769:
770: axl_return_if_fail (list);
771:
772: /* simulate adding the node at the first position */
773: new_node = __axl_list_get_next_node_available (list);
1.1.1.2 ! misho 774: /* check allocated node */
! 775: if (new_node == NULL)
! 776: return;
1.1 misho 777: new_node->data = pointer;
778:
779: /* make the new node the be the first one */
780: if (list->last_node == NULL) {
781: list->first_node = new_node;
782: list->last_node = new_node;
783: }else {
784: list->last_node->next = new_node;
785: new_node->previous = list->last_node;
786: list->last_node = new_node;
787: }
788:
789: /* update number of items inside */
790: list->length++;
791:
792: return;
793: }
794:
795: /**
796: * @internal Internal list lookup using a linear search, checking all
797: * items inside the list taking into considerations hints provided by
798: * equal function.
799: *
800: * @param list The list where the linear search will be performed.
801: * @param pointer The pointer that is being looked up.
802: *
803: * @return A reference to the internal axl list node containing the
804: * pointer.
805: */
806: axlListNode * axl_list_internal_linear_lookup (axlList * list,
807: axlPointer pointer)
808: {
809: axlListNode * node;
810:
811: axl_return_val_if_fail (list, NULL);
812:
813: /* complex case */
814: node = list->first_node;
815:
816: /* lookup */
817: while (node != NULL) {
818: if (list->are_equal (node->data, pointer) == 0)
819: return node;
820:
821: /* the node should be after this one */
822: node = node->next;
823:
824: } /* end while */
825:
826: return NULL;
827: }
828:
829: /**
830: * @internal Internal list lookup using a linear search, checking all
831: * items inside the list withtout taking into considerations hints
832: * provided by equal function (search by pointer).
833: *
834: * @param list The list where the linear search will be performed.
835: * @param pointer The pointer that is being looked up.
836: *
837: * @return A reference to the internal axl list node containing the
838: * pointer.
839: */
840: axlListNode * axl_list_internal_linear_lookup_ptr (axlList * list,
841: axlPointer pointer)
842: {
843: axlListNode * node;
844:
845: axl_return_val_if_fail (list, NULL);
846:
847: /* complex case */
848: node = list->first_node;
849:
850: /* lookup */
851: while (node && node->data != pointer) {
852: /* the node should be after this one */
853: node = node->next;
854: } /* end while */
855:
856: /* return current result */
857: return node;
858: }
859:
860: /**
861: * @internal
862: * @brief Internal lookup function to locate the axlListNode that contains the pointer.
863: *
864: *
865: * @param list The list where the lookup will be performed.
866: * @param pointer The pointer data to lookup.
867: *
868: * @return A reference to the \ref axlListNode or NULL if no pointer
869: * is found.
870: */
871: axlListNode * axl_list_internal_lookup (axlList * list, axlPointer pointer)
872: {
873: axlListNode * node;
874: axlListNode * node2;
875:
876: axl_return_val_if_fail (list, NULL);
877: axl_return_val_if_fail (pointer, NULL);
878:
879: /* complex case */
880: node = list->first_node;
881: node2 = list->last_node;
882:
883: /* lookup */
884: while ((node != NULL) || (node2 != NULL)) {
885: /* lookup the head */
886: if (node != NULL) {
887: switch (list->are_equal (node->data, pointer)) {
888: case -1:
889: default:
890: /* node should be before the node
891: * found. So we are not going to find
892: * a node that is lower, the element
893: * is not in the list.
894: */
895: return NULL;
896: case 0:
897: return node;
898: case 1:
899: /* the node should be after this one */
900: node = node->next;
901: break;
902: }
903: } /* end if */
904:
905: /* lookup from the tail */
906: if (node2 != NULL) {
907: switch (list->are_equal (node2->data, pointer)) {
908: case -1:
909: /* the node should be added before node */
910: node2 = node2->next;
911: break;
912: case 0:
913: return node2;
914: case 1:
915: default:
916: /* it seems that the node should be
917: * found after this node but this is
918: * not going to be possible. The node is not in the list.
919: */
920: return NULL;
921: }
922: } /* end if */
923: } /* end while */
924:
925: return NULL;
926: }
927:
928:
929: /**
930: * @internal
931: *
932: * @brief Allows to lookup the pointer stored, inside the provided
933: * list, on the given position.
934: *
935: * @param list The list where the operation will be performed.
936: * @param position The position to lookup for stored data.
937: *
938: * @return A reference or NULL if fails.
939: */
940: axlListNode * axl_list_internal_get_nth (axlList * list, int position)
941: {
942: axlListNode * node;
943: int iterator = 0;
944:
945: axl_return_val_if_fail (list, NULL);
946: axl_return_val_if_fail (position >= 0 && position < list->length, NULL);
947:
948: /* iterate until the node is found */
949: node = list->first_node;
950: while (node != NULL && (iterator != position)) {
951: iterator ++;
952: node = node->next;
953: }
954:
955: /* return data found */
956: if (iterator == position)
957: return node;
958: return NULL;
959: }
960:
961: /* remove the selected node */
962: void __axl_list_common_remove_selected_node (axlList * list, axlListNode * node,
963: axl_bool alsoRemove)
964: {
965: axlPointer pointer;
966:
967: /* do not remove anything if a null reference is received */
968: if (node == NULL)
969: return;
970:
971: /* get a reference to the pointer */
972: pointer = node->data;
973:
974: if (node->previous == NULL)
975: list->first_node = node->next;
976: else
977: node->previous->next = node->next;
978:
979: if (node->next == NULL)
980: list->last_node = node->previous;
981: else
982: node->next->previous = node->previous;
983:
984: /* release user space allocated memory
985: * if defined destroy function */
986: if (alsoRemove && (list->destroy_data != NULL))
987: list->destroy_data (pointer);
988:
989: /* release memory allocated by the node */
990: __axl_list_dispose_node (list, node);
991:
992: /* decrease list length */
993: list->length--;
994:
995: /* nothing more to do */
996: return;
997: }
998:
999: /**
1000: * @internal
1001: *
1002: * Internal support for axl_list_remove and axl_list_unlink
1003: * function. The function perform a node removing, the one that
1004: * contains the node pointed by the provided pointer, and making a
1005: * node deallocation according to the configuration of the
1006: * <b>alsoRemove</b>.
1007: *
1008: * @param list The list where the operation will be performed.
1009: *
1010: * @param pointer The pointer to remove
1011: *
1012: * @param alsoRemove Also call to destroy function.
1013: *
1014: * @param byPtr Makes the linear search to be done by pointer.
1015: */
1016: void axl_list_common_remove (axlList * list, axlPointer pointer, axl_bool alsoRemove, axl_bool byPtr)
1017: {
1018: axlListNode * node;
1019:
1020: axl_return_if_fail (list);
1021:
1022: /* complex case */
1023: if (byPtr)
1024: node = axl_list_internal_linear_lookup_ptr (list, pointer);
1025: else
1026: node = axl_list_internal_linear_lookup (list, pointer);
1027: if (node == NULL) {
1028: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "unable to find item by pointer (0x%x)",
1029: pointer);
1030: return;
1031: }
1032:
1033: /* remove the selected node */
1034: __axl_list_common_remove_selected_node (list, node, alsoRemove);
1035:
1036: return;
1037: }
1038:
1039:
1040: /**
1041: * @brief Allows to remove the given pointer from the list.
1042: *
1043: * The element referenced by <b>pointer</b> will be removed from the
1044: * list, include the memory allocated if a destroy function were
1045: * provided.
1046: *
1047: * If it is required to remove a pointer from the list, without
1048: * calling to the destroy function, you can use \ref axl_list_unlink.
1049: *
1050: * The function will fail to work if references provided are NULL.
1051: *
1052: * @param list The list where the removal operation will be performed.
1053: * @param pointer The pointer where the
1054: *
1055: * NOTE: The function uses the current equal function configured. A
1056: * not properly configured equal function will make this function to
1057: * not remove the item selected. If you are trying to remove by
1058: * pointer, you can use \ref axl_list_remove_ptr.
1059: */
1060: void axl_list_remove (axlList * list, axlPointer pointer)
1061: {
1062:
1063: /* perform a complete removing */
1064: axl_list_common_remove (list, pointer,
1065: /* alsoRemove */
1066: axl_true,
1067: /* byPtr */
1068: axl_false);
1069:
1070: return;
1071: }
1072:
1073: /**
1074: * @internal Implementation that removes or unlinks a selected node at
1075: * a particular position.
1076: */
1077: void __axl_list_remove_at_common (axlList * list, int position, axl_bool remove_node)
1078: {
1079: axlListNode * node;
1080: int iterator = 0;
1081:
1082: axl_return_if_fail (list);
1083:
1084: /* find the item by position */
1085: node = list->first_node;
1086:
1087: /* lookup */
1088: while (node) {
1089: /* return selected node */
1090: if (iterator == position)
1091: break;
1092:
1093: /* the node should be after this one */
1094: node = node->next;
1095:
1096: /* next iterator */
1097: iterator++;
1098: } /* end while */
1099:
1100: if (node) {
1101: /* remove selected node */
1102: __axl_list_common_remove_selected_node (list, node, remove_node);
1103: } /* end if */
1104: return;
1105: }
1106:
1107: /**
1108: * @brief Allows to remove a particular item inside the list at a
1109: * selected position.
1110: *
1111: * This function also deallocates the memory used by the node located
1112: * at the particular position. In the case only a removal operation is
1113: * required use \ref axl_list_unlink_at.
1114: *
1115: * @param list The list where the remove operation will take place.
1116: *
1117: * @param position The position where the removal operation will take
1118: * place. Position values ranges from 0 up to (N - 1).
1119: */
1120: void axl_list_remove_at (axlList * list, int position)
1121: {
1122: /* call to common implementation */
1123: __axl_list_remove_at_common (list, position, axl_true);
1124: return;
1125: }
1126:
1127: /**
1128: * @brief Allows to remove the provided pointer from the list (calling
1129: * to the destroy function defined).
1130: *
1131: * Unlike \ref axl_list_remove, which removes the element selected by
1132: * using the equal function configured at \ref axl_list_new, this
1133: * function allows to perform a remove operation by pointer.
1134: *
1135: * @param list The list on which the operation is performed.
1136: *
1137: * @param pointer The pointer to remove from the list.
1138: */
1139: void axl_list_remove_ptr (axlList * list, axlPointer pointer)
1140: {
1141: /* perform a complete removing */
1142: axl_list_common_remove (list, pointer,
1143: /* alsoRemove */
1144: axl_true,
1145: /* byPtr */
1146: axl_true);
1147: }
1148:
1149: /**
1150: * @brief Removes the given pointer from the list, without calling the
1151: * destroy function, even when it is configured.
1152: *
1153: * @param list The list where the operation will be performed.
1154: *
1155: * @param pointer The pointer to remove.
1156: */
1157: void axl_list_unlink (axlList * list, axlPointer pointer)
1158: {
1159: /* perform a complete removing */
1160: axl_list_common_remove (list, pointer,
1161: /* alsoRemove */
1162: axl_false,
1163: /* byPtr */
1164: axl_false);
1165:
1166: return;
1167: }
1168:
1169: /**
1170: * @brief Allows to remove the provided item from the axl list
1171: * withtout using the equal function provided (remove by pointer) and
1172: * without calling to the associated destroy function.
1173: *
1174: * @param list The list where the operation will be implemented.
1175: *
1176: * @param pointer the pointer to remove from the list without calling
1177: * to the destroy function.
1178: */
1179: void axl_list_unlink_ptr (axlList * list, axlPointer pointer)
1180: {
1181:
1182: /* perform an unlink operation, without using equal
1183: * function */
1184: /* perform a complete removing */
1185: axl_list_common_remove (list, pointer,
1186: /* alsoRemove */
1187: axl_false,
1188: /* byPtr */
1189: axl_true);
1190:
1191: return;
1192: }
1193:
1194: /**
1195: * @brief Allows to unlink a particular item inside the list at a
1196: * selected position.
1197: *
1198: * This function DO NOT deallocates the memory used by the node located
1199: * at the particular position. In the case a complete removal operation is
1200: * required use \ref axl_list_remove_at.
1201: *
1202: * @param list The list where the unlink operation will take place.
1203: *
1204: * @param position The position where the unlink operation will take
1205: * place. Position values ranges from 0 up to (N - 1).
1206: */
1207: void axl_list_unlink_at (axlList * list, int position)
1208: {
1209: /* call to common implementation */
1210: __axl_list_remove_at_common (list, position, axl_false);
1211: return;
1212: }
1213:
1214:
1215: /**
1216: * @brief Allows to remove the first element, calling to the destroy
1217: * function if defined.
1218: *
1219: * @param list The list where the first element will be removed.
1220: */
1221: void axl_list_remove_first (axlList * list)
1222: {
1223:
1224: axl_return_if_fail (list);
1225:
1226: /* do not perform any operation if no node is stored */
1227: if (list->first_node == NULL)
1228: return;
1229:
1230: /* remove the selected node */
1231: __axl_list_common_remove_selected_node (list, list->first_node, axl_true);
1232:
1233: return;
1234: }
1235:
1236: /**
1237: * @brief Allows to remove the first element from the list without
1238: * calling to the destroy function, even with it is defined.
1239: *
1240: * @param list The list where the first element will be removed.
1241: */
1242: void axl_list_unlink_first (axlList * list)
1243: {
1244:
1245: axl_return_if_fail (list);
1246:
1247: /* do not perform any operation if no node is stored */
1248: if (list->first_node == NULL)
1249: return;
1250:
1251: /* remove the selected node */
1252: __axl_list_common_remove_selected_node (list, list->first_node, axl_false);
1253:
1254: return;
1255: }
1256:
1257: /**
1258: * @brief Allows to remove the last element, calling to the destroy
1259: * function if defined.
1260: *
1261: * @param list The list where the last element will be removed.
1262: */
1263: void axl_list_remove_last (axlList * list)
1264: {
1265: axl_return_if_fail (list);
1266:
1267: /* do not perform any operation if no node is stored */
1268: if (list->last_node == NULL)
1269: return;
1270:
1271: /* remove the selected node */
1272: __axl_list_common_remove_selected_node (list, list->last_node, axl_true);
1273:
1274: return;
1275: }
1276:
1277: /**
1278: * @brief Allows to remove the last element from the list without
1279: * calling to the destroy function, even with it is defined.
1280: *
1281: * @param list The list where the last element will be removed.
1282: */
1283: void axl_list_unlink_last (axlList * list)
1284: {
1285: axl_return_if_fail (list);
1286:
1287: /* do not perform any operation if no node is stored */
1288: if (list->last_node == NULL)
1289: return;
1290:
1291: /* remove the selected node */
1292: __axl_list_common_remove_selected_node (list, list->last_node, axl_false);
1293:
1294: return;
1295: }
1296:
1297: /**
1298: * @brief Allows to check if the given pointer is stored on the given
1299: * list.
1300: *
1301: * @param list The list where the lookup will be performed.
1302: *
1303: * @param pointer The pointer to lookup.
1304: *
1305: * @return \ref axl_true if the element is stored on the list,
1306: * otherwise axl_false is returned. The function will fail to lookup
1307: * if a NULL reference is received, either the list or the pointer.
1308: */
1309: axl_bool axl_list_exists (axlList * list, axlPointer pointer)
1310: {
1311: axl_return_val_if_fail (list, axl_false);
1312: axl_return_val_if_fail (pointer, axl_false);
1313:
1314: if (axl_list_internal_lookup (list, pointer) != NULL)
1315: return axl_true;
1316: return axl_false;
1317: }
1318:
1319: /**
1320: * @brief Allows to check if the provided list is empty (no element
1321: * stored).
1322: *
1323: * @param list The list to check for emptyness.
1324: *
1325: * @return axl_true if the list is empty, axl_false if not. The function
1326: * return axl_false in the case a null reference is provided.
1327: */
1328: axl_bool axl_list_is_empty (axlList * list)
1329: {
1330: axl_return_val_if_fail (list, axl_false);
1331:
1332: /* check if the first node is defined */
1333: return (list->first_node == NULL);
1334: }
1335:
1336: /**
1337: * @brief Allows to check if the given pointer is stored on the given position.
1338: *
1339: * @param list The list where the operation will be run.
1340: * @param pointer The pointer to check.
1341: * @param position The position where is expected to find the pointer.
1342: *
1343: * @return axl_true if the given data, referenced by the pointer, is
1344: * stored on the given position.
1345: */
1346: axl_bool axl_list_exists_at (axlList * list, axlPointer pointer, int position)
1347: {
1348: axlListNode * node;
1349:
1350: node = axl_list_internal_get_nth (list, position);
1351: if (node != NULL) {
1352: if (! list->are_equal (node->data, pointer))
1353: return axl_true;
1354: }
1355: return axl_false;
1356: }
1357:
1358: /**
1359: * @brief Returns the first element stored on the list.
1360: *
1361: *
1362: * @param list The list where the first element stored will be
1363: * returned.
1364: *
1365: * @return An \ref axlPointer containing the data stored on the list.
1366: */
1367: axlPointer axl_list_get_first (axlList * list)
1368: {
1369: axl_return_val_if_fail (list, NULL);
1370:
1371: if (list->first_node == NULL)
1372: return NULL;
1373: return list->first_node->data;
1374: }
1375:
1376: /**
1377: * @brief Returns the last element stored on the list.
1378: *
1379: * @param list The list where the last element will be returned.
1380: *
1381: * @return An \ref axlPointer reference containing the last stored
1382: * value.
1383: */
1384: axlPointer axl_list_get_last (axlList * list)
1385: {
1386: axl_return_val_if_fail (list, NULL);
1387:
1388: if (list->last_node == NULL)
1389: return NULL;
1390: return list->last_node->data;
1391: }
1392:
1393: /**
1394: * @brief Allows to get current pointer stored at the given position.
1395: *
1396: * @param list The list where the data will be retrieved.
1397: *
1398: * @param position A value ranging from 0 up to the the list lenght -
1399: * 1.
1400: *
1401: * @return The \ref axlPointer stored on the given position or NULL if
1402: * fail.
1403: */
1404: axlPointer axl_list_get_nth (axlList * list, int position)
1405: {
1406: axlListNode * node;
1407:
1408: node = axl_list_internal_get_nth (list, position);
1409: if (node != NULL)
1410: return node->data;
1411: return NULL;
1412: }
1413:
1414: /**
1415: * @brief Allows to perform a linear lookup on the list provided,
1416: * givin a function that is used to now the object to return due to
1417: * the lookup.
1418: *
1419: * The function can also be used as a foreach function. The following
1420: * example shows how to launch the function and perform a tasks on the
1421: * lookup function:
1422: * \code
1423: * // perform the lookup
1424: * return axl_list_lookup (list, __find_item, name);
1425: *
1426: * // the lookup function
1427: * axl_bool __find_item (axlPointer _element, axlPointer data)
1428: * {
1429: * SomeItem * element = _element;
1430: * char * name = data;
1431: *
1432: * // check the name
1433: * if (axl_cmp (element->name, name))
1434: * return axl_true;
1435: *
1436: * // it is not the element
1437: * return axl_false;
1438: * }
1439: * \endcode
1440: *
1441: * In the case you create a list to hold string values, you can use
1442: * \ref axl_list_find_string as lookup function predefined to perform
1443: * the search.
1444: *
1445: * @param list The list where the lookup will be performed.
1446: *
1447: * @param func The function to use to perform the lookup.
1448: *
1449: * @param data User defined data that will be passed to the func provided.
1450: *
1451: * @return A pointer to the object found or NULL if no item was found.
1452: */
1453: axlPointer axl_list_lookup (axlList * list, axlLookupFunc func, axlPointer data)
1454: {
1455: axlListNode * node;
1456: axl_return_val_if_fail (list, NULL);
1457: axl_return_val_if_fail (func, NULL);
1458:
1459: /* get the first pointer */
1460: node = list->first_node;
1461: do {
1462: /* if the next node to check is NULL, terminate the
1463: * lookup. */
1464: if (node == NULL)
1465: return NULL;
1466:
1467: /* check if the node found is the one looked up */
1468: if (func (node->data, data))
1469: return node->data;
1470:
1471: /* seems not, update to the next reference */
1472: node = node->next;
1473:
1474: }while (1);
1475:
1476: /* return no node found */
1477: return NULL;
1478: }
1479:
1480: /**
1481: * @brief Helper function that could be used at \ref axl_list_lookup if
1482: * the list created only contains strings.
1483: *
1484: * Use this function as a parameter for the lookup function at \ref
1485: * axl_list_lookup.
1486: *
1487: * @param element The element at the list, in this case, an string value.
1488: *
1489: * @param data The data provided at \ref axl_list_lookup, in this
1490: * case, the value we are looking.
1491: *
1492: * @return \ref axl_true if the string was found, \ref axl_false if not.
1493: */
1494: axl_bool axl_list_find_string (axlPointer element, axlPointer data)
1495: {
1496: /* if the string received is null, just return axl_false */
1497: if (data == NULL)
1498: return axl_false;
1499:
1500: /* return the comparison status */
1501: return axl_cmp ((char *) element, (char *) data);
1502: }
1503:
1504: /**
1505: * @brief Allows to get current list length.
1506: *
1507: * @param list The list to operate.
1508: *
1509: * @return The list length or -1 if fail (the list reference received
1510: * is null).
1511: */
1512: int axl_list_length (axlList * list)
1513: {
1514: axl_return_val_if_fail (list, -1);
1515: return list->length;
1516: }
1517:
1518: /**
1519: * @brief Allows to destroy the given list, and all user space
1520: * associated memory if a destroy handler was provided.
1521: *
1522: * @param list The list to destroy
1523: */
1524: void axl_list_free (axlList * list)
1525: {
1526: axlListNode * node;
1527: axlListNode * node2;
1528: int iterator;
1529:
1530: /* if a null reference is received do not oper */
1531: if (list == NULL)
1532: return;
1533:
1534: node = list->first_node;
1535: while (node != NULL) {
1536: if (list->destroy_data != NULL) {
1537: list->destroy_data (node->data);
1538: }
1539: node2 = node;
1540: node = node->next;
1541:
1542: axl_free (node2);
1543: }
1544:
1545: /* allocate a node for each available position */
1546: for (iterator = 0; iterator < list->available; iterator++) {
1547: axl_free (list->preallocated[iterator]);
1548: }
1549:
1550: /* free the array */
1551: axl_free (list->preallocated);
1552:
1553: /* free the list itself */
1554: axl_free (list);
1555:
1556: return;
1557: }
1558:
1559: /* @} */
1560:
1561: /**
1562: * \defgroup axl_list_cursor_module Axl List Cursor: Iterator support for the Axl List
1563: */
1564:
1565: /**
1566: * \addtogroup axl_list_cursor_module
1567: * @{
1568: */
1569:
1570: /**
1571: * @brief Allows to get a cursor to iterate the list in a linear and
1572: * efficient way.
1573: *
1574: * The \ref axlListCursor could be used to iterate an \ref axlList in
1575: * an efficient way because it stores current state (position). Then
1576: * using the following functions you can modify the state (current
1577: * position to get):
1578: *
1579: * - \ref axl_list_cursor_first
1580: * - \ref axl_list_cursor_last
1581: * - \ref axl_list_cursor_next
1582: * - \ref axl_list_cursor_previous
1583: *
1584: * Finally, a function is provided to get the data stored at a
1585: * particular position, pointed by the current status of the cursor:
1586: *
1587: * - \ref axl_list_cursor_get
1588: *
1589: * You are allowed to remove elements from the list (\ref axlList)
1590: * having a cursor created (\ref axlListCursor), using \ref
1591: * axl_list_cursor_unlink.
1592: *
1593: * Here is an example:
1594: * \code
1595: * axlPointer value;
1596: * axlListCursor * cursor;
1597: *
1598: * // create the cursor
1599: * cursor = axl_list_cursor_new (list);
1600: *
1601: * // while there are more elements
1602: * while (axl_list_cursor_has_item (cursor)) {
1603: *
1604: * // get the value
1605: * value = axl_list_cursor_get (cursor);
1606: *
1607: *
1608: * // get the next
1609: * axl_list_cursor_next (cursor);
1610: *
1611: * // update the iterator
1612: * iterator++;
1613: *
1614: * }
1615: *
1616: * // free the cursor
1617: * axl_list_cursor_free (cursor);
1618: * \endcode
1619: *
1620: * @param list The list that the new cursor (\ref axlListCursor) will
1621: * provide access.
1622: *
1623: * @return A newly created \ref axlListCursor used to iterate the
1624: * list. Once finished you must call to \ref axl_list_cursor_free.
1625: */
1626: axlListCursor * axl_list_cursor_new (axlList * list)
1627: {
1628: axlListCursor * cursor;
1629:
1630: axl_return_val_if_fail (list, NULL);
1631:
1632: /* create the cursor */
1633: cursor = axl_new (axlListCursor, 1);
1634:
1635: /* initial configuration */
1636: cursor->list = list;
1637: cursor->current = list->first_node;
1638:
1639: return cursor;
1640: }
1641:
1642: /**
1643: * @brief Allows to configure the cursor to point to the first item of
1644: * the list (if there are any).
1645: *
1646: * @param cursor The cursor that is required to be configured to point the first item.
1647: */
1648: void axl_list_cursor_first (axlListCursor * cursor)
1649: {
1650: axl_return_if_fail (cursor);
1651:
1652: if (cursor->list->length == 0) {
1653: cursor->current = NULL;
1654: return;
1655: } /* end if */
1656:
1657: /* set the first node */
1658: cursor->current = cursor->list->first_node;
1659:
1660: return;
1661: }
1662:
1663: /**
1664: * @brief Allows to configure the cursor to point to the last item of
1665: * the list (if there are any).
1666: *
1667: * @param cursor The cursor that is required to be configured to point
1668: * to the last item.
1669: */
1670: void axl_list_cursor_last (axlListCursor * cursor)
1671: {
1672: axl_return_if_fail (cursor);
1673:
1674: /* set the first node */
1675: cursor->current = cursor->list->last_node;
1676:
1677: return;
1678: }
1679:
1680: /**
1681: * @brief Allows to configure the cursor to point to the next item of
1682: * the list (if there are any).
1683: *
1684: * @param cursor The cursor that is required to be configured to point
1685: * to the next item.
1686: */
1687: void axl_list_cursor_next (axlListCursor * cursor)
1688: {
1689: axl_return_if_fail (cursor);
1690:
1691: /* set the next node */
1692: if (cursor->current != NULL)
1693: cursor->current = cursor->current->next;
1694:
1695: return;
1696: }
1697:
1698: /**
1699: * @brief Allows to configure the cursor to point to the previous item
1700: * of the list (if there are any).
1701: *
1702: * @param cursor The cursor that is required to be configured to point
1703: * to the previous item.
1704: */
1705: void axl_list_cursor_previous (axlListCursor * cursor)
1706: {
1707: axl_return_if_fail (cursor);
1708:
1709: /* set the next node */
1710: if (cursor->current != NULL)
1711: cursor->current = cursor->current->previous;
1712:
1713: return;
1714: }
1715:
1716: /**
1717: * @brief Allows to check if there are more elements next to the
1718: * current element pointed by the cursor.
1719: *
1720: * @param cursor The cursor that is required to return if there are
1721: * next items.
1722: *
1723: * @return \ref axl_true if more items are found, otherwise \ref axl_false is
1724: * returned.
1725: */
1726: axl_bool axl_list_cursor_has_next (axlListCursor * cursor)
1727: {
1728: axl_return_val_if_fail (cursor, axl_false);
1729:
1730: /* check for empty list */
1731: if (cursor->current == NULL)
1732: return axl_false;
1733:
1734: /* return if the next element isn't null */
1735: return (cursor->current->next != NULL);
1736: }
1737:
1738: /**
1739: * @brief Allows to check if there are more elements next to the
1740: * current element pointed by the cursor.
1741: *
1742: * @param cursor The cursor that is required to return if there are
1743: * next items.
1744: *
1745: * @return \ref axl_true if more items are found, otherwise \ref axl_false is
1746: * returned.
1747: */
1748: axl_bool axl_list_cursor_has_previous (axlListCursor * cursor)
1749: {
1750: axl_return_val_if_fail (cursor, axl_false);
1751:
1752: /* check for empty list */
1753: if (cursor->current == NULL)
1754: return axl_false;
1755:
1756: /* return if the next element isn't null */
1757: return (cursor->current->previous != NULL);
1758: }
1759:
1760: /**
1761: * @brief Allows to know if the current position has items.
1762: *
1763: * @param cursor The cursor that is requested to return if a call to
1764: * \ref axl_list_cursor_get will return data.
1765: *
1766: * @return \ref axl_true if the list that is iterated can return data at
1767: * the current position, otherwise \ref axl_false is returned.
1768: */
1769: axl_bool axl_list_cursor_has_item (axlListCursor * cursor)
1770: {
1771: axl_return_val_if_fail (cursor, axl_false);
1772:
1773: /* return if there are current */
1774: return (cursor->current != NULL);
1775: }
1776:
1777: /**
1778: * @brief Allows to remove current element pointed by the cursor,
1779: * maintainig internal state of the cursor.
1780: *
1781: * The function won't call to the destroy function asociated to the
1782: * list. If you want the item stored to be also destroyed call \ref
1783: * axl_list_cursor_remove.
1784: *
1785: * @param cursor The cursor pointing to the item inside the list that
1786: * must be removed.
1787: */
1788: void axl_list_cursor_unlink (axlListCursor * cursor)
1789: {
1790: axlListNode * node;
1791:
1792: axl_return_if_fail (cursor);
1793:
1794: /* if current cursor is pointing nowhere, just do nothing */
1795: if (cursor->current == NULL)
1796: return;
1797:
1798: /* remember node */
1799: node = cursor->current;
1800:
1801: /* configure the cursor to point to the next element (or the previous if the next element is null) */
1802: cursor->current = (node->next != NULL) ? node->next : node->previous;
1803:
1804: /* call to unlik */
1805: __axl_list_common_remove_selected_node (cursor->list, node, axl_false);
1806:
1807: return;
1808: }
1809:
1810: /**
1811: * @brief Allows to remove current element pointed by the cursor,
1812: * maintainig internal state of the cursor, calling to the destroy
1813: * function associated in the list.
1814: *
1815: * The function will call to the destroy function asociated to the
1816: * list. If you don't want the item stored to be also destroyed call \ref
1817: * axl_list_cursor_unlink.
1818: *
1819: * @param cursor The cursor pointing to the item inside the list that
1820: * must be removed.
1821: */
1822: void axl_list_cursor_remove (axlListCursor * cursor)
1823: {
1824: axlListNode * node;
1825:
1826: axl_return_if_fail (cursor);
1827:
1828: /* if current cursor is pointing nowhere, just do nothing */
1829: if (cursor->current == NULL)
1830: return;
1831:
1832: /* remember node */
1833: node = cursor->current;
1834:
1835: /* configure the cursor to point to the next element (or the previous if the next element is null) */
1836: cursor->current = (node->next != NULL) ? node->next : node->previous;
1837:
1838: /* call to remove */
1839: __axl_list_common_remove_selected_node (cursor->list, node, axl_true);
1840:
1841: return;
1842: }
1843:
1844: /**
1845: * @brief Allows to get current data at the current cursor state.
1846: *
1847: * @param cursor The cursor that will be used to return the data
1848: * located at the list, using cursor current state.
1849: */
1850: axlPointer axl_list_cursor_get (axlListCursor * cursor)
1851: {
1852: axl_return_val_if_fail (cursor, NULL);
1853:
1854: /* nothing to return if current is NULL */
1855: if (cursor->current == NULL)
1856: return NULL;
1857:
1858: /* return data */
1859: return cursor->current->data;
1860: }
1861:
1862: /**
1863: * @brief Allows to get the reference to the list that is associated
1864: * to the cursor received.
1865: *
1866: * @param cursor The cursor that is required to return the list associated.
1867: *
1868: * @return A reference to the list being iterated or NULL if fails.
1869: */
1870: axlList * axl_list_cursor_list (axlListCursor * cursor)
1871: {
1872: /* check incoming cursor */
1873: axl_return_val_if_fail (cursor, NULL);
1874:
1875: /* return the list */
1876: return cursor->list;
1877: }
1878:
1879: /**
1880: * @brief Deallocates memory used by the cursor.
1881: *
1882: * @param cursor The cursor to be deallocated.
1883: */
1884: void axl_list_cursor_free (axlListCursor * cursor)
1885: {
1886: axl_return_if_fail (cursor);
1887:
1888: /* free the cursor */
1889: axl_free (cursor);
1890:
1891: return;
1892: }
1893:
1894: /* @} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>