1 /*
2 Copyright (c) 2008-2013, Troy D. Hanson   http://uthash.sourceforge.net
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 
8     * Redistributions of source code must retain the above copyright
9       notice, this list of conditions and the following disclaimer.
10 
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
12 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
13 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
15 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23 
24 /* $Id: utarray.h 2694 2012-11-24 17:11:58Z kaiwang27 $ */
25 
26 /* a dynamic array implementation using macros
27  * see http://uthash.sourceforge.net/utarray
28  */
29 #ifndef UTARRAY_H
30 #define UTARRAY_H
31 
32 #define UTARRAY_VERSION 1.9.7
33 
34 #ifdef __GNUC__
35 #define _UNUSED_ __attribute__ ((__unused__))
36 #else
37 #define _UNUSED_
38 #endif
39 
40 #include <stddef.h>  /* size_t */
41 #include <string.h>  /* memset, etc */
42 #include <stdlib.h>  /* exit */
43 
44 #ifndef oom
45 #define oom() exit(-1)
46 #endif
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   utarray_reserve(a,1);                                                       \
124   if (j > (a)->i) break;                                                      \
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) break;                                                      \
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) : (((int)((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)) ? (int)(((char*)(e) - (char*)((a)->d))/(a)->icd.sz) : -1)
222 
223 /* last we pre-define a few icd for common utarrays of ints and strings */
utarray_str_cpy(void * dst,const void * src)224 static void utarray_str_cpy(void *dst, const void *src) {
225   char *const*_src = (char*const*)src, **_dst = (char**)dst;
226   *_dst = (*_src == NULL) ? NULL : strdup(*_src);
227 }
utarray_str_dtor(void * elt)228 static void utarray_str_dtor(void *elt) {
229   char **eltc = (char**)elt;
230   if (*eltc) free(*eltc);
231 }
232 static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
233 static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
234 static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL};
235 
236 
237 #endif /* UTARRAY_H */
238