1/*	$NetBSD: utarray.h,v 1.5 2024/03/03 17:37:29 christos Exp $	*/
2
3/*-
4Copyright (c) 2008-2021, Troy D. Hanson   http://troydhanson.github.com/uthash/
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9
10    * Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12
13THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
14IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
15TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
17OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*/
25
26/* a dynamic array implementation using macros
27 */
28#ifndef UTARRAY_H
29#define UTARRAY_H
30
31#define UTARRAY_VERSION 2.3.0
32
33#include <stddef.h>  /* size_t */
34#include <string.h>  /* memset, etc */
35#include <stdlib.h>  /* exit */
36
37#ifdef __GNUC__
38#define UTARRAY_UNUSED __attribute__((__unused__))
39#else
40#define UTARRAY_UNUSED
41#endif
42
43#ifdef oom
44#error "The name of macro 'oom' has been changed to 'utarray_oom'. Please update your code."
45#define utarray_oom() oom()
46#endif
47
48#ifndef utarray_oom
49#define utarray_oom() exit(-1)
50#endif
51
52typedef void (ctor_f)(void *dst, const void *src);
53typedef void (dtor_f)(void *elt);
54typedef void (init_f)(void *elt);
55typedef struct {
56    size_t sz;
57    init_f *init;
58    ctor_f *copy;
59    dtor_f *dtor;
60} UT_icd;
61
62typedef struct {
63    unsigned i,n;/* i: index of next available slot, n: num slots */
64    UT_icd icd;  /* initializer, copy and destructor functions */
65    char *d;     /* n slots of size icd->sz*/
66} UT_array;
67
68#define utarray_init(a,_icd) do {                                             \
69  memset(a,0,sizeof(UT_array));                                               \
70  (a)->icd = *(_icd);                                                         \
71} while(0)
72
73#define utarray_done(a) do {                                                  \
74  if ((a)->n) {                                                               \
75    if ((a)->icd.dtor) {                                                      \
76      unsigned _ut_i;                                                         \
77      for(_ut_i=0; _ut_i < (a)->i; _ut_i++) {                                 \
78        (a)->icd.dtor(utarray_eltptr(a,_ut_i));                               \
79      }                                                                       \
80    }                                                                         \
81    free((a)->d);                                                             \
82  }                                                                           \
83  (a)->n=0;                                                                   \
84} while(0)
85
86#define utarray_new(a,_icd) do {                                              \
87  (a) = (UT_array*)malloc(sizeof(UT_array));                                  \
88  if ((a) == NULL) {                                                          \
89    utarray_oom();                                                            \
90  }                                                                           \
91  utarray_init(a,_icd);                                                       \
92} while(0)
93
94#define utarray_free(a) do {                                                  \
95  utarray_done(a);                                                            \
96  free(a);                                                                    \
97} while(0)
98
99#define utarray_reserve(a,by) do {                                            \
100  if (((a)->i+(by)) > (a)->n) {                                               \
101    char *utarray_tmp;                                                        \
102    while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); }    \
103    utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz);                   \
104    if (utarray_tmp == NULL) {                                                \
105      utarray_oom();                                                          \
106    }                                                                         \
107    (a)->d=utarray_tmp;                                                       \
108  }                                                                           \
109} while(0)
110
111#define utarray_push_back(a,p) do {                                           \
112  utarray_reserve(a,1);                                                       \
113  if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); }      \
114  else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); };              \
115} while(0)
116
117#define utarray_pop_back(a) do {                                              \
118  if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); }       \
119  else { (a)->i--; }                                                          \
120} while(0)
121
122#define utarray_extend_back(a) do {                                           \
123  utarray_reserve(a,1);                                                       \
124  if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); }            \
125  else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); }                   \
126  (a)->i++;                                                                   \
127} while(0)
128
129#define utarray_len(a) ((a)->i)
130
131#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
132#define _utarray_eltptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j))))
133
134#define utarray_insert(a,p,j) do {                                            \
135  if ((j) > (a)->i) utarray_resize(a,j);                                      \
136  utarray_reserve(a,1);                                                       \
137  if ((j) < (a)->i) {                                                         \
138    memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j),                  \
139             ((a)->i - (j))*((a)->icd.sz));                                   \
140  }                                                                           \
141  if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); }             \
142  else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); };                     \
143  (a)->i++;                                                                   \
144} while(0)
145
146#define utarray_inserta(a,w,j) do {                                           \
147  if (utarray_len(w) == 0) break;                                             \
148  if ((j) > (a)->i) utarray_resize(a,j);                                      \
149  utarray_reserve(a,utarray_len(w));                                          \
150  if ((j) < (a)->i) {                                                         \
151    memmove(_utarray_eltptr(a,(j)+utarray_len(w)),                            \
152            _utarray_eltptr(a,j),                                             \
153            ((a)->i - (j))*((a)->icd.sz));                                    \
154  }                                                                           \
155  if ((a)->icd.copy) {                                                        \
156    unsigned _ut_i;                                                           \
157    for(_ut_i=0;_ut_i<(w)->i;_ut_i++) {                                       \
158      (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \
159    }                                                                         \
160  } else {                                                                    \
161    memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0),                        \
162           utarray_len(w)*((a)->icd.sz));                                     \
163  }                                                                           \
164  (a)->i += utarray_len(w);                                                   \
165} while(0)
166
167#define utarray_resize(dst,num) do {                                          \
168  unsigned _ut_i;                                                             \
169  if ((dst)->i > (unsigned)(num)) {                                           \
170    if ((dst)->icd.dtor) {                                                    \
171      for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) {                        \
172        (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i));                         \
173      }                                                                       \
174    }                                                                         \
175  } else if ((dst)->i < (unsigned)(num)) {                                    \
176    utarray_reserve(dst, (num) - (dst)->i);                                   \
177    if ((dst)->icd.init) {                                                    \
178      for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) {              \
179        (dst)->icd.init(_utarray_eltptr(dst, _ut_i));                         \
180      }                                                                       \
181    } else {                                                                  \
182      memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \
183    }                                                                         \
184  }                                                                           \
185  (dst)->i = (num);                                                           \
186} while(0)
187
188#define utarray_concat(dst,src) do {                                          \
189  utarray_inserta(dst, src, utarray_len(dst));                                \
190} while(0)
191
192#define utarray_erase(a,pos,len) do {                                         \
193  if ((a)->icd.dtor) {                                                        \
194    unsigned _ut_i;                                                           \
195    for (_ut_i = 0; _ut_i < (len); _ut_i++) {                                 \
196      (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i));                        \
197    }                                                                         \
198  }                                                                           \
199  if ((a)->i > ((pos) + (len))) {                                             \
200    memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)),       \
201            ((a)->i - ((pos) + (len))) * (a)->icd.sz);                        \
202  }                                                                           \
203  (a)->i -= (len);                                                            \
204} while(0)
205
206#define utarray_renew(a,u) do {                                               \
207  if (a) utarray_clear(a);                                                    \
208  else utarray_new(a, u);                                                     \
209} while(0)
210
211#define utarray_clear(a) do {                                                 \
212  if ((a)->i > 0) {                                                           \
213    if ((a)->icd.dtor) {                                                      \
214      unsigned _ut_i;                                                         \
215      for(_ut_i=0; _ut_i < (a)->i; _ut_i++) {                                 \
216        (a)->icd.dtor(_utarray_eltptr(a, _ut_i));                             \
217      }                                                                       \
218    }                                                                         \
219    (a)->i = 0;                                                               \
220  }                                                                           \
221} while(0)
222
223#define utarray_sort(a,cmp) do {                                              \
224  qsort((a)->d, (a)->i, (a)->icd.sz, cmp);                                    \
225} while(0)
226
227#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
228
229#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
230#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : (((a)->i != utarray_eltidx(a,e)+1) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
231#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) != 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
232#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
233#define utarray_eltidx(a,e) (((char*)(e) - (a)->d) / (a)->icd.sz)
234
235/* last we pre-define a few icd for common utarrays of ints and strings */
236static void utarray_str_cpy(void *dst, const void *src) {
237  char *const *srcc = (char *const *)src;
238  char **dstc = (char**)dst;
239  *dstc = (*srcc == NULL) ? NULL : strdup(*srcc);
240}
241static void utarray_str_dtor(void *elt) {
242  char **eltc = (char**)elt;
243  if (*eltc != NULL) free(*eltc);
244}
245static const UT_icd ut_str_icd UTARRAY_UNUSED = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
246static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int),NULL,NULL,NULL};
247static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void*),NULL,NULL,NULL};
248
249
250#endif /* UTARRAY_H */
251