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. */ 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. */ 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. */ 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. */ 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 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. */ 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. */ 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 */ 192 void listReleaseIterator(listIter *iter) { 193 zfree(iter); 194 } 195 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; 200 } 201 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 * */ 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. */ 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. */ 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. */ 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. */ 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