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