quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

llist.c (6546B)


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