/src/clib/deps/list/list.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | // |
3 | | // list.c |
4 | | // |
5 | | // Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca> |
6 | | // |
7 | | |
8 | | #include "list.h" |
9 | | |
10 | | /* |
11 | | * Allocate a new list_t. NULL on failure. |
12 | | */ |
13 | | |
14 | | list_t * |
15 | 259 | list_new(void) { |
16 | 259 | list_t *self; |
17 | 259 | if (!(self = LIST_MALLOC(sizeof(list_t)))) |
18 | 0 | return NULL; |
19 | 259 | self->head = NULL; |
20 | 259 | self->tail = NULL; |
21 | 259 | self->free = NULL; |
22 | 259 | self->match = NULL; |
23 | 259 | self->len = 0; |
24 | 259 | return self; |
25 | 259 | } |
26 | | |
27 | | /* |
28 | | * Free the list. |
29 | | */ |
30 | | |
31 | | void |
32 | 259 | list_destroy(list_t *self) { |
33 | 259 | unsigned int len = self->len; |
34 | 259 | list_node_t *next; |
35 | 259 | list_node_t *curr = self->head; |
36 | | |
37 | 232k | while (len--) { |
38 | 232k | next = curr->next; |
39 | 232k | if (self->free) self->free(curr->val); |
40 | 232k | LIST_FREE(curr); |
41 | 232k | curr = next; |
42 | 232k | } |
43 | | |
44 | 259 | LIST_FREE(self); |
45 | 259 | } |
46 | | |
47 | | /* |
48 | | * Append the given node to the list |
49 | | * and return the node, NULL on failure. |
50 | | */ |
51 | | |
52 | | list_node_t * |
53 | 232k | list_rpush(list_t *self, list_node_t *node) { |
54 | 232k | if (!node) return NULL; |
55 | | |
56 | 232k | if (self->len) { |
57 | 232k | node->prev = self->tail; |
58 | 232k | node->next = NULL; |
59 | 232k | self->tail->next = node; |
60 | 232k | self->tail = node; |
61 | 232k | } else { |
62 | 211 | self->head = self->tail = node; |
63 | 211 | node->prev = node->next = NULL; |
64 | 211 | } |
65 | | |
66 | 232k | ++self->len; |
67 | 232k | return node; |
68 | 232k | } |
69 | | |
70 | | /* |
71 | | * Return / detach the last node in the list, or NULL. |
72 | | */ |
73 | | |
74 | | list_node_t * |
75 | 0 | list_rpop(list_t *self) { |
76 | 0 | if (!self->len) return NULL; |
77 | | |
78 | 0 | list_node_t *node = self->tail; |
79 | |
|
80 | 0 | if (--self->len) { |
81 | 0 | (self->tail = node->prev)->next = NULL; |
82 | 0 | } else { |
83 | 0 | self->tail = self->head = NULL; |
84 | 0 | } |
85 | |
|
86 | 0 | node->next = node->prev = NULL; |
87 | 0 | return node; |
88 | 0 | } |
89 | | |
90 | | /* |
91 | | * Return / detach the first node in the list, or NULL. |
92 | | */ |
93 | | |
94 | | list_node_t * |
95 | 0 | list_lpop(list_t *self) { |
96 | 0 | if (!self->len) return NULL; |
97 | | |
98 | 0 | list_node_t *node = self->head; |
99 | |
|
100 | 0 | if (--self->len) { |
101 | 0 | (self->head = node->next)->prev = NULL; |
102 | 0 | } else { |
103 | 0 | self->head = self->tail = NULL; |
104 | 0 | } |
105 | |
|
106 | 0 | node->next = node->prev = NULL; |
107 | 0 | return node; |
108 | 0 | } |
109 | | |
110 | | /* |
111 | | * Prepend the given node to the list |
112 | | * and return the node, NULL on failure. |
113 | | */ |
114 | | |
115 | | list_node_t * |
116 | 0 | list_lpush(list_t *self, list_node_t *node) { |
117 | 0 | if (!node) return NULL; |
118 | | |
119 | 0 | if (self->len) { |
120 | 0 | node->next = self->head; |
121 | 0 | node->prev = NULL; |
122 | 0 | self->head->prev = node; |
123 | 0 | self->head = node; |
124 | 0 | } else { |
125 | 0 | self->head = self->tail = node; |
126 | 0 | node->prev = node->next = NULL; |
127 | 0 | } |
128 | |
|
129 | 0 | ++self->len; |
130 | 0 | return node; |
131 | 0 | } |
132 | | |
133 | | /* |
134 | | * Return the node associated to val or NULL. |
135 | | */ |
136 | | |
137 | | list_node_t * |
138 | 0 | list_find(list_t *self, void *val) { |
139 | 0 | list_iterator_t *it = list_iterator_new(self, LIST_HEAD); |
140 | 0 | list_node_t *node; |
141 | |
|
142 | 0 | while ((node = list_iterator_next(it))) { |
143 | 0 | if (self->match) { |
144 | 0 | if (self->match(val, node->val)) { |
145 | 0 | list_iterator_destroy(it); |
146 | 0 | return node; |
147 | 0 | } |
148 | 0 | } else { |
149 | 0 | if (val == node->val) { |
150 | 0 | list_iterator_destroy(it); |
151 | 0 | return node; |
152 | 0 | } |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | 0 | list_iterator_destroy(it); |
157 | 0 | return NULL; |
158 | 0 | } |
159 | | |
160 | | /* |
161 | | * Return the node at the given index or NULL. |
162 | | */ |
163 | | |
164 | | list_node_t * |
165 | 0 | list_at(list_t *self, int index) { |
166 | 0 | list_direction_t direction = LIST_HEAD; |
167 | |
|
168 | 0 | if (index < 0) { |
169 | 0 | direction = LIST_TAIL; |
170 | 0 | index = ~index; |
171 | 0 | } |
172 | |
|
173 | 0 | if ((unsigned)index < self->len) { |
174 | 0 | list_iterator_t *it = list_iterator_new(self, direction); |
175 | 0 | list_node_t *node = list_iterator_next(it); |
176 | 0 | while (index--) node = list_iterator_next(it); |
177 | 0 | list_iterator_destroy(it); |
178 | 0 | return node; |
179 | 0 | } |
180 | | |
181 | 0 | return NULL; |
182 | 0 | } |
183 | | |
184 | | /* |
185 | | * Remove the given node from the list, freeing it and it's value. |
186 | | */ |
187 | | |
188 | | void |
189 | 0 | list_remove(list_t *self, list_node_t *node) { |
190 | 0 | node->prev |
191 | 0 | ? (node->prev->next = node->next) |
192 | 0 | : (self->head = node->next); |
193 | |
|
194 | 0 | node->next |
195 | 0 | ? (node->next->prev = node->prev) |
196 | 0 | : (self->tail = node->prev); |
197 | |
|
198 | 0 | if (self->free) self->free(node->val); |
199 | |
|
200 | 0 | LIST_FREE(node); |
201 | 0 | --self->len; |
202 | 0 | } |