LCOV - code coverage report
Current view: directory - redis/src - adlist.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 144 126 87.5 %
Date: 2012-04-04 Functions: 15 13 86.7 %
Colors: not hit hit

       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            5090 : list *listCreate(void)
      42                 : {
      43                 :     struct list *list;
      44                 : 
      45            5090 :     if ((list = zmalloc(sizeof(*list))) == NULL)
      46               0 :         return NULL;
      47            5090 :     list->head = list->tail = NULL;
      48            5090 :     list->len = 0;
      49            5090 :     list->dup = NULL;
      50            5090 :     list->free = NULL;
      51            5090 :     list->match = NULL;
      52            5090 :     return list;
      53                 : }
      54                 : 
      55                 : /* Free the whole list.
      56                 :  *
      57                 :  * This function can't fail. */
      58            2789 : void listRelease(list *list)
      59                 : {
      60                 :     unsigned long len;
      61                 :     listNode *current, *next;
      62                 : 
      63            2789 :     current = list->head;
      64            2789 :     len = list->len;
      65           48676 :     while(len--) {
      66           43098 :         next = current->next;
      67           43098 :         if (list->free) list->free(current->value);
      68           43098 :         zfree(current);
      69           43098 :         current = next;
      70                 :     }
      71            2789 :     zfree(list);
      72            2789 : }
      73                 : 
      74                 : /* Add a new node to the list, to head, contaning 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           18873 : list *listAddNodeHead(list *list, void *value)
      81                 : {
      82                 :     listNode *node;
      83                 : 
      84           18873 :     if ((node = zmalloc(sizeof(*node))) == NULL)
      85               0 :         return NULL;
      86           18873 :     node->value = value;
      87           18873 :     if (list->len == 0) {
      88            2756 :         list->head = list->tail = node;
      89            2756 :         node->prev = node->next = NULL;
      90                 :     } else {
      91           16117 :         node->prev = NULL;
      92           16117 :         node->next = list->head;
      93           16117 :         list->head->prev = node;
      94           16117 :         list->head = node;
      95                 :     }
      96           18873 :     list->len++;
      97           18873 :     return list;
      98                 : }
      99                 : 
     100                 : /* Add a new node to the list, to tail, contaning 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           57384 : list *listAddNodeTail(list *list, void *value)
     107                 : {
     108                 :     listNode *node;
     109                 : 
     110           57384 :     if ((node = zmalloc(sizeof(*node))) == NULL)
     111               0 :         return NULL;
     112           57384 :     node->value = value;
     113           57384 :     if (list->len == 0) {
     114            3501 :         list->head = list->tail = node;
     115            3501 :         node->prev = node->next = NULL;
     116                 :     } else {
     117           53883 :         node->prev = list->tail;
     118           53883 :         node->next = NULL;
     119           53883 :         list->tail->next = node;
     120           53883 :         list->tail = node;
     121                 :     }
     122           57384 :     list->len++;
     123           57384 :     return list;
     124                 : }
     125                 : 
     126               7 : list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
     127                 :     listNode *node;
     128                 : 
     129               7 :     if ((node = zmalloc(sizeof(*node))) == NULL)
     130               0 :         return NULL;
     131               7 :     node->value = value;
     132               7 :     if (after) {
     133               3 :         node->prev = old_node;
     134               3 :         node->next = old_node->next;
     135               3 :         if (list->tail == old_node) {
     136               2 :             list->tail = node;
     137                 :         }
     138                 :     } else {
     139               4 :         node->next = old_node;
     140               4 :         node->prev = old_node->prev;
     141               4 :         if (list->head == old_node) {
     142               3 :             list->head = node;
     143                 :         }
     144                 :     }
     145               7 :     if (node->prev != NULL) {
     146               4 :         node->prev->next = node;
     147                 :     }
     148               7 :     if (node->next != NULL) {
     149               5 :         node->next->prev = node;
     150                 :     }
     151               7 :     list->len++;
     152               7 :     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           30134 : void listDelNode(list *list, listNode *node)
     160                 : {
     161           30134 :     if (node->prev)
     162            7434 :         node->prev->next = node->next;
     163                 :     else
     164           22700 :         list->head = node->next;
     165           30134 :     if (node->next)
     166           17928 :         node->next->prev = node->prev;
     167                 :     else
     168           12206 :         list->tail = node->prev;
     169           30134 :     if (list->free) list->free(node->value);
     170           30134 :     zfree(node);
     171           30134 :     list->len--;
     172           30134 : }
     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             200 : listIter *listGetIterator(list *list, int direction)
     179                 : {
     180                 :     listIter *iter;
     181                 :     
     182             200 :     if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
     183             200 :     if (direction == AL_START_HEAD)
     184             200 :         iter->next = list->head;
     185                 :     else
     186               0 :         iter->next = list->tail;
     187             200 :     iter->direction = direction;
     188             200 :     return iter;
     189                 : }
     190                 : 
     191                 : /* Release the iterator memory */
     192               0 : void listReleaseIterator(listIter *iter) {
     193             200 :     zfree(iter);
     194               0 : }
     195                 : 
     196                 : /* Create an iterator in the list private iterator structure */
     197          351108 : void listRewind(list *list, listIter *li) {
     198          351108 :     li->next = list->head;
     199          351108 :     li->direction = AL_START_HEAD;
     200          351108 : }
     201                 : 
     202               0 : void listRewindTail(list *list, listIter *li) {
     203               0 :     li->next = list->tail;
     204               0 :     li->direction = AL_START_TAIL;
     205               0 : }
     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          875656 : listNode *listNext(listIter *iter)
     222                 : {
     223          876143 :     listNode *current = iter->next;
     224                 : 
     225          876143 :     if (current != NULL) {
     226          525025 :         if (iter->direction == AL_START_HEAD)
     227          525025 :             iter->next = current->next;
     228                 :         else
     229               0 :             iter->next = current->prev;
     230                 :     }
     231          876143 :     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               2 : list *listDup(list *orig)
     243                 : {
     244                 :     list *copy;
     245                 :     listIter *iter;
     246                 :     listNode *node;
     247                 : 
     248               2 :     if ((copy = listCreate()) == NULL)
     249               0 :         return NULL;
     250               2 :     copy->dup = orig->dup;
     251               2 :     copy->free = orig->free;
     252               2 :     copy->match = orig->match;
     253               2 :     iter = listGetIterator(orig, AL_START_HEAD);
     254             137 :     while((node = listNext(iter)) != NULL) {
     255                 :         void *value;
     256                 : 
     257             133 :         if (copy->dup) {
     258             133 :             value = copy->dup(node->value);
     259             133 :             if (value == NULL) {
     260               0 :                 listRelease(copy);
     261                 :                 listReleaseIterator(iter);
     262               0 :                 return NULL;
     263                 :             }
     264                 :         } else
     265               0 :             value = node->value;
     266             133 :         if (listAddNodeTail(copy, value) == NULL) {
     267               0 :             listRelease(copy);
     268                 :             listReleaseIterator(iter);
     269               0 :             return NULL;
     270                 :         }
     271                 :     }
     272                 :     listReleaseIterator(iter);
     273               2 :     return copy;
     274                 : }
     275                 : 
     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.
     281                 :  *
     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             198 : listNode *listSearchKey(list *list, void *key)
     286                 : {
     287                 :     listIter *iter;
     288                 :     listNode *node;
     289                 : 
     290             198 :     iter = listGetIterator(list, AL_START_HEAD);
     291             550 :     while((node = listNext(iter)) != NULL) {
     292             341 :         if (list->match) {
     293              20 :             if (list->match(node->value, key)) {
     294                 :                 listReleaseIterator(iter);
     295              16 :                 return node;
     296                 :             }
     297                 :         } else {
     298             321 :             if (key == node->value) {
     299                 :                 listReleaseIterator(iter);
     300             171 :                 return node;
     301                 :             }
     302                 :         }
     303                 :     }
     304                 :     listReleaseIterator(iter);
     305              11 :     return NULL;
     306                 : }
     307                 : 
     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           35200 : listNode *listIndex(list *list, long index) {
     314                 :     listNode *n;
     315                 : 
     316           35200 :     if (index < 0) {
     317            2004 :         index = (-index)-1;
     318            2004 :         n = list->tail;
     319            2004 :         while(index-- && n) n = n->prev;
     320                 :     } else {
     321           33196 :         n = list->head;
     322           33196 :         while(index-- && n) n = n->next;
     323                 :     }
     324           35200 :     return n;
     325                 : }
     326                 : 
     327                 : /* Rotate the list removing the tail node and inserting it to the head. */
     328            7038 : void listRotate(list *list) {
     329            7038 :     listNode *tail = list->tail;
     330                 : 
     331            7038 :     if (listLength(list) <= 1) return;
     332                 : 
     333                 :     /* Detatch current tail */
     334            6086 :     list->tail = tail->prev;
     335            6086 :     list->tail->next = NULL;
     336                 :     /* Move it as head */
     337            6086 :     list->head->prev = tail;
     338            6086 :     tail->prev = NULL;
     339            6086 :     tail->next = list->head;
     340            6086 :     list->head = tail;
     341                 : }

Generated by: LCOV version 1.7