]>
git.saurik.com Git - redis.git/blob - src/adlist.c
1 /* adlist.c - A generic doubly linked list implementation
3 * Copyright (c) 2006-2010, 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 list
*listInsertNode(list
*list
, listNode
*old_node
, void *value
, int after
) {
129 if ((node
= zmalloc(sizeof(*node
))) == NULL
)
133 node
->prev
= old_node
;
134 node
->next
= old_node
->next
;
135 if (list
->tail
== old_node
) {
139 node
->next
= old_node
;
140 node
->prev
= old_node
->prev
;
141 if (list
->head
== old_node
) {
145 if (node
->prev
!= NULL
) {
146 node
->prev
->next
= node
;
148 if (node
->next
!= NULL
) {
149 node
->next
->prev
= node
;
155 /* Remove the specified node from the specified list.
156 * It's up to the caller to free the private value of the node.
158 * This function can't fail. */
159 void listDelNode(list
*list
, listNode
*node
)
162 node
->prev
->next
= node
->next
;
164 list
->head
= node
->next
;
166 node
->next
->prev
= node
->prev
;
168 list
->tail
= node
->prev
;
169 if (list
->free
) list
->free(node
->value
);
174 /* Returns a list iterator 'iter'. After the initialization every
175 * call to listNext() will return the next element of the list.
177 * This function can't fail. */
178 listIter
*listGetIterator(list
*list
, int direction
)
182 if ((iter
= zmalloc(sizeof(*iter
))) == NULL
) return NULL
;
183 if (direction
== AL_START_HEAD
)
184 iter
->next
= list
->head
;
186 iter
->next
= list
->tail
;
187 iter
->direction
= direction
;
191 /* Release the iterator memory */
192 void listReleaseIterator(listIter
*iter
) {
196 /* Create an iterator in the list private iterator structure */
197 void listRewind(list
*list
, listIter
*li
) {
198 li
->next
= list
->head
;
199 li
->direction
= AL_START_HEAD
;
202 void listRewindTail(list
*list
, listIter
*li
) {
203 li
->next
= list
->tail
;
204 li
->direction
= AL_START_TAIL
;
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.
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
215 * iter = listGetIterator(list,<direction>);
216 * while ((node = listNext(iter)) != NULL) {
217 * doSomethingWith(listNodeValue(node));
221 listNode
*listNext(listIter
*iter
)
223 listNode
*current
= iter
->next
;
225 if (current
!= NULL
) {
226 if (iter
->direction
== AL_START_HEAD
)
227 iter
->next
= current
->next
;
229 iter
->next
= current
->prev
;
234 /* Duplicate the whole list. On out of memory NULL is returned.
235 * On success a copy of the original list is returned.
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.
241 * The original list both on success or error is never modified. */
242 list
*listDup(list
*orig
)
248 if ((copy
= listCreate()) == NULL
)
250 copy
->dup
= orig
->dup
;
251 copy
->free
= orig
->free
;
252 copy
->match
= orig
->match
;
253 iter
= listGetIterator(orig
, AL_START_HEAD
);
254 while((node
= listNext(iter
)) != NULL
) {
258 value
= copy
->dup(node
->value
);
261 listReleaseIterator(iter
);
266 if (listAddNodeTail(copy
, value
) == NULL
) {
268 listReleaseIterator(iter
);
272 listReleaseIterator(iter
);
276 /* Search the list for a node matching a given key.
277 * The match is performed using the 'match' method
278 * set with listSetMatchMethod(). If no 'match' method
279 * is set, the 'value' pointer of every node is directly
280 * compared with the 'key' pointer.
282 * On success the first matching node pointer is returned
283 * (search starts from head). If no matching node exists
284 * NULL is returned. */
285 listNode
*listSearchKey(list
*list
, void *key
)
290 iter
= listGetIterator(list
, AL_START_HEAD
);
291 while((node
= listNext(iter
)) != NULL
) {
293 if (list
->match(node
->value
, key
)) {
294 listReleaseIterator(iter
);
298 if (key
== node
->value
) {
299 listReleaseIterator(iter
);
304 listReleaseIterator(iter
);
308 /* Return the element at the specified zero-based index
309 * where 0 is the head, 1 is the element next to head
310 * and so on. Negative integers are used in order to count
311 * from the tail, -1 is the last element, -2 the penultimante
312 * and so on. If the index is out of range NULL is returned. */
313 listNode
*listIndex(list
*list
, long index
) {
319 while(index
-- && n
) n
= n
->prev
;
322 while(index
-- && n
) n
= n
->next
;
327 /* Rotate the list removing the tail node and inserting it to the head. */
328 void listRotate(list
*list
) {
329 listNode
*tail
= list
->tail
;
331 if (listLength(list
) <= 1) return;
333 /* Detatch current tail */
334 list
->tail
= tail
->prev
;
335 list
->tail
->next
= NULL
;
336 /* Move it as head */
337 list
->head
->prev
= tail
;
339 tail
->next
= list
->head
;