From: Florent Bruneau Date: Sun, 9 Nov 2008 15:01:22 +0000 (+0100) Subject: A bit of cleanup of the array API. X-Git-Url: http://git.madism.org/?p=apps%2Fpfixtools.git;a=commitdiff_plain;h=471db7e648c8a6b41e14ed90e370fe3b70af0e7f A bit of cleanup of the array API. Signed-off-by: Florent Bruneau --- diff --git a/common/array.h b/common/array.h index 4a5b88d..d32eeef 100644 --- a/common/array.h +++ b/common/array.h @@ -48,6 +48,8 @@ unsigned locked : 1; \ } +/** Declare type PA(Type). + */ #define PARRAY(Type) \ typedef PRIV_ARRAY(Type*) Type ## _ptr_array_t; \ static inline Type ## _ptr_array_t *Type ## _ptr_array_new(void) \ @@ -66,6 +68,8 @@ } \ } +/** Declare types A(Type) and PA(Type). + */ #define ARRAY(Type) \ typedef PRIV_ARRAY(Type) Type ## _array_t; \ \ @@ -87,7 +91,12 @@ \ PARRAY(Type) +/** Type A(Type) is a dynamic array of elements of type @c Type. + */ #define A(Type) Type ## _array_t + +/** Type PA(Type) is a dynamic array of pointers to type @c Type. + */ #define PA(Type) Type ## _ptr_array_t #define ARRAY_INIT { NULL, 0, 0, false } @@ -106,19 +115,33 @@ (array).len = 0; \ (array).size = 0; \ } while (0) -#define array_add(array, obj) \ - do { \ - array_ensure_capacity_delta(array, 1); \ - (array).data[(array).len++] = (obj); \ - } while (0) -#define array_append(array, objs, Len) \ - do { \ - const typeof((array).len) __len = (Len); \ - array_ensure_capacity_delta(array, __len); \ - memcpy((array).data + (array).len, objs, \ - __len * sizeof(*(array).data)); \ - (array).len += __len; \ - } while (0) + + +/******* MEMORY MANAGEMENT *******/ + +/** Return the len of the array (number of elements contained in the array). + */ +#define array_len(array) ((array).len) + +/** Return the capacity of the array (number of elements the array can contain + * without growing its internal buffer). + */ +#define array_size(array) ((array).size) + +/** Return the number of free places in the array. + */ +#define array_free_space(array) (array_size(array) - array_len(array)) + +/** Return the size of an element of the array. + */ +#define array_elt_len(array) (sizeof(*(array).data)) + +/** Return the number of bytes used by the content of the array. + */ +#define array_byte_len(array) ((array).len * array_elt_len(array)) + +/** Ensure the capacity of the array if *at least* @c goal *elements*. + */ #define array_ensure_capacity(array, goal) \ do { \ array_ensure_can_edit(array); \ @@ -131,13 +154,22 @@ p_allocgrow(&(array).data, next_size, &(array).size); \ } \ } while (0) + +/** Ensure the array contains place for *at least* @c delta more elements. + */ #define array_ensure_capacity_delta(array, delta) \ array_ensure_capacity(array, (array).len + (delta)) + +/** Ensure the array can contain @c goal elements. + */ #define array_ensure_exact_capacity(array, goal) \ if ((array).size < (goal)) { \ array_ensure_can_edit(array); \ p_allocgrow(&(array).data, (goal), &(array).size); \ } + +/** Shrink capacity of the array to MAX(len, @c cap). + */ #define array_shrink(array, cap) \ do { \ array_ensure_can_edit(array); \ @@ -145,42 +177,112 @@ p_shrink(&(array).data, MAX((array).len, (cap)), &(array).size); \ } \ } while (0) + +/** Ensure the capacity of the array does not exceed its len. + */ #define array_adjust(array) array_shrink(array, 0) +#define array_lock(array) \ + ((array).locked \ + || (mlock((array).data, array_byte_len(array)) == 0 \ + && ((array).locked = true))) + +#define array_unlock(array) \ + if ((array).locked) { \ + (void)munlock((array).data, array_byte_len(array)); \ + (array).locked = false; \ + } + + +/******* ADDING ELEMENTS *******/ + +#define array_add(array, obj) \ + do { \ + array_ensure_capacity_delta(array, 1); \ + (array).data[(array).len++] = (obj); \ + } while (0) + +#define array_append(array, objs, Len) \ + do { \ + const typeof((array).len) __len = (Len); \ + array_ensure_capacity_delta(array, __len); \ + memcpy((array).data + (array).len, objs, \ + __len * sizeof(*(array).data)); \ + (array).len += __len; \ + } while (0) + + +/******* ACCESSSING ELEMENTS ********/ + +/** Getting the n'th element of the array. + */ #define array_elt(array, n) ((array).data[(n)]) + +#define array_first(array) array_elt(array, 0) #define array_last(array) array_elt(array, (array).len - 1) + #define array_pop_last(array) array_elt(array, --((array).len)) +/** Getting a pointer to the n'th element of the array. + */ #define array_ptr(array, n) ((array).data + (n)) +#define array_start(array) array_ptr((array), 0) +#define array_end(array) array_ptr((array), array_len(array)) + +/****** TRAVERSING AN ARRAY *******/ + +/** Gives the position of pointer ptr in the array. + * This macro may only be used withing a loop. @ref foreach. + */ +#define array_pos(array, ptr) ((ptr) - array_start(array)) + +/** Build a loop over the elements of an array. + * + * + * A(MyType) array; + * ... + * foreach (MyType* element, array) { + * do_something(element); + * }} + * + * + * Warnings: + * * remember the loop must be ended with }} (the foreach macro contains + * a not-matched opening brace). + * * the macro uses a counter name __Ai, so you cannot build imbricated + * array enumerations. You SHOULD NOT use this counter in your code since + * it is part of the internal API and may change in the future. + */ + #define foreach(var, array) \ for (uint32_t __Ai = 0 ; __Ai < (array).len ; ++__Ai) { \ var = array_ptr(array, __Ai); +/** Execute @c action for each element of the array. + * + * + * static void do_something(MyType *element) { ... } + * + * A(MyType) array; + * ... + * array_foreach(array, do_something); + * + */ #define array_foreach(array, action) \ for (uint32_t __Ai = 0 ; __Ai < (array).len ; ++__Ai) { \ action(array_ptr(array, __Ai)); \ } + +/** Wipe each element of the array using @c wipe, then wipe the array. + */ #define array_deep_wipe(array, wipe) \ do { \ array_foreach(array, wipe); \ array_wipe(array); \ } while (0) -#define array_len(array) (array).len -#define array_size(array) (array).size -#define array_elt_len(array) sizeof(*(array).data) -#define array_byte_len(array) ((array).len * array_elt_len(array)) -#define array_lock(array) \ - ((array).locked \ - || (mlock((array).data, array_byte_len(array)) == 0 \ - && ((array).locked = true))) -#define array_unlock(array) \ - if ((array).locked) { \ - (void)munlock((array).data, array_byte_len(array)); \ - (array).locked = false; \ - } ARRAY(char) ARRAY(int) diff --git a/common/buffer.h b/common/buffer.h index c3e1adf..b4e5baa 100644 --- a/common/buffer.h +++ b/common/buffer.h @@ -43,7 +43,7 @@ typedef A(char) buffer_t; -#define BUFFER_INIT {NULL, 0, 0} +#define BUFFER_INIT ARRAY_INIT DO_INIT(buffer_t, buffer); static inline void buffer_wipe(buffer_t *buf) {