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