You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
13 KiB

#pragma once
#include <stdint.h>
#include <stdlib.h>
#define VEC(TYPE) \
\
struct vec_##TYPE { \
size_t length; \
size_t capacity; \
TYPE *buffer; /* Backing heap allocation. Different lifetime because realloc might move this */ \
}; \
\
static inline int vec_##TYPE##_init(struct vec_##TYPE *vec, size_t capacity); \
static inline struct vec_##TYPE *vec_##TYPE##_alloc(size_t capacity); \
static inline void vec_##TYPE##_deinit(struct vec_##TYPE *vec); \
static inline void vec_##TYPE##_free(struct vec_##TYPE *vec); \
\
/** \
* Initializes a vec, allocating a backing buffer for the provided capcity \
* @param vec pointer to an uninitialized vec \
* @param capacity \
* @returns 0 on success, -1 on failure \
*/ \
static inline int vec_##TYPE##_init(struct vec_##TYPE *vec, size_t capacity) \
{ \
if (capacity == 0) { \
vec->buffer = NULL; \
} else { \
vec->buffer = calloc(capacity, sizeof(TYPE)); \
if (vec->buffer == NULL) return -1; \
} \
\
vec->length = 0; \
vec->capacity = capacity; \
\
return 0; \
} \
\
/** \
* Allocate and initialize a vec with a backing buffer \
* @param capacity \
* @returns a pointer to an initialized vec on the heap, ready for use \
*/ \
static inline struct vec_##TYPE *vec_##TYPE##_alloc(size_t capacity) \
{ \
struct vec_##TYPE *vec = (struct vec_##TYPE *)calloc(1, sizeof(struct vec_##TYPE)); \
if (vec == NULL) return vec; \
\
int rc = vec_##TYPE##_init(vec, capacity); \
if (rc < 0) { \
vec_##TYPE##_free(vec); \
return NULL; \
} \
\
return vec; \
} \
\
/** \
* Deinitialize a vec, clearing out members and releasing the backing buffer \
* @param vec \
*/ \
static inline void vec_##TYPE##_deinit(struct vec_##TYPE *vec) \
{ \
if (vec->capacity == 0) { \
assert(vec->buffer == NULL); \
assert(vec->length == 0); \
return; \
} \
\
assert(vec->buffer != NULL); \
free(vec->buffer); \
vec->buffer = NULL; \
vec->length = 0; \
vec->capacity = 0; \
} \
\
/** \
* Deinitializes and frees a vec allocated to the heap \
* @param vec \
*/ \
static inline void vec_##TYPE##_free(struct vec_##TYPE *vec) \
{ \
vec_##TYPE##_deinit(vec); \
free(vec); \
} \
\
static inline int vec_##TYPE##_resize(struct vec_##TYPE *vec, size_t capacity) \
{ \
if (vec->capacity != capacity) { \
TYPE *temp = (TYPE *)realloc(vec->buffer, sizeof(TYPE) * capacity); \
if (temp == NULL) return -1; \
vec->buffer = temp; \
vec->capacity = capacity; \
} \
return 0; \
} \
\
\
static inline int vec_##TYPE##_grow(struct vec_##TYPE *vec) \
{ \
size_t capacity = vec->capacity == 0 ? 1 : vec->capacity * 2; \
return vec_##TYPE##_resize(vec, capacity); \
} \
\
static inline int vec_##TYPE##_insert(struct vec_##TYPE *vec, uint32_t idx, TYPE value) \
{ \
if (vec->length == vec->capacity) { \
int rc = vec_##TYPE##_grow(vec); \
if (rc != 0) return -1; \
} \
\
vec->buffer[idx] = value; \
return 0; \
} \
\
static inline TYPE *vec_##TYPE##_get(struct vec_##TYPE *vec, uint32_t idx) \
{ \
if (idx >= vec->capacity) return NULL; \
\
return &vec->buffer[idx]; \
} \
\
static inline int vec_##TYPE##_push(struct vec_##TYPE *vec, TYPE value) \
{ \
if (vec->length == vec->capacity) { \
int rc = vec_##TYPE##_grow(vec); \
if (rc != 0) return -1; \
} \
\
vec->buffer[vec->length] = value; \
vec->length++; \
\
return 0; \
}