array.h revision 6ef7e31619edfaa17ed044b45861d106a86191ef
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen/* Array is a buffer accessible using fixed size elements. If DEBUG is
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen enabled, it also provides compile time type safety:
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen If DEBUG is enabled, an extra variable is defined along with the array
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen itself. This is used to cast array_idx() return value correctly, so
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen compiler gives a warning if it's assigned into variable with a different
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen Example usage:
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen array_t ARRAY_DEFINE(bars, struct bar);
bd3714d623d67f7dc8bd70ba39b467762ae409e8Timo Sirainen ARRAY_CREATE(&foo->bars, default_pool, struct bar, 10);
bd3714d623d67f7dc8bd70ba39b467762ae409e8Timo Sirainen ARRAY_CREATE(&foo->bars, default_pool, struct baz, 10); // compiler warning
bd3714d623d67f7dc8bd70ba39b467762ae409e8Timo Sirainen struct bar *bar = array_idx(&foo->bars, 5);
bd3714d623d67f7dc8bd70ba39b467762ae409e8Timo Sirainen struct baz *baz = array_idx(&foo->bars, 5); // compiler warning
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen When passing array_t as a parameter to function, or when it's otherwise
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen accessed in a way that the extra variable cannot be accessed, the code
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen won't compile. For situations like those, there's a ARRAY_SET_TYPE() macro.
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen void do_foo(array_t *bars) {
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen ARRAY_SET_TYPE(bars, struct foo);
3bc4e3b9f4ce6c3e771fa5ba284daa42828a9ce6Timo Sirainen struct foo *foo = array_idx(bars, 0);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen# define ARRAY_CREATE(array, pool, array_type, init_count) STMT_START { \
954dc3045a1df5594a1a7a0bc212ad4a92d62a20Timo Sirainen array_type **_array_tmp = array ## __ ## type; _array_tmp = NULL; \
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen array_create(array, pool, sizeof(array_type), init_count); \
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen# define ARRAY_CREATE(array, pool, array_type, init_count) \
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen array_create(array, pool, sizeof(array_type), init_count)
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen/* The reason we do this for non-ARRAY_TYPE_CHECKS as well is because if we
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen left this empty, some compilers wouldn't like an extra ";" character at
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen the beginning of the function (eg. gcc 2.95).
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen However just declaring the variable gives "unused variable" warning.
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen I couldn't think of anything better, so we just use gcc-specific
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen unused-attribute to get rid of that with gcc. */
0bed9236fca9b177d4bc3b4663e938097a73bab2Timo Sirainen array_type **array ## __ ## type __attr_unused__ = NULL
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenarray_create_from_buffer(array_t *array, buffer_t *buffer, size_t element_size)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer = buffer_create_dynamic(pool, init_count * element_size);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen array_create_from_buffer(array, buffer, element_size);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic inline bool
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen_array_append(array_t *array, const void *data, unsigned int count)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_append(array->buffer, data, count * array->element_size);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen# define array_append(array, data, count) STMT_START { \
2a7666fd3168ba04c4c027391cdddf0b7fc8074bTimo Sirainen typeof(const typeof(**(array ## __ ## type)) *) _array_tmp = data; \
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenarray_append_array(array_t *dest_array, const array_t *src_array)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen i_assert(dest_array->element_size == src_array->element_size);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_append_buf(dest_array->buffer, src_array->buffer, 0, (size_t)-1);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen_array_insert(array_t *array, unsigned int idx,
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_insert(array->buffer, idx * array->element_size,
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen# define array_insert(array, idx, data, count) STMT_START { \
2a7666fd3168ba04c4c027391cdddf0b7fc8074bTimo Sirainen typeof(const typeof(**(array ## __ ## type)) *) _array_tmp = data; \
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen _array_insert(array, idx, _array_tmp, count); \
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenarray_delete(array_t *array, unsigned int idx, unsigned int count)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_delete(array->buffer, idx * array->element_size,
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline const void *
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen_array_get(const array_t *array, unsigned int *count_r)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen *count_r = array->buffer->used / array->element_size;
2a7666fd3168ba04c4c027391cdddf0b7fc8074bTimo Sirainen (typeof(typeof(**array ## __ ## type) const *))_array_get(array, count)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline const void *
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen_array_idx(const array_t *array, unsigned int idx)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen i_assert(idx * array->element_size < array->buffer->used);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size);
2a7666fd3168ba04c4c027391cdddf0b7fc8074bTimo Sirainen (typeof(typeof(**array ## __ ## type) const *))_array_idx(array, idx)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void *
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen_array_get_modifyable(array_t *array, unsigned int *count_r)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen *count_r = array->buffer->used / array->element_size;
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen return buffer_get_modifyable_data(array->buffer, NULL);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen# define array_get_modifyable _array_get_modifyable
2a7666fd3168ba04c4c027391cdddf0b7fc8074bTimo Sirainen (typeof(*array ## __ ## type))_array_get_modifyable(array, count)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void *
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen_array_idx_modifyable(array_t *array, unsigned int idx)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen /* index doesn't exist yet, initialize with zero */
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_append_zero(array->buffer, pos + array->element_size -
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen return buffer_get_space_unsafe(array->buffer, pos, array->element_size);
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen# define array_idx_modifyable _array_idx_modifyable
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen (typeof(*array ## __ ## type))_array_idx_modifyable(array, count)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen_array_idx_set(array_t *array, unsigned int idx, const void *data)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen /* index doesn't exist yet, initialize with zero */
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_append_zero(array->buffer, pos - array->buffer->used);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_write(array->buffer, pos, data, array->element_size);
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen# define array_idx_set(array, idx, data) STMT_START { \
2a7666fd3168ba04c4c027391cdddf0b7fc8074bTimo Sirainen typeof(const typeof(**(array ## __ ## type)) *) _array_tmp = data; \
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void *
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen data = buffer_append_space_unsafe(array->buffer, array->element_size);
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen# define array_append_space _array_append_space
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen (typeof(*array ## __ ## type))_array_append_space(array)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline void *
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen_array_insert_space(array_t *array, unsigned int idx)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen buffer_copy(array->buffer, pos + array->element_size,
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen data = buffer_get_space_unsafe(array->buffer, pos, array->element_size);
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen# define array_insert_space _array_insert_space
053843989f13d9013b265fb401a4bde7e0e6568eTimo Sirainen (typeof(*array ## __ ## type))_array_insert_space(array, idx)
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainenstatic inline unsigned int
30972f343b285b6214ea053e1939b92cfe79040cTimo Sirainen return array->buffer->used / array->element_size;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic inline bool
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenarray_cmp(const array_t *array1, const array_t *array2)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!array_is_created(array1) || array1->buffer->used == 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return !array_is_created(array2) || array2->buffer->used == 0;