Coverage Report

Created: 2026-07-30 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/llist.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#include "llist.h"
27
28
#ifdef DEBUGBUILD
29
21.1M
#define LLISTINIT 0x100cc001 /* random pattern */
30
1.15M
#define NODEINIT  0x12344321 /* random pattern */
31
922k
#define NODEREM   0x54321012 /* random pattern */
32
33
58.5M
#define VERIFYNODE(x) verifynode(x)
34
static struct Curl_llist_node *verifynode(struct Curl_llist_node *n)
35
58.5M
{
36
58.5M
  DEBUGASSERT(!n || (n->_init == NODEINIT));
37
58.5M
  return n;
38
58.5M
}
39
#else
40
#define VERIFYNODE(x) x
41
#endif
42
/*
43
 * @unittest 1300
44
 */
45
void Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
46
21.1M
{
47
21.1M
  l->_size = 0;
48
21.1M
  l->_dtor = dtor;
49
21.1M
  l->_head = NULL;
50
21.1M
  l->_tail = NULL;
51
21.1M
#ifdef DEBUGBUILD
52
21.1M
  l->_init = LLISTINIT;
53
21.1M
#endif
54
21.1M
}
55
56
/*
57
 * Curl_llist_insert_next()
58
 *
59
 * Inserts a new list element after the given one 'e'. If the given existing
60
 * entry is NULL and the list already has elements, the new one will be
61
 * inserted first in the list.
62
 *
63
 * The 'ne' argument should be a pointer into the object to store.
64
 *
65
 * @unittest 1300
66
 */
67
void Curl_llist_insert_next(struct Curl_llist *list,
68
                            struct Curl_llist_node *e, /* may be NULL */
69
                            const void *p,
70
                            struct Curl_llist_node *ne)
71
1.15M
{
72
1.15M
  DEBUGASSERT(list);
73
1.15M
  DEBUGASSERT(list->_init == LLISTINIT);
74
1.15M
  DEBUGASSERT(ne);
75
76
1.15M
#ifdef DEBUGBUILD
77
1.15M
  ne->_init = NODEINIT;
78
1.15M
#endif
79
1.15M
  ne->_ptr = CURL_UNCONST(p);
80
1.15M
  ne->_list = list;
81
1.15M
  if(list->_size == 0) {
82
550k
    list->_head = ne;
83
550k
    list->_head->_prev = NULL;
84
550k
    list->_head->_next = NULL;
85
550k
    list->_tail = ne;
86
550k
  }
87
602k
  else {
88
    /* if 'e' is NULL here, we insert the new element first in the list */
89
602k
    ne->_next = e ? e->_next : list->_head;
90
602k
    ne->_prev = e;
91
602k
    if(!e) {
92
117k
      list->_head->_prev = ne;
93
117k
      list->_head = ne;
94
117k
    }
95
484k
    else if(e->_next) {
96
89.4k
      e->_next->_prev = ne;
97
89.4k
    }
98
395k
    else {
99
395k
      list->_tail = ne;
100
395k
    }
101
602k
    if(e)
102
484k
      e->_next = ne;
103
602k
  }
104
105
1.15M
  ++list->_size;
106
1.15M
}
107
108
/*
109
 * Curl_llist_append()
110
 *
111
 * Adds a new list element to the end of the list.
112
 *
113
 * The 'ne' argument should be a pointer into the object to store.
114
 *
115
 * @unittest 1300
116
 */
117
void Curl_llist_append(struct Curl_llist *list, const void *p,
118
                       struct Curl_llist_node *ne)
119
640k
{
120
640k
  DEBUGASSERT(list);
121
640k
  DEBUGASSERT(list->_init == LLISTINIT);
122
640k
  DEBUGASSERT(ne);
123
640k
  Curl_llist_insert_next(list, list->_tail, p, ne);
124
640k
}
125
126
void *Curl_node_take_elem(struct Curl_llist_node *e)
127
922k
{
128
922k
  void *ptr;
129
922k
  struct Curl_llist *list;
130
922k
  if(!e)
131
0
    return NULL;
132
133
922k
  list = e->_list;
134
922k
  DEBUGASSERT(list);
135
922k
  DEBUGASSERT(list->_init == LLISTINIT);
136
922k
  DEBUGASSERT(list->_size);
137
922k
  DEBUGASSERT(e->_init == NODEINIT);
138
922k
  if(list) {
139
922k
    if(e == list->_head) {
140
663k
      list->_head = e->_next;
141
142
663k
      if(!list->_head)
143
534k
        list->_tail = NULL;
144
128k
      else
145
128k
        e->_next->_prev = NULL;
146
663k
    }
147
258k
    else {
148
258k
      if(e->_prev)
149
258k
        e->_prev->_next = e->_next;
150
151
258k
      if(!e->_next)
152
173k
        list->_tail = e->_prev;
153
85.4k
      else
154
85.4k
        e->_next->_prev = e->_prev;
155
258k
    }
156
922k
    --list->_size;
157
922k
  }
158
922k
  ptr = e->_ptr;
159
160
922k
  e->_list = NULL;
161
922k
  e->_ptr  = NULL;
162
922k
  e->_prev = NULL;
163
922k
  e->_next = NULL;
164
922k
#ifdef DEBUGBUILD
165
922k
  e->_init = NODEREM; /* specific pattern on remove - not zero */
166
922k
#endif
167
168
922k
  return ptr;
169
922k
}
170
171
static void node_uremove(struct Curl_llist_node *e, void *user)
172
908k
{
173
908k
  struct Curl_llist *list;
174
908k
  void *ptr;
175
908k
  if(!e)
176
0
    return;
177
178
908k
  list = e->_list;
179
908k
  DEBUGASSERT(list);
180
908k
  if(list) {
181
908k
    ptr = Curl_node_take_elem(e);
182
908k
    if(list->_dtor)
183
2.18k
      list->_dtor(user, ptr);
184
908k
  }
185
908k
}
186
187
void Curl_node_remove(struct Curl_llist_node *e)
188
726k
{
189
726k
  node_uremove(e, NULL);
190
726k
}
191
192
void Curl_llist_destroy(struct Curl_llist *list, void *user)
193
5.44M
{
194
5.44M
  if(list) {
195
5.44M
    DEBUGASSERT(list->_init == LLISTINIT);
196
5.62M
    while(list->_size > 0)
197
182k
      node_uremove(list->_tail, user);
198
5.44M
  }
199
5.44M
}
200
201
/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
202
   might be NULL */
203
struct Curl_llist_node *Curl_llist_head(const struct Curl_llist *list)
204
56.0M
{
205
56.0M
  DEBUGASSERT(list);
206
56.0M
  DEBUGASSERT(list->_init == LLISTINIT);
207
56.0M
  return VERIFYNODE(list->_head);
208
56.0M
}
209
210
#ifdef UNITTESTS
211
/* llist_tail() returns the last 'struct Curl_llist_node *', which might be
212
   NULL
213
214
   @unittest 1300 */
215
UNITTEST struct Curl_llist_node *llist_tail(const struct Curl_llist *list);
216
UNITTEST struct Curl_llist_node *llist_tail(const struct Curl_llist *list)
217
0
{
218
0
  DEBUGASSERT(list);
219
0
  DEBUGASSERT(list->_init == LLISTINIT);
220
0
  return VERIFYNODE(list->_tail);
221
0
}
222
#endif
223
224
/* Curl_llist_count() returns a size_t the number of nodes in the list */
225
size_t Curl_llist_count(const struct Curl_llist *list)
226
18.1M
{
227
18.1M
  DEBUGASSERT(list);
228
18.1M
  DEBUGASSERT(list->_init == LLISTINIT);
229
18.1M
  return list->_size;
230
18.1M
}
231
232
/* Curl_node_elem() returns the custom data from a Curl_llist_node */
233
void *Curl_node_elem(const struct Curl_llist_node *n)
234
3.20M
{
235
3.20M
  DEBUGASSERT(n);
236
3.20M
  DEBUGASSERT(n->_init == NODEINIT);
237
3.20M
  return n->_ptr;
238
3.20M
}
239
240
/* Curl_node_next() returns the next element in a list from a given
241
   Curl_llist_node */
242
struct Curl_llist_node *Curl_node_next(const struct Curl_llist_node *n)
243
2.43M
{
244
2.43M
  DEBUGASSERT(n);
245
2.43M
  DEBUGASSERT(n->_init == NODEINIT);
246
2.43M
  return VERIFYNODE(n->_next);
247
2.43M
}
248
249
#ifdef UNITTESTS
250
/* llist_node_prev() returns the previous element in a list from a given
251
   Curl_llist_node
252
253
   @unittest 1300 */
254
UNITTEST struct Curl_llist_node *llist_node_prev(
255
  const struct Curl_llist_node *n);
256
UNITTEST struct Curl_llist_node *llist_node_prev(
257
  const struct Curl_llist_node *n)
258
0
{
259
0
  DEBUGASSERT(n);
260
0
  DEBUGASSERT(n->_init == NODEINIT);
261
0
  return VERIFYNODE(n->_prev);
262
0
}
263
#endif
264
265
struct Curl_llist *Curl_node_llist(const struct Curl_llist_node *n)
266
417k
{
267
417k
  DEBUGASSERT(n);
268
417k
  DEBUGASSERT(!n->_list || n->_init == NODEINIT);
269
417k
  return n->_list;
270
417k
}