xref: /redis-3.2.3/src/adlist.c (revision cfc08b65)
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 /* Free the whole list.
56  *
57  * This function can't fail. */
listRelease(list * list)58 void listRelease(list *list)
59 {
60     unsigned long len;
61     listNode *current, *next;
62 
63     current = list->head;
64     len = list->len;
65     while(len--) {
66         next = current->next;
67         if (list->free) list->free(current->value);
68         zfree(current);
69         current = next;
70     }
71     zfree(list);
72 }
73 
74 /* Add a new node to the list, to head, containing the specified 'value'
75  * pointer as value.
76  *
77  * On error, NULL is returned and no operation is performed (i.e. the
78  * list remains unaltered).
79  * On success the 'list' pointer you pass to the function is returned. */
listAddNodeHead(list * list,void * value)80 list *listAddNodeHead(list *list, void *value)
81 {
82     listNode *node;
83 
84     if ((node = zmalloc(sizeof(*node))) == NULL)
85         return NULL;
86     node->value = value;
87     if (list->len == 0) {
88         list->head = list->tail = node;
89         node->prev = node->next = NULL;
90     } else {
91         node->prev = NULL;
92         node->next = list->head;
93         list->head->prev = node;
94         list->head = node;
95     }
96     list->len++;
97     return list;
98 }
99 
100 /* Add a new node to the list, to tail, containing the specified 'value'
101  * pointer as value.
102  *
103  * On error, NULL is returned and no operation is performed (i.e. the
104  * list remains unaltered).
105  * On success the 'list' pointer you pass to the function is returned. */
listAddNodeTail(list * list,void * value)106 list *listAddNodeTail(list *list, void *value)
107 {
108     listNode *node;
109 
110     if ((node = zmalloc(sizeof(*node))) == NULL)
111         return NULL;
112     node->value = value;
113     if (list->len == 0) {
114         list->head = list->tail = node;
115         node->prev = node->next = NULL;
116     } else {
117         node->prev = list->tail;
118         node->next = NULL;
119         list->tail->next = node;
120         list->tail = node;
121     }
122     list->len++;
123     return list;
124 }
125 
listInsertNode(list * list,listNode * old_node,void * value,int after)126 list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
127     listNode *node;
128 
129     if ((node = zmalloc(sizeof(*node))) == NULL)
130         return NULL;
131     node->value = value;
132     if (after) {
133         node->prev = old_node;
134         node->next = old_node->next;
135         if (list->tail == old_node) {
136             list->tail = node;
137         }
138     } else {
139         node->next = old_node;
140         node->prev = old_node->prev;
141         if (list->head == old_node) {
142             list->head = node;
143         }
144     }
145     if (node->prev != NULL) {
146         node->prev->next = node;
147     }
148     if (node->next != NULL) {
149         node->next->prev = node;
150     }
151     list->len++;
152     return list;
153 }
154 
155 /* Remove the specified node from the specified list.
156  * It's up to the caller to free the private value of the node.
157  *
158  * This function can't fail. */
listDelNode(list * list,listNode * node)159 void listDelNode(list *list, listNode *node)
160 {
161     if (node->prev)
162         node->prev->next = node->next;
163     else
164         list->head = node->next;
165     if (node->next)
166         node->next->prev = node->prev;
167     else
168         list->tail = node->prev;
169     if (list->free) list->free(node->value);
170     zfree(node);
171     list->len--;
172 }
173 
174 /* Returns a list iterator 'iter'. After the initialization every
175  * call to listNext() will return the next element of the list.
176  *
177  * This function can't fail. */
listGetIterator(list * list,int direction)178 listIter *listGetIterator(list *list, int direction)
179 {
180     listIter *iter;
181 
182     if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
183     if (direction == AL_START_HEAD)
184         iter->next = list->head;
185     else
186         iter->next = list->tail;
187     iter->direction = direction;
188     return iter;
189 }
190 
191 /* Release the iterator memory */
listReleaseIterator(listIter * iter)192 void listReleaseIterator(listIter *iter) {
193     zfree(iter);
194 }
195 
196 /* Create an iterator in the list private iterator structure */
listRewind(list * list,listIter * li)197 void listRewind(list *list, listIter *li) {
198     li->next = list->head;
199     li->direction = AL_START_HEAD;
200 }
201 
listRewindTail(list * list,listIter * li)202 void listRewindTail(list *list, listIter *li) {
203     li->next = list->tail;
204     li->direction = AL_START_TAIL;
205 }
206 
207 /* Return the next element of an iterator.
208  * It's valid to remove the currently returned element using
209  * listDelNode(), but not to remove other elements.
210  *
211  * The function returns a pointer to the next element of the list,
212  * or NULL if there are no more elements, so the classical usage patter
213  * is:
214  *
215  * iter = listGetIterator(list,<direction>);
216  * while ((node = listNext(iter)) != NULL) {
217  *     doSomethingWith(listNodeValue(node));
218  * }
219  *
220  * */
listNext(listIter * iter)221 listNode *listNext(listIter *iter)
222 {
223     listNode *current = iter->next;
224 
225     if (current != NULL) {
226         if (iter->direction == AL_START_HEAD)
227             iter->next = current->next;
228         else
229             iter->next = current->prev;
230     }
231     return current;
232 }
233 
234 /* Duplicate the whole list. On out of memory NULL is returned.
235  * On success a copy of the original list is returned.
236  *
237  * The 'Dup' method set with listSetDupMethod() function is used
238  * to copy the node value. Otherwise the same pointer value of
239  * the original node is used as value of the copied node.
240  *
241  * The original list both on success or error is never modified. */
listDup(list * orig)242 list *listDup(list *orig)
243 {
244     list *copy;
245     listIter iter;
246     listNode *node;
247 
248     if ((copy = listCreate()) == NULL)
249         return NULL;
250     copy->dup = orig->dup;
251     copy->free = orig->free;
252     copy->match = orig->match;
253     listRewind(orig, &iter);
254     while((node = listNext(&iter)) != NULL) {
255         void *value;
256 
257         if (copy->dup) {
258             value = copy->dup(node->value);
259             if (value == NULL) {
260                 listRelease(copy);
261                 return NULL;
262             }
263         } else
264             value = node->value;
265         if (listAddNodeTail(copy, value) == NULL) {
266             listRelease(copy);
267             return NULL;
268         }
269     }
270     return copy;
271 }
272 
273 /* Search the list for a node matching a given key.
274  * The match is performed using the 'match' method
275  * set with listSetMatchMethod(). If no 'match' method
276  * is set, the 'value' pointer of every node is directly
277  * compared with the 'key' pointer.
278  *
279  * On success the first matching node pointer is returned
280  * (search starts from head). If no matching node exists
281  * NULL is returned. */
listSearchKey(list * list,void * key)282 listNode *listSearchKey(list *list, void *key)
283 {
284     listIter iter;
285     listNode *node;
286 
287     listRewind(list, &iter);
288     while((node = listNext(&iter)) != NULL) {
289         if (list->match) {
290             if (list->match(node->value, key)) {
291                 return node;
292             }
293         } else {
294             if (key == node->value) {
295                 return node;
296             }
297         }
298     }
299     return NULL;
300 }
301 
302 /* Return the element at the specified zero-based index
303  * where 0 is the head, 1 is the element next to head
304  * and so on. Negative integers are used in order to count
305  * from the tail, -1 is the last element, -2 the penultimate
306  * and so on. If the index is out of range NULL is returned. */
listIndex(list * list,long index)307 listNode *listIndex(list *list, long index) {
308     listNode *n;
309 
310     if (index < 0) {
311         index = (-index)-1;
312         n = list->tail;
313         while(index-- && n) n = n->prev;
314     } else {
315         n = list->head;
316         while(index-- && n) n = n->next;
317     }
318     return n;
319 }
320 
321 /* Rotate the list removing the tail node and inserting it to the head. */
listRotate(list * list)322 void listRotate(list *list) {
323     listNode *tail = list->tail;
324 
325     if (listLength(list) <= 1) return;
326 
327     /* Detach current tail */
328     list->tail = tail->prev;
329     list->tail->next = NULL;
330     /* Move it as head */
331     list->head->prev = tail;
332     tail->prev = NULL;
333     tail->next = list->head;
334     list->head = tail;
335 }
336