PageRenderTime 67ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/adlist.c

http://github.com/antirez/redis-tools
C | 296 lines | 176 code | 25 blank | 95 comment | 42 complexity | a45e721a5ef6711f9b4bb2bb142fdf24 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /* adlist.c - A generic doubly linked list implementation
  2. *
  3. * Copyright (c) 2006-2009, 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. #include <stdlib.h>
  31. #include "adlist.h"
  32. #include "zmalloc.h"
  33. /* Create a new list. The created list can be freed with
  34. * AlFreeList(), but private value of every node need to be freed
  35. * by the user before to call AlFreeList().
  36. *
  37. * On error, NULL is returned. Otherwise the pointer to the new list. */
  38. list *listCreate(void)
  39. {
  40. struct list *list;
  41. if ((list = zmalloc(sizeof(*list))) == NULL)
  42. return NULL;
  43. list->head = list->tail = NULL;
  44. list->len = 0;
  45. list->dup = NULL;
  46. list->free = NULL;
  47. list->match = NULL;
  48. return list;
  49. }
  50. /* Free the whole list.
  51. *
  52. * This function can't fail. */
  53. void listRelease(list *list)
  54. {
  55. unsigned int len;
  56. listNode *current, *next;
  57. current = list->head;
  58. len = list->len;
  59. while(len--) {
  60. next = current->next;
  61. if (list->free) list->free(current->value);
  62. zfree(current);
  63. current = next;
  64. }
  65. zfree(list);
  66. }
  67. /* Add a new node to the list, to head, contaning the specified 'value'
  68. * pointer as value.
  69. *
  70. * On error, NULL is returned and no operation is performed (i.e. the
  71. * list remains unaltered).
  72. * On success the 'list' pointer you pass to the function is returned. */
  73. list *listAddNodeHead(list *list, void *value)
  74. {
  75. listNode *node;
  76. if ((node = zmalloc(sizeof(*node))) == NULL)
  77. return NULL;
  78. node->value = value;
  79. if (list->len == 0) {
  80. list->head = list->tail = node;
  81. node->prev = node->next = NULL;
  82. } else {
  83. node->prev = NULL;
  84. node->next = list->head;
  85. list->head->prev = node;
  86. list->head = node;
  87. }
  88. list->len++;
  89. return list;
  90. }
  91. /* Add a new node to the list, to tail, contaning the specified 'value'
  92. * pointer as value.
  93. *
  94. * On error, NULL is returned and no operation is performed (i.e. the
  95. * list remains unaltered).
  96. * On success the 'list' pointer you pass to the function is returned. */
  97. list *listAddNodeTail(list *list, void *value)
  98. {
  99. listNode *node;
  100. if ((node = zmalloc(sizeof(*node))) == NULL)
  101. return NULL;
  102. node->value = value;
  103. if (list->len == 0) {
  104. list->head = list->tail = node;
  105. node->prev = node->next = NULL;
  106. } else {
  107. node->prev = list->tail;
  108. node->next = NULL;
  109. list->tail->next = node;
  110. list->tail = node;
  111. }
  112. list->len++;
  113. return list;
  114. }
  115. /* Remove the specified node from the specified list.
  116. * It's up to the caller to free the private value of the node.
  117. *
  118. * This function can't fail. */
  119. void listDelNode(list *list, listNode *node)
  120. {
  121. if (node->prev)
  122. node->prev->next = node->next;
  123. else
  124. list->head = node->next;
  125. if (node->next)
  126. node->next->prev = node->prev;
  127. else
  128. list->tail = node->prev;
  129. if (list->free) list->free(node->value);
  130. zfree(node);
  131. list->len--;
  132. }
  133. /* Returns a list iterator 'iter'. After the initialization every
  134. * call to listNext() will return the next element of the list.
  135. *
  136. * This function can't fail. */
  137. listIter *listGetIterator(list *list, int direction)
  138. {
  139. listIter *iter;
  140. if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
  141. if (direction == AL_START_HEAD)
  142. iter->next = list->head;
  143. else
  144. iter->next = list->tail;
  145. iter->direction = direction;
  146. return iter;
  147. }
  148. /* Release the iterator memory */
  149. void listReleaseIterator(listIter *iter) {
  150. zfree(iter);
  151. }
  152. /* Create an iterator in the list private iterator structure */
  153. void listRewind(list *list, listIter *li) {
  154. li->next = list->head;
  155. li->direction = AL_START_HEAD;
  156. }
  157. void listRewindTail(list *list, listIter *li) {
  158. li->next = list->tail;
  159. li->direction = AL_START_TAIL;
  160. }
  161. /* Return the next element of an iterator.
  162. * It's valid to remove the currently returned element using
  163. * listDelNode(), but not to remove other elements.
  164. *
  165. * The function returns a pointer to the next element of the list,
  166. * or NULL if there are no more elements, so the classical usage patter
  167. * is:
  168. *
  169. * iter = listGetItarotr(list,<direction>);
  170. * while ((node = listNextIterator(iter)) != NULL) {
  171. * DoSomethingWith(listNodeValue(node));
  172. * }
  173. *
  174. * */
  175. listNode *listNext(listIter *iter)
  176. {
  177. listNode *current = iter->next;
  178. if (current != NULL) {
  179. if (iter->direction == AL_START_HEAD)
  180. iter->next = current->next;
  181. else
  182. iter->next = current->prev;
  183. }
  184. return current;
  185. }
  186. /* Duplicate the whole list. On out of memory NULL is returned.
  187. * On success a copy of the original list is returned.
  188. *
  189. * The 'Dup' method set with listSetDupMethod() function is used
  190. * to copy the node value. Otherwise the same pointer value of
  191. * the original node is used as value of the copied node.
  192. *
  193. * The original list both on success or error is never modified. */
  194. list *listDup(list *orig)
  195. {
  196. list *copy;
  197. listIter *iter;
  198. listNode *node;
  199. if ((copy = listCreate()) == NULL)
  200. return NULL;
  201. copy->dup = orig->dup;
  202. copy->free = orig->free;
  203. copy->match = orig->match;
  204. iter = listGetIterator(orig, AL_START_HEAD);
  205. while((node = listNext(iter)) != NULL) {
  206. void *value;
  207. if (copy->dup) {
  208. value = copy->dup(node->value);
  209. if (value == NULL) {
  210. listRelease(copy);
  211. listReleaseIterator(iter);
  212. return NULL;
  213. }
  214. } else
  215. value = node->value;
  216. if (listAddNodeTail(copy, value) == NULL) {
  217. listRelease(copy);
  218. listReleaseIterator(iter);
  219. return NULL;
  220. }
  221. }
  222. listReleaseIterator(iter);
  223. return copy;
  224. }
  225. /* Search the list for a node matching a given key.
  226. * The match is performed using the 'match' method
  227. * set with listSetMatchMethod(). If no 'match' method
  228. * is set, the 'value' pointer of every node is directly
  229. * compared with the 'key' pointer.
  230. *
  231. * On success the first matching node pointer is returned
  232. * (search starts from head). If no matching node exists
  233. * NULL is returned. */
  234. listNode *listSearchKey(list *list, void *key)
  235. {
  236. listIter *iter;
  237. listNode *node;
  238. iter = listGetIterator(list, AL_START_HEAD);
  239. while((node = listNext(iter)) != NULL) {
  240. if (list->match) {
  241. if (list->match(node->value, key)) {
  242. listReleaseIterator(iter);
  243. return node;
  244. }
  245. } else {
  246. if (key == node->value) {
  247. listReleaseIterator(iter);
  248. return node;
  249. }
  250. }
  251. }
  252. listReleaseIterator(iter);
  253. return NULL;
  254. }
  255. /* Return the element at the specified zero-based index
  256. * where 0 is the head, 1 is the element next to head
  257. * and so on. Negative integers are used in order to count
  258. * from the tail, -1 is the last element, -2 the penultimante
  259. * and so on. If the index is out of range NULL is returned. */
  260. listNode *listIndex(list *list, int index) {
  261. listNode *n;
  262. if (index < 0) {
  263. index = (-index)-1;
  264. n = list->tail;
  265. while(index-- && n) n = n->prev;
  266. } else {
  267. n = list->head;
  268. while(index-- && n) n = n->next;
  269. }
  270. return n;
  271. }