view src/lib/array.h @ 4891:6ab2712f1a93 HEAD

Only imap binary was actually working.
author Timo Sirainen <tss@iki.fi>
date Sun, 10 Dec 2006 14:35:02 +0200
parents ef3e7ba494bc
children d0b50249e816
line wrap: on
line source

#ifndef __ARRAY_H
#define __ARRAY_H

/* Array is a buffer accessible using fixed size elements. As long as the
   compiler provides typeof() function, the array provides type safety. If
   a wrong type is tried to be added to the array, or if the array's contents
   are tried to be used using a wrong type, the compiler will give a warning.

   Example usage:

   struct foo {
	ARRAY_DEFINE(bars, struct bar);
	...
   };

   i_array_init(&foo->bars, 10);

   struct bar *bar = array_idx(&foo->bars, 5);
   struct baz *baz = array_idx(&foo->bars, 5); // compiler warning

   If you want to pass an array as a parameter to a function, you'll need to
   create a type for the array using ARRAY_DEFINE_TYPE() and use the type in
   the parameter using ARRAY_TYPE().

   Example:

   ARRAY_DEFINE_TYPE(foo, struct foo);
   void do_foo(ARRAY_TYPE(foo) *bars) {
	struct foo *foo = array_idx(bars, 0);
   }
*/
#include "array-decl.h"
#include "buffer.h"

#define p_array_init(array, pool, init_count) \
	array_create(array, pool, sizeof(**(array)->v), init_count)
#define i_array_init(array, init_count) \
	p_array_init(array, default_pool, init_count)
#define t_array_init(array, init_count) \
	p_array_init(array, pool_datastack_create(), init_count)

#ifdef __GNUC__
#  define ARRAY_TYPE_CAST_CONST(array) \
	(typeof(*(array)->v))
#  define ARRAY_TYPE_CAST_MODIFIABLE(array) \
	(typeof(*(array)->v_modifiable))
#  define ARRAY_TYPE_CHECK(array, data) \
	typeof(const typeof(**(array)->v_modifiable) *) \
		__tmp_array_data2 __attr_unused__ = \
			(typeof(const typeof(typeof(*(data)) *)))NULL;
#else
#  define ARRAY_TYPE_CAST_CONST(array)
#  define ARRAY_TYPE_CAST_MODIFIABLE(array)
#  define ARRAY_TYPE_CHECK(array, data)
#endif

static inline void
_array_create_from_buffer(struct array *array, buffer_t *buffer,
			  size_t element_size)
{
	array->buffer = buffer;
	array->element_size = element_size;
}
#define array_create_from_buffer(array, buffer, element_size) \
	_array_create_from_buffer(&(array)->arr, buffer, element_size)

static inline void
_array_create(struct array *array, pool_t pool,
	      size_t element_size, unsigned int init_count)
{
	buffer_t *buffer;

        buffer = buffer_create_dynamic(pool, init_count * element_size);
	_array_create_from_buffer(array, buffer, element_size);
}
#define array_create(array, pool, element_size, init_count) \
	_array_create(&(array)->arr, pool, element_size, init_count)

static inline void
_array_free(struct array *array)
{
	buffer_free(array->buffer);
	array->buffer = NULL;
}
#define array_free(array) \
	_array_free(&(array)->arr)

static inline bool
_array_is_created(const struct array *array)
{
	return array->buffer != NULL;
}
#define array_is_created(array) \
	_array_is_created(&(array)->arr)

static inline void
_array_clear(struct array *array)
{
	buffer_set_used_size(array->buffer, 0);
}
#define array_clear(array) \
	_array_clear(&(array)->arr)

static inline void
_array_append(struct array *array, const void *data, unsigned int count)
{
	buffer_append(array->buffer, data, count * array->element_size);
}

#define array_append(array, data, count) STMT_START { \
	ARRAY_TYPE_CHECK(array, data) \
	_array_append(&(array)->arr, data, count); \
} STMT_END

static inline void
_array_append_array(struct array *dest_array, const struct array *src_array)
{
	i_assert(dest_array->element_size == src_array->element_size);
	buffer_append_buf(dest_array->buffer, src_array->buffer, 0, (size_t)-1);
}
#define array_append_array(dest_array, src_array) \
	_array_append_array(&(dest_array)->arr, &(src_array)->arr)

static inline void
_array_insert(struct array *array, unsigned int idx,
	      const void *data, unsigned int count)
{
	buffer_insert(array->buffer, idx * array->element_size,
		      data, count * array->element_size);
}

#define array_insert(array, idx, data, count) STMT_START { \
	ARRAY_TYPE_CHECK(array, data) \
	_array_insert(&(array)->arr, idx, data, count); \
	} STMT_END

static inline void
_array_delete(struct array *array, unsigned int idx, unsigned int count)
{
	buffer_delete(array->buffer, idx * array->element_size,
		      count * array->element_size);
}
#define array_delete(array, idx, count) \
	_array_delete(&(array)->arr, idx, count)

static inline const void *
_array_get(const struct array *array, unsigned int *count_r)
{
	*count_r = array->buffer->used / array->element_size;
	return array->buffer->data;
}
#define array_get(array, count) \
	ARRAY_TYPE_CAST_CONST(array)_array_get(&(array)->arr, count)

static inline const void *
_array_idx(const struct array *array, unsigned int idx)
{
	i_assert(idx * array->element_size < array->buffer->used);
	return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size);
}
#ifdef DISABLE_ASSERTS
#  define array_idx(array, idx) \
	&((*(array)->v)[idx])
#else
#  define array_idx(array, idx) \
	ARRAY_TYPE_CAST_CONST(array)_array_idx(&(array)->arr, idx)
#endif

static inline void *
_array_get_modifiable(struct array *array, unsigned int *count_r)
{
	*count_r = array->buffer->used / array->element_size;
	return buffer_get_modifiable_data(array->buffer, NULL);
}
#define array_get_modifiable(array, count) \
	ARRAY_TYPE_CAST_MODIFIABLE(array) \
		_array_get_modifiable(&(array)->arr, count)

static inline void *
_array_idx_modifiable(struct array *array, unsigned int idx)
{
	size_t pos;

	pos = idx * array->element_size;
	if (pos >= array->buffer->used) {
		/* index doesn't exist yet, initialize with zero */
		buffer_append_zero(array->buffer, pos + array->element_size -
				   array->buffer->used);
	}
	return buffer_get_space_unsafe(array->buffer, pos, array->element_size);
}
#define array_idx_modifiable(array, idx) \
	ARRAY_TYPE_CAST_MODIFIABLE(array) \
		_array_idx_modifiable(&(array)->arr, idx)

static inline void
_array_idx_set(struct array *array, unsigned int idx, const void *data)
{
	size_t pos;

	pos = idx * array->element_size;
	if (pos > array->buffer->used) {
		/* index doesn't exist yet, initialize with zero */
		buffer_append_zero(array->buffer, pos - array->buffer->used);
	}
	buffer_write(array->buffer, pos, data, array->element_size);
}
#define array_idx_set(array, idx, data) STMT_START { \
	ARRAY_TYPE_CHECK(array, data) \
	_array_idx_set(&(array)->arr, idx, data); \
	} STMT_END

static inline void
_array_idx_clear(struct array *array, unsigned int idx)
{
	size_t pos;

	pos = idx * array->element_size;
	if (pos > array->buffer->used) {
		/* index doesn't exist yet, initialize with zero */
		buffer_append_zero(array->buffer, pos - array->buffer->used);
	} else {
		buffer_write_zero(array->buffer, pos, array->element_size);
	}
}
#define array_idx_clear(array, idx) \
	_array_idx_clear(&(array)->arr, idx)

static inline void *
_array_append_space(struct array *array)
{
	void *data;

	data = buffer_append_space_unsafe(array->buffer, array->element_size);
	memset(data, 0, array->element_size);
	return data;
}
#define array_append_space(array) \
	ARRAY_TYPE_CAST_MODIFIABLE(array)_array_append_space(&(array)->arr)

static inline void *
_array_insert_space(struct array *array, unsigned int idx)
{
	void *data;
	size_t pos;

	pos = idx * array->element_size;
	buffer_copy(array->buffer, pos + array->element_size,
		    array->buffer, pos, (size_t)-1);

	data = buffer_get_space_unsafe(array->buffer, pos, array->element_size);
	memset(data, 0, array->element_size);
	return data;
}
#define array_insert_space(array, idx) \
	ARRAY_TYPE_CAST_MODIFIABLE(array) \
		_array_insert_space(&(array)->arr, idx)

static inline unsigned int
_array_count(const struct array *array)
{
	return array->buffer->used / array->element_size;
}
#define array_count(array) \
	_array_count(&(array)->arr)

static inline bool
_array_cmp(const struct array *array1, const struct array *array2)
{
	if (!_array_is_created(array1) || array1->buffer->used == 0)
		return !_array_is_created(array2) || array2->buffer->used == 0;

	if (!_array_is_created(array2))
		return FALSE;

	return buffer_cmp(array1->buffer, array2->buffer);
}
#define array_cmp(array1, array2) \
	_array_cmp(&(array1)->arr, &(array2)->arr)

#endif