#ifndef DYNBUF_H
#define DYNBUF_H

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

/**
 * For enabling predictable growth rate, always sizing to a power of two when
 * growing. Keep in mind that manual resizing with dynbuf_capacity() will not
 * obey this.
 */
#define GROWTH_POW2

/**
 * Set the growth factor for the buffer. When expanding capacity, the new
 * capacity will be sized in proportion to this value. Two is a decent
 * value, while 1.5 is suited for a more conservative rate.
 */
#define GROWTH_FACTOR 2

/**
 * Initial capacity for the buffer. Anything >= 1 works here.
 */
#define INITIAL_CAPACITY 4

/**
 * Dynamic array/buffer
 *
 * Holds homogenous data. The underlying array will expand automatically.
 */
typedef struct {
    void *data;
    size_t elem_size;
    size_t length;
    size_t capacity;
} Dynbuf;

/** Initialize the buffer */
void dynbuf_init(Dynbuf *v, size_t elem_size);

/** Free the buffer */
void dynbuf_free(Dynbuf *v);

/** Push some data to the buffer */
void dynbuf_push(Dynbuf *v, const void *elem);

/** Resize the buffer */
void dynbuf_resize(Dynbuf *v, size_t newcap);

/** Pop the topmost element */
void dynbuf_pop(Dynbuf *v);

/** Get some data from the buffer */
void *dynbuf_get(Dynbuf *v, size_t index);

/** Check the current size of the buffer (not capacity) */
size_t dynbuf_size(const Dynbuf *v);

/** Check the capacity of the buffer (not size) */
size_t dynbuf_capacity(const Dynbuf *v);

#endif