1 /******************************************************************************/
2 /* pfixtools: a collection of postfix related tools */
4 /* ________________________________________________________________________ */
6 /* Redistribution and use in source and binary forms, with or without */
7 /* modification, are permitted provided that the following conditions */
10 /* 1. Redistributions of source code must retain the above copyright */
11 /* notice, this list of conditions and the following disclaimer. */
12 /* 2. Redistributions in binary form must reproduce the above copyright */
13 /* notice, this list of conditions and the following disclaimer in the */
14 /* documentation and/or other materials provided with the distribution. */
15 /* 3. The names of its contributors may not be used to endorse or promote */
16 /* products derived from this software without specific prior written */
19 /* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS */
20 /* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY */
23 /* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
24 /* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS */
25 /* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */
26 /* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */
27 /* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
28 /* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
29 /* POSSIBILITY OF SUCH DAMAGE. */
31 /* Copyright (c) 2006-2008 the Authors */
32 /* see AUTHORS and source files for details */
33 /******************************************************************************/
36 * Copyright © 2008 Florent Bruneau
39 #ifndef PFIXTOOLS_ARRAY_H
40 #define PFIXTOOLS_ARRAY_H
46 #define PRIV_ARRAY(Type) \
51 unsigned locked : 1; \
54 /** Declare type PA(Type).
56 #define PARRAY(Type) \
57 typedef PRIV_ARRAY(Type*) Type ## _ptr_array_t; \
58 static inline Type ## _ptr_array_t *Type ## _ptr_array_new(void) \
60 return p_new(Type ## _ptr_array_t, 1); \
63 static inline void Type ## _ptr_array_delete(Type ## _ptr_array_t **array) \
66 if ((*array)->locked) { \
67 array_unlock(**array); \
69 array_wipe(**array); \
74 /** Declare types A(Type) and PA(Type).
77 typedef PRIV_ARRAY(Type) Type ## _array_t; \
79 static inline Type ## _array_t *Type ## _array_new(void) \
81 return p_new(Type ## _array_t, 1); \
84 static inline void Type ## _array_delete(Type ## _array_t **array) \
87 if ((*array)->locked) { \
88 array_unlock(**array); \
90 array_wipe(**array); \
97 /** Type A(Type) is a dynamic array of elements of type @c Type.
99 #define A(Type) Type ## _array_t
101 /** Type PA(Type) is a dynamic array of pointers to type @c Type.
103 #define PA(Type) Type ## _ptr_array_t
105 #define ARRAY_INIT { NULL, 0, 0, false }
107 #define array_init(array) (array) = ARRAY_INIT
109 #define array_can_edit(array) (!(array).locked)
111 #define array_ensure_can_edit(array) \
112 assert(array_can_edit(array) && "Trying to edit array while it is locked")
114 #define array_wipe(array) \
116 array_ensure_can_edit(array); \
117 p_delete(&(array).data); \
123 /******* MEMORY MANAGEMENT *******/
125 /** Return the len of the array (number of elements contained in the array).
127 #define array_len(array) ((array).len)
129 /** Return the capacity of the array (number of elements the array can contain
130 * without growing its internal buffer).
132 #define array_size(array) ((array).size)
134 /** Return the number of free places in the array.
136 #define array_free_space(array) (array_size(array) - array_len(array))
138 /** Return the size of an element of the array.
140 #define array_elt_len(array) (sizeof(*(array).data))
142 /** Return the number of bytes used by the content of the array.
144 #define array_byte_len(array) ((array).len * array_elt_len(array))
146 /** Ensure the capacity of the array if *at least* @c goal *elements*.
148 #define array_ensure_capacity(array, goal) \
150 array_ensure_can_edit(array); \
151 if ((array).size < (goal)) { \
152 const typeof((array).size) required_size = (goal); \
153 typeof((array).size) next_size = (array).size; \
155 next_size = p_alloc_nr(next_size); \
156 } while (next_size < required_size); \
157 p_allocgrow(&(array).data, next_size, &(array).size); \
161 /** Ensure the array contains place for *at least* @c delta more elements.
163 #define array_ensure_capacity_delta(array, delta) \
164 array_ensure_capacity(array, (array).len + (delta))
166 /** Ensure the array can contain @c goal elements.
168 #define array_ensure_exact_capacity(array, goal) \
169 if ((array).size < (goal)) { \
170 array_ensure_can_edit(array); \
171 p_allocgrow(&(array).data, (goal), &(array).size); \
174 /** Shrink capacity of the array to MAX(len, @c cap).
176 #define array_shrink(array, cap) \
178 array_ensure_can_edit(array); \
179 if ((cap) < (array).size && (array).size != (array).len) { \
180 p_shrink(&(array).data, MAX((array).len, (cap)), &(array).size); \
184 /** Ensure the capacity of the array does not exceed its len.
186 #define array_adjust(array) array_shrink(array, 0)
188 #define array_lock(array) \
190 || (mlock((array).data, array_byte_len(array)) == 0 \
191 && ((array).locked = true)))
193 #define array_unlock(array) \
194 if ((array).locked) { \
195 (void)munlock((array).data, array_byte_len(array)); \
196 (array).locked = false; \
200 /******* ADDING ELEMENTS *******/
202 #define array_add(array, obj) \
204 array_ensure_capacity_delta(array, 1); \
205 (array).data[(array).len++] = (obj); \
208 #define array_append(array, objs, Len) \
210 const typeof((array).len) __len = (Len); \
211 array_ensure_capacity_delta(array, __len); \
212 memcpy((array).data + (array).len, objs, \
213 __len * sizeof(*(array).data)); \
214 (array).len += __len; \
218 /******* ACCESSSING ELEMENTS ********/
220 /** Getting the n'th element of the array.
222 #define array_elt(array, n) ((array).data[(n)])
224 #define array_first(array) array_elt(array, 0)
225 #define array_last(array) array_elt(array, (array).len - 1)
227 #define array_pop_last(array) array_elt(array, --((array).len))
229 /** Getting a pointer to the n'th element of the array.
231 #define array_ptr(array, n) ((array).data + (n))
233 #define array_start(array) array_ptr((array), 0)
234 #define array_end(array) array_ptr((array), array_len(array))
236 /****** TRAVERSING AN ARRAY *******/
238 /** Gives the position of pointer ptr in the array.
239 * This macro may only be used withing a loop. @ref foreach.
241 #define array_pos(array, ptr) ((ptr) - array_start(array))
243 /** Build a loop over the elements of an array.
248 * foreach (MyType* element, array) {
249 * do_something(element);
254 * * remember the loop must be ended with }} (the foreach macro contains
255 * a not-matched opening brace).
256 * * the macro uses a counter name __Ai, so you cannot build imbricated
257 * array enumerations. You SHOULD NOT use this counter in your code since
258 * it is part of the internal API and may change in the future.
261 #define foreach(var, array) \
262 for (uint32_t __Ai = 0 ; __Ai < (array).len ; ++__Ai) { \
263 var = array_ptr(array, __Ai);
265 /** Execute @c action for each element of the array.
268 * static void do_something(MyType *element) { ... }
272 * array_foreach(array, do_something);
275 #define array_foreach(array, action) \
276 for (uint32_t __Ai = 0 ; __Ai < (array).len ; ++__Ai) { \
277 action(array_ptr(array, __Ai)); \
280 /** Wipe each element of the array using @c wipe, then wipe the array.
282 #define array_deep_wipe(array, wipe) \
284 array_foreach(array, wipe); \