src/lib/array.h
author Timo Sirainen <tss@iki.fi>
Fri Jun 13 11:21:07 2014 +0300 (4 months ago)
changeset 15020 74037ec725d3
parent 10405 cc4e9d1fef7e
permissions -rw-r--r--
dbox: Fixed potential infinite looping when scanning a broken dbox file.
     1 #ifndef ARRAY_H
     2 #define ARRAY_H
     3 
     4 /* Array is a buffer accessible using fixed size elements. As long as the
     5    compiler provides typeof() function, the array provides type safety. If
     6    a wrong type is tried to be added to the array, or if the array's contents
     7    are tried to be used using a wrong type, the compiler will give a warning.
     8 
     9    Example usage:
    10 
    11    struct foo {
    12 	ARRAY_DEFINE(bars, struct bar);
    13 	...
    14    };
    15 
    16    i_array_init(&foo->bars, 10);
    17 
    18    struct bar *bar = array_idx(&foo->bars, 5);
    19    struct baz *baz = array_idx(&foo->bars, 5); // compiler warning
    20 
    21    If you want to pass an array as a parameter to a function, you'll need to
    22    create a type for the array using ARRAY_DEFINE_TYPE() and use the type in
    23    the parameter using ARRAY_TYPE().
    24 
    25    Example:
    26 
    27    ARRAY_DEFINE_TYPE(foo, struct foo);
    28    void do_foo(ARRAY_TYPE(foo) *bars) {
    29 	struct foo *foo = array_idx(bars, 0);
    30    }
    31 */
    32 #include "array-decl.h"
    33 #include "buffer.h"
    34 
    35 #define p_array_init(array, pool, init_count) \
    36 	array_create(array, pool, sizeof(**(array)->v), init_count)
    37 #define i_array_init(array, init_count) \
    38 	p_array_init(array, default_pool, init_count)
    39 #define t_array_init(array, init_count) \
    40 	p_array_init(array, pool_datastack_create(), init_count)
    41 
    42 #ifdef __GNUC__
    43 #  define ARRAY_TYPE_CAST_CONST(array) \
    44 	(typeof(*(array)->v))
    45 #  define ARRAY_TYPE_CAST_MODIFIABLE(array) \
    46 	(typeof(*(array)->v_modifiable))
    47 #  define ARRAY_TYPE_CHECK(array, data) \
    48 	COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
    49 		**(array)->v_modifiable, *data)
    50 #else
    51 #  define ARRAY_TYPE_CAST_CONST(array)
    52 #  define ARRAY_TYPE_CAST_MODIFIABLE(array)
    53 #  define ARRAY_TYPE_CHECK(array, data) 0
    54 #endif
    55 
    56 /* usage: struct foo *foo; array_foreach(foo_arr, foo) { .. } */
    57 #if (defined(__STDC__) && __STDC_VERSION__ >= 199901L)
    58 #  define array_foreach(array, elem) \
    59 	for (const void *elem ## __foreach_end = \
    60 		(const char *)(elem = *(array)->v) + (array)->arr.buffer->used; \
    61 	     elem != elem ## __foreach_end; (elem)++)
    62 #  define array_foreach_modifiable(array, elem) \
    63 	for (const void *elem ## _end = \
    64 		(const char *)(elem = ARRAY_TYPE_CAST_MODIFIABLE(array) \
    65 			buffer_get_modifiable_data((array)->arr.buffer, NULL)) + \
    66 			(array)->arr.buffer->used; \
    67 	 elem != elem ## _end; elem++)
    68 #else
    69 #  define array_foreach(array, elem) \
    70 	for (elem = *(array)->v; \
    71 	     elem != CONST_PTR_OFFSET(*(array)->v, (array)->arr.buffer->used); \
    72 	     (elem)++)
    73 #  define array_foreach_modifiable(array, elem) \
    74 	for (elem = ARRAY_TYPE_CAST_MODIFIABLE(array) \
    75 			buffer_get_modifiable_data((array)->arr.buffer, NULL); \
    76 	     elem != CONST_PTR_OFFSET(*(array)->v, (array)->arr.buffer->used); \
    77 	     (elem)++)
    78 #endif
    79 
    80 #define array_foreach_idx(array, elem) \
    81 	((elem) - (array)->v[0])
    82 
    83 static inline void
    84 array_create_from_buffer_i(struct array *array, buffer_t *buffer,
    85 			   size_t element_size)
    86 {
    87 	array->buffer = buffer;
    88 	array->element_size = element_size;
    89 }
    90 #define array_create_from_buffer(array, buffer, element_size) \
    91 	array_create_from_buffer_i(&(array)->arr, buffer, element_size)
    92 
    93 static inline void
    94 array_create_i(struct array *array, pool_t pool,
    95 	       size_t element_size, unsigned int init_count)
    96 {
    97 	buffer_t *buffer;
    98 
    99         buffer = buffer_create_dynamic(pool, init_count * element_size);
   100 	array_create_from_buffer_i(array, buffer, element_size);
   101 }
   102 #define array_create(array, pool, element_size, init_count) \
   103 	array_create_i(&(array)->arr, pool, element_size, init_count)
   104 
   105 static inline void
   106 array_free_i(struct array *array)
   107 {
   108 	buffer_free(&array->buffer);
   109 }
   110 #define array_free(array) \
   111 	array_free_i(&(array)->arr)
   112 
   113 static inline bool
   114 array_is_created_i(const struct array *array)
   115 {
   116 	return array->buffer != NULL;
   117 }
   118 #define array_is_created(array) \
   119 	array_is_created_i(&(array)->arr)
   120 
   121 static inline pool_t ATTR_PURE
   122 array_get_pool_i(struct array *array)
   123 {
   124 	return buffer_get_pool(array->buffer);
   125 }
   126 #define array_get_pool(array) \
   127 	array_get_pool_i(&(array)->arr)
   128 
   129 static inline void
   130 array_clear_i(struct array *array)
   131 {
   132 	buffer_set_used_size(array->buffer, 0);
   133 }
   134 #define array_clear(array) \
   135 	array_clear_i(&(array)->arr)
   136 
   137 static inline unsigned int ATTR_PURE
   138 array_count_i(const struct array *array)
   139 {
   140 	return array->buffer->used / array->element_size;
   141 }
   142 #define array_count(array) \
   143 	array_count_i(&(array)->arr)
   144 
   145 static inline void
   146 array_append_i(struct array *array, const void *data, unsigned int count)
   147 {
   148 	buffer_append(array->buffer, data, count * array->element_size);
   149 }
   150 
   151 #define array_append(array, data, count) \
   152 	array_append_i(&(array)->arr + ARRAY_TYPE_CHECK(array, data), \
   153 		data, count)
   154 
   155 static inline void
   156 array_append_array_i(struct array *dest_array, const struct array *src_array)
   157 {
   158 	i_assert(dest_array->element_size == src_array->element_size);
   159 	buffer_append_buf(dest_array->buffer, src_array->buffer, 0, (size_t)-1);
   160 }
   161 #define array_append_array(dest_array, src_array) \
   162 	array_append_array_i(&(dest_array)->arr, &(src_array)->arr)
   163 
   164 static inline void
   165 array_insert_i(struct array *array, unsigned int idx,
   166 	       const void *data, unsigned int count)
   167 {
   168 	buffer_insert(array->buffer, idx * array->element_size,
   169 		      data, count * array->element_size);
   170 }
   171 
   172 #define array_insert(array, idx, data, count) \
   173 	array_insert_i(&(array)->arr + ARRAY_TYPE_CHECK(array, data), \
   174 		idx, data, count)
   175 
   176 static inline void
   177 array_delete_i(struct array *array, unsigned int idx, unsigned int count)
   178 {
   179 	buffer_delete(array->buffer, idx * array->element_size,
   180 		      count * array->element_size);
   181 }
   182 #define array_delete(array, idx, count) \
   183 	array_delete_i(&(array)->arr, idx, count)
   184 
   185 static inline const void *
   186 array_get_i(const struct array *array, unsigned int *count_r)
   187 {
   188 	*count_r = array_count_i(array);
   189 	return array->buffer->data;
   190 }
   191 #define array_get(array, count) \
   192 	ARRAY_TYPE_CAST_CONST(array)array_get_i(&(array)->arr, count)
   193 
   194 static inline const void * ATTR_PURE
   195 array_idx_i(const struct array *array, unsigned int idx)
   196 {
   197 	i_assert(idx * array->element_size < array->buffer->used);
   198 	return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size);
   199 }
   200 #define array_idx(array, idx) \
   201 	ARRAY_TYPE_CAST_CONST(array)array_idx_i(&(array)->arr, idx)
   202 
   203 static inline void *
   204 array_get_modifiable_i(struct array *array, unsigned int *count_r)
   205 {
   206 	*count_r = array_count_i(array);
   207 	return buffer_get_modifiable_data(array->buffer, NULL);
   208 }
   209 #define array_get_modifiable(array, count) \
   210 	ARRAY_TYPE_CAST_MODIFIABLE(array) \
   211 		array_get_modifiable_i(&(array)->arr, count)
   212 
   213 void *array_idx_modifiable_i(struct array *array, unsigned int idx);
   214 #define array_idx_modifiable(array, idx) \
   215 	ARRAY_TYPE_CAST_MODIFIABLE(array) \
   216 		array_idx_modifiable_i(&(array)->arr, idx)
   217 
   218 void array_idx_set_i(struct array *array, unsigned int idx, const void *data);
   219 #define array_idx_set(array, idx, data) \
   220 	array_idx_set_i(&(array)->arr + ARRAY_TYPE_CHECK(array, data), \
   221 		idx, data)
   222 
   223 void array_idx_clear_i(struct array *array, unsigned int idx);
   224 #define array_idx_clear(array, idx) \
   225 	array_idx_clear_i(&(array)->arr, idx)
   226 
   227 static inline void *
   228 array_append_space_i(struct array *array)
   229 {
   230 	void *data;
   231 
   232 	data = buffer_append_space_unsafe(array->buffer, array->element_size);
   233 	memset(data, 0, array->element_size);
   234 	return data;
   235 }
   236 #define array_append_space(array) \
   237 	ARRAY_TYPE_CAST_MODIFIABLE(array)array_append_space_i(&(array)->arr)
   238 
   239 void *array_insert_space_i(struct array *array, unsigned int idx);
   240 #define array_insert_space(array, idx) \
   241 	ARRAY_TYPE_CAST_MODIFIABLE(array) \
   242 		array_insert_space_i(&(array)->arr, idx)
   243 
   244 static inline void
   245 array_copy(struct array *dest, unsigned int dest_idx,
   246 	   const struct array *src, unsigned int src_idx, unsigned int count)
   247 {
   248 	i_assert(dest->element_size == src->element_size);
   249 
   250 	buffer_copy(dest->buffer, dest_idx * dest->element_size,
   251 		    src->buffer, src_idx * src->element_size,
   252 		    count * dest->element_size);
   253 }
   254 
   255 bool array_cmp_i(const struct array *array1,
   256 		 const struct array *array2) ATTR_PURE;
   257 #define array_cmp(array1, array2) \
   258 	array_cmp_i(&(array1)->arr, &(array2)->arr)
   259 
   260 void array_reverse_i(struct array *array);
   261 #define array_reverse(array) \
   262 	array_reverse_i(&(array)->arr)
   263 
   264 void array_sort_i(struct array *array, int (*cmp)(const void *, const void *));
   265 #ifdef CONTEXT_TYPE_SAFETY
   266 #define array_sort(array, cmp) \
   267 	({(void)(1 ? 0 : cmp(ARRAY_TYPE_CAST_CONST(array)NULL, \
   268 			     ARRAY_TYPE_CAST_CONST(array)NULL)); \
   269 	array_sort_i(&(array)->arr, \
   270 		(int (*)(const void *, const void *))cmp); })
   271 #else
   272 #define array_sort(array, cmp) \
   273 	array_sort_i(&(array)->arr, (int (*)(const void *, const void *))cmp)
   274 #endif
   275 
   276 void *array_bsearch_i(struct array *array, const void *key,
   277 		      int (*cmp)(const void *, const void *));
   278 #ifdef CONTEXT_TYPE_SAFETY
   279 #define array_bsearch(array, key, cmp) \
   280 	ARRAY_TYPE_CAST_MODIFIABLE(array) \
   281 	({(void)(1 ? 0 : cmp(key, ARRAY_TYPE_CAST_CONST(array)NULL)); \
   282 	array_bsearch_i(&(array)->arr, (const void *)key, \
   283 		(int (*)(const void *, const void *))cmp); })
   284 #else
   285 #define array_bsearch(array, key, cmp) \
   286 	array_bsearch_i(&(array)->arr, (const void *)key, \
   287 		(int (*)(const void *, const void *))cmp)
   288 #endif
   289 
   290 #endif