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 /* Remove all the elements from the list without destroying the list itself. */ 56 void listEmpty(list *list) 57 { 58 unsigned long len; 59 listNode *current, *next; 60 61 current = list->head; 62 len = list->len; 63 while(len--) { 64 next = current->next; 65 if (list->free) list->free(current->value); 66 zfree(current); 67 current = next; 68 } 69 list->head = list->tail = NULL; 70 list->len = 0; 71 } 72 73 /* Free the whole list. 74 * 75 * This function can't fail. */ 76 void listRelease(list *list) 77 { 78 listEmpty(list); 79 zfree(list); 80 } 81 82 /* Add a new node to the list, to head, containing the specified 'value' 83 * pointer as value. 84 * 85 * On error, NULL is returned and no operation is performed (i.e. the 86 * list remains unaltered). 87 * On success the 'list' pointer you pass to the function is returned. */ 88 list *listAddNodeHead(list *list, void *value) 89 { 90 listNode *node; 91 92 if ((node = zmalloc(sizeof(*node))) == NULL) 93 return NULL; 94 node->value = value; 95 if (list->len == 0) { 96 list->head = list->tail = node; 97 node->prev = node->next = NULL; 98 } else { 99 node->prev = NULL; 100 node->next = list->head; 101 list->head->prev = node; 102 list->head = node; 103 } 104 list->len++; 105 return list; 106 } 107 108 /* Add a new node to the list, to tail, containing the specified 'value' 109 * pointer as value. 110 * 111 * On error, NULL is returned and no operation is performed (i.e. the 112 * list remains unaltered). 113 * On success the 'list' pointer you pass to the function is returned. */ 114 list *listAddNodeTail(list *list, void *value) 115 { 116 listNode *node; 117 118 if ((node = zmalloc(sizeof(*node))) == NULL) 119 return NULL; 120 node->value = value; 121 if (list->len == 0) { 122 list->head = list->tail = node; 123 node->prev = node->next = NULL; 124 } else { 125 node->prev = list->tail; 126 node->next = NULL; 127 list->tail->next = node; 128 list->tail = node; 129 } 130 list->len++; 131 return list; 132 } 133 134 list *listInsertNode(list *list, listNode *old_node, void *value, int after) { 135 listNode *node; 136 137 if ((node = zmalloc(sizeof(*node))) == NULL) 138 return NULL; 139 node->value = value; 140 if (after) { 141 node->prev = old_node; 142 node->next = old_node->next; 143 if (list->tail == old_node) { 144 list->tail = node; 145 } 146 } else { 147 node->next = old_node; 148 node->prev = old_node->prev; 149 if (list->head == old_node) { 150 list->head = node; 151 } 152 } 153 if (node->prev != NULL) { 154 node->prev->next = node; 155 } 156 if (node->next != NULL) { 157 node->next->prev = node; 158 } 159 list->len++; 160 return list; 161 } 162 163 /* Remove the specified node from the specified list. 164 * It's up to the caller to free the private value of the node. 165 * 166 * This function can't fail. */ 167 void listDelNode(list *list, listNode *node) 168 { 169 if (node->prev) 170 node->prev->next = node->next; 171 else 172 list->head = node->next; 173 if (node->next) 174 node->next->prev = node->prev; 175 else 176 list->tail = node->prev; 177 if (list->free) list->free(node->value); 178 zfree(node); 179 list->len--; 180 } 181 182 /* Returns a list iterator 'iter'. After the initialization every 183 * call to listNext() will return the next element of the list. 184 * 185 * This function can't fail. */ 186 listIter *listGetIterator(list *list, int direction) 187 { 188 listIter *iter; 189 190 if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL; 191 if (direction == AL_START_HEAD) 192 iter->next = list->head; 193 else 194 iter->next = list->tail; 195 iter->direction = direction; 196 return iter; 197 } 198 199 /* Release the iterator memory */ 200 void listReleaseIterator(listIter *iter) { 201 zfree(iter); 202 } 203 204 /* Create an iterator in the list private iterator structure */ 205 void listRewind(list *list, listIter *li) { 206 li->next = list->head; 207 li->direction = AL_START_HEAD; 208 } 209 210 void listRewindTail(list *list, listIter *li) { 211 li->next = list->tail; 212 li->direction = AL_START_TAIL; 213 } 214 215 /* Return the next element of an iterator. 216 * It's valid to remove the currently returned element using 217 * listDelNode(), but not to remove other elements. 218 * 219 * The function returns a pointer to the next element of the list, 220 * or NULL if there are no more elements, so the classical usage patter 221 * is: 222 * 223 * iter = listGetIterator(list,<direction>); 224 * while ((node = listNext(iter)) != NULL) { 225 * doSomethingWith(listNodeValue(node)); 226 * } 227 * 228 * */ 229 listNode *listNext(listIter *iter) 230 { 231 listNode *current = iter->next; 232 233 if (current != NULL) { 234 if (iter->direction == AL_START_HEAD) 235 iter->next = current->next; 236 else 237 iter->next = current->prev; 238 } 239 return current; 240 } 241 242 /* Duplicate the whole list. On out of memory NULL is returned. 243 * On success a copy of the original list is returned. 244 * 245 * The 'Dup' method set with listSetDupMethod() function is used 246 * to copy the node value. Otherwise the same pointer value of 247 * the original node is used as value of the copied node. 248 * 249 * The original list both on success or error is never modified. */ 250 list *listDup(list *orig) 251 { 252 list *copy; 253 listIter iter; 254 listNode *node; 255 256 if ((copy = listCreate()) == NULL) 257 return NULL; 258 copy->dup = orig->dup; 259 copy->free = orig->free; 260 copy->match = orig->match; 261 listRewind(orig, &iter); 262 while((node = listNext(&iter)) != NULL) { 263 void *value; 264 265 if (copy->dup) { 266 value = copy->dup(node->value); 267 if (value == NULL) { 268 listRelease(copy); 269 return NULL; 270 } 271 } else 272 value = node->value; 273 if (listAddNodeTail(copy, value) == NULL) { 274 listRelease(copy); 275 return NULL; 276 } 277 } 278 return copy; 279 } 280 281 /* Search the list for a node matching a given key. 282 * The match is performed using the 'match' method 283 * set with listSetMatchMethod(). If no 'match' method 284 * is set, the 'value' pointer of every node is directly 285 * compared with the 'key' pointer. 286 * 287 * On success the first matching node pointer is returned 288 * (search starts from head). If no matching node exists 289 * NULL is returned. */ 290 listNode *listSearchKey(list *list, void *key) 291 { 292 listIter iter; 293 listNode *node; 294 295 listRewind(list, &iter); 296 while((node = listNext(&iter)) != NULL) { 297 if (list->match) { 298 if (list->match(node->value, key)) { 299 return node; 300 } 301 } else { 302 if (key == node->value) { 303 return node; 304 } 305 } 306 } 307 return NULL; 308 } 309 310 /* Return the element at the specified zero-based index 311 * where 0 is the head, 1 is the element next to head 312 * and so on. Negative integers are used in order to count 313 * from the tail, -1 is the last element, -2 the penultimate 314 * and so on. If the index is out of range NULL is returned. */ 315 listNode *listIndex(list *list, long index) { 316 listNode *n; 317 318 if (index < 0) { 319 index = (-index)-1; 320 n = list->tail; 321 while(index-- && n) n = n->prev; 322 } else { 323 n = list->head; 324 while(index-- && n) n = n->next; 325 } 326 return n; 327 } 328 329 /* Rotate the list removing the tail node and inserting it to the head. */ 330 void listRotate(list *list) { 331 listNode *tail = list->tail; 332 333 if (listLength(list) <= 1) return; 334 335 /* Detach current tail */ 336 list->tail = tail->prev; 337 list->tail->next = NULL; 338 /* Move it as head */ 339 list->head->prev = tail; 340 tail->prev = NULL; 341 tail->next = list->head; 342 list->head = tail; 343 } 344 345 /* Add all the elements of the list 'o' at the end of the 346 * list 'l'. The list 'other' remains empty but otherwise valid. */ 347 void listJoin(list *l, list *o) { 348 if (o->head) 349 o->head->prev = l->tail; 350 351 if (l->tail) 352 l->tail->next = o->head; 353 else 354 l->head = o->head; 355 356 if (o->tail) l->tail = o->tail; 357 l->len += o->len; 358 359 /* Setup other as an empty list. */ 360 o->head = o->tail = NULL; 361 o->len = 0; 362 } 363