/src/php-src/Zend/zend_llist.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Zend Engine | |
4 | | +----------------------------------------------------------------------+ |
5 | | | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | |
6 | | +----------------------------------------------------------------------+ |
7 | | | This source file is subject to version 2.00 of the Zend license, | |
8 | | | that is bundled with this package in the file LICENSE, and is | |
9 | | | available through the world-wide-web at the following url: | |
10 | | | http://www.zend.com/license/2_00.txt. | |
11 | | | If you did not receive a copy of the Zend license and are unable to | |
12 | | | obtain it through the world-wide-web, please send a note to | |
13 | | | license@zend.com so we can mail you a copy immediately. | |
14 | | +----------------------------------------------------------------------+ |
15 | | | Authors: Andi Gutmans <andi@php.net> | |
16 | | | Zeev Suraski <zeev@php.net> | |
17 | | +----------------------------------------------------------------------+ |
18 | | */ |
19 | | |
20 | | #include "zend.h" |
21 | | #include "zend_llist.h" |
22 | | #include "zend_sort.h" |
23 | | |
24 | | ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) |
25 | 536k | { |
26 | 536k | l->head = NULL; |
27 | 536k | l->tail = NULL; |
28 | 536k | l->count = 0; |
29 | 536k | l->size = size; |
30 | 536k | l->dtor = dtor; |
31 | 536k | l->persistent = persistent; |
32 | 536k | } |
33 | | |
34 | | ZEND_API void zend_llist_add_element(zend_llist *l, const void *element) |
35 | 411k | { |
36 | 411k | zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); |
37 | | |
38 | 411k | tmp->prev = l->tail; |
39 | 411k | tmp->next = NULL; |
40 | 411k | if (l->tail) { |
41 | 108 | l->tail->next = tmp; |
42 | 411k | } else { |
43 | 411k | l->head = tmp; |
44 | 411k | } |
45 | 411k | l->tail = tmp; |
46 | 411k | memcpy(tmp->data, element, l->size); |
47 | | |
48 | 411k | ++l->count; |
49 | 411k | } |
50 | | |
51 | | |
52 | | ZEND_API void zend_llist_prepend_element(zend_llist *l, const void *element) |
53 | 0 | { |
54 | 0 | zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); |
55 | |
|
56 | 0 | tmp->next = l->head; |
57 | 0 | tmp->prev = NULL; |
58 | 0 | if (l->head) { |
59 | 0 | l->head->prev = tmp; |
60 | 0 | } else { |
61 | 0 | l->tail = tmp; |
62 | 0 | } |
63 | 0 | l->head = tmp; |
64 | 0 | memcpy(tmp->data, element, l->size); |
65 | |
|
66 | 0 | ++l->count; |
67 | 0 | } |
68 | | |
69 | | |
70 | | #define DEL_LLIST_ELEMENT(current, l) \ |
71 | 137k | if ((current)->prev) {\ |
72 | 0 | (current)->prev->next = (current)->next;\ |
73 | 137k | } else {\ |
74 | 137k | (l)->head = (current)->next;\ |
75 | 137k | }\ |
76 | 137k | if ((current)->next) {\ |
77 | 0 | (current)->next->prev = (current)->prev;\ |
78 | 137k | } else {\ |
79 | 137k | (l)->tail = (current)->prev;\ |
80 | 137k | }\ |
81 | 137k | if ((l)->dtor) {\ |
82 | 137k | (l)->dtor((current)->data);\ |
83 | 137k | }\ |
84 | 137k | pefree((current), (l)->persistent);\ |
85 | 137k | --l->count; |
86 | | |
87 | | |
88 | | ZEND_API void zend_llist_del_element(zend_llist *l, void *element, int (*compare)(void *element1, void *element2)) |
89 | 137k | { |
90 | 137k | zend_llist_element *current=l->head; |
91 | | |
92 | 137k | while (current) { |
93 | 137k | if (compare(current->data, element)) { |
94 | 137k | DEL_LLIST_ELEMENT(current, l); |
95 | 137k | break; |
96 | 137k | } |
97 | 0 | current = current->next; |
98 | 0 | } |
99 | 137k | } |
100 | | |
101 | | |
102 | | ZEND_API void zend_llist_destroy(zend_llist *l) |
103 | 805k | { |
104 | 805k | zend_llist_element *current=l->head, *next; |
105 | | |
106 | 1.07M | while (current) { |
107 | 274k | next = current->next; |
108 | 274k | if (l->dtor) { |
109 | 274k | l->dtor(current->data); |
110 | 274k | } |
111 | 274k | pefree(current, l->persistent); |
112 | 274k | current = next; |
113 | 274k | } |
114 | | |
115 | 805k | l->head = NULL; |
116 | 805k | l->tail = NULL; |
117 | 805k | l->count = 0; |
118 | 805k | } |
119 | | |
120 | | |
121 | | ZEND_API void zend_llist_clean(zend_llist *l) |
122 | 268k | { |
123 | 268k | zend_llist_destroy(l); |
124 | 268k | } |
125 | | |
126 | | |
127 | | ZEND_API void zend_llist_remove_tail(zend_llist *l) |
128 | 0 | { |
129 | 0 | zend_llist_element *old_tail = l->tail; |
130 | 0 | if (!old_tail) { |
131 | 0 | return; |
132 | 0 | } |
133 | | |
134 | 0 | if (old_tail->prev) { |
135 | 0 | old_tail->prev->next = NULL; |
136 | 0 | } else { |
137 | 0 | l->head = NULL; |
138 | 0 | } |
139 | |
|
140 | 0 | l->tail = old_tail->prev; |
141 | 0 | --l->count; |
142 | |
|
143 | 0 | if (l->dtor) { |
144 | 0 | l->dtor(old_tail->data); |
145 | 0 | } |
146 | 0 | pefree(old_tail, l->persistent); |
147 | 0 | } |
148 | | |
149 | | |
150 | | ZEND_API void zend_llist_copy(zend_llist *dst, zend_llist *src) |
151 | 0 | { |
152 | 0 | zend_llist_element *ptr; |
153 | |
|
154 | 0 | zend_llist_init(dst, src->size, src->dtor, src->persistent); |
155 | 0 | ptr = src->head; |
156 | 0 | while (ptr) { |
157 | 0 | zend_llist_add_element(dst, ptr->data); |
158 | 0 | ptr = ptr->next; |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | | |
163 | | ZEND_API void zend_llist_apply_with_del(zend_llist *l, int (*func)(void *data)) |
164 | 16 | { |
165 | 16 | zend_llist_element *element, *next; |
166 | | |
167 | 16 | element=l->head; |
168 | 20 | while (element) { |
169 | 4 | next = element->next; |
170 | 4 | if (func(element->data)) { |
171 | 0 | DEL_LLIST_ELEMENT(element, l); |
172 | 0 | } |
173 | 4 | element = next; |
174 | 4 | } |
175 | 16 | } |
176 | | |
177 | | |
178 | | ZEND_API void zend_llist_apply(zend_llist *l, llist_apply_func_t func) |
179 | 536k | { |
180 | 536k | zend_llist_element *element; |
181 | | |
182 | 745k | for (element=l->head; element; element=element->next) { |
183 | 208k | func(element->data); |
184 | 208k | } |
185 | 536k | } |
186 | | |
187 | | static void zend_llist_swap(zend_llist_element **p, zend_llist_element **q) |
188 | 0 | { |
189 | 0 | zend_llist_element *t; |
190 | 0 | t = *p; |
191 | 0 | *p = *q; |
192 | 0 | *q = t; |
193 | 0 | } |
194 | | |
195 | | ZEND_API void zend_llist_sort(zend_llist *l, llist_compare_func_t comp_func) |
196 | 0 | { |
197 | 0 | size_t i; |
198 | |
|
199 | 0 | zend_llist_element **elements; |
200 | 0 | zend_llist_element *element, **ptr; |
201 | |
|
202 | 0 | if (l->count == 0) { |
203 | 0 | return; |
204 | 0 | } |
205 | | |
206 | 0 | elements = (zend_llist_element **) emalloc(l->count * sizeof(zend_llist_element *)); |
207 | |
|
208 | 0 | ptr = &elements[0]; |
209 | |
|
210 | 0 | for (element=l->head; element; element=element->next) { |
211 | 0 | *ptr++ = element; |
212 | 0 | } |
213 | |
|
214 | 0 | zend_sort(elements, l->count, sizeof(zend_llist_element *), |
215 | 0 | (compare_func_t) comp_func, (swap_func_t) zend_llist_swap); |
216 | |
|
217 | 0 | l->head = elements[0]; |
218 | 0 | elements[0]->prev = NULL; |
219 | |
|
220 | 0 | for (i = 1; i < l->count; i++) { |
221 | 0 | elements[i]->prev = elements[i-1]; |
222 | 0 | elements[i-1]->next = elements[i]; |
223 | 0 | } |
224 | 0 | elements[i-1]->next = NULL; |
225 | 0 | l->tail = elements[i-1]; |
226 | 0 | efree(elements); |
227 | 0 | } |
228 | | |
229 | | |
230 | | ZEND_API void zend_llist_apply_with_argument(zend_llist *l, llist_apply_with_arg_func_t func, void *arg) |
231 | 268k | { |
232 | 268k | zend_llist_element *element; |
233 | | |
234 | 537k | for (element=l->head; element; element=element->next) { |
235 | 268k | func(element->data, arg); |
236 | 268k | } |
237 | 268k | } |
238 | | |
239 | | |
240 | | ZEND_API void zend_llist_apply_with_arguments(zend_llist *l, llist_apply_with_args_func_t func, int num_args, ...) |
241 | 4 | { |
242 | 4 | zend_llist_element *element; |
243 | 4 | va_list args; |
244 | | |
245 | 4 | va_start(args, num_args); |
246 | 4 | for (element=l->head; element; element=element->next) { |
247 | 0 | func(element->data, num_args, args); |
248 | 0 | } |
249 | 4 | va_end(args); |
250 | 4 | } |
251 | | |
252 | | |
253 | | ZEND_API size_t zend_llist_count(zend_llist *l) |
254 | 7 | { |
255 | 7 | return l->count; |
256 | 7 | } |
257 | | |
258 | | |
259 | | ZEND_API void *zend_llist_get_first_ex(zend_llist *l, zend_llist_position *pos) |
260 | 14 | { |
261 | 14 | zend_llist_position *current = pos ? pos : &l->traverse_ptr; |
262 | | |
263 | 14 | *current = l->head; |
264 | 14 | if (*current) { |
265 | 14 | return (*current)->data; |
266 | 14 | } else { |
267 | 0 | return NULL; |
268 | 0 | } |
269 | 14 | } |
270 | | |
271 | | |
272 | | ZEND_API void *zend_llist_get_last_ex(zend_llist *l, zend_llist_position *pos) |
273 | 0 | { |
274 | 0 | zend_llist_position *current = pos ? pos : &l->traverse_ptr; |
275 | |
|
276 | 0 | *current = l->tail; |
277 | 0 | if (*current) { |
278 | 0 | return (*current)->data; |
279 | 0 | } else { |
280 | 0 | return NULL; |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | | |
285 | | ZEND_API void *zend_llist_get_next_ex(zend_llist *l, zend_llist_position *pos) |
286 | 14 | { |
287 | 14 | zend_llist_position *current = pos ? pos : &l->traverse_ptr; |
288 | | |
289 | 14 | if (*current) { |
290 | 14 | *current = (*current)->next; |
291 | 14 | if (*current) { |
292 | 0 | return (*current)->data; |
293 | 0 | } |
294 | 14 | } |
295 | 14 | return NULL; |
296 | 14 | } |
297 | | |
298 | | |
299 | | ZEND_API void *zend_llist_get_prev_ex(zend_llist *l, zend_llist_position *pos) |
300 | 0 | { |
301 | 0 | zend_llist_position *current = pos ? pos : &l->traverse_ptr; |
302 | |
|
303 | 0 | if (*current) { |
304 | 0 | *current = (*current)->prev; |
305 | 0 | if (*current) { |
306 | 0 | return (*current)->data; |
307 | 0 | } |
308 | 0 | } |
309 | 0 | return NULL; |
310 | 0 | } |