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 | } |