array.h revision 489a4b34972902602320f910fc0c6014ea072c50
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce/* Array is a buffer accessible using fixed size elements. As long as the
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce compiler provides typeof() function, the array provides type safety. If
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce a wrong type is tried to be added to the array, or if the array's contents
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce are tried to be used using a wrong type, the compiler will give a warning.
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce Example usage:
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce struct foo {
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_DEFINE(bars, struct bar);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_CREATE(&foo->bars, default_pool, struct bar, 10);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_CREATE(&foo->bars, default_pool, struct baz, 10); // compiler warning
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce struct bar *bar = array_idx(&foo->bars, 5);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce struct baz *baz = array_idx(&foo->bars, 5); // compiler warning
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce If you want to pass an array as a parameter to a function, you'll need to
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce create a type for the array using ARRAY_DEFINE_TYPE() and use the type in
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce the parameter using ARRAY_TYPE().
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_DEFINE_TYPE(foo, struct foo);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce void do_foo(ARRAY_TYPE(foo) *bars) {
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce struct foo *foo = array_idx(bars, 0);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define ARRAY_CREATE(array, pool, array_type, init_count) STMT_START { \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce array_type const *_array_tmp = (array)->v; _array_tmp = NULL; \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce array_create(array, pool, sizeof(array_type), init_count); \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce typeof((array)->v_modifiable) __tmp_array_data2 __attr_unused__ = \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_create_from_buffer(struct array *array, buffer_t *buffer,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define array_create_from_buffer(array, buffer, element_size) \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce _array_create_from_buffer(&(array)->arr, buffer, element_size)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer = buffer_create_dynamic(pool, init_count * element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce _array_create_from_buffer(array, buffer, element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define array_create(array, pool, element_size, init_count) \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce _array_create(&(array)->arr, pool, element_size, init_count)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline bool
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_append(struct array *array, const void *data, unsigned int count)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_append(array->buffer, data, count * array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define array_append(array, data, count) STMT_START { \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_append_array(struct array *dest_array, const struct array *src_array)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce i_assert(dest_array->element_size == src_array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_append_buf(dest_array->buffer, src_array->buffer, 0, (size_t)-1);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define array_append_array(dest_array, src_array) \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce _array_append_array(&(dest_array)->arr, &(src_array)->arr)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_insert(struct array *array, unsigned int idx,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_insert(array->buffer, idx * array->element_size,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define array_insert(array, idx, data, count) STMT_START { \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce _array_insert(&(array)->arr, idx, data, count); \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_delete(struct array *array, unsigned int idx, unsigned int count)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_delete(array->buffer, idx * array->element_size,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline const void *
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_get(const struct array *array, unsigned int *count_r)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce *count_r = array->buffer->used / array->element_size;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_TYPE_CAST_CONST(array)_array_get(&(array)->arr, count)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline const void *
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_idx(const struct array *array, unsigned int idx)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce i_assert(idx * array->element_size < array->buffer->used);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_TYPE_CAST_CONST(array)_array_idx(&(array)->arr, idx)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void *
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_get_modifiable(struct array *array, unsigned int *count_r)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce *count_r = array->buffer->used / array->element_size;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce return buffer_get_modifiable_data(array->buffer, NULL);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void *
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_idx_modifiable(struct array *array, unsigned int idx)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* index doesn't exist yet, initialize with zero */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_append_zero(array->buffer, pos + array->element_size -
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce return buffer_get_space_unsafe(array->buffer, pos, array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_idx_set(struct array *array, unsigned int idx, const void *data)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* index doesn't exist yet, initialize with zero */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_append_zero(array->buffer, pos - array->buffer->used);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_write(array->buffer, pos, data, array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce#define array_idx_set(array, idx, data) STMT_START { \
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_idx_clear(struct array *array, unsigned int idx)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce /* index doesn't exist yet, initialize with zero */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_append_zero(array->buffer, pos - array->buffer->used);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_write_zero(array->buffer, pos, array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void *
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce data = buffer_append_space_unsafe(array->buffer, array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce ARRAY_TYPE_CAST_MODIFIABLE(array)_array_append_space(&(array)->arr)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline void *
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_insert_space(struct array *array, unsigned int idx)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce buffer_copy(array->buffer, pos + array->element_size,
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce data = buffer_get_space_unsafe(array->buffer, pos, array->element_size);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline unsigned int
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce return array->buffer->used / array->element_size;
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorcestatic inline bool
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce_array_cmp(const struct array *array1, const struct array *array2)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce if (!_array_is_created(array1) || array1->buffer->used == 0)
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce return !_array_is_created(array2) || array2->buffer->used == 0;