1 /* adlist.c - A generic doubly linked list implementation
2 *
3 * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * 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.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32 #include <stdlib.h>
33 #include "adlist.h"
34 #include "zmalloc.h"
35
36 /* Create a new list. The created list can be freed with
37 * AlFreeList(), but private value of every node need to be freed
38 * by the user before to call AlFreeList().
39 *
40 * On error, NULL is returned. Otherwise the pointer to the new list. */
listCreate(void)41 list *listCreate(void)
42 {
43 struct list *list;
44
45 if ((list = zmalloc(sizeof(*list))) == NULL)
46 return NULL;
47 list->head = list->tail = NULL;
48 list->len = 0;
49 list->dup = NULL;
50 list->free = NULL;
51 list->match = NULL;
52 return list;
53 }
54
55 /* Remove all the elements from the list without destroying the list itself. */
listEmpty(list * list)56 void listEmpty(list *list)
57 {
58 unsigned long len;
59 listNode *current, *next;
60
61 current = list->head;
62 len = list->len;
63 while(len--) {
64 next = current->next;
65 if (list->free) list->free(current->value);
66 zfree(current);
67 current = next;
68 }
69 list->head = list->tail = NULL;
70 list->len = 0;
71 }
72
73 /* Free the whole list.
74 *
75 * This function can't fail. */
listRelease(list * list)76 void listRelease(list *list)
77 {
78 listEmpty(list);
79 zfree(list);
80 }
81
82 /* Add a new node to the list, to head, containing the specified 'value'
83 * pointer as value.
84 *
85 * On error, NULL is returned and no operation is performed (i.e. the
86 * list remains unaltered).
87 * On success the 'list' pointer you pass to the function is returned. */
listAddNodeHead(list * list,void * value)88 list *listAddNodeHead(list *list, void *value)
89 {
90 listNode *node;
91
92 if ((node = zmalloc(sizeof(*node))) == NULL)
93 return NULL;
94 node->value = value;
95 if (list->len == 0) {
96 list->head = list->tail = node;
97 node->prev = node->next = NULL;
98 } else {
99 node->prev = NULL;
100 node->next = list->head;
101 list->head->prev = node;
102 list->head = node;
103 }
104 list->len++;
105 return list;
106 }
107
108 /* Add a new node to the list, to tail, containing the specified 'value'
109 * pointer as value.
110 *
111 * On error, NULL is returned and no operation is performed (i.e. the
112 * list remains unaltered).
113 * On success the 'list' pointer you pass to the function is returned. */
listAddNodeTail(list * list,void * value)114 list *listAddNodeTail(list *list, void *value)
115 {
116 listNode *node;
117
118 if ((node = zmalloc(sizeof(*node))) == NULL)
119 return NULL;
120 node->value = value;
121 if (list->len == 0) {
122 list->head = list->tail = node;
123 node->prev = node->next = NULL;
124 } else {
125 node->prev = list->tail;
126 node->next = NULL;
127 list->tail->next = node;
128 list->tail = node;
129 }
130 list->len++;
131 return list;
132 }
133
listInsertNode(list * list,listNode * old_node,void * value,int after)134 list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
135 listNode *node;
136
137 if ((node = zmalloc(sizeof(*node))) == NULL)
138 return NULL;
139 node->value = value;
140 if (after) {
141 node->prev = old_node;
142 node->next = old_node->next;
143 if (list->tail == old_node) {
144 list->tail = node;
145 }
146 } else {
147 node->next = old_node;
148 node->prev = old_node->prev;
149 if (list->head == old_node) {
150 list->head = node;
151 }
152 }
153 if (node->prev != NULL) {
154 node->prev->next = node;
155 }
156 if (node->next != NULL) {
157 node->next->prev = node;
158 }
159 list->len++;
160 return list;
161 }
162
163 /* Remove the specified node from the specified list.
164 * It's up to the caller to free the private value of the node.
165 *
166 * This function can't fail. */
listDelNode(list * list,listNode * node)167 void listDelNode(list *list, listNode *node)
168 {
169 if (node->prev)
170 node->prev->next = node->next;
171 else
172 list->head = node->next;
173 if (node->next)
174 node->next->prev = node->prev;
175 else
176 list->tail = node->prev;
177 if (list->free) list->free(node->value);
178 zfree(node);
179 list->len--;
180 }
181
182 /* Returns a list iterator 'iter'. After the initialization every
183 * call to listNext() will return the next element of the list.
184 *
185 * This function can't fail. */
listGetIterator(list * list,int direction)186 listIter *listGetIterator(list *list, int direction)
187 {
188 listIter *iter;
189
190 if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
191 if (direction == AL_START_HEAD)
192 iter->next = list->head;
193 else
194 iter->next = list->tail;
195 iter->direction = direction;
196 return iter;
197 }
198
199 /* Release the iterator memory */
listReleaseIterator(listIter * iter)200 void listReleaseIterator(listIter *iter) {
201 zfree(iter);
202 }
203
204 /* Create an iterator in the list private iterator structure */
listRewind(list * list,listIter * li)205 void listRewind(list *list, listIter *li) {
206 li->next = list->head;
207 li->direction = AL_START_HEAD;
208 }
209
listRewindTail(list * list,listIter * li)210 void listRewindTail(list *list, listIter *li) {
211 li->next = list->tail;
212 li->direction = AL_START_TAIL;
213 }
214
215 /* Return the next element of an iterator.
216 * It's valid to remove the currently returned element using
217 * listDelNode(), but not to remove other elements.
218 *
219 * The function returns a pointer to the next element of the list,
220 * or NULL if there are no more elements, so the classical usage patter
221 * is:
222 *
223 * iter = listGetIterator(list,<direction>);
224 * while ((node = listNext(iter)) != NULL) {
225 * doSomethingWith(listNodeValue(node));
226 * }
227 *
228 * */
listNext(listIter * iter)229 listNode *listNext(listIter *iter)
230 {
231 listNode *current = iter->next;
232
233 if (current != NULL) {
234 if (iter->direction == AL_START_HEAD)
235 iter->next = current->next;
236 else
237 iter->next = current->prev;
238 }
239 return current;
240 }
241
242 /* Duplicate the whole list. On out of memory NULL is returned.
243 * On success a copy of the original list is returned.
244 *
245 * The 'Dup' method set with listSetDupMethod() function is used
246 * to copy the node value. Otherwise the same pointer value of
247 * the original node is used as value of the copied node.
248 *
249 * The original list both on success or error is never modified. */
listDup(list * orig)250 list *listDup(list *orig)
251 {
252 list *copy;
253 listIter iter;
254 listNode *node;
255
256 if ((copy = listCreate()) == NULL)
257 return NULL;
258 copy->dup = orig->dup;
259 copy->free = orig->free;
260 copy->match = orig->match;
261 listRewind(orig, &iter);
262 while((node = listNext(&iter)) != NULL) {
263 void *value;
264
265 if (copy->dup) {
266 value = copy->dup(node->value);
267 if (value == NULL) {
268 listRelease(copy);
269 return NULL;
270 }
271 } else
272 value = node->value;
273 if (listAddNodeTail(copy, value) == NULL) {
274 listRelease(copy);
275 return NULL;
276 }
277 }
278 return copy;
279 }
280
281 /* Search the list for a node matching a given key.
282 * The match is performed using the 'match' method
283 * set with listSetMatchMethod(). If no 'match' method
284 * is set, the 'value' pointer of every node is directly
285 * compared with the 'key' pointer.
286 *
287 * On success the first matching node pointer is returned
288 * (search starts from head). If no matching node exists
289 * NULL is returned. */
listSearchKey(list * list,void * key)290 listNode *listSearchKey(list *list, void *key)
291 {
292 listIter iter;
293 listNode *node;
294
295 listRewind(list, &iter);
296 while((node = listNext(&iter)) != NULL) {
297 if (list->match) {
298 if (list->match(node->value, key)) {
299 return node;
300 }
301 } else {
302 if (key == node->value) {
303 return node;
304 }
305 }
306 }
307 return NULL;
308 }
309
310 /* Return the element at the specified zero-based index
311 * where 0 is the head, 1 is the element next to head
312 * and so on. Negative integers are used in order to count
313 * from the tail, -1 is the last element, -2 the penultimate
314 * and so on. If the index is out of range NULL is returned. */
listIndex(list * list,long index)315 listNode *listIndex(list *list, long index) {
316 listNode *n;
317
318 if (index < 0) {
319 index = (-index)-1;
320 n = list->tail;
321 while(index-- && n) n = n->prev;
322 } else {
323 n = list->head;
324 while(index-- && n) n = n->next;
325 }
326 return n;
327 }
328
329 /* Rotate the list removing the tail node and inserting it to the head. */
listRotate(list * list)330 void listRotate(list *list) {
331 listNode *tail = list->tail;
332
333 if (listLength(list) <= 1) return;
334
335 /* Detach current tail */
336 list->tail = tail->prev;
337 list->tail->next = NULL;
338 /* Move it as head */
339 list->head->prev = tail;
340 tail->prev = NULL;
341 tail->next = list->head;
342 list->head = tail;
343 }
344
345 /* Add all the elements of the list 'o' at the end of the
346 * list 'l'. The list 'other' remains empty but otherwise valid. */
listJoin(list * l,list * o)347 void listJoin(list *l, list *o) {
348 if (o->head)
349 o->head->prev = l->tail;
350
351 if (l->tail)
352 l->tail->next = o->head;
353 else
354 l->head = o->head;
355
356 if (o->tail) l->tail = o->tail;
357 l->len += o->len;
358
359 /* Setup other as an empty list. */
360 o->head = o->tail = NULL;
361 o->len = 0;
362 }
363