1 /* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2 All rights reserved.
3 This software was developed in the APRIL Robotics Lab under the
4 direction of Edwin Olson, ebolson@umich.edu. This software may be
5 available under alternative licensing terms; contact the address above.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 The views and conclusions contained in the software and documentation are those
24 of the authors and should not be interpreted as representing official policies,
25 either expressed or implied, of the Regents of The University of Michigan.
26 */
27 
28 #ifndef _ZARRAY_H
29 #define _ZARRAY_H
30 //#pragma once
31 
32 #include <assert.h>
33 #include <stddef.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #ifdef __cplusplus
38 // extern "C" {
39 #endif
40 
41 /**
42  * Defines a structure which acts as a resize-able array ala Java's ArrayList.
43  */
44 typedef struct zarray zarray_t;
45 struct zarray {
46   size_t el_sz; // size of each element
47 
48   int size;  // how many elements?
49   int alloc; // we've allocated storage for how many elements?
50   char *data;
51 };
52 
53 /**
54  * Creates and returns a variable array structure capable of holding elements of
55  * the specified size. It is the caller's responsibility to call zarray_destroy()
56  * on the returned array when it is no longer needed.
57  */
zarray_create(size_t el_sz)58 static inline zarray_t *zarray_create(size_t el_sz)
59 {
60   assert(el_sz > 0);
61 
62   zarray_t *za = (zarray_t *)calloc(1, sizeof(zarray_t));
63   za->el_sz = el_sz;
64   return za;
65 }
66 
67 /**
68  * Frees all resources associated with the variable array structure which was
69  * created by zarray_create(). After calling, 'za' will no longer be valid for storage.
70  */
zarray_destroy(zarray_t * za)71 static inline void zarray_destroy(zarray_t *za)
72 {
73   if (za == NULL)
74     return;
75 
76   if (za->data != NULL)
77     free(za->data);
78   memset(za, 0, sizeof(zarray_t));
79   free(za);
80 }
81 
82 /** Allocate a new zarray that contains a copy of the data in the argument. **/
zarray_copy(const zarray_t * za)83 static inline zarray_t *zarray_copy(const zarray_t *za)
84 {
85   assert(za != NULL);
86 
87   zarray_t *zb = (zarray_t *)calloc(1, sizeof(zarray_t));
88   zb->el_sz = za->el_sz;
89   zb->size = za->size;
90   zb->alloc = za->alloc;
91   zb->data = (char *)malloc(zb->alloc * zb->el_sz);
92   memcpy(zb->data, za->data, za->size * za->el_sz);
93   return zb;
94 }
95 
iceillog2(int v)96 static int iceillog2(int v)
97 {
98   v--;
99   v |= v >> 1;
100   v |= v >> 2;
101   v |= v >> 4;
102   v |= v >> 8;
103   v |= v >> 16;
104   v++;
105   return v;
106 }
107 
108 /**
109  * Allocate a new zarray that contains a subset of the original
110  * elements. NOTE: end index is EXCLUSIVE, that is one past the last
111  * element you want.
112  */
zarray_copy_subset(const zarray_t * za,int start_idx,int end_idx_exclusive)113 static inline zarray_t *zarray_copy_subset(const zarray_t *za, int start_idx, int end_idx_exclusive)
114 {
115   zarray_t *out = (zarray_t *)calloc(1, sizeof(zarray_t));
116   out->el_sz = za->el_sz;
117   out->size = end_idx_exclusive - start_idx;
118   out->alloc = iceillog2(out->size); // round up pow 2
119   out->data = (char *)malloc(out->alloc * out->el_sz);
120   memcpy(out->data, za->data + (start_idx * out->el_sz), out->size * out->el_sz);
121   return out;
122 }
123 
124 /**
125  * Retrieves the number of elements currently being contained by the passed
126  * array, which may be different from its capacity. The index of the last element
127  * in the array will be one less than the returned value.
128  */
zarray_size(const zarray_t * za)129 static inline int zarray_size(const zarray_t *za)
130 {
131   assert(za != NULL);
132 
133   return za->size;
134 }
135 
136 /**
137  * Returns 1 if zarray_size(za) == 0,
138  * returns 0 otherwise.
139  */
140 /*
141 JUST CALL zarray_size
142 int zarray_isempty(const zarray_t *za)
143 {
144     assert(za != NULL);
145     if (za->size <= 0)
146         return 1;
147     else
148         return 0;
149 }
150 */
151 
152 /**
153  * Allocates enough internal storage in the supplied variable array structure to
154  * guarantee that the supplied number of elements (capacity) can be safely stored.
155  */
156 #include <stdio.h>
zarray_ensure_capacity(zarray_t * za,int capacity)157 static inline void zarray_ensure_capacity(zarray_t *za, int capacity)
158 {
159   assert(za != NULL);
160 
161   if (capacity <= za->alloc)
162     return;
163 
164   while (za->alloc < capacity) {
165     za->alloc *= 2;
166     if (za->alloc < 8)
167       za->alloc = 8;
168   }
169 
170   // za->data = (char *)realloc(za->data, za->alloc * za->el_sz);
171   char *tmp = (char *)realloc(za->data, za->alloc * za->el_sz);
172   if (tmp != NULL) {
173     za->data = tmp;
174   }
175 }
176 
177 /**
178  * Adds a new element to the end of the supplied array, and sets its value
179  * (by copying) from the data pointed to by the supplied pointer 'p'.
180  * Automatically ensures that enough storage space is available for the new element.
181  */
zarray_add(zarray_t * za,const void * p)182 static inline void zarray_add(zarray_t *za, const void *p)
183 {
184   assert(za != NULL);
185   assert(p != NULL);
186 
187   zarray_ensure_capacity(za, za->size + 1);
188 
189   memcpy(&za->data[za->size * za->el_sz], p, za->el_sz);
190   za->size++;
191 }
192 
193 /**
194  * Retrieves the element from the supplied array located at the zero-based
195  * index of 'idx' and copies its value into the variable pointed to by the pointer
196  * 'p'.
197  */
zarray_get(const zarray_t * za,int idx,void * p)198 static inline void zarray_get(const zarray_t *za, int idx, void *p)
199 {
200   assert(za != NULL);
201   assert(p != NULL);
202   assert(idx >= 0);
203   assert(idx < za->size);
204 
205   memcpy(p, &za->data[idx * za->el_sz], za->el_sz);
206 }
207 
208 /**
209  * Similar to zarray_get(), but returns a "live" pointer to the internal
210  * storage, avoiding a memcpy. This pointer is not valid across
211  * operations which might move memory around (i.e. zarray_remove_value(),
212  * zarray_remove_index(), zarray_insert(), zarray_sort(), zarray_clear()).
213  * 'p' should be a pointer to the pointer which will be set to the internal address.
214  */
zarray_get_volatile(const zarray_t * za,int idx,void * p)215 inline static void zarray_get_volatile(const zarray_t *za, int idx, void *p)
216 {
217   assert(za != NULL);
218   assert(p != NULL);
219   assert(idx >= 0);
220   assert(idx < za->size);
221 
222   *((void **)p) = &za->data[idx * za->el_sz];
223 }
224 
zarray_truncate(zarray_t * za,int sz)225 inline static void zarray_truncate(zarray_t *za, int sz)
226 {
227   assert(za != NULL);
228   assert(sz <= za->size);
229   za->size = sz;
230 }
231 
232 /**
233  * Copies the memory array used internally by zarray to store its owned
234  * elements to the address pointed by 'buffer'. It is the caller's responsibility
235  * to allocate zarray_size()*el_sz bytes for the copy to be stored and
236  * to free the memory when no longer needed. The memory allocated at 'buffer'
237  * and the internal zarray storage must not overlap. 'buffer_bytes' should be
238  * the size of the 'buffer' memory space, in bytes, and must be at least
239  * zarray_size()*el_sz.
240  *
241  * Returns the number of bytes copied into 'buffer'.
242  */
zarray_copy_data(const zarray_t * za,void * buffer,size_t buffer_bytes)243 static inline size_t zarray_copy_data(const zarray_t *za, void *buffer, size_t buffer_bytes)
244 {
245   assert(za != NULL);
246   assert(buffer != NULL);
247   assert(buffer_bytes >= za->el_sz * za->size);
248   memcpy(buffer, za->data, za->el_sz * za->size);
249   (void)buffer_bytes; // To avoid a warning on iOS
250   return za->el_sz * za->size;
251 }
252 
253 /**
254  * Removes the entry at index 'idx'.
255  * If shuffle is true, the last element in the array will be placed in
256  * the newly-open space; if false, the zarray is compacted.
257  */
zarray_remove_index(zarray_t * za,int idx,int shuffle)258 static inline void zarray_remove_index(zarray_t *za, int idx, int shuffle)
259 {
260   assert(za != NULL);
261   assert(idx >= 0);
262   assert(idx < za->size);
263 
264   if (shuffle) {
265     if (idx < za->size - 1)
266       memcpy(&za->data[idx * za->el_sz], &za->data[((size_t)(za->size) - (size_t)1) * (za->el_sz)], za->el_sz);
267     za->size--;
268     return;
269   } else {
270     // size = 10, idx = 7. Should copy 2 entries (at idx=8 and idx=9).
271     // size = 10, idx = 9. Should copy 0 entries.
272     int ncopy = za->size - idx - 1;
273     if (ncopy > 0)
274       memmove(&za->data[idx * za->el_sz], &za->data[((size_t)(idx) + (size_t)1) * (za->el_sz)], ncopy * za->el_sz);
275     za->size--;
276     return;
277   }
278 }
279 
280 /**
281  * Remove the entry whose value is equal to the value pointed to by 'p'.
282  * If shuffle is true, the last element in the array will be placed in
283  * the newly-open space; if false, the zarray is compacted. At most
284  * one element will be removed.
285  *
286  * Note that objects will be compared using memcmp over the full size
287  * of the value. If the value is a struct that contains padding,
288  * differences in the padding bytes can cause comparisons to
289  * fail. Thus, it remains best practice to bzero all structs so that
290  * the padding is set to zero.
291  *
292  * Returns the number of elements removed (0 or 1).
293  */
294 // remove the entry whose value is equal to the value pointed to by p.
295 // if shuffle is true, the last element in the array will be placed in
296 // the newly-open space; if false, the zarray is compacted.
zarray_remove_value(zarray_t * za,const void * p,int shuffle)297 static inline int zarray_remove_value(zarray_t *za, const void *p, int shuffle)
298 {
299   assert(za != NULL);
300   assert(p != NULL);
301 
302   for (int idx = 0; idx < za->size; idx++) {
303     if (!memcmp(p, &za->data[idx * za->el_sz], za->el_sz)) {
304       zarray_remove_index(za, idx, shuffle);
305       return 1;
306     }
307   }
308 
309   return 0;
310 }
311 
312 /**
313  * Creates a new entry and inserts it into the array so that it will have the
314  * index 'idx' (i.e. before the item which currently has that index). The value
315  * of the new entry is set to (copied from) the data pointed to by 'p'. 'idx'
316  * can be one larger than the current max index to place the new item at the end
317  * of the array, or zero to add it to an empty array.
318  */
zarray_insert(zarray_t * za,int idx,const void * p)319 static inline void zarray_insert(zarray_t *za, int idx, const void *p)
320 {
321   assert(za != NULL);
322   assert(p != NULL);
323   assert(idx >= 0);
324   assert(idx <= za->size);
325 
326   zarray_ensure_capacity(za, za->size + 1);
327   // size = 10, idx = 7. Should copy three entries (idx=7, idx=8, idx=9)
328   int ncopy = za->size - idx;
329 
330   memmove(&za->data[((size_t)(idx) + (size_t)1) * (za->el_sz)], &za->data[idx * za->el_sz], ncopy * za->el_sz);
331   memcpy(&za->data[idx * za->el_sz], p, za->el_sz);
332 
333   za->size++;
334 }
335 
336 /**
337  * Sets the value of the current element at index 'idx' by copying its value from
338  * the data pointed to by 'p'. The previous value of the changed element will be
339  * copied into the data pointed to by 'outp' if it is not null.
340  */
zarray_set(zarray_t * za,int idx,const void * p,void * outp)341 static inline void zarray_set(zarray_t *za, int idx, const void *p, void *outp)
342 {
343   assert(za != NULL);
344   assert(p != NULL);
345   assert(idx >= 0);
346   assert(idx < za->size);
347 
348   if (outp != NULL)
349     memcpy(outp, &za->data[idx * za->el_sz], za->el_sz);
350 
351   memcpy(&za->data[idx * za->el_sz], p, za->el_sz);
352 }
353 
354 /**
355  * Calls the supplied function for every element in the array in index order.
356  * The map function will be passed a pointer to each element in turn and must
357  * have the following format:
358  *
359  * void map_function(element_type *element)
360  */
zarray_map(zarray_t * za,void (* f)(void *))361 static inline void zarray_map(zarray_t *za, void (*f)(void *))
362 {
363   assert(za != NULL);
364   assert(f != NULL);
365 
366   for (int idx = 0; idx < za->size; idx++)
367     f(&za->data[idx * za->el_sz]);
368 }
369 
370 /**
371  * Calls the supplied function for every element in the array in index order.
372  * HOWEVER values are passed to the function, not pointers to values. In the
373  * case where the zarray stores object pointers, zarray_vmap allows you to
374  * pass in the object's destroy function (or free) directly. Can only be used
375  * with zarray's which contain pointer data. The map function should have the
376  * following format:
377  *
378  * void map_function(element_type *element)
379  */
380 void zarray_vmap(zarray_t *za, void (*f)(void *));
381 
382 /**
383  * Removes all elements from the array and sets its size to zero. Pointers to
384  * any data elements obtained i.e. by zarray_get_volatile() will no longer be
385  * valid.
386  */
zarray_clear(zarray_t * za)387 static inline void zarray_clear(zarray_t *za)
388 {
389   assert(za != NULL);
390   za->size = 0;
391 }
392 
393 /**
394  * Determines whether any element in the array has a value which matches the
395  * data pointed to by 'p'.
396  *
397  * Returns 1 if a match was found anywhere in the array, else 0.
398  */
zarray_contains(const zarray_t * za,const void * p)399 static inline int zarray_contains(const zarray_t *za, const void *p)
400 {
401   assert(za != NULL);
402   assert(p != NULL);
403 
404   for (int idx = 0; idx < za->size; idx++) {
405     if (!memcmp(p, &za->data[idx * za->el_sz], za->el_sz)) {
406       return 1;
407     }
408   }
409 
410   return 0;
411 }
412 
413 /**
414  * Uses qsort() to sort the elements contained by the array in ascending order.
415  * Uses the supplied comparison function to determine the appropriate order.
416  *
417  * The comparison function will be passed a pointer to two elements to be compared
418  * and should return a measure of the difference between them (see strcmp()).
419  * I.e. it should return a negative number if the first element is 'less than'
420  * the second, zero if they are equivalent, and a positive number if the first
421  * element is 'greater than' the second. The function should have the following format:
422  *
423  * int comparison_function(const element_type *first, const element_type *second)
424  *
425  * zstrcmp() can be used as the comparison function for string elements, which
426  * will call strcmp() internally.
427  */
zarray_sort(zarray_t * za,int (* compar)(const void *,const void *))428 static inline void zarray_sort(zarray_t *za, int (*compar)(const void *, const void *))
429 {
430   assert(za != NULL);
431   assert(compar != NULL);
432   if (za->size == 0)
433     return;
434 
435   qsort(za->data, za->size, za->el_sz, compar);
436 }
437 
438 /**
439  * A comparison function for comparing strings which can be used by zarray_sort()
440  * to sort arrays with char* elements.
441  */
442 int zstrcmp(const void *a_pp, const void *b_pp);
443 
444 /**
445  * Find the index of an element, or return -1 if not found. Remember that p is
446  * a pointer to the element.
447  **/
448 // returns -1 if not in array. Remember p is a pointer to the item.
zarray_index_of(const zarray_t * za,const void * p)449 static inline int zarray_index_of(const zarray_t *za, const void *p)
450 {
451   assert(za != NULL);
452   assert(p != NULL);
453 
454   for (int i = 0; i < za->size; i++) {
455     if (!memcmp(p, &za->data[i * za->el_sz], za->el_sz))
456       return i;
457   }
458 
459   return -1;
460 }
461 
462 /**
463  * Add all elements from 'source' into 'dest'. el_size must be the same
464  * for both lists
465  **/
zarray_add_all(zarray_t * dest,const zarray_t * source)466 static inline void zarray_add_all(zarray_t *dest, const zarray_t *source)
467 {
468   assert(dest->el_sz == source->el_sz);
469 
470   // Don't allocate on stack because el_sz could be larger than ~8 MB
471   // stack size
472   char *tmp = (char *)calloc(1, dest->el_sz);
473 
474   for (int i = 0; i < zarray_size(source); i++) {
475     zarray_get(source, i, tmp);
476     zarray_add(dest, tmp);
477   }
478 
479   free(tmp);
480 }
481 
482 #ifdef __cplusplus
483 //}
484 #endif
485 
486 #endif
487