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