PageRenderTime 65ms CodeModel.GetById 44ms RepoModel.GetById 0ms app.codeStats 0ms

/src/adlist.c

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