view src/lib/array.h @ 3283:21f30709ead8 HEAD

Added ARRAY_DEFINE_EXTERN().
author Timo Sirainen <tss@iki.fi>
date Fri, 08 Apr 2005 18:22:28 +0300
parents a2943c050571
children ed782bb26632
line wrap: on
line source

#ifndef __ARRAY_H
#define __ARRAY_H

#include "buffer.h"

/* Array is a buffer accessible using fixed size elements. If DEBUG is
   enabled, it also provides compile time type safety:

   If DEBUG is enabled, an extra variable is defined along with the array
   itself. This is used to cast array_idx() return value correctly, so
   compiler gives a warning if it's assigned into variable with a different
   type.

   Example usage:

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

   ARRAY_CREATE(&foo->bars, default_pool, struct bar, 10);
   ARRAY_CREATE(&foo->bars, default_pool, struct baz, 10); // compiler warning

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

   When passing array_t as a parameter to function, or when it's otherwise
   accessed in a way that the extra variable cannot be accessed, the code
   won't compile. For situations like those, there's a ARRAY_SET_TYPE() macro.

   Example:

   void do_foo(array_t *bars) {
	ARRAY_SET_TYPE(bars, struct foo);
	struct foo *foo = array_idx(bars, 0);
   }
*/
#if defined (DEBUG) && defined (__GNUC__)
#  define ARRAY_TYPE_CHECKS
#endif

#ifdef ARRAY_TYPE_CHECKS
#  define ARRAY_DEFINE(name, array_type) name; array_type *name ## __ ## type
#  define ARRAY_DEFINE_EXTERN(name, array_type) \
	name; extern array_type *name ## __ ## type
#  define ARRAY_DEFINE_PTR(name, array_type) \
	name; array_type **name ## __ ## type
#  define ARRAY_CREATE(array, pool, array_type, init_count) STMT_START { \
	array_type *_array_tmp = *(array ## __ ## type); _array_tmp = NULL; \
	array_create(array, pool, sizeof(array_type), init_count); \
	} STMT_END
#  define ARRAY_SET_TYPE(array, array_type) \
	array_type **array ## __ ## type = NULL
#  define ARRAY_INIT { 0, 0 }, 0
#else
#  define ARRAY_DEFINE(name, array_type) name
#  define ARRAY_DEFINE_EXTERN(name, array_type) name
#  define ARRAY_DEFINE_PTR(name, array_type) name
#  define ARRAY_CREATE(array, pool, array_type, init_count) \
	array_create(array, pool, sizeof(array_type), init_count)
/* The reason we do this for non-ARRAY_TYPE_CHECKS as well is because if we
   left this empty, some compilers wouldn't like an extra ";" character at
   the beginning of the function (eg. gcc 2.95).

   However just declaring the variable gives "unused variable" warning.
   I couldn't think of anything better, so we just use gcc-specific
   unused-attribute to get rid of that with gcc. */
#  define ARRAY_SET_TYPE(array, array_type) \
	array_type **array ## __ ## type __attr_unused__ = NULL
#  define ARRAY_INIT { 0, 0 }
#endif

struct array {
	buffer_t *buffer;
	size_t element_size;
};

static inline void
array_create_from_buffer(array_t *array, buffer_t *buffer, size_t element_size)
{
	array->buffer = buffer;
	array->element_size = element_size;
}

static inline void
array_create(array_t *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);
}

static inline void
array_free(array_t *array)
{
	buffer_free(array->buffer);
	array->buffer = NULL;
}

static inline int
array_is_created(const array_t *array)
{
	return array->buffer != NULL;
}

static inline void
array_clear(array_t *array)
{
	buffer_set_used_size(array->buffer, 0);
}

static inline void
_array_append(array_t *array, const void *data, unsigned int count)
{
	buffer_append(array->buffer, data, count * array->element_size);
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_append _array_append
#else
#  define array_append(array, data, count) STMT_START { \
	typeof(*(array ## __ ## type)) _array_tmp = data; \
	_array_append(array, _array_tmp, count); \
	} STMT_END
#endif

static inline void
array_append_array(array_t *dest_array, const array_t *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);
}

static inline void
_array_insert(array_t *array, unsigned int idx,
	      const void *data, unsigned int count)
{
	buffer_insert(array->buffer, idx * array->element_size,
		      data, count * array->element_size);
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_insert _array_insert
#else
#  define array_insert(array, idx, data, count) STMT_START { \
	typeof(*(array ## __ ## type)) _array_tmp = data; \
	_array_insert(array, idx, _array_tmp, count); \
	} STMT_END
#endif

static inline void
array_delete(array_t *array, unsigned int idx, unsigned int count)
{
	buffer_delete(array->buffer, idx * array->element_size,
		      count * array->element_size);
}

static inline const void *
_array_get(const array_t *array, unsigned int *count_r)
{
	if (count_r != NULL)
		*count_r = array->buffer->used / array->element_size;
	return array->buffer->data;
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_get _array_get
#else
#  define array_get(array, count) \
	(const typeof(*(array ## __ ## type)))_array_get(array, count)
#endif

static inline const void *
_array_idx(const array_t *array, unsigned int idx)
{
	i_assert(idx * array->element_size < array->buffer->used);
	return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size);
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_idx _array_idx
#else
#  define array_idx(array, idx) \
	(const typeof(*(array ## __ ## type)))_array_idx(array, idx)
#endif

static inline void *
_array_get_modifyable(array_t *array, unsigned int *count_r)
{
	if (count_r != NULL)
		*count_r = array->buffer->used / array->element_size;
	return buffer_get_modifyable_data(array->buffer, NULL);
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_get_modifyable _array_get_modifyable
#else
#  define array_get_modifyable(array, count) \
	(typeof(*(array ## __ ## type))) \
		_array_get_modifyable(array, count)
#endif

static inline void *
_array_modifyable_idx(array_t *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);
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_modifyable_idx _array_modifyable_idx
#else
#  define array_modifyable_idx(array, count) \
	(typeof(*(array ## __ ## type))) \
		_array_modifyable_idx(array, count)
#endif

static inline void
_array_idx_set(array_t *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);
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_idx_set _array_idx_set
#else
#  define array_idx_set(array, idx, data) STMT_START { \
	typeof(*(array ## __ ## type)) _array_tmp = data; \
	_array_idx_set(array, idx, _array_tmp); \
	} STMT_END
#endif

static inline void *
_array_modifyable_append(array_t *array)
{
	void *data;

	data = buffer_append_space_unsafe(array->buffer, array->element_size);
	memset(data, 0, array->element_size);
	return data;
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_modifyable_append _array_modifyable_append
#else
#  define array_modifyable_append(array) \
	(typeof(*(array ## __ ## type))) \
		_array_modifyable_append(array)
#endif

static inline void *
_array_modifyable_insert(array_t *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;
}
#ifndef ARRAY_TYPE_CHECKS
#  define array_modifyable_insert _array_modifyable_insert
#else
#  define array_modifyable_insert(array, idx) \
	(typeof(*(array ## __ ## type))) \
		_array_modifyable_insert(array, idx)
#endif

static inline unsigned int
array_count(const array_t *array)
{
	return array->buffer->used / array->element_size;
}

static inline int
array_cmp(const array_t *array1, const array_t *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);
}

#endif