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