Home | History | Annotate | Line # | Download | only in make
lst.c revision 1.90
      1 /* $NetBSD: lst.c,v 1.90 2020/10/25 13:06:12 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.90 2020/10/25 13:06:12 rillig Exp $");
     38 
     39 static ListNode *
     40 LstNodeNew(ListNode *prev, ListNode *next, void *datum)
     41 {
     42     ListNode *node = bmake_malloc(sizeof *node);
     43     node->prev = prev;
     44     node->next = next;
     45     node->datum = datum;
     46     return node;
     47 }
     48 
     49 /* Create and initialize a new, empty list. */
     50 List *
     51 Lst_New(void)
     52 {
     53     List *list = bmake_malloc(sizeof *list);
     54 
     55     list->first = NULL;
     56     list->last = NULL;
     57 
     58     return list;
     59 }
     60 
     61 /* Free a list and all its nodes. The node data are not freed though. */
     62 void
     63 Lst_Free(List *list)
     64 {
     65     ListNode *node;
     66     ListNode *next;
     67 
     68     for (node = list->first; node != NULL; node = next) {
     69 	next = node->next;
     70 	free(node);
     71     }
     72 
     73     free(list);
     74 }
     75 
     76 /* Destroy a list and free all its resources. The freeProc is called with the
     77  * datum from each node in turn before the node is freed. */
     78 void
     79 Lst_Destroy(List *list, LstFreeProc freeProc)
     80 {
     81     ListNode *node;
     82     ListNode *next;
     83 
     84     for (node = list->first; node != NULL; node = next) {
     85 	next = node->next;
     86 	freeProc(node->datum);
     87 	free(node);
     88     }
     89 
     90     free(list);
     91 }
     92 
     93 /*
     94  * Functions to modify a list
     95  */
     96 
     97 /* Insert a new node with the datum before the given node. */
     98 void
     99 Lst_InsertBefore(List *list, ListNode *node, void *datum)
    100 {
    101     ListNode *newNode;
    102 
    103     assert(datum != NULL);
    104 
    105     newNode = LstNodeNew(node->prev, node, datum);
    106 
    107     if (node->prev != NULL)
    108 	node->prev->next = newNode;
    109     node->prev = newNode;
    110 
    111     if (node == list->first)
    112 	list->first = newNode;
    113 }
    114 
    115 /* Add a piece of data at the start of the given list. */
    116 void
    117 Lst_Prepend(List *list, void *datum)
    118 {
    119     ListNode *node;
    120 
    121     assert(datum != NULL);
    122 
    123     node = LstNodeNew(NULL, list->first, datum);
    124 
    125     if (list->first == NULL) {
    126 	list->first = node;
    127 	list->last = node;
    128     } else {
    129 	list->first->prev = node;
    130 	list->first = node;
    131     }
    132 }
    133 
    134 /* Add a piece of data at the end of the given list. */
    135 void
    136 Lst_Append(List *list, void *datum)
    137 {
    138     ListNode *node;
    139 
    140     assert(datum != NULL);
    141 
    142     node = LstNodeNew(list->last, NULL, datum);
    143 
    144     if (list->last == NULL) {
    145 	list->first = node;
    146 	list->last = node;
    147     } else {
    148 	list->last->next = node;
    149 	list->last = node;
    150     }
    151 }
    152 
    153 /* Remove the given node from the given list.
    154  * The datum stored in the node must be freed by the caller, if necessary. */
    155 void
    156 Lst_Remove(List *list, ListNode *node)
    157 {
    158     /* unlink it from its neighbors */
    159     if (node->next != NULL)
    160 	node->next->prev = node->prev;
    161     if (node->prev != NULL)
    162 	node->prev->next = node->next;
    163 
    164     /* unlink it from the list */
    165     if (list->first == node)
    166 	list->first = node->next;
    167     if (list->last == node)
    168 	list->last = node->prev;
    169 }
    170 
    171 /* Replace the datum in the given node with the new datum. */
    172 void
    173 LstNode_Set(ListNode *node, void *datum)
    174 {
    175     assert(datum != NULL);
    176 
    177     node->datum = datum;
    178 }
    179 
    180 /* Replace the datum in the given node to NULL.
    181  * Having NULL values in a list is unusual though. */
    182 void
    183 LstNode_SetNull(ListNode *node)
    184 {
    185     node->datum = NULL;
    186 }
    187 
    188 /*
    189  * Functions for entire lists
    190  */
    191 
    192 /* Return the first node that contains the given datum, or NULL. */
    193 ListNode *
    194 Lst_FindDatum(List *list, const void *datum)
    195 {
    196     ListNode *node;
    197 
    198     assert(datum != NULL);
    199 
    200     for (node = list->first; node != NULL; node = node->next)
    201 	if (node->datum == datum)
    202 	    return node;
    203 
    204     return NULL;
    205 }
    206 
    207 int
    208 Lst_ForEachUntil(List *list, LstActionUntilProc proc, void *procData)
    209 {
    210     ListNode *node;
    211     int result = 0;
    212 
    213     for (node = list->first; node != NULL; node = node->next) {
    214 	result = proc(node->datum, procData);
    215 	if (result != 0)
    216 	    break;
    217     }
    218     return result;
    219 }
    220 
    221 /* Move all nodes from list2 to the end of list1.
    222  * List2 is destroyed and freed. */
    223 void
    224 Lst_MoveAll(List *list1, List *list2)
    225 {
    226     if (list2->first != NULL) {
    227 	list2->first->prev = list1->last;
    228 	if (list1->last != NULL)
    229 	    list1->last->next = list2->first;
    230 	else
    231 	    list1->first = list2->first;
    232 
    233 	list1->last = list2->last;
    234     }
    235     free(list2);
    236 }
    237 
    238 /* Copy the element data from src to the start of dst. */
    239 void
    240 Lst_PrependAll(List *dst, List *src)
    241 {
    242     ListNode *node;
    243     for (node = src->last; node != NULL; node = node->prev)
    244 	Lst_Prepend(dst, node->datum);
    245 }
    246 
    247 /* Copy the element data from src to the end of dst. */
    248 void
    249 Lst_AppendAll(List *dst, List *src)
    250 {
    251     ListNode *node;
    252     for (node = src->first; node != NULL; node = node->next)
    253 	Lst_Append(dst, node->datum);
    254 }
    255 
    256 /*
    257  * for using the list as a queue
    258  */
    259 
    260 /* Add the datum to the tail of the given list. */
    261 void
    262 Lst_Enqueue(List *list, void *datum)
    263 {
    264     Lst_Append(list, datum);
    265 }
    266 
    267 /* Remove and return the datum at the head of the given list. */
    268 void *
    269 Lst_Dequeue(List *list)
    270 {
    271     void *datum = list->first->datum;
    272     Lst_Remove(list, list->first);
    273     assert(datum != NULL);	/* since NULL would mean end of the list */
    274     return datum;
    275 }
    276 
    277 void
    278 Vector_Init(Vector *v, size_t itemSize)
    279 {
    280     v->len = 0;
    281     v->priv_cap = 10;
    282     v->itemSize = itemSize;
    283     v->items = bmake_malloc(v->priv_cap * v->itemSize);
    284 }
    285 
    286 /* Return the pointer to the given item in the vector.
    287  * The returned data is valid until the next modifying operation. */
    288 void *
    289 Vector_Get(Vector *v, size_t i)
    290 {
    291     unsigned char *items = v->items;
    292     return items + i * v->itemSize;
    293 }
    294 
    295 /* Add space for a new item to the vector and return a pointer to that space.
    296  * The returned data is valid until the next modifying operation. */
    297 void *
    298 Vector_Push(Vector *v)
    299 {
    300     if (v->len >= v->priv_cap) {
    301 	v->priv_cap *= 2;
    302 	v->items = bmake_realloc(v->items, v->priv_cap * v->itemSize);
    303     }
    304     v->len++;
    305     return Vector_Get(v, v->len - 1);
    306 }
    307 
    308 /* Return the pointer to the last item in the vector.
    309  * The returned data is valid until the next modifying operation. */
    310 void *
    311 Vector_Pop(Vector *v)
    312 {
    313     assert(v->len > 0);
    314     v->len--;
    315     return Vector_Get(v, v->len);
    316 }
    317 
    318 void
    319 Vector_Done(Vector *v)
    320 {
    321     free(v->items);
    322 }
    323