Created
February 21, 2025 20:41
-
-
Save cartercanedy/deb8cbd9c6e1c46b96a4d83976791514 to your computer and use it in GitHub Desktop.
A macro for generating and using strongly-typed dynamic arrays in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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