Coverage Report

Created: 2025-12-14 06:39

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