Add missing files
[gmpc-magnatune.git] / src / axl / axl_list.c
blob025e2c7a85dbf50973e7b32c17d288be615f5b57
1 /*
2 * LibAxl: Another XML library
3 * Copyright (C) 2006 Advanced Software Production Line, S.L.
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.
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.
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
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.
27 * For commercial support on build XML enabled solutions contact us:
29 * Postal address:
30 * Advanced Software Production Line, S.L.
31 * C/ Dr. Michavila NÂș 14
32 * Coslada 28820 Madrid
33 * Spain
35 * Email address:
36 * info@aspl.es - http://fact.aspl.es
39 #include <axl_decl.h>
40 #include <axl_list.h>
41 #include <axl_log.h>
42 #include <axl_stream.h>
44 #define LOG_DOMAIN "axl-list"
46 typedef struct _axlListNode axlListNode;
48 struct _axlList {
49 /* functions used by the list to properly order elements
50 * inside it and how they are destroyed */
51 axlEqualFunc are_equal;
52 axlDestroyFunc destroy_data;
54 /* pointers to the list content */
55 axlListNode * first_node;
56 axlListNode * last_node;
58 /* list length */
59 int length;
61 /* memory management functions */
62 axlListNode ** preallocated;
63 int available;
64 int allocated;
67 struct _axlListNode {
68 axlListNode * previous;
69 axlListNode * next;
70 axlPointer data;
73 struct _axlListCursor {
74 axlList * list;
75 axlListNode * current;
78 /**
79 * \defgroup axl_list_module Axl List: A configurable double-linked list used across the library.
82 /**
83 * \addtogroup axl_list_module
84 * @{
87 /**
88 * @internal
90 * Internal are equal handler implementation for the axl list module
91 * that always return 0.
93 int __axl_list_always_true (axlPointer a, axlPointer b)
95 return 0;
98 /**
99 * @internal
101 * Preallocates nodes to be used to store data on the lists.
103 * @param list The list where the preallocation operation will be
104 * performed.
106 void __axl_list_allocate_nodes (axlList * list)
108 int iterator;
110 list->available = 1;
111 list->allocated += list->available;
113 /* allocate enough memory to hold all nodes already
114 * allocated */
115 if (list->preallocated == NULL)
116 list->preallocated = axl_new (axlListNode *, list->allocated);
117 else
118 list->preallocated = realloc (list->preallocated, (sizeof (axlListNode *)) * list->allocated);
120 /* allocate a node for each available position */
121 for (iterator = 0; iterator < list->available; iterator++) {
122 list->preallocated[iterator] = axl_new (axlListNode, 1);
125 return;
128 /**
129 * @internal
131 * Disposes the node provided, reusing on the next operation
132 * requested.
134 void __axl_list_dispose_node (axlList * list, axlListNode * node)
136 /* store the node to be usable again */
137 list->preallocated [list->available] = node;
139 /* increase current available nodes */
140 list->available++;
142 return;
145 /**
146 * @internal
148 * Returns a reference to an list node to be used.
150 axlListNode * __axl_list_get_next_node_available (axlList * list)
152 axlListNode * node;
154 /* check that there are nodes available */
155 if (list->available == 0)
156 __axl_list_allocate_nodes (list);
158 /* get the next node available */
159 node = list->preallocated[list->available - 1];
160 list->available--;
162 /* clean node */
163 node->next = NULL;
164 node->previous = NULL;
165 node->data = NULL;
167 return node;
171 /**
172 * @brief Creates a new \ref axlList, using provided handlers.
174 * An \ref axlList is a double linked list, with the hability to
175 * recognize elements inside its list by providing the \ref
176 * axlEqualFunc "are_equal" function and the ability to release
177 * memory allocated by the data stored by providing a \ref
178 * axlDestroyFunc "destroy_data" handler.
180 * The destroy handler is a optional value. If not provided, any
181 * automatic deallocation function will not provided.
183 * The "are equal" handler is not optinal. You must provide it to make
184 * the list work. In the case you don't like a ordering feature you
185 * can provide an are equal that just return 0 when elements are equal
186 * and always -1 for the rest of the cases if element should be
187 * appended or 1 if the element should be prepended.
189 * The list is not prepared to be managed at the same type by several
190 * threads. If the list is created and then used by several threads it
191 * will work properly. However, if several threads add and removes
192 * elements at the same time rainy days will come and you'll get funny
193 * behaviours.
195 * To create the list you must provide two function that performs some
196 * minimal functions required by the list o properly order the data
197 * inside the list and how this data is deallocated (this is
198 * optional).
200 * For example, to create a list that will hold strings dinamically
201 * allocated you can use:
202 * \code
203 * axlList * list = axl_list_new (axl_list_equal_string, axl_free);
204 * \endcode
206 * For a list that will holds integer values you can use: \ref
207 * axl_list_equal_int.
209 * Previous list will cause all strings inside to be deallocated once
210 * called to \ref axl_list_free. If you don't like this, do not
211 * provide the deallocation function.
213 * You can always use the following function to make the list to allways
214 * add all data at the end of the list: \ref axl_list_always_return_1,
215 * which, as its names indicates, allways return 1, causing the item
216 * to be added at the end of the list. See \ref axlEqualFunc
217 * documentation to know more about creating ordenation functions.
219 * Now you have your list created, you can use the following functions
220 * to add items:
222 * - \ref axl_list_add
223 * - \ref axl_list_add_at
224 * - \ref axl_list_prepend
225 * - \ref axl_list_append
227 * Once you have inserted some data, you can use the following piece
228 * of code to perform an iteration:
230 * \code
231 * int iterator = 0;
232 * while (iterator < axl_list_length (list)) {
233 * // get the data at the given position
234 * data = axl_list_get_nth (list, iterator);
236 * // update the iterator
237 * iterator++;
239 * \endcode
241 * However, it is preferred to use the \ref axlListCursor, which is
242 * far more efficient. See the following function to get more
243 * information: \ref axl_list_cursor_new.
245 * In general, if you are going to perform a lookup for a single item
246 * you can use \ref axl_list_lookup (by providing a handler) or \ref
247 * axl_list_get_nth if you know the position.
250 * @param are_equal The equal function to be used by the list to find
251 * and order elements inside the list.
253 * @param destroy_data An optional handler to destroy nodes in the
254 * case the list is unrefered.
256 * @return A newly allocated list, that must be destroy by calling to
257 * \ref axl_list_free.
259 axlList * axl_list_new (axlEqualFunc are_equal, axlDestroyFunc destroy_data)
261 axlList * result;
263 axl_return_val_if_fail (are_equal, NULL);
265 result = axl_new (axlList, 1);
266 result->are_equal = are_equal;
267 result->destroy_data = destroy_data;
269 /* preallocate memory for nodes */
270 /* __axl_list_allocate_nodes (result); */
272 return result;
275 /**
276 * @brief Allows to copy the provided list, returning a newly
277 * allocated structure.
279 * The copy process can also perform a deep copy for all data stored
280 * inside the \ref axlList. However, for this purpose it is required
281 * to provide a duplication function that is able to implement the
282 * duplication operation over the data received.
284 * This handler is optional, and in the case it is not provided, the
285 * list returned will be a copy having reference to the content
286 * stored.
288 * @param list The list to copy.
289 * @param func The duplication function used to perform a deep copy (optional handler).
291 * @return A newly allocated \ref axlList with the same configuration
292 * as the one provided.
294 axlList * axl_list_copy (axlList * list, axlDuplicateFunc func)
296 axlList * result;
297 int iterator;
298 axlPointer data;
300 axl_return_val_if_fail (list, NULL);
302 /* create a new axl list */
303 result = axl_list_new (list->are_equal, list->destroy_data);
305 /* if the duplicate function is NULL, remove the destroy
306 * function */
307 if (func == NULL)
308 result->destroy_data = NULL;
310 /* add all elements */
311 iterator = 0;
312 while (iterator < axl_list_length (list)) {
313 /* get data pointer from the list */
314 data = axl_list_get_nth (list, iterator);
316 /* try to make a copy */
317 if (func != NULL)
318 data = func (data);
320 /* add the data to the new list */
321 axl_list_add (result, data);
323 /* update index */
324 iterator++;
327 return result;
330 /**
331 * @brief Equal function that is prepared to receive two strings a
332 * return if they are equal.
334 * This function is provided as a convenience implementation for the
335 * \ref axl_list_new function, allowing to store strings inside the
336 * given list.
338 * The function will return 0 if the string are equal and 1 if
339 * not. This will cause to make the strings addes to be append at the
340 * end of the list.
342 * @param a The first string to compare.
343 * @param b The second string to compare.
345 int axl_list_equal_string (axlPointer a, axlPointer b)
347 int length = strlen (a);
348 axl_return_val_if_fail (a, 1);
349 axl_return_val_if_fail (b, 1);
352 if (axl_stream_cmp (a, b, length))
353 return 0;
354 return 1;
357 /**
358 * @brief Equal function that is preprated to receive to integers and
359 * return if they are equal.
361 * It is assumed that integers are stored in the list using the
362 * following:
363 * \code
364 * axl_list_add (list, INT_TO_PTR (integer));
365 * \endcode
367 * You can use this function to create an \ref axlList that stores
368 * integer values as follows:
369 * \code
370 * list = axl_list_new (axl_list_equal_int, NULL);
371 * \endcode
373 * The list created with this function will order data from litter to
374 * greater values.
377 * @param a A reference to the first integer.
378 * @param b A reference to the second integer.
380 * @return 0 if values received are equal, and 1 if b is greater than
381 * b. Otherwise -1 is returned.
383 int axl_list_equal_int (axlPointer a, axlPointer b)
385 /* especial case where a 0 is stored */
386 if (PTR_TO_INT (a) == PTR_TO_INT (b))
387 return 0;
388 else if (PTR_TO_INT (a) < PTR_TO_INT (b))
389 return -1;
390 else
391 return 1;
394 /**
395 * @brief An equal function that could be used to make elements to be
396 * stored inside an \ref axlList at the end as the are added, without
397 * replacing any previously added item.
400 * If it is needed to create a list that stores elements at the end as
401 * they are added, this function could be used as the \ref
402 * axlEqualFunc, while calling to axl_list_new.
404 * @param a First item.
405 * @param b Second item.
407 * @return The function always return 1.
409 int axl_list_always_return_1 (axlPointer a, axlPointer b)
411 return 1;
414 /**
415 * @brief Allows to store a new element inside the list, using the
416 * provided data.
418 * The function will fail to perform any action if a null reference is
419 * provided to the function.
421 * @param list The list where the element will be added.
423 * @param pointer The pointer to store.
426 void axl_list_add (axlList * list, axlPointer pointer)
428 axlListNode * new_node;
429 axlListNode * node;
430 axlListNode * node2;
433 /* perform some environment checkings */
434 axl_return_if_fail (list);
436 new_node = __axl_list_get_next_node_available (list);
437 new_node->data = pointer;
439 /* check basic case */
440 if (list->first_node == NULL) {
441 list->first_node = new_node;
442 list->last_node = new_node;
443 list->length = 1;
444 return;
447 /* complex case */
448 node = list->first_node;
449 node2 = list->last_node;
451 /* lookup */
452 while ((node != NULL) || (node2 != NULL)) {
453 /* lookup the head */
454 if (node != NULL) {
455 switch (list->are_equal (node->data, pointer)) {
456 case -1:
457 /* the node should be added before node */
458 new_node->next = node;
459 new_node->previous = node->previous;
460 node->previous = new_node;
462 /* if new previous is null do not update it */
463 if (new_node->previous != NULL)
464 new_node->previous->next = new_node;
465 else
466 list->first_node = new_node;
468 /* update list length */
469 list->length ++;
470 return;
471 case 0:
473 /* the node found is equal, do not perform any operation */
474 return;
475 case 1:
476 default:
477 /* the node should be added after */
478 node = node->next;
479 break;
481 } /* end if */
483 /* lookup from the tail */
484 if (node2 != NULL) {
485 switch (list->are_equal (node2->data, pointer)) {
486 case -1:
487 default:
488 /* the node should be added before node */
489 node2 = node2->previous;
490 break;
491 case 0:
493 /* the node found is equal, do not perform any operation */
494 return;
495 case 1:
496 /* the node should be added after */
497 new_node->previous = node2;
498 new_node->next = node2->next;
499 node2->next = new_node;
501 /* do not update if next is NULL */
502 if (new_node->next != NULL)
503 new_node->next->previous = new_node;
504 else
505 list->last_node = new_node;
507 /* update length size */
508 list->length ++;
509 return;
511 } /* end if */
512 } /* end while */
514 /* nothing more to do */
515 return;
518 /**
519 * @brief Allows to adds the provided item to the given list at the
520 * selected position.
522 * The function will perform an indexed addition, using the value
523 * <b>position</b>, by-passing current list configuration (\ref
524 * axl_list_new).
526 * If the position is greater than the length of the list, the item is
527 * added at the end of the list. If the position is 0, the item is
528 * added at the begin (equivalent to call \ref axl_list_prepend).
530 * If an item is found at the provided position, the element is added
531 * before the already found.
533 * @param list The list where the addition operation will be performed.
535 * @param pointer The item to add to the list.
537 * @param position Position where the addition operation will be
538 * performed. Values allowed ranges from 0 up to list length - 1.
540 void axl_list_add_at (axlList * list, axlPointer pointer, int position)
542 int iterator;
543 axlListNode * node;
544 axlListNode * new_node;
546 /* check incoming values */
547 axl_return_if_fail (list);
549 /* check if we have a prepend operation */
550 if (position <= 0) {
551 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item using prepend");
552 /* prepend */
553 axl_list_prepend (list, pointer);
555 return;
557 /* check if we have an append operation */
558 if (position >= list->length) {
559 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item using append (position=%d >= length=%d)",
560 position, list->length);
561 /* append */
562 axl_list_append (list, pointer);
564 return;
567 /* allocate a new node */
568 new_node = __axl_list_get_next_node_available (list);
569 new_node->data = pointer;
572 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "looking node position: %d", position);
574 /* basic case isn't reached here (remove first and last
575 * cases) */
576 iterator = 1;
577 node = list->first_node->next;
578 while (iterator < position) {
580 /* get the next element */
581 node = node->next;
583 /* update the iterator */
584 iterator++;
587 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "adding item at: %d", iterator);
589 /* add the element */
590 new_node->previous = node->previous;
591 if (node->previous != NULL)
592 node->previous->next = new_node;
594 new_node->next = node;
595 node->previous = new_node;
597 /* update number of items inside */
598 list->length++;
599 return;
602 /**
603 * @brief Allows to add a node to the provided list, at the first
604 * position, without taking into consideration current \ref axlList
605 * configuration (\ref axlEqualFunc at \ref axl_list_new).
607 * @param list The list where the data will be added at the first
608 * position.
610 * @param pointer The pointer to add.
612 void axl_list_prepend (axlList * list, axlPointer pointer)
614 axlListNode * new_node;
616 axl_return_if_fail (list);
618 /* simulate adding the node at the first position */
619 new_node = __axl_list_get_next_node_available (list);
620 new_node->data = pointer;
622 /* make the new node the be the first one */
623 if (list->first_node == NULL) {
624 list->first_node = new_node;
625 list->last_node = new_node;
626 }else {
627 list->first_node->previous = new_node;
628 new_node->next = list->first_node;
629 list->first_node = new_node;
632 /* update number of items inside */
633 list->length++;
635 return;
639 /**
640 * @brief Allows to add a node to the provided list, at the last
641 * position, without taking into consideration current \ref axlList
642 * configuration (\ref axlEqualFunc at \ref axl_list_new).
644 * @param list The list where the data will be added at the last
645 * position.
647 * @param pointer The pointer to add.
649 void axl_list_append (axlList * list, axlPointer pointer)
651 axlListNode * new_node;
653 axl_return_if_fail (list);
655 /* simulate adding the node at the first position */
656 new_node = __axl_list_get_next_node_available (list);
657 new_node->data = pointer;
659 /* make the new node the be the first one */
660 if (list->last_node == NULL) {
661 list->first_node = new_node;
662 list->last_node = new_node;
663 }else {
664 list->last_node->next = new_node;
665 new_node->previous = list->last_node;
666 list->last_node = new_node;
669 /* update number of items inside */
670 list->length++;
672 return;
675 /**
676 * @internal Internal list lookup using a linear search, checking all
677 * items inside the list withtout taking into considerations hints
678 * provided by equal function.
680 * @param list The list where the linear search will be performed.
681 * @param pointer The pointer that is being looked up.
683 * @return A reference to the internal axl list node containing the
684 * pointer.
686 axlListNode * axl_list_internal_linear_lookup (axlList * list,
687 axlPointer pointer)
689 axlListNode * node;
691 axl_return_val_if_fail (list, NULL);
692 axl_return_val_if_fail (pointer, NULL);
694 /* complex case */
695 node = list->first_node;
697 /* lookup */
698 while (node != NULL) {
699 if (list->are_equal (node->data, pointer) == 0)
700 return node;
702 /* the node should be after this one */
703 node = node->next;
705 } /* end while */
707 return NULL;
710 /**
711 * @internal
712 * @brief Internal lookup function to locate the axlListNode that contains the pointer.
715 * @param list The list where the lookup will be performed.
716 * @param pointer The pointer data to lookup.
718 * @return A reference to the \ref axlListNode or NULL if no pointer
719 * is found.
721 axlListNode * axl_list_internal_lookup (axlList * list, axlPointer pointer)
723 axlListNode * node;
724 axlListNode * node2;
726 axl_return_val_if_fail (list, NULL);
727 axl_return_val_if_fail (pointer, NULL);
729 /* complex case */
730 node = list->first_node;
731 node2 = list->last_node;
733 /* lookup */
734 while ((node != NULL) || (node2 != NULL)) {
735 /* lookup the head */
736 if (node != NULL) {
737 switch (list->are_equal (node->data, pointer)) {
738 case -1:
739 default:
740 /* node should be before the node
741 * found. So we are not going to find
742 * a node that is lower, the element
743 * is not in the list.
745 return NULL;
746 case 0:
747 return node;
748 case 1:
749 /* the node should be after this one */
750 node = node->next;
751 break;
753 } /* end if */
755 /* lookup from the tail */
756 if (node2 != NULL) {
757 switch (list->are_equal (node2->data, pointer)) {
758 case -1:
759 /* the node should be added before node */
760 node2 = node2->next;
761 break;
762 case 0:
763 return node2;
764 case 1:
765 default:
766 /* it seems that the node should be
767 * found after this node but this is
768 * not going to be possible. The node is not in the list.
770 return NULL;
772 } /* end if */
773 } /* end while */
775 return NULL;
779 /**
780 * @internal
782 * @brief Allows to lookup the pointer stored, inside the provided
783 * list, on the given position.
785 * @param list The list where the operation will be performed.
786 * @param position The position to lookup for stored data.
788 * @return A reference or NULL if fails.
790 axlListNode * axl_list_internal_get_nth (axlList * list, int position)
792 axlListNode * node;
793 int iterator = 0;
795 axl_return_val_if_fail (list, NULL);
796 axl_return_val_if_fail (position >= 0 && position < list->length, NULL);
798 /* iterate until the node is found */
799 node = list->first_node;
800 while (node != NULL && (iterator != position)) {
801 iterator ++;
802 node = node->next;
805 /* return data found */
806 if (iterator == position)
807 return node;
808 return NULL;
811 /* remove the selected node */
812 void __axl_list_common_remove_selected_node (axlList * list, axlListNode * node,
813 bool alsoRemove)
815 axlPointer pointer;
817 /* do not remove anything if a null reference is received */
818 if (node == NULL)
819 return;
821 /* get a reference to the pointer */
822 pointer = node->data;
824 if (node->previous == NULL)
825 list->first_node = node->next;
826 else
827 node->previous->next = node->next;
829 if (node->next == NULL)
830 list->last_node = node->previous;
831 else
832 node->next->previous = node->previous;
834 /* release user space allocated memory
835 * if defined destroy function */
836 if (alsoRemove && (list->destroy_data != NULL))
837 list->destroy_data (pointer);
839 /* release memory allocated by the node */
840 __axl_list_dispose_node (list, node);
842 /* decrease list length */
843 list->length--;
845 /* nothing more to do */
846 return;
849 /**
850 * @internal
852 * Internal support for axl_list_remove and axl_list_unlink
853 * function. The function perform a node removing, the one that
854 * contains the node pointed by the provided pointer, and making a
855 * node deallocation according to the configuration of the
856 * <b>alsoRemove</b>.
858 * @param list The list where the operation will be performed.
860 * @param pointer The pointer to remove
862 * @param alsoRemove Also call to destroy function.
864 void axl_list_common_remove (axlList * list, axlPointer pointer, bool alsoRemove)
866 axlListNode * node;
868 axl_return_if_fail (list);
869 axl_return_if_fail (pointer);
871 /* complex case */
872 node = axl_list_internal_linear_lookup (list, pointer);
873 if (node == NULL) {
874 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "unable to find item by pointer (0x%x)",
875 pointer);
876 return;
879 /* remove the selected node */
880 __axl_list_common_remove_selected_node (list, node, alsoRemove);
882 return;
886 /**
887 * @brief Allows to remove the given pointer from the list.
889 * The element referenced by <b>pointer</b> will be removed from the
890 * list, include the memory allocated if a destroy function were
891 * provided.
893 * If it is required to remove a pointer from the list, without
894 * calling to the destroy function, you can use \ref axl_list_unlink.
896 * The function will fail to work if references provided are NULL.
898 * @param list The list where the removal operation will be performed.
899 * @param pointer The pointer where the
901 void axl_list_remove (axlList * list, axlPointer pointer)
904 __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attempting to remove pointer: 0x%x", pointer);
906 /* perform a complete removing */
907 axl_list_common_remove (list, pointer, true);
909 return;
912 /**
913 * @brief Removes the given pointer from the list, without calling the
914 * destroy function, even when it is configured.
916 * @param list The list where the operation will be performed.
918 * @param pointer The pointer to remove.
920 void axl_list_unlink (axlList * list, axlPointer pointer)
922 /* perform a complete removing */
923 axl_list_common_remove (list, pointer, false);
925 return;
928 /**
929 * @brief Allows to remove the first element, calling to the destroy
930 * function if defined.
932 * @param list The list where the first element will be removed.
934 void axl_list_remove_first (axlList * list)
937 axl_return_if_fail (list);
939 /* do not perform any operation if no node is stored */
940 if (list->first_node == NULL)
941 return;
943 /* remove the selected node */
944 __axl_list_common_remove_selected_node (list, list->first_node, true);
946 return;
949 /**
950 * @brief Allows to remove the first element from the list without
951 * calling to the destroy function, even with it is defined.
953 * @param list The list where the first element will be removed.
955 void axl_list_unlink_first (axlList * list)
958 axl_return_if_fail (list);
960 /* do not perform any operation if no node is stored */
961 if (list->first_node == NULL)
962 return;
964 /* remove the selected node */
965 __axl_list_common_remove_selected_node (list, list->first_node, false);
967 return;
970 /**
971 * @brief Allows to remove the last element, calling to the destroy
972 * function if defined.
974 * @param list The list where the last element will be removed.
976 void axl_list_remove_last (axlList * list)
978 axl_return_if_fail (list);
980 /* do not perform any operation if no node is stored */
981 if (list->last_node == NULL)
982 return;
984 /* remove the selected node */
985 __axl_list_common_remove_selected_node (list, list->last_node, true);
987 return;
990 /**
991 * @brief Allows to remove the last element from the list without
992 * calling to the destroy function, even with it is defined.
994 * @param list The list where the last element will be removed.
996 void axl_list_unlink_last (axlList * list)
998 axl_return_if_fail (list);
1000 /* do not perform any operation if no node is stored */
1001 if (list->last_node == NULL)
1002 return;
1004 /* remove the selected node */
1005 __axl_list_common_remove_selected_node (list, list->last_node, false);
1007 return;
1010 /**
1011 * @brief Allows to check if the given pointer is stored on the given
1012 * list.
1014 * @param list The list where the lookup will be performed.
1016 * @param pointer The pointer to lookup.
1018 * @return \ref true if the element is stored on the list,
1019 * otherwise false is returned. The function will fail to lookup
1020 * if a NULL reference is received, either the list or the pointer.
1022 bool axl_list_exists (axlList * list, axlPointer pointer)
1024 axl_return_val_if_fail (list, false);
1025 axl_return_val_if_fail (pointer, false);
1027 if (axl_list_internal_lookup (list, pointer) != NULL)
1028 return true;
1029 return false;
1032 /**
1033 * @brief Allows to check if the provided list is empty (no element
1034 * stored).
1036 * @param list The list to check for emptyness.
1038 * @return true if the list is empty, false if not. The function
1039 * return false in the case a null reference is provided.
1041 bool axl_list_is_empty (axlList * list)
1043 axl_return_val_if_fail (list, false);
1045 /* check if the first node is defined */
1046 return (list->first_node == NULL);
1049 /**
1050 * @brief Allows to check if the given pointer is stored on the given position.
1052 * @param list The list where the operation will be run.
1053 * @param pointer The pointer to check.
1054 * @param position The position where is expected to find the pointer.
1056 * @return true if the given data, referenced by the pointer, is
1057 * stored on the given position.
1059 bool axl_list_exists_at (axlList * list, axlPointer pointer, int position)
1061 axlListNode * node;
1063 node = axl_list_internal_get_nth (list, position);
1064 if (node != NULL) {
1065 if (! list->are_equal (node->data, pointer))
1066 return true;
1068 return false;
1071 /**
1072 * @brief Returns the first element stored on the list.
1075 * @param list The list where the first element stored will be
1076 * returned.
1078 * @return An \ref axlPointer containing the data stored on the list.
1080 axlPointer axl_list_get_first (axlList * list)
1082 axl_return_val_if_fail (list, NULL);
1084 if (list->first_node == NULL)
1085 return NULL;
1086 return list->first_node->data;
1089 /**
1090 * @brief Returns the last element stored on the list.
1092 * @param list The list where the last element will be returned.
1094 * @return An \ref axlPointer reference containing the last stored
1095 * value.
1097 axlPointer axl_list_get_last (axlList * list)
1099 axl_return_val_if_fail (list, NULL);
1101 if (list->last_node == NULL)
1102 return NULL;
1103 return list->last_node->data;
1106 /**
1107 * @brief Allows to get current pointer stored at the given position.
1109 * @param list The list where the data will be retrieved.
1111 * @param position A value ranging from 0 up to the the list lenght -
1112 * 1.
1114 * @return The \ref axlPointer stored on the given position or NULL if
1115 * fail.
1117 axlPointer axl_list_get_nth (axlList * list, int position)
1119 axlListNode * node;
1121 node = axl_list_internal_get_nth (list, position);
1122 if (node != NULL)
1123 return node->data;
1124 return NULL;
1127 /**
1128 * @brief Allows to perform a linear lookup on the list provided,
1129 * givin a function that is used to now the object to return due to
1130 * the lookup.
1132 * The function can also be used as a foreach function. The following
1133 * example shows how to launch the function and perform a tasks on the
1134 * lookup function:
1135 * \code
1136 * // perform the lookup
1137 * return axl_list_lookup (list, __find_item, name);
1139 * // the lookup function
1140 * bool __find_item (axlPointer _element, axlPointer data)
1142 * SomeItem * element = _element;
1143 * char * name = data;
1145 * // check the name
1146 * if (axl_cmp (element->name, name))
1147 * return true;
1149 * // it is not the element
1150 * return false;
1152 * \endcode
1154 * In the case you create a list to hold string values, you can use
1155 * \ref axl_list_find_string as lookup function predefined to perform
1156 * the search.
1158 * @param list The list where the lookup will be performed.
1160 * @param func The function to use to perform the lookup.
1162 * @param data User defined data that will be passed to the func provided.
1164 * @return A pointer to the object found or NULL if no item was found.
1166 axlPointer axl_list_lookup (axlList * list, axlLookupFunc func, axlPointer data)
1168 axlListNode * node;
1169 axl_return_val_if_fail (list, NULL);
1170 axl_return_val_if_fail (func, NULL);
1172 /* get the first pointer */
1173 node = list->first_node;
1174 do {
1175 /* if the next node to check is NULL, terminate the
1176 * lookup. */
1177 if (node == NULL)
1178 return NULL;
1180 /* check if the node found is the one looked up */
1181 if (func (node->data, data))
1182 return node->data;
1184 /* seems not, update to the next reference */
1185 node = node->next;
1187 }while (1);
1189 /* return no node found */
1190 return NULL;
1193 /**
1194 * @brief Helper function that could be used at \ref axl_list_lookup if
1195 * the list created only contains strings.
1197 * Use this function as a parameter for the lookup function at \ref
1198 * axl_list_lookup.
1200 * @param element The element at the list, in this case, an string value.
1202 * @param data The data provided at \ref axl_list_lookup, in this
1203 * case, the value we are looking.
1205 * @return \ref true if the string was found, \ref false if not.
1207 bool axl_list_find_string (axlPointer element, axlPointer data)
1209 /* if the string received is null, just return false */
1210 if (data == NULL)
1211 return false;
1213 /* return the comparison status */
1214 return axl_cmp ((char *) element, (char *) data);
1217 /**
1218 * @brief Allows to get current list length.
1220 * @param list The list to operate.
1222 * @return The list length or -1 if fail (the list reference received
1223 * is null).
1225 int axl_list_length (axlList * list)
1227 axl_return_val_if_fail (list, -1);
1228 return list->length;
1231 /**
1232 * @brief Allows to destroy the given list, and all user space
1233 * associated memory if a destroy handler was provided.
1235 * @param list The list to destroy
1237 void axl_list_free (axlList * list)
1239 axlListNode * node;
1240 axlListNode * node2;
1241 int iterator;
1243 /* if a null reference is received do not oper */
1244 if (list == NULL)
1245 return;
1247 node = list->first_node;
1248 while (node != NULL) {
1249 if (list->destroy_data != NULL) {
1250 list->destroy_data (node->data);
1252 node2 = node;
1253 node = node->next;
1255 axl_free (node2);
1258 /* allocate a node for each available position */
1259 for (iterator = 0; iterator < list->available; iterator++) {
1260 axl_free (list->preallocated[iterator]);
1263 /* free the array */
1264 axl_free (list->preallocated);
1266 /* free the list itself */
1267 axl_free (list);
1269 return;
1272 /* @} */
1275 * \defgroup axl_list_cursor_module Axl List Cursor: Iterator support for the Axl List
1278 /**
1279 * \addtogroup axl_list_cursor_module
1280 * @{
1283 /**
1284 * @brief Allows to get a cursor to iterate the list in a linear and
1285 * efficient way.
1287 * The \ref axlListCursor could be used to iterate an \ref axlList in
1288 * an efficient way because it stores current state (position). Then
1289 * using the following functions you can modify the state (current
1290 * position to get):
1292 * - \ref axl_list_cursor_first
1293 * - \ref axl_list_cursor_last
1294 * - \ref axl_list_cursor_next
1295 * - \ref axl_list_cursor_previous
1297 * Finally, a function is provided to get the data stored at a
1298 * particular position, pointed by the current status of the cursor:
1300 * - \ref axl_list_cursor_get
1302 * You are allowed to remove elements from the list (\ref axlList)
1303 * having a cursor created (\ref axlListCursor), using \ref
1304 * axl_list_cursor_unlink.
1306 * Here is an example:
1307 * \code
1308 * axlPointer value;
1309 * axlListCursor * cursor;
1311 * // create the cursor
1312 * cursor = axl_list_cursor_new (list);
1314 * // while there are more elements
1315 * while (axl_list_cursor_has_item (cursor)) {
1317 * // get the value
1318 * value = axl_list_cursor_get (cursor);
1321 * // get the next
1322 * axl_list_cursor_next (cursor);
1324 * // update the iterator
1325 * iterator++;
1327 * }
1329 * // free the cursor
1330 * axl_list_cursor_free (cursor);
1331 * \endcode
1333 * @param list The list that the new cursor (\ref axlListCursor) will
1334 * provide access.
1336 * @return A newly created \ref axlListCursor used to iterate the
1337 * list. Once finished you must call to \ref axl_list_cursor_free.
1339 axlListCursor * axl_list_cursor_new (axlList * list)
1341 axlListCursor * cursor;
1343 axl_return_val_if_fail (list, NULL);
1345 /* create the cursor */
1346 cursor = axl_new (axlListCursor, 1);
1348 /* initial configuration */
1349 cursor->list = list;
1350 cursor->current = list->first_node;
1352 return cursor;
1355 /**
1356 * @brief Allows to configure the cursor to point to the first item of
1357 * the list (if there are any).
1359 * @param cursor The cursor that is required to be configured to point the first item.
1361 void axl_list_cursor_first (axlListCursor * cursor)
1363 axl_return_if_fail (cursor);
1365 if (cursor->list->length == 0) {
1366 cursor->current = NULL;
1367 return;
1368 } /* end if */
1370 /* set the first node */
1371 cursor->current = cursor->list->first_node;
1373 return;
1376 /**
1377 * @brief Allows to configure the cursor to point to the last item of
1378 * the list (if there are any).
1380 * @param cursor The cursor that is required to be configured to point
1381 * to the last item.
1383 void axl_list_cursor_last (axlListCursor * cursor)
1385 axl_return_if_fail (cursor);
1387 /* set the first node */
1388 cursor->current = cursor->list->last_node;
1390 return;
1393 /**
1394 * @brief Allows to configure the cursor to point to the next item of
1395 * the list (if there are any).
1397 * @param cursor The cursor that is required to be configured to point
1398 * to the next item.
1400 void axl_list_cursor_next (axlListCursor * cursor)
1402 axl_return_if_fail (cursor);
1404 /* set the next node */
1405 if (cursor->current != NULL)
1406 cursor->current = cursor->current->next;
1408 return;
1411 /**
1412 * @brief Allows to configure the cursor to point to the previous item
1413 * of the list (if there are any).
1415 * @param cursor The cursor that is required to be configured to point
1416 * to the previous item.
1418 void axl_list_cursor_previous (axlListCursor * cursor)
1420 axl_return_if_fail (cursor);
1422 /* set the next node */
1423 if (cursor->current != NULL)
1424 cursor->current = cursor->current->previous;
1426 return;
1429 /**
1430 * @brief Allows to check if there are more elements next to the
1431 * current element pointed by the cursor.
1433 * @param cursor The cursor that is required to return if there are
1434 * next items.
1436 * @return \ref true if more items are found, otherwise \ref false is
1437 * returned.
1439 bool axl_list_cursor_has_next (axlListCursor * cursor)
1441 axl_return_val_if_fail (cursor, false);
1443 /* check for empty list */
1444 if (cursor->current == NULL)
1445 return false;
1447 /* return if the next element isn't null */
1448 return (cursor->current->next != NULL);
1451 /**
1452 * @brief Allows to check if there are more elements next to the
1453 * current element pointed by the cursor.
1455 * @param cursor The cursor that is required to return if there are
1456 * next items.
1458 * @return \ref true if more items are found, otherwise \ref false is
1459 * returned.
1461 bool axl_list_cursor_has_previous (axlListCursor * cursor)
1463 axl_return_val_if_fail (cursor, false);
1465 /* check for empty list */
1466 if (cursor->current == NULL)
1467 return false;
1469 /* return if the next element isn't null */
1470 return (cursor->current->previous != NULL);
1473 /**
1474 * @brief Allows to know if the current position has items.
1476 * @param cursor The cursor that is requested to return if a call to
1477 * \ref axl_list_cursor_get will return data.
1479 * @return \ref true if the list that is iterated can return data at
1480 * the current position, otherwise \ref false is returned.
1482 bool axl_list_cursor_has_item (axlListCursor * cursor)
1484 axl_return_val_if_fail (cursor, false);
1486 /* return if there are current */
1487 return (cursor->current != NULL);
1490 /**
1491 * @brief Allows to remove current element pointed by the cursor,
1492 * maintainig internal state of the cursor.
1494 * The function won't call to the destroy function asociated to the
1495 * list. If you want the item stored to be also destroyed call \ref
1496 * axl_list_cursor_remove.
1498 * @param cursor The cursor pointing to the item inside the list that
1499 * must be removed.
1501 void axl_list_cursor_unlink (axlListCursor * cursor)
1503 axlListNode * node;
1505 axl_return_if_fail (cursor);
1507 /* if current cursor is pointing nowhere, just do nothing */
1508 if (cursor->current == NULL)
1509 return;
1511 /* remember node */
1512 node = cursor->current;
1514 /* configure the cursor to point to the next element (or the previous if the next element is null) */
1515 cursor->current = (node->next != NULL) ? node->next : node->previous;
1517 /* call to unlik */
1518 __axl_list_common_remove_selected_node (cursor->list, node, false);
1520 return;
1523 /**
1524 * @brief Allows to remove current element pointed by the cursor,
1525 * maintainig internal state of the cursor, calling to the destroy
1526 * function associated in the list.
1528 * The function will call to the destroy function asociated to the
1529 * list. If you don't want the item stored to be also destroyed call \ref
1530 * axl_list_cursor_unlink.
1532 * @param cursor The cursor pointing to the item inside the list that
1533 * must be removed.
1535 void axl_list_cursor_remove (axlListCursor * cursor)
1537 axlListNode * node;
1539 axl_return_if_fail (cursor);
1541 /* if current cursor is pointing nowhere, just do nothing */
1542 if (cursor->current == NULL)
1543 return;
1545 /* remember node */
1546 node = cursor->current;
1548 /* configure the cursor to point to the next element (or the previous if the next element is null) */
1549 cursor->current = (node->next != NULL) ? node->next : node->previous;
1551 /* call to remove */
1552 __axl_list_common_remove_selected_node (cursor->list, node, false);
1554 return;
1557 /**
1558 * @brief Allows to get current data at the current cursor state.
1560 * @param cursor The cursor that will be used to return the data
1561 * located at the list, using cursor current state.
1563 axlPointer axl_list_cursor_get (axlListCursor * cursor)
1565 axl_return_val_if_fail (cursor, NULL);
1567 /* nothing to return if current is NULL */
1568 if (cursor->current == NULL)
1569 return NULL;
1571 /* return data */
1572 return cursor->current->data;
1575 /**
1576 * @brief Allows to get the reference to the list that is associated
1577 * to the cursor received.
1579 * @param cursor The cursor that is required to return the list associated.
1581 * @return A reference to the list being iterated or NULL if fails.
1583 axlList * axl_list_cursor_list (axlListCursor * cursor)
1585 /* check incoming cursor */
1586 axl_return_val_if_fail (cursor, NULL);
1588 /* return the list */
1589 return cursor->list;
1592 /**
1593 * @brief Deallocates memory used by the cursor.
1595 * @param cursor The cursor to be deallocated.
1597 void axl_list_cursor_free (axlListCursor * cursor)
1599 axl_return_if_fail (cursor);
1601 /* free the cursor */
1602 axl_free (cursor);
1604 return;
1607 /* @} */