Coverage Report

Created: 2026-06-02 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
67.8k
{
25
67.8k
  l->head  = NULL;
26
67.8k
  l->tail  = NULL;
27
67.8k
  l->count = 0;
28
67.8k
  l->size  = size;
29
67.8k
  l->dtor  = dtor;
30
67.8k
  l->persistent = persistent;
31
67.8k
}
32
33
ZEND_API void zend_llist_add_element(zend_llist *l, const void *element)
34
41.9k
{
35
41.9k
  zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent);
36
37
41.9k
  tmp->prev = l->tail;
38
41.9k
  tmp->next = NULL;
39
41.9k
  if (l->tail) {
40
0
    l->tail->next = tmp;
41
41.9k
  } else {
42
41.9k
    l->head = tmp;
43
41.9k
  }
44
41.9k
  l->tail = tmp;
45
41.9k
  memcpy(tmp->data, element, l->size);
46
47
41.9k
  ++l->count;
48
41.9k
}
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
7.18k
      if ((current)->prev) {\
71
0
        (current)->prev->next = (current)->next;\
72
7.18k
      } else {\
73
7.18k
        (l)->head = (current)->next;\
74
7.18k
      }\
75
7.18k
      if ((current)->next) {\
76
0
        (current)->next->prev = (current)->prev;\
77
7.18k
      } else {\
78
7.18k
        (l)->tail = (current)->prev;\
79
7.18k
      }\
80
7.18k
      if ((l)->dtor) {\
81
7.18k
        (l)->dtor((current)->data);\
82
7.18k
      }\
83
7.18k
      pefree((current), (l)->persistent);\
84
7.18k
      --l->count;
85
86
87
ZEND_API void zend_llist_del_element(zend_llist *l, void *element, int (*compare)(void *element1, void *element2))
88
7.18k
{
89
7.18k
  zend_llist_element *current=l->head;
90
91
7.18k
  while (current) {
92
7.18k
    if (compare(current->data, element)) {
93
7.18k
      DEL_LLIST_ELEMENT(current, l);
94
7.18k
      break;
95
7.18k
    }
96
0
    current = current->next;
97
0
  }
98
7.18k
}
99
100
101
ZEND_API void zend_llist_destroy(zend_llist *l)
102
101k
{
103
101k
  zend_llist_element *current=l->head, *next;
104
105
136k
  while (current) {
106
34.7k
    next = current->next;
107
34.7k
    if (l->dtor) {
108
34.7k
      l->dtor(current->data);
109
34.7k
    }
110
34.7k
    pefree(current, l->persistent);
111
34.7k
    current = next;
112
34.7k
  }
113
114
101k
  l->head  = NULL;
115
101k
  l->tail  = NULL;
116
101k
  l->count = 0;
117
101k
}
118
119
120
ZEND_API void zend_llist_clean(zend_llist *l)
121
33.5k
{
122
33.5k
  zend_llist_destroy(l);
123
33.5k
}
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
67.1k
{
179
67.1k
  zend_llist_element *element;
180
181
134k
  for (element=l->head; element; element=element->next) {
182
67.1k
    func(element->data);
183
67.1k
  }
184
67.1k
}
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
33.6k
{
231
33.6k
  zend_llist_element *element;
232
233
67.2k
  for (element=l->head; element; element=element->next) {
234
33.5k
    func(element->data, arg);
235
33.5k
  }
236
33.6k
}
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
662
{
254
662
  return l->count;
255
662
}
256
257
258
ZEND_API void *zend_llist_get_first_ex(zend_llist *l, zend_llist_position *pos)
259
1.32k
{
260
1.32k
  zend_llist_position *current = pos ? pos : &l->traverse_ptr;
261
262
1.32k
  *current = l->head;
263
1.32k
  if (*current) {
264
1.32k
    return (*current)->data;
265
1.32k
  } else {
266
0
    return NULL;
267
0
  }
268
1.32k
}
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
1.32k
{
286
1.32k
  zend_llist_position *current = pos ? pos : &l->traverse_ptr;
287
288
1.32k
  if (*current) {
289
1.32k
    *current = (*current)->next;
290
1.32k
    if (*current) {
291
0
      return (*current)->data;
292
0
    }
293
1.32k
  }
294
1.32k
  return NULL;
295
1.32k
}
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
}