Coverage Report

Created: 2025-08-26 07:17

/src/curl/lib/llist.c
Line
Count
Source (jump to first uncovered line)
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
25
#include "curl_setup.h"
26
27
#include <curl/curl.h>
28
29
#include "llist.h"
30
#include "curl_memory.h"
31
32
/* this must be the last include file */
33
#include "memdebug.h"
34
35
#ifdef DEBUGBUILD
36
16.5M
#define LLISTINIT 0x100cc001 /* random pattern */
37
7.73M
#define NODEINIT  0x12344321 /* random pattern */
38
7.48M
#define NODEREM   0x54321012 /* random pattern */
39
40
228M
#define VERIFYNODE(x) verifynode(x)
41
static struct Curl_llist_node *verifynode(struct Curl_llist_node *n)
42
228M
{
43
228M
  DEBUGASSERT(!n || (n->_init == NODEINIT));
44
228M
  return n;
45
228M
}
46
#else
47
#define VERIFYNODE(x) x
48
#endif
49
/*
50
 * @unittest: 1300
51
 */
52
void
53
Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
54
16.5M
{
55
16.5M
  l->_size = 0;
56
16.5M
  l->_dtor = dtor;
57
16.5M
  l->_head = NULL;
58
16.5M
  l->_tail = NULL;
59
16.5M
#ifdef DEBUGBUILD
60
16.5M
  l->_init = LLISTINIT;
61
16.5M
#endif
62
16.5M
}
63
64
/*
65
 * Curl_llist_insert_next()
66
 *
67
 * Inserts a new list element after the given one 'e'. If the given existing
68
 * entry is NULL and the list already has elements, the new one will be
69
 * inserted first in the list.
70
 *
71
 * The 'ne' argument should be a pointer into the object to store.
72
 *
73
 * @unittest: 1300
74
 */
75
void
76
Curl_llist_insert_next(struct Curl_llist *list,
77
                       struct Curl_llist_node *e, /* may be NULL */
78
                       const void *p,
79
                       struct Curl_llist_node *ne)
80
7.73M
{
81
7.73M
  DEBUGASSERT(list);
82
7.73M
  DEBUGASSERT(list->_init == LLISTINIT);
83
7.73M
  DEBUGASSERT(ne);
84
85
7.73M
#ifdef DEBUGBUILD
86
7.73M
  ne->_init = NODEINIT;
87
7.73M
#endif
88
7.73M
  ne->_ptr = CURL_UNCONST(p);
89
7.73M
  ne->_list = list;
90
7.73M
  if(list->_size == 0) {
91
460k
    list->_head = ne;
92
460k
    list->_head->_prev = NULL;
93
460k
    list->_head->_next = NULL;
94
460k
    list->_tail = ne;
95
460k
  }
96
7.27M
  else {
97
    /* if 'e' is NULL here, we insert the new element first in the list */
98
7.27M
    ne->_next = e ? e->_next : list->_head;
99
7.27M
    ne->_prev = e;
100
7.27M
    if(!e) {
101
645k
      list->_head->_prev = ne;
102
645k
      list->_head = ne;
103
645k
    }
104
6.63M
    else if(e->_next) {
105
1.41M
      e->_next->_prev = ne;
106
1.41M
    }
107
5.21M
    else {
108
5.21M
      list->_tail = ne;
109
5.21M
    }
110
7.27M
    if(e)
111
6.63M
      e->_next = ne;
112
7.27M
  }
113
114
7.73M
  ++list->_size;
115
7.73M
}
116
117
/*
118
 * Curl_llist_append()
119
 *
120
 * Adds a new list element to the end of the list.
121
 *
122
 * The 'ne' argument should be a pointer into the object to store.
123
 *
124
 * @unittest: 1300
125
 */
126
void
127
Curl_llist_append(struct Curl_llist *list, const void *p,
128
                  struct Curl_llist_node *ne)
129
573k
{
130
573k
  DEBUGASSERT(list);
131
573k
  DEBUGASSERT(list->_init == LLISTINIT);
132
573k
  DEBUGASSERT(ne);
133
573k
  Curl_llist_insert_next(list, list->_tail, p, ne);
134
573k
}
135
136
void *Curl_node_take_elem(struct Curl_llist_node *e)
137
7.48M
{
138
7.48M
  void *ptr;
139
7.48M
  struct Curl_llist *list;
140
7.48M
  if(!e)
141
0
    return NULL;
142
143
7.48M
  list = e->_list;
144
7.48M
  DEBUGASSERT(list);
145
7.48M
  DEBUGASSERT(list->_init == LLISTINIT);
146
7.48M
  DEBUGASSERT(list->_size);
147
7.48M
  DEBUGASSERT(e->_init == NODEINIT);
148
7.48M
  if(list) {
149
7.48M
    if(e == list->_head) {
150
1.09M
      list->_head = e->_next;
151
152
1.09M
      if(!list->_head)
153
444k
        list->_tail = NULL;
154
646k
      else
155
646k
        e->_next->_prev = NULL;
156
1.09M
    }
157
6.39M
    else {
158
6.39M
      if(e->_prev)
159
6.39M
        e->_prev->_next = e->_next;
160
161
6.39M
      if(!e->_next)
162
4.97M
        list->_tail = e->_prev;
163
1.41M
      else
164
1.41M
        e->_next->_prev = e->_prev;
165
6.39M
    }
166
7.48M
    --list->_size;
167
7.48M
  }
168
7.48M
  ptr = e->_ptr;
169
170
7.48M
  e->_list = NULL;
171
7.48M
  e->_ptr  = NULL;
172
7.48M
  e->_prev = NULL;
173
7.48M
  e->_next = NULL;
174
7.48M
#ifdef DEBUGBUILD
175
7.48M
  e->_init = NODEREM; /* specific pattern on remove - not zero */
176
7.48M
#endif
177
178
7.48M
  return ptr;
179
7.48M
}
180
181
/*
182
 * @unittest: 1300
183
 */
184
UNITTEST void Curl_node_uremove(struct Curl_llist_node *, void *);
185
UNITTEST void
186
Curl_node_uremove(struct Curl_llist_node *e, void *user)
187
7.48M
{
188
7.48M
  struct Curl_llist *list;
189
7.48M
  void *ptr;
190
7.48M
  if(!e)
191
0
    return;
192
193
7.48M
  list = e->_list;
194
7.48M
  DEBUGASSERT(list);
195
7.48M
  if(list) {
196
7.48M
    ptr = Curl_node_take_elem(e);
197
7.48M
    if(list->_dtor)
198
156
      list->_dtor(user, ptr);
199
7.48M
  }
200
7.48M
}
201
202
void Curl_node_remove(struct Curl_llist_node *e)
203
7.33M
{
204
7.33M
  Curl_node_uremove(e, NULL);
205
7.33M
}
206
207
void
208
Curl_llist_destroy(struct Curl_llist *list, void *user)
209
4.17M
{
210
4.17M
  if(list) {
211
4.17M
    DEBUGASSERT(list->_init == LLISTINIT);
212
4.32M
    while(list->_size > 0)
213
146k
      Curl_node_uremove(list->_tail, user);
214
4.17M
  }
215
4.17M
}
216
217
/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
218
   might be NULL */
219
struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list)
220
215M
{
221
215M
  DEBUGASSERT(list);
222
215M
  DEBUGASSERT(list->_init == LLISTINIT);
223
215M
  return VERIFYNODE(list->_head);
224
215M
}
225
226
#ifdef UNITTESTS
227
/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which
228
   might be NULL */
229
struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list)
230
{
231
  DEBUGASSERT(list);
232
  DEBUGASSERT(list->_init == LLISTINIT);
233
  return VERIFYNODE(list->_tail);
234
}
235
#endif
236
237
/* Curl_llist_count() returns a size_t the number of nodes in the list */
238
size_t Curl_llist_count(struct Curl_llist *list)
239
7.84M
{
240
7.84M
  DEBUGASSERT(list);
241
7.84M
  DEBUGASSERT(list->_init == LLISTINIT);
242
7.84M
  return list->_size;
243
7.84M
}
244
245
/* Curl_node_elem() returns the custom data from a Curl_llist_node */
246
void *Curl_node_elem(struct Curl_llist_node *n)
247
22.5M
{
248
22.5M
  DEBUGASSERT(n);
249
22.5M
  DEBUGASSERT(n->_init == NODEINIT);
250
22.5M
  return n->_ptr;
251
22.5M
}
252
253
/* Curl_node_next() returns the next element in a list from a given
254
   Curl_llist_node */
255
struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n)
256
13.3M
{
257
13.3M
  DEBUGASSERT(n);
258
13.3M
  DEBUGASSERT(n->_init == NODEINIT);
259
13.3M
  return VERIFYNODE(n->_next);
260
13.3M
}
261
262
#ifdef UNITTESTS
263
264
/* Curl_node_prev() returns the previous element in a list from a given
265
   Curl_llist_node */
266
struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n)
267
{
268
  DEBUGASSERT(n);
269
  DEBUGASSERT(n->_init == NODEINIT);
270
  return VERIFYNODE(n->_prev);
271
}
272
273
#endif
274
275
struct Curl_llist *Curl_node_llist(struct Curl_llist_node *n)
276
353k
{
277
353k
  DEBUGASSERT(n);
278
353k
  DEBUGASSERT(!n->_list || n->_init == NODEINIT);
279
353k
  return n->_list;
280
353k
}