]>
git.saurik.com Git - redis.git/blob - adlist.c
1 /* adlist.c - A generic doubly linked list implementation
3 * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
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.
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.
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().
40 * On error, NULL is returned. Otherwise the pointer to the new list. */
41 list
*listCreate(void)
45 if ((list
= zmalloc(sizeof(*list
))) == NULL
)
47 list
->head
= list
->tail
= NULL
;
55 /* Free the whole list.
57 * This function can't fail. */
58 void listRelease(list
*list
)
61 listNode
*current
, *next
;
67 if (list
->free
) list
->free(current
->value
);
74 /* Add a new node to the list, to head, contaning the specified 'value'
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. */
80 list
*listAddNodeHead(list
*list
, void *value
)
84 if ((node
= zmalloc(sizeof(*node
))) == NULL
)
88 list
->head
= list
->tail
= node
;
89 node
->prev
= node
->next
= NULL
;
92 node
->next
= list
->head
;
93 list
->head
->prev
= node
;
100 /* Add a new node to the list, to tail, contaning the specified 'value'
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. */
106 list
*listAddNodeTail(list
*list
, void *value
)
110 if ((node
= zmalloc(sizeof(*node
))) == NULL
)
113 if (list
->len
== 0) {
114 list
->head
= list
->tail
= node
;
115 node
->prev
= node
->next
= NULL
;
117 node
->prev
= list
->tail
;
119 list
->tail
->next
= node
;
126 /* Remove the specified node from the specified list.
127 * It's up to the caller to free the private value of the node.
129 * This function can't fail. */
130 void listDelNode(list
*list
, listNode
*node
)
133 node
->prev
->next
= node
->next
;
135 list
->head
= node
->next
;
137 node
->next
->prev
= node
->prev
;
139 list
->tail
= node
->prev
;
140 if (list
->free
) list
->free(node
->value
);
145 /* Returns a list iterator 'iter'. After the initialization every
146 * call to listNext() will return the next element of the list.
148 * This function can't fail. */
149 listIter
*listGetIterator(list
*list
, int direction
)
153 if ((iter
= zmalloc(sizeof(*iter
))) == NULL
) return NULL
;
154 if (direction
== AL_START_HEAD
)
155 iter
->next
= list
->head
;
157 iter
->next
= list
->tail
;
158 iter
->direction
= direction
;
162 /* Release the iterator memory */
163 void listReleaseIterator(listIter
*iter
) {
167 /* Create an iterator in the list private iterator structure */
168 void listRewind(list
*list
) {
169 list
->iter
.next
= list
->head
;
170 list
->iter
.direction
= AL_START_HEAD
;
173 void listRewindTail(list
*list
) {
174 list
->iter
.next
= list
->tail
;
175 list
->iter
.direction
= AL_START_TAIL
;
178 /* Return the next element of an iterator.
179 * It's valid to remove the currently returned element using
180 * listDelNode(), but not to remove other elements.
182 * The function returns a pointer to the next element of the list,
183 * or NULL if there are no more elements, so the classical usage patter
186 * iter = listGetItarotr(list,<direction>);
187 * while ((node = listNextIterator(iter)) != NULL) {
188 * DoSomethingWith(listNodeValue(node));
192 listNode
*listNext(listIter
*iter
)
194 listNode
*current
= iter
->next
;
196 if (current
!= NULL
) {
197 if (iter
->direction
== AL_START_HEAD
)
198 iter
->next
= current
->next
;
200 iter
->next
= current
->prev
;
205 /* List Yield just call listNext() against the list private iterator */
206 listNode
*listYield(list
*list
) {
207 return listNext(&list
->iter
);
210 /* Duplicate the whole list. On out of memory NULL is returned.
211 * On success a copy of the original list is returned.
213 * The 'Dup' method set with listSetDupMethod() function is used
214 * to copy the node value. Otherwise the same pointer value of
215 * the original node is used as value of the copied node.
217 * The original list both on success or error is never modified. */
218 list
*listDup(list
*orig
)
224 if ((copy
= listCreate()) == NULL
)
226 copy
->dup
= orig
->dup
;
227 copy
->free
= orig
->free
;
228 copy
->match
= orig
->match
;
229 iter
= listGetIterator(orig
, AL_START_HEAD
);
230 while((node
= listNext(iter
)) != NULL
) {
234 value
= copy
->dup(node
->value
);
237 listReleaseIterator(iter
);
242 if (listAddNodeTail(copy
, value
) == NULL
) {
244 listReleaseIterator(iter
);
248 listReleaseIterator(iter
);
252 /* Search the list for a node matching a given key.
253 * The match is performed using the 'match' method
254 * set with listSetMatchMethod(). If no 'match' method
255 * is set, the 'value' pointer of every node is directly
256 * compared with the 'key' pointer.
258 * On success the first matching node pointer is returned
259 * (search starts from head). If no matching node exists
260 * NULL is returned. */
261 listNode
*listSearchKey(list
*list
, void *key
)
266 iter
= listGetIterator(list
, AL_START_HEAD
);
267 while((node
= listNext(iter
)) != NULL
) {
269 if (list
->match(node
->value
, key
)) {
270 listReleaseIterator(iter
);
274 if (key
== node
->value
) {
275 listReleaseIterator(iter
);
280 listReleaseIterator(iter
);
284 /* Return the element at the specified zero-based index
285 * where 0 is the head, 1 is the element next to head
286 * and so on. Negative integers are used in order to count
287 * from the tail, -1 is the last element, -2 the penultimante
288 * and so on. If the index is out of range NULL is returned. */
289 listNode
*listIndex(list
*list
, int index
) {
295 while(index
-- && n
) n
= n
->prev
;
298 while(index
-- && n
) n
= n
->next
;