#ifndef VEC_TYPE
#error "Need vector type"
#endif

#ifndef VEC_NAME
#error "Need vector name"
#endif

#ifndef VEC_MALLOC
#define VEC_MALLOC malloc
#endif

#ifndef VEC_CALLOC
#define VEC_CALLOC calloc
#endif

#ifndef VEC_REALLOC
#define VEC_REALLOC realloc
#endif

#ifndef VEC_FREE
#define VEC_FREE free
#endif

#ifndef CONTS_VEC_H
#define CONTS_VEC_H

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "conts.h"

#endif /* CONTS_VEC_H */

#define VEC(a) CONTS_JOIN(VEC_NAME, a)

#define VEC_STRUCT VEC_NAME
struct VEC_STRUCT {
	size_t n;
	size_t s;
	VEC_TYPE *buf;
};

typedef VEC_TYPE *VEC(iter);

static inline struct VEC_STRUCT VEC(create)(size_t reserve)
{
	/* first alloc doubles size of s, so divide by two to get wanted
	 * reservation size. Add 1 for odd cases. */
	return (struct VEC_STRUCT) {
		       .n = 0,
		       .s = (reserve + 1) / 2,
		       .buf = NULL,
	};
}

static inline size_t VEC(len)(struct VEC_STRUCT *v)
{
	return v->n;
}

static inline VEC_TYPE *VEC(at)(struct VEC_STRUCT *v, size_t i)
{
	assert(i < v->n && "out of vector bounds");
	return &v->buf[i];
}

static inline VEC_TYPE *VEC(back)(struct VEC_STRUCT *v)
{
	assert(v->n);
	return &v->buf[v->n - 1];
}

static inline VEC_TYPE *VEC(pop)(struct VEC_STRUCT *v)
{
	assert(v->n && "attempting to pop empty vector");
	v->n--;
	return &v->buf[v->n];
}

static inline VEC_TYPE *VEC(append)(struct VEC_STRUCT *v, VEC_TYPE n)
{
	v->n++;
	if (v->n >= v->s || !v->buf) {
		v->s = v->s == 0 ? 1 : 2 * v->s;
		VEC_TYPE *new_buf = VEC_REALLOC(v->buf, v->s * sizeof(VEC_TYPE));
		if (!new_buf) {
			v->n--;
			return NULL;
		}

		v->buf = new_buf;
	}

	v->buf[v->n - 1] = n;
	return &v->buf[v->n - 1];
}

static inline void VEC(reset)(struct VEC_STRUCT *v)
{
	v->n = 0;
}

static inline void VEC(destroy)(struct VEC_STRUCT *v) {
	VEC_FREE(v->buf);
}

typedef int (*VEC(comp_t))(VEC_TYPE *a, VEC_TYPE *b);
static inline void VEC(sort)(struct VEC_STRUCT *v, VEC(comp_t) comp)
{
	qsort(v->buf, v->n, sizeof(VEC_TYPE),
			(int(*)(const void *, const void *))comp);
}

static inline VEC_TYPE *VEC(reserve)(struct VEC_STRUCT *v, size_t n)
{
	if (v->s >= n) {
		v->n = n;
		return v->buf;
	}

	size_t s = v->s;
	while (s <= n)
		s = s == 0 ? 1 : 2 * s;

	VEC_TYPE *new_buf = VEC_REALLOC(v->buf, s * sizeof(VEC_TYPE));
	if (!new_buf)
		return NULL;

	v->n = n;
	v->s = s;
	v->buf = new_buf;
	return v->buf;
}

static inline void VEC(shrink)(struct VEC_STRUCT *v, size_t n)
{
	assert(v->n >= n);
	v->n = n;
}

static inline void VEC(remove)(struct VEC_STRUCT *v, size_t i)
{
	assert(v->n > i);
	size_t c = sizeof(VEC_TYPE) * (v->n - i);
	memcpy(&v->buf[i], &v->buf[i + 1], c);
	v->n--;
}

static inline VEC_TYPE *VEC(begin)(struct VEC_STRUCT *v)
{
	return &v->buf[0];
}

static inline bool VEC(end)(struct VEC_STRUCT *v, VEC_TYPE *i)
{
	return &v->buf[v->n] == i;
}

static inline VEC_TYPE *VEC(next)(struct VEC_STRUCT *v, VEC_TYPE *i)
{
	(void)v;
	return i + 1;
}

#undef VEC
#undef VEC_TYPE
#undef VEC_NAME
#undef VEC_STRUCT

#undef VEC_MALLOC
#undef VEC_CALLOC
#undef VEC_REALLOC
#undef VEC_FREE
