2 * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
29 * Double linked list for collisions into hashtables.
31 * This list is a double linked list mainly targetted for handling collisions
32 * into an hashtables, but useable also as a generic list.
34 * The main feature of this list is to require only one pointer to represent the
35 * list, compared to a classic implementation requiring a head an a tail pointers.
36 * This reduces the memory usage in hashtables.
38 * Another feature is to support the insertion at the end of the list. This allow to store
39 * collisions in a stable order. Where for stable order we mean that equal elements keep
40 * their insertion order.
42 * To initialize the list, you have to call tommy_list_init(), or to simply assign
43 * to it NULL, as an empty list is represented by the NULL value.
48 * tommy_list_init(&list); // initializes the list
51 * To insert elements in the list you have to call tommy_list_insert_tail()
52 * or tommy_list_insert_head() for each element.
53 * In the insertion call you have to specify the address of the node and the
54 * address of the object.
55 * The address of the object is used to initialize the tommy_node::data field
65 * struct object* obj = malloc(sizeof(struct object)); // creates the object
67 * obj->value = ...; // initializes the object
69 * tommy_list_insert_tail(&list, &obj->node, obj); // inserts the object
72 * To iterate over all the elements in the list you have to call
73 * tommy_list_head() to get the head of the list and follow the
74 * tommy_node::next pointer until NULL.
77 * tommy_node* i = tommy_list_head(&list);
79 * struct object* obj = i->data; // gets the object pointer
81 * printf("%d\n", obj->value); // process the object
83 * i = i->next; // go to the next element
87 * To destroy the list you have to remove all the elements,
88 * as the list is completely inplace and it doesn't allocate memory.
89 * This can be done with the tommy_list_foreach() function.
92 * // deallocates all the objects iterating the list
93 * tommy_list_foreach(&list, free);
100 #include "tommytypes.h"
102 /******************************************************************************/
106 * Double linked list type.
108 typedef tommy_node
* tommy_list
;
111 * Initializes the list.
112 * The list is completely inplace, so it doesn't need to be deinitialized.
114 tommy_inline
void tommy_list_init(tommy_list
* list
)
120 * Gets the head of the list.
121 * \return The head node. For empty lists 0 is returned.
123 tommy_inline tommy_node
* tommy_list_head(tommy_list
* list
)
129 * Gets the tail of the list.
130 * \return The tail node. For empty lists 0 is returned.
132 tommy_inline tommy_node
* tommy_list_tail(tommy_list
* list
)
134 tommy_node
* head
= tommy_list_head(list
);
143 * Creates a new list with a single element.
144 * \param list The list to initialize.
145 * \param node The node to insert.
147 tommy_inline
void tommy_list_insert_first(tommy_list
* list
, tommy_node
* node
)
149 /* one element "circular" prev list */
152 /* one element "0 terminated" next list */
159 * Inserts an element at the head of a not empty list.
160 * The element is inserted at the head of the list. The list cannot be empty.
161 * \param list The list. The list cannot be empty.
162 * \param node The node to insert.
164 tommy_inline
void tommy_list_insert_head_not_empty(tommy_list
* list
, tommy_node
* node
)
166 tommy_node
* head
= tommy_list_head(list
);
168 /* insert in the "circular" prev list */
169 node
->prev
= head
->prev
;
172 /* insert in the "0 terminated" next list */
179 * Inserts an element at the tail of a not empty list.
180 * The element is inserted at the tail of the list. The list cannot be empty.
181 * \param head The node at the list head. It cannot be 0.
182 * \param node The node to insert.
184 tommy_inline
void tommy_list_insert_tail_not_empty(tommy_node
* head
, tommy_node
* node
)
186 /* insert in the "circular" prev list */
187 node
->prev
= head
->prev
;
190 /* insert in the "0 terminated" next list */
192 node
->prev
->next
= node
;
196 * Inserts an element at the head of a list.
197 * \param node The node to insert.
198 * \param data The object containing the node. It's used to set the tommy_node::data field of the node.
200 tommy_inline
void tommy_list_insert_head_check(tommy_list
* list
, tommy_node
* node
)
202 tommy_node
* head
= tommy_list_head(list
);
205 tommy_list_insert_head_not_empty(list
, node
);
207 tommy_list_insert_first(list
, node
);
211 * Inserts an element at the tail of a list.
212 * \param node The node to insert.
213 * \param data The object containing the node. It's used to set the tommy_node::data field of the node.
215 tommy_inline
void tommy_list_insert_tail_check(tommy_list
* list
, tommy_node
* node
)
217 tommy_node
* head
= tommy_list_head(list
);
220 tommy_list_insert_tail_not_empty(head
, node
);
222 tommy_list_insert_first(list
, node
);
226 * Inserts an element at the head of a list and sets the data.
227 * \param node The node to insert.
228 * \param data The object containing the node. It's used to set the tommy_node::data field of the node.
230 tommy_inline
void tommy_list_insert_head(tommy_list
* list
, tommy_node
* node
, void* data
)
232 tommy_list_insert_head_check(list
, node
);
238 * Inserts an element at the tail of a list and sets the data.
239 * \param node The node to insert.
240 * \param data The object containing the node. It's used to set the tommy_node::data field of the node.
242 tommy_inline
void tommy_list_insert_tail(tommy_list
* list
, tommy_node
* node
, void* data
)
244 tommy_list_insert_tail_check(list
, node
);
250 * Removes an element from the list.
251 * You must already have the address of the element to remove.
252 * \note The node content is left unchanged, including the tommy_node::next
253 * and tommy_node::prev fields that still contain pointers at the list.
254 * \param node The node to remove. The node must be in the list.
255 * \return The tommy_node::data field of the node removed.
257 tommy_inline
void tommy_list_remove_existing(tommy_list
* list
, tommy_node
* node
)
259 tommy_node
* head
= tommy_list_head(list
);
261 /* remove from the "circular" prev list */
263 node
->next
->prev
= node
->prev
;
265 head
->prev
= node
->prev
; /* the last */
267 /* remove from the "0 terminated" next list */
269 *list
= node
->next
; /* the new head, in case 0 */
271 node
->prev
->next
= node
->next
;
276 * The second list is concatenated at the first list.
277 * \param first The first list.
278 * \param second The second list. After this call the list content is undefined,
279 * and you should not use it anymore.
281 tommy_inline
void tommy_list_concat(tommy_list
* first
, tommy_list
* second
)
283 tommy_node
* first_head
;
284 tommy_node
* first_tail
;
285 tommy_node
* second_head
;
287 /* if the second is empty, nothing to do */
288 second_head
= tommy_list_head(second
);
289 if (second_head
== 0)
292 /* if the first is empty, copy the second */
293 first_head
= tommy_list_head(first
);
294 if (first_head
== 0) {
299 /* tail of the first list */
300 first_tail
= first_head
->prev
;
302 /* set the "circular" prev list */
303 first_head
->prev
= second_head
->prev
;
304 second_head
->prev
= first_tail
;
306 /* set the "0 terminated" next list */
307 first_tail
->next
= second_head
;
312 * It's a stable merge sort with O(N*log(N)) worst complexity.
313 * It's faster on degenerated cases like partially ordered lists.
314 * \param cmp Compare function called with two elements.
315 * The function should return <0 if the first element is less than the second, ==0 if equal, and >0 if greather.
317 void tommy_list_sort(tommy_list
* list
, tommy_compare_func
* cmp
);
321 * \return If the list is empty.
323 tommy_inline tommy_bool_t
tommy_list_empty(tommy_list
* list
)
325 return tommy_list_head(list
) == 0;
329 * Gets the number of elements.
330 * \note This operation is O(n).
332 tommy_inline tommy_size_t
tommy_list_count(tommy_list
* list
)
334 tommy_size_t count
= 0;
335 tommy_node
* i
= tommy_list_head(list
);
346 * Calls the specified function for each element in the list.
348 * You cannot add or remove elements from the inside of the callback,
349 * but can use it to deallocate them.
354 * // initializes the list
355 * tommy_list_init(&list);
359 * // creates an object
360 * struct object* obj = malloc(sizeof(struct object));
364 * // insert it in the list
365 * tommy_list_insert_tail(&list, &obj->node, obj);
369 * // deallocates all the objects iterating the list
370 * tommy_list_foreach(&list, free);
373 tommy_inline
void tommy_list_foreach(tommy_list
* list
, tommy_foreach_func
* func
)
375 tommy_node
* node
= tommy_list_head(list
);
378 void* data
= node
->data
;
385 * Calls the specified function with an argument for each element in the list.
387 tommy_inline
void tommy_list_foreach_arg(tommy_list
* list
, tommy_foreach_arg_func
* func
, void* arg
)
389 tommy_node
* node
= tommy_list_head(list
);
392 void* data
= node
->data
;