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
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
27 * For commercial support on build XML enabled solutions contact us:
30 * Advanced Software Production Line, S.L.
31 * C/ Dr. Michavila NÂș 14
32 * Coslada 28820 Madrid
36 * info@aspl.es - http://fact.aspl.es
42 #include <axl_stream.h>
44 #define LOG_DOMAIN "axl-list"
46 typedef struct _axlListNode axlListNode
;
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
;
61 /* memory management functions */
62 axlListNode
** preallocated
;
68 axlListNode
* previous
;
73 struct _axlListCursor
{
75 axlListNode
* current
;
79 * \defgroup axl_list_module Axl List: A configurable double-linked list used across the library.
83 * \addtogroup axl_list_module
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
)
101 * Preallocates nodes to be used to store data on the lists.
103 * @param list The list where the preallocation operation will be
106 void __axl_list_allocate_nodes (axlList
* list
)
111 list
->allocated
+= list
->available
;
113 /* allocate enough memory to hold all nodes already
115 if (list
->preallocated
== NULL
)
116 list
->preallocated
= axl_new (axlListNode
*, list
->allocated
);
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);
131 * Disposes the node provided, reusing on the next operation
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 */
148 * Returns a reference to an list node to be used.
150 axlListNode
* __axl_list_get_next_node_available (axlList
* list
)
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];
164 node
->previous
= NULL
;
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
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
200 * For example, to create a list that will hold strings dinamically
201 * allocated you can use:
203 * axlList * list = axl_list_new (axl_list_equal_string, axl_free);
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
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:
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
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
)
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); */
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
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
)
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
308 result
->destroy_data
= NULL
;
310 /* add all elements */
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 */
320 /* add the data to the new list */
321 axl_list_add (result
, data
);
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
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
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
))
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
364 * axl_list_add (list, INT_TO_PTR (integer));
367 * You can use this function to create an \ref axlList that stores
368 * integer values as follows:
370 * list = axl_list_new (axl_list_equal_int, NULL);
373 * The list created with this function will order data from litter to
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
))
388 else if (PTR_TO_INT (a
) < PTR_TO_INT (b
))
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
)
415 * @brief Allows to store a new element inside the list, using the
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
;
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
;
448 node
= list
->first_node
;
449 node2
= list
->last_node
;
452 while ((node
!= NULL
) || (node2
!= NULL
)) {
453 /* lookup the head */
455 switch (list
->are_equal (node
->data
, pointer
)) {
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
;
466 list
->first_node
= new_node
;
468 /* update list length */
473 /* the node found is equal, do not perform any operation */
477 /* the node should be added after */
483 /* lookup from the tail */
485 switch (list
->are_equal (node2
->data
, pointer
)) {
488 /* the node should be added before node */
489 node2
= node2
->previous
;
493 /* the node found is equal, do not perform any operation */
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
;
505 list
->last_node
= new_node
;
507 /* update length size */
514 /* nothing more to do */
519 * @brief Allows to adds the provided item to the given list at the
522 * The function will perform an indexed addition, using the value
523 * <b>position</b>, by-passing current list configuration (\ref
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
)
544 axlListNode
* new_node
;
546 /* check incoming values */
547 axl_return_if_fail (list
);
549 /* check if we have a prepend operation */
551 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "adding item using prepend");
553 axl_list_prepend (list
, pointer
);
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
);
562 axl_list_append (list
, pointer
);
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
577 node
= list
->first_node
->next
;
578 while (iterator
< position
) {
580 /* get the next element */
583 /* update the 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 */
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
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
;
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 */
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
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
;
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 */
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
686 axlListNode
* axl_list_internal_linear_lookup (axlList
* list
,
691 axl_return_val_if_fail (list
, NULL
);
692 axl_return_val_if_fail (pointer
, NULL
);
695 node
= list
->first_node
;
698 while (node
!= NULL
) {
699 if (list
->are_equal (node
->data
, pointer
) == 0)
702 /* the node should be after this one */
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
721 axlListNode
* axl_list_internal_lookup (axlList
* list
, axlPointer pointer
)
726 axl_return_val_if_fail (list
, NULL
);
727 axl_return_val_if_fail (pointer
, NULL
);
730 node
= list
->first_node
;
731 node2
= list
->last_node
;
734 while ((node
!= NULL
) || (node2
!= NULL
)) {
735 /* lookup the head */
737 switch (list
->are_equal (node
->data
, pointer
)) {
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.
749 /* the node should be after this one */
755 /* lookup from the tail */
757 switch (list
->are_equal (node2
->data
, pointer
)) {
759 /* the node should be added before node */
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.
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
)
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
)) {
805 /* return data found */
806 if (iterator
== position
)
811 /* remove the selected node */
812 void __axl_list_common_remove_selected_node (axlList
* list
, axlListNode
* node
,
817 /* do not remove anything if a null reference is received */
821 /* get a reference to the pointer */
822 pointer
= node
->data
;
824 if (node
->previous
== NULL
)
825 list
->first_node
= node
->next
;
827 node
->previous
->next
= node
->next
;
829 if (node
->next
== NULL
)
830 list
->last_node
= node
->previous
;
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 */
845 /* nothing more to do */
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
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
)
868 axl_return_if_fail (list
);
869 axl_return_if_fail (pointer
);
872 node
= axl_list_internal_linear_lookup (list
, pointer
);
874 __axl_log (LOG_DOMAIN
, AXL_LEVEL_DEBUG
, "unable to find item by pointer (0x%x)",
879 /* remove the selected node */
880 __axl_list_common_remove_selected_node (list
, node
, alsoRemove
);
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
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);
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);
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
)
943 /* remove the selected node */
944 __axl_list_common_remove_selected_node (list
, list
->first_node
, true);
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
)
964 /* remove the selected node */
965 __axl_list_common_remove_selected_node (list
, list
->first_node
, false);
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
)
984 /* remove the selected node */
985 __axl_list_common_remove_selected_node (list
, list
->last_node
, true);
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
)
1004 /* remove the selected node */
1005 __axl_list_common_remove_selected_node (list
, list
->last_node
, false);
1011 * @brief Allows to check if the given pointer is stored on the given
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
)
1033 * @brief Allows to check if the provided list is empty (no element
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
);
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
)
1063 node
= axl_list_internal_get_nth (list
, position
);
1065 if (! list
->are_equal (node
->data
, pointer
))
1072 * @brief Returns the first element stored on the list.
1075 * @param list The list where the first element stored will be
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
)
1086 return list
->first_node
->data
;
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
1097 axlPointer
axl_list_get_last (axlList
* list
)
1099 axl_return_val_if_fail (list
, NULL
);
1101 if (list
->last_node
== NULL
)
1103 return list
->last_node
->data
;
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 -
1114 * @return The \ref axlPointer stored on the given position or NULL if
1117 axlPointer
axl_list_get_nth (axlList
* list
, int position
)
1121 node
= axl_list_internal_get_nth (list
, position
);
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
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
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;
1146 * if (axl_cmp (element->name, name))
1149 * // it is not the element
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
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
)
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
;
1175 /* if the next node to check is NULL, terminate the
1180 /* check if the node found is the one looked up */
1181 if (func (node
->data
, data
))
1184 /* seems not, update to the next reference */
1189 /* return no node found */
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
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 */
1213 /* return the comparison status */
1214 return axl_cmp ((char *) element
, (char *) data
);
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
1225 int axl_list_length (axlList
* list
)
1227 axl_return_val_if_fail (list
, -1);
1228 return list
->length
;
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
)
1240 axlListNode
* node2
;
1243 /* if a null reference is received do not oper */
1247 node
= list
->first_node
;
1248 while (node
!= NULL
) {
1249 if (list
->destroy_data
!= NULL
) {
1250 list
->destroy_data (node
->data
);
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 */
1275 * \defgroup axl_list_cursor_module Axl List Cursor: Iterator support for the Axl List
1279 * \addtogroup axl_list_cursor_module
1284 * @brief Allows to get a cursor to iterate the list in a linear and
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
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:
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)) {
1318 * value = axl_list_cursor_get (cursor);
1322 * axl_list_cursor_next (cursor);
1324 * // update the iterator
1329 * // free the cursor
1330 * axl_list_cursor_free (cursor);
1333 * @param list The list that the new cursor (\ref axlListCursor) will
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
;
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
;
1370 /* set the first node */
1371 cursor
->current
= cursor
->list
->first_node
;
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
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
;
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
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
;
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
;
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
1436 * @return \ref true if more items are found, otherwise \ref false is
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
)
1447 /* return if the next element isn't null */
1448 return (cursor
->current
->next
!= NULL
);
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
1458 * @return \ref true if more items are found, otherwise \ref false is
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
)
1469 /* return if the next element isn't null */
1470 return (cursor
->current
->previous
!= NULL
);
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
);
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
1501 void axl_list_cursor_unlink (axlListCursor
* cursor
)
1505 axl_return_if_fail (cursor
);
1507 /* if current cursor is pointing nowhere, just do nothing */
1508 if (cursor
->current
== NULL
)
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
;
1518 __axl_list_common_remove_selected_node (cursor
->list
, node
, false);
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
1535 void axl_list_cursor_remove (axlListCursor
* cursor
)
1539 axl_return_if_fail (cursor
);
1541 /* if current cursor is pointing nowhere, just do nothing */
1542 if (cursor
->current
== NULL
)
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);
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
)
1572 return cursor
->current
->data
;
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
;
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 */