#ifndef DA_H
#define DA_H

#include <stddef.h>
#include <stdlib.h>

#define CONCAT(a, b) CONCAT_INNER(a, b)
#define CONCAT_INNER(a, b) a ## b

#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__)

#define DA_DEF_STRUCT(type, name)		\
	struct name {				\
		type *items;			\
		size_t size;			\
		size_t cap;			\
	}

#define DA_DEF_STRUCT_ITEM(type, name)		\
	struct {				\
		type *items;			\
		size_t size;			\
		size_t cap;			\
	} name

#define DA_CREATE(da)						\
	do {							\
		(da).cap = 16;					\
		(da).size = 0;					\
		(da).items = calloc((da).cap, sizeof(*(da).items));	\
	} while(0)

#define DA_DESTROY(da)					\
	do {						\
		free((da).items);			\
	} while(0)

#define DA_CLEAR(da)					\
	do {						\
		(da).size = 0;				\
	} while(0)

#define _DA_DELETE(da, index, i)					\
	do {								\
		if ( index > (da).size ) {				\
			break;						\
		}							\
		memmove((da).items+index, (da).items+index+1,		\
			(da).cap - (index+1));				\
		--(da).size;						\
	} while(0)

#define DA_DELETE(da, index) \
	_DA_DELETE(da, index, UNIQUE_NAME(_i))

#define _DA_INSERT(da, item, index, i)					\
	do {								\
		if ( index > (da.size) ) {				\
			break;						\
		}							\
		if ( (da).size+1 >= (da).cap ) {			\
			(da).cap *= 2;					\
			(da).items = realloc((da).items,		\
					     (da).cap * sizeof(*(da).items)); \
		}							\
		memmove((da).items+index+1, (da).items+index,		\
			(da).cap - index);				\
		(da).items[index] = item;				\
		(da).size++;						\
	} while(0)

#define DA_INSERT(da, item, index) \
	_DA_INSERT(da, item, index, UNIQUE_NAME(_i))

#define DA_APPEND(da, item)						\
	do {								\
		if ( (da).size+1 >= (da).cap ) {			\
			(da).items = _realloc((da).items,		\
					      (da).cap,		\
					      ((da).cap*2)		\
					      * sizeof(*(da).items));	\
			(da).cap *= 2;					\
		}							\
		(da).items[(da).size++] = item;			\
	} while(0)

#define DA_TAIL(da) (da).items[(da).size-1]

#define DA_ASSIGN(dst, src)			\
	(dst).items = (src).items;		\
	(dst).size = (src).size;		\
	(dst).cap = (src).cap;

#include <stddef.h>

void * _realloc(void *old, size_t old_size, size_t new_size);

#if defined(DA_IMP) || defined(IMP)

#include <stdlib.h>
#include <string.h>

void *
_realloc(void *old, size_t old_size, size_t new_size)
{
	return realloc(old, new_size);
	void *new = malloc(new_size);
	memset(new, 0, new_size);
	memcpy(new, old, old_size);
	free(old);
	return new;
}

#endif /* defined(DA_IMP) || defined(IMP) */


#endif
