xref: /f-stack/app/redis-5.0.5/src/adlist.c (revision 572c4311)
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