]>
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
, listIter
*li
) {
169 li
->next
= list
->head
;
170 li
->direction
= AL_START_HEAD
;
173 void listRewindTail(list
*list
, listIter
*li
) {
174 li
->next
= list
->tail
;
175 li
->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 /* Duplicate the whole list. On out of memory NULL is returned.
206 * On success a copy of the original list is returned.
208 * The 'Dup' method set with listSetDupMethod() function is used
209 * to copy the node value. Otherwise the same pointer value of
210 * the original node is used as value of the copied node.
212 * The original list both on success or error is never modified. */
213 list
*listDup(list
*orig
)
219 if ((copy
= listCreate()) == NULL
)
221 copy
->dup
= orig
->dup
;
222 copy
->free
= orig
->free
;
223 copy
->match
= orig
->match
;
224 iter
= listGetIterator(orig
, AL_START_HEAD
);
225 while((node
= listNext(iter
)) != NULL
) {
229 value
= copy
->dup(node
->value
);
232 listReleaseIterator(iter
);
237 if (listAddNodeTail(copy
, value
) == NULL
) {
239 listReleaseIterator(iter
);
243 listReleaseIterator(iter
);
247 /* Search the list for a node matching a given key.
248 * The match is performed using the 'match' method
249 * set with listSetMatchMethod(). If no 'match' method
250 * is set, the 'value' pointer of every node is directly
251 * compared with the 'key' pointer.
253 * On success the first matching node pointer is returned
254 * (search starts from head). If no matching node exists
255 * NULL is returned. */
256 listNode
*listSearchKey(list
*list
, void *key
)
261 iter
= listGetIterator(list
, AL_START_HEAD
);
262 while((node
= listNext(iter
)) != NULL
) {
264 if (list
->match(node
->value
, key
)) {
265 listReleaseIterator(iter
);
269 if (key
== node
->value
) {
270 listReleaseIterator(iter
);
275 listReleaseIterator(iter
);
279 /* Return the element at the specified zero-based index
280 * where 0 is the head, 1 is the element next to head
281 * and so on. Negative integers are used in order to count
282 * from the tail, -1 is the last element, -2 the penultimante
283 * and so on. If the index is out of range NULL is returned. */
284 listNode
*listIndex(list
*list
, int index
) {
290 while(index
-- && n
) n
= n
->prev
;
293 while(index
-- && n
) n
= n
->next
;