Skip to content

Instantly share code, notes, and snippets.

@cartercanedy
Created February 21, 2025 20:41
Show Gist options
  • Save cartercanedy/deb8cbd9c6e1c46b96a4d83976791514 to your computer and use it in GitHub Desktop.
Save cartercanedy/deb8cbd9c6e1c46b96a4d83976791514 to your computer and use it in GitHub Desktop.
A macro for generating and using strongly-typed dynamic arrays in C
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
#include <stdlib.h>
#define VECTOR_INIT_CAPACITY 4
// Macro for non-pointer types.
#define DEFINE_VECTOR_TYPE(type) \
typedef struct \
{ \
size_t size; \
size_t capacity; \
type *data; \
} vector_##type; \
\
static inline void vector_##type##_init(vector_##type *v) \
{ \
v->size = 0; \
v->capacity = VECTOR_INIT_CAPACITY; \
v->data = malloc(sizeof(type) * v->capacity); \
if (!v->data) \
{ \
fprintf(stderr, "Allocation error\n"); \
exit(EXIT_FAILURE); \
} \
} \
\
static inline void vector_##type##_free(vector_##type *v) \
{ \
free(v->data); \
v->data = NULL; \
v->size = 0; \
v->capacity = 0; \
} \
\
static inline void vector_##type##_resize(vector_##type *v, size_t capacity) \
{ \
type *new_data = realloc(v->data, sizeof(type) * capacity); \
if (!new_data) \
{ \
fprintf(stderr, "Reallocation error\n"); \
exit(EXIT_FAILURE); \
} \
v->data = new_data; \
v->capacity = capacity; \
} \
\
static inline void vector_##type##_push_back(vector_##type *v, type value) \
{ \
if (v->size >= v->capacity) \
{ \
vector_##type##_resize(v, v->capacity * 2); \
} \
v->data[v->size++] = value; \
} \
\
static inline type vector_##type##_pop_back(vector_##type *v) \
{ \
if (v->size == 0) \
{ \
fprintf(stderr, "Pop from empty vector\n"); \
exit(EXIT_FAILURE); \
} \
return v->data[--v->size]; \
} \
\
static inline type vector_##type##_get(const vector_##type *v, size_t index) \
{ \
if (index >= v->size) \
{ \
fprintf(stderr, "Index out of bounds\n"); \
exit(EXIT_FAILURE); \
} \
return v->data[index]; \
} \
\
static inline void vector_##type##_set(vector_##type *v, size_t index, type value) \
{ \
if (index >= v->size) \
{ \
fprintf(stderr, "Index out of bounds\n"); \
exit(EXIT_FAILURE); \
} \
v->data[index] = value; \
}
// Macro for pointer types.
#define DEFINE_VECTOR_PTR_TYPE(type) \
typedef struct \
{ \
size_t size; \
size_t capacity; \
type **data; \
} vector_ptr_##type; \
\
static inline void vector_ptr_##type##_init(vector_ptr_##type *v) \
{ \
v->size = 0; \
v->capacity = VECTOR_INIT_CAPACITY; \
v->data = malloc(sizeof(type *) * v->capacity); \
if (!v->data) \
{ \
fprintf(stderr, "Allocation error\n"); \
exit(EXIT_FAILURE); \
} \
} \
\
static inline void vector_ptr_##type##_free(vector_ptr_##type *v) \
{ \
free(v->data); \
v->data = NULL; \
v->size = 0; \
v->capacity = 0; \
} \
\
static inline void vector_ptr_##type##_resize(vector_ptr_##type *v, size_t capacity) \
{ \
type **new_data = realloc(v->data, sizeof(type *) * capacity); \
if (!new_data) \
{ \
fprintf(stderr, "Reallocation error\n"); \
exit(EXIT_FAILURE); \
} \
v->data = new_data; \
v->capacity = capacity; \
} \
\
static inline void vector_ptr_##type##_push_back(vector_ptr_##type *v, type *value) \
{ \
if (v->size >= v->capacity) \
{ \
vector_ptr_##type##_resize(v, v->capacity * 2); \
} \
v->data[v->size++] = value; \
} \
\
static inline type *vector_ptr_##type##_pop_back(vector_ptr_##type *v) \
{ \
if (v->size == 0) \
{ \
fprintf(stderr, "Pop from empty vector\n"); \
exit(EXIT_FAILURE); \
} \
return v->data[--v->size]; \
} \
\
static inline type *vector_ptr_##type##_get(const vector_ptr_##type *v, size_t index) \
{ \
if (index >= v->size) \
{ \
fprintf(stderr, "Index out of bounds\n"); \
exit(EXIT_FAILURE); \
} \
return v->data[index]; \
} \
\
static inline void vector_ptr_##type##_set(vector_ptr_##type *v, size_t index, type *value) \
{ \
if (index >= v->size) \
{ \
fprintf(stderr, "Index out of bounds\n"); \
exit(EXIT_FAILURE); \
} \
v->data[index] = value; \
}
#ifdef __cplusplus
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment