/* An as-small-as-possible dynamic array implementation. */
#define MVM_VECTOR_DECL(type, x) type *x; \
    size_t x ## _num; \
    size_t x ## _alloc


#define MVM_VECTOR_INIT(x, size) do { \
        size_t _s = (size); \
        x = (_s > 0) ? MVM_calloc(_s, sizeof(*x)) : NULL; \
        x ## _num = 0; \
        x ## _alloc = _s; \
    } while (0)

#define MVM_VECTOR_CLEAR(x) do { \
        x ## _num = 0; \
    } while (0)

#define MVM_VECTOR_DESTROY(x) do { \
        MVM_free(x); \
        x = NULL; \
        x ## _num = 0; \
        x ## _alloc = 0; \
    } while (0)

#define MVM_VECTOR_ELEMS(x) \
    (x ## _num)

#define MVM_VECTOR_SIZE(x) \
    (sizeof(*x) * (x ## _alloc))

#define MVM_VECTOR_TOP(x) \
    ((x) + (x ## _num))

#define MVM_VECTOR_GROW(x, size) do {\
        size_t _s = (size); \
        (x) = MVM_recalloc(x, MVM_VECTOR_SIZE(x), _s*sizeof(*x));   \
        (x ## _alloc) = _s; \
    } while (0)


#define MVM_VECTOR_ENSURE_SIZE(x, size) do {\
        size_t _s = (size); \
        if (_s >= (x ## _alloc)) {    \
            size_t newsize = (x ## _alloc) * 2 + 2; \
            while (_s >= newsize) newsize *= 2; \
            MVM_VECTOR_GROW(x, newsize); \
        } \
    } while (0)

#define MVM_VECTOR_ENSURE_SPACE(x, space) \
    MVM_VECTOR_ENSURE_SIZE(x, (x ## _num) + (space))

#define MVM_VECTOR_PUSH(x, value) do { \
        MVM_VECTOR_ENSURE_SPACE(x, 1); \
        (x)[(x ## _num)++] = (value); \
    } while(0)

#define MVM_VECTOR_POP(x) \
    (x)[--(x ## _num)]


#define MVM_VECTOR_APPEND(x, ar, len) do { \
        size_t _l = (len); \
        MVM_VECTOR_ENSURE_SPACE(x, _l); \
        memcpy(MVM_VECTOR_TOP(x), ar, _l * sizeof((x)[0])); \
        (x ## _num) += _l; \
    } while(0)

#define MVM_VECTOR_SPLICE(x, ofs, len, out) do { \
        size_t _l = (len), _o = (ofs); \
        void * buf = (out); \
        if (buf != NULL) { memcpy(buf, (x) + _o, _l * sizeof((x)[0])); } \
        memmove((x) + _o, (x) + _o + _l, ((x ## _num) - _l - _o) * sizeof((x)[0])); \
        (x ## _num) -= _l; \
    } while (0)

#define MVM_VECTOR_ASSIGN(a, b) do { \
        (a) = (b); \
        (a ## _alloc) = (b ## _alloc); \
        (a ## _num) = (b ## _num); \
    } while (0)
