| @@ -1,288 +1,292 @@ | | | @@ -1,288 +1,292 @@ |
1 | /* $NetBSD: lst.c,v 1.104 2021/02/01 19:39:31 rillig Exp $ */ | | 1 | /* $NetBSD: lst.c,v 1.105 2021/03/15 16:45:30 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include "make.h" | | 35 | #include "make.h" |
36 | | | 36 | |
37 | MAKE_RCSID("$NetBSD: lst.c,v 1.104 2021/02/01 19:39:31 rillig Exp $"); | | 37 | MAKE_RCSID("$NetBSD: lst.c,v 1.105 2021/03/15 16:45:30 rillig Exp $"); |
38 | | | 38 | |
39 | static ListNode * | | 39 | static ListNode * |
40 | LstNodeNew(ListNode *prev, ListNode *next, void *datum) | | 40 | LstNodeNew(ListNode *prev, ListNode *next, void *datum) |
41 | { | | 41 | { |
42 | ListNode *ln = bmake_malloc(sizeof *ln); | | 42 | ListNode *ln = bmake_malloc(sizeof *ln); |
43 | | | 43 | |
44 | ln->prev = prev; | | 44 | ln->prev = prev; |
45 | ln->next = next; | | 45 | ln->next = next; |
46 | ln->datum = datum; | | 46 | ln->datum = datum; |
47 | | | 47 | |
48 | return ln; | | 48 | return ln; |
49 | } | | 49 | } |
50 | | | 50 | |
51 | /* Create and initialize a new, empty list. */ | | 51 | /* Create and initialize a new, empty list. */ |
52 | List * | | 52 | List * |
53 | Lst_New(void) | | 53 | Lst_New(void) |
54 | { | | 54 | { |
55 | List *list = bmake_malloc(sizeof *list); | | 55 | List *list = bmake_malloc(sizeof *list); |
56 | Lst_Init(list); | | 56 | Lst_Init(list); |
57 | return list; | | 57 | return list; |
58 | } | | 58 | } |
59 | | | 59 | |
60 | void | | 60 | void |
61 | Lst_Done(List *list) | | 61 | Lst_Done(List *list) |
62 | { | | 62 | { |
63 | ListNode *ln, *next; | | 63 | ListNode *ln, *next; |
64 | | | 64 | |
65 | for (ln = list->first; ln != NULL; ln = next) { | | 65 | for (ln = list->first; ln != NULL; ln = next) { |
66 | next = ln->next; | | 66 | next = ln->next; |
67 | free(ln); | | 67 | free(ln); |
68 | } | | 68 | } |
69 | } | | 69 | } |
70 | | | 70 | |
71 | void | | 71 | void |
72 | Lst_DoneCall(List *list, LstFreeProc freeProc) | | 72 | Lst_DoneCall(List *list, LstFreeProc freeProc) |
73 | { | | 73 | { |
74 | ListNode *ln, *next; | | 74 | ListNode *ln, *next; |
75 | | | 75 | |
76 | for (ln = list->first; ln != NULL; ln = next) { | | 76 | for (ln = list->first; ln != NULL; ln = next) { |
77 | next = ln->next; | | 77 | next = ln->next; |
78 | freeProc(ln->datum); | | 78 | freeProc(ln->datum); |
79 | free(ln); | | 79 | free(ln); |
80 | } | | 80 | } |
81 | } | | 81 | } |
82 | | | 82 | |
83 | /* Free a list and all its nodes. The node data are not freed though. */ | | 83 | /* Free a list and all its nodes. The node data are not freed though. */ |
84 | void | | 84 | void |
85 | Lst_Free(List *list) | | 85 | Lst_Free(List *list) |
86 | { | | 86 | { |
87 | | | 87 | |
88 | Lst_Done(list); | | 88 | Lst_Done(list); |
89 | free(list); | | 89 | free(list); |
90 | } | | 90 | } |
91 | | | 91 | |
92 | /* Insert a new node with the datum before the given node. */ | | 92 | /* Insert a new node with the datum before the given node. */ |
93 | void | | 93 | void |
94 | Lst_InsertBefore(List *list, ListNode *ln, void *datum) | | 94 | Lst_InsertBefore(List *list, ListNode *ln, void *datum) |
95 | { | | 95 | { |
96 | ListNode *newNode; | | 96 | ListNode *newNode; |
97 | | | 97 | |
98 | assert(datum != NULL); | | 98 | assert(datum != NULL); |
99 | | | 99 | |
100 | newNode = LstNodeNew(ln->prev, ln, datum); | | 100 | newNode = LstNodeNew(ln->prev, ln, datum); |
101 | | | 101 | |
102 | if (ln->prev != NULL) | | 102 | if (ln->prev != NULL) |
103 | ln->prev->next = newNode; | | 103 | ln->prev->next = newNode; |
104 | ln->prev = newNode; | | 104 | ln->prev = newNode; |
105 | | | 105 | |
106 | if (ln == list->first) | | 106 | if (ln == list->first) |
107 | list->first = newNode; | | 107 | list->first = newNode; |
108 | } | | 108 | } |
109 | | | 109 | |
110 | /* Add a piece of data at the start of the given list. */ | | 110 | /* Add a piece of data at the start of the given list. */ |
111 | void | | 111 | void |
112 | Lst_Prepend(List *list, void *datum) | | 112 | Lst_Prepend(List *list, void *datum) |
113 | { | | 113 | { |
114 | ListNode *ln; | | 114 | ListNode *ln; |
115 | | | 115 | |
116 | assert(datum != NULL); | | 116 | assert(datum != NULL); |
117 | | | 117 | |
118 | ln = LstNodeNew(NULL, list->first, datum); | | 118 | ln = LstNodeNew(NULL, list->first, datum); |
119 | | | 119 | |
120 | if (list->first == NULL) { | | 120 | if (list->first == NULL) { |
121 | list->first = ln; | | 121 | list->first = ln; |
122 | list->last = ln; | | 122 | list->last = ln; |
123 | } else { | | 123 | } else { |
124 | list->first->prev = ln; | | 124 | list->first->prev = ln; |
125 | list->first = ln; | | 125 | list->first = ln; |
126 | } | | 126 | } |
127 | } | | 127 | } |
128 | | | 128 | |
129 | /* Add a piece of data at the end of the given list. */ | | 129 | /* Add a piece of data at the end of the given list. */ |
130 | void | | 130 | void |
131 | Lst_Append(List *list, void *datum) | | 131 | Lst_Append(List *list, void *datum) |
132 | { | | 132 | { |
133 | ListNode *ln; | | 133 | ListNode *ln; |
134 | | | 134 | |
135 | assert(datum != NULL); | | 135 | assert(datum != NULL); |
136 | | | 136 | |
137 | ln = LstNodeNew(list->last, NULL, datum); | | 137 | ln = LstNodeNew(list->last, NULL, datum); |
138 | | | 138 | |
139 | if (list->last == NULL) { | | 139 | if (list->last == NULL) { |
140 | list->first = ln; | | 140 | list->first = ln; |
141 | list->last = ln; | | 141 | list->last = ln; |
142 | } else { | | 142 | } else { |
143 | list->last->next = ln; | | 143 | list->last->next = ln; |
144 | list->last = ln; | | 144 | list->last = ln; |
145 | } | | 145 | } |
146 | } | | 146 | } |
147 | | | 147 | |
148 | /* | | 148 | /* |
149 | * Remove the given node from the given list. | | 149 | * Remove the given node from the given list. |
150 | * The datum stored in the node must be freed by the caller, if necessary. | | 150 | * The datum stored in the node must be freed by the caller, if necessary. |
151 | */ | | 151 | */ |
152 | void | | 152 | void |
153 | Lst_Remove(List *list, ListNode *ln) | | 153 | Lst_Remove(List *list, ListNode *ln) |
154 | { | | 154 | { |
155 | /* unlink it from its neighbors */ | | 155 | /* unlink it from its neighbors */ |
156 | if (ln->next != NULL) | | 156 | if (ln->next != NULL) |
157 | ln->next->prev = ln->prev; | | 157 | ln->next->prev = ln->prev; |
158 | if (ln->prev != NULL) | | 158 | if (ln->prev != NULL) |
159 | ln->prev->next = ln->next; | | 159 | ln->prev->next = ln->next; |
160 | | | 160 | |
161 | /* unlink it from the list */ | | 161 | /* unlink it from the list */ |
162 | if (list->first == ln) | | 162 | if (list->first == ln) |
163 | list->first = ln->next; | | 163 | list->first = ln->next; |
164 | if (list->last == ln) | | 164 | if (list->last == ln) |
165 | list->last = ln->prev; | | 165 | list->last = ln->prev; |
166 | } | | 166 | } |
167 | | | 167 | |
168 | /* Replace the datum in the given node with the new datum. */ | | 168 | /* Replace the datum in the given node with the new datum. */ |
169 | void | | 169 | void |
170 | LstNode_Set(ListNode *ln, void *datum) | | 170 | LstNode_Set(ListNode *ln, void *datum) |
171 | { | | 171 | { |
172 | assert(datum != NULL); | | 172 | assert(datum != NULL); |
173 | | | 173 | |
174 | ln->datum = datum; | | 174 | ln->datum = datum; |
175 | } | | 175 | } |
176 | | | 176 | |
177 | /* | | 177 | /* |
178 | * Replace the datum in the given node with NULL. | | 178 | * Replace the datum in the given node with NULL. |
179 | * Having NULL values in a list is unusual though. | | 179 | * Having NULL values in a list is unusual though. |
180 | */ | | 180 | */ |
181 | void | | 181 | void |
182 | LstNode_SetNull(ListNode *ln) | | 182 | LstNode_SetNull(ListNode *ln) |
183 | { | | 183 | { |
184 | ln->datum = NULL; | | 184 | ln->datum = NULL; |
185 | } | | 185 | } |
186 | | | 186 | |
187 | /* | | 187 | /* |
188 | * Return the first node that contains the given datum, or NULL. | | 188 | * Return the first node that contains the given datum, or NULL. |
189 | * | | 189 | * |
190 | * Time complexity: O(length(list)) | | 190 | * Time complexity: O(length(list)) |
191 | */ | | 191 | */ |
192 | ListNode * | | 192 | ListNode * |
193 | Lst_FindDatum(List *list, const void *datum) | | 193 | Lst_FindDatum(List *list, const void *datum) |
194 | { | | 194 | { |
195 | ListNode *ln; | | 195 | ListNode *ln; |
196 | | | 196 | |
197 | assert(datum != NULL); | | 197 | assert(datum != NULL); |
198 | | | 198 | |
199 | for (ln = list->first; ln != NULL; ln = ln->next) | | 199 | for (ln = list->first; ln != NULL; ln = ln->next) |
200 | if (ln->datum == datum) | | 200 | if (ln->datum == datum) |
201 | return ln; | | 201 | return ln; |
202 | | | 202 | |
203 | return NULL; | | 203 | return NULL; |
204 | } | | 204 | } |
205 | | | 205 | |
206 | /* | | 206 | /* |
207 | * Move all nodes from src to the end of dst. | | 207 | * Move all nodes from src to the end of dst. |
208 | * The source list becomes empty but is not freed. | | 208 | * The source list becomes indeterminate. |
209 | */ | | 209 | */ |
210 | void | | 210 | void |
211 | Lst_MoveAll(List *dst, List *src) | | 211 | Lst_MoveAll(List *dst, List *src) |
212 | { | | 212 | { |
213 | if (src->first != NULL) { | | 213 | if (src->first != NULL) { |
214 | src->first->prev = dst->last; | | 214 | src->first->prev = dst->last; |
215 | if (dst->last != NULL) | | 215 | if (dst->last != NULL) |
216 | dst->last->next = src->first; | | 216 | dst->last->next = src->first; |
217 | else | | 217 | else |
218 | dst->first = src->first; | | 218 | dst->first = src->first; |
219 | | | 219 | |
220 | dst->last = src->last; | | 220 | dst->last = src->last; |
221 | } | | 221 | } |
| | | 222 | #ifdef CLEANUP |
| | | 223 | src->first = NULL; |
| | | 224 | src->last = NULL; |
| | | 225 | #endif |
222 | } | | 226 | } |
223 | | | 227 | |
224 | /* Copy the element data from src to the start of dst. */ | | 228 | /* Copy the element data from src to the start of dst. */ |
225 | void | | 229 | void |
226 | Lst_PrependAll(List *dst, List *src) | | 230 | Lst_PrependAll(List *dst, List *src) |
227 | { | | 231 | { |
228 | ListNode *ln; | | 232 | ListNode *ln; |
229 | | | 233 | |
230 | for (ln = src->last; ln != NULL; ln = ln->prev) | | 234 | for (ln = src->last; ln != NULL; ln = ln->prev) |
231 | Lst_Prepend(dst, ln->datum); | | 235 | Lst_Prepend(dst, ln->datum); |
232 | } | | 236 | } |
233 | | | 237 | |
234 | /* Copy the element data from src to the end of dst. */ | | 238 | /* Copy the element data from src to the end of dst. */ |
235 | void | | 239 | void |
236 | Lst_AppendAll(List *dst, List *src) | | 240 | Lst_AppendAll(List *dst, List *src) |
237 | { | | 241 | { |
238 | ListNode *ln; | | 242 | ListNode *ln; |
239 | | | 243 | |
240 | for (ln = src->first; ln != NULL; ln = ln->next) | | 244 | for (ln = src->first; ln != NULL; ln = ln->next) |
241 | Lst_Append(dst, ln->datum); | | 245 | Lst_Append(dst, ln->datum); |
242 | } | | 246 | } |
243 | | | 247 | |
244 | /* Remove and return the datum at the head of the given list. */ | | 248 | /* Remove and return the datum at the head of the given list. */ |
245 | void * | | 249 | void * |
246 | Lst_Dequeue(List *list) | | 250 | Lst_Dequeue(List *list) |
247 | { | | 251 | { |
248 | void *datum = list->first->datum; | | 252 | void *datum = list->first->datum; |
249 | Lst_Remove(list, list->first); | | 253 | Lst_Remove(list, list->first); |
250 | assert(datum != NULL); /* since NULL would mean end of the list */ | | 254 | assert(datum != NULL); /* since NULL would mean end of the list */ |
251 | return datum; | | 255 | return datum; |
252 | } | | 256 | } |
253 | | | 257 | |
254 | void | | 258 | void |
255 | Vector_Init(Vector *v, size_t itemSize) | | 259 | Vector_Init(Vector *v, size_t itemSize) |
256 | { | | 260 | { |
257 | v->len = 0; | | 261 | v->len = 0; |
258 | v->cap = 10; | | 262 | v->cap = 10; |
259 | v->itemSize = itemSize; | | 263 | v->itemSize = itemSize; |
260 | v->items = bmake_malloc(v->cap * v->itemSize); | | 264 | v->items = bmake_malloc(v->cap * v->itemSize); |
261 | } | | 265 | } |
262 | | | 266 | |
263 | /* | | 267 | /* |
264 | * Add space for a new item to the vector and return a pointer to that space. | | 268 | * Add space for a new item to the vector and return a pointer to that space. |
265 | * The returned data is valid until the next modifying operation. | | 269 | * The returned data is valid until the next modifying operation. |
266 | */ | | 270 | */ |
267 | void * | | 271 | void * |
268 | Vector_Push(Vector *v) | | 272 | Vector_Push(Vector *v) |
269 | { | | 273 | { |
270 | if (v->len >= v->cap) { | | 274 | if (v->len >= v->cap) { |
271 | v->cap *= 2; | | 275 | v->cap *= 2; |
272 | v->items = bmake_realloc(v->items, v->cap * v->itemSize); | | 276 | v->items = bmake_realloc(v->items, v->cap * v->itemSize); |
273 | } | | 277 | } |
274 | v->len++; | | 278 | v->len++; |
275 | return Vector_Get(v, v->len - 1); | | 279 | return Vector_Get(v, v->len - 1); |
276 | } | | 280 | } |
277 | | | 281 | |
278 | /* | | 282 | /* |
279 | * Remove the last item from the vector, return the pointer to it. | | 283 | * Remove the last item from the vector, return the pointer to it. |
280 | * The returned data is valid until the next modifying operation. | | 284 | * The returned data is valid until the next modifying operation. |
281 | */ | | 285 | */ |
282 | void * | | 286 | void * |
283 | Vector_Pop(Vector *v) | | 287 | Vector_Pop(Vector *v) |
284 | { | | 288 | { |
285 | assert(v->len > 0); | | 289 | assert(v->len > 0); |
286 | v->len--; | | 290 | v->len--; |
287 | return Vector_Get(v, v->len); | | 291 | return Vector_Get(v, v->len); |
288 | } | | 292 | } |