PageRenderTime 77ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/redis-server/adlist.c

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