]>
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 listNextElement() 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 /* Return the next element of an iterator.
168 * It's valid to remove the currently returned element using
169 * listDelNode(), but not to remove other elements.
171 * The function returns a pointer to the next element of the list,
172 * or NULL if there are no more elements, so the classical usage patter
175 * iter = listGetItarotr(list,<direction>);
176 * while ((node = listNextIterator(iter)) != NULL) {
177 * DoSomethingWith(listNodeValue(node));
181 listNode
*listNextElement(listIter
*iter
)
183 listNode
*current
= iter
->next
;
185 if (current
!= NULL
) {
186 if (iter
->direction
== AL_START_HEAD
)
187 iter
->next
= current
->next
;
189 iter
->next
= current
->prev
;
194 /* Duplicate the whole list. On out of memory NULL is returned.
195 * On success a copy of the original list is returned.
197 * The 'Dup' method set with listSetDupMethod() function is used
198 * to copy the node value. Otherwise the same pointer value of
199 * the original node is used as value of the copied node.
201 * The original list both on success or error is never modified. */
202 list
*listDup(list
*orig
)
208 if ((copy
= listCreate()) == NULL
)
210 copy
->dup
= orig
->dup
;
211 copy
->free
= orig
->free
;
212 copy
->match
= orig
->match
;
213 iter
= listGetIterator(orig
, AL_START_HEAD
);
214 while((node
= listNextElement(iter
)) != NULL
) {
218 value
= copy
->dup(node
->value
);
221 listReleaseIterator(iter
);
226 if (listAddNodeTail(copy
, value
) == NULL
) {
228 listReleaseIterator(iter
);
232 listReleaseIterator(iter
);
236 /* Search the list for a node matching a given key.
237 * The match is performed using the 'match' method
238 * set with listSetMatchMethod(). If no 'match' method
239 * is set, the 'value' pointer of every node is directly
240 * compared with the 'key' pointer.
242 * On success the first matching node pointer is returned
243 * (search starts from head). If no matching node exists
244 * NULL is returned. */
245 listNode
*listSearchKey(list
*list
, void *key
)
250 iter
= listGetIterator(list
, AL_START_HEAD
);
251 while((node
= listNextElement(iter
)) != NULL
) {
253 if (list
->match(node
->value
, key
)) {
254 listReleaseIterator(iter
);
258 if (key
== node
->value
) {
259 listReleaseIterator(iter
);
264 listReleaseIterator(iter
);
268 /* Return the element at the specified zero-based index
269 * where 0 is the head, 1 is the element next to head
270 * and so on. Negative integers are used in order to count
271 * from the tail, -1 is the last element, -2 the penultimante
272 * and so on. If the index is out of range NULL is returned. */
273 listNode
*listIndex(list
*list
, int index
) {
279 while(index
-- && n
) n
= n
->prev
;
282 while(index
-- && n
) n
= n
->next
;