diff options
| author | Lion Kortlepel <[email protected]> | 2026-01-15 00:28:30 +0100 |
|---|---|---|
| committer | Lion Kortlepel <[email protected]> | 2026-01-15 00:28:30 +0100 |
| commit | 0b6d6b70f171b18cad86c0ac8d79a2c849175324 (patch) | |
| tree | 33fa0f9291aa4c6b99b53fb437ef2af6164ea190 /ls_vec.h | |
| download | vec-0b6d6b70f171b18cad86c0ac8d79a2c849175324.tar.zst vec-0b6d6b70f171b18cad86c0ac8d79a2c849175324.zip | |
initial commit
Diffstat (limited to 'ls_vec.h')
| -rw-r--r-- | ls_vec.h | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/ls_vec.h b/ls_vec.h new file mode 100644 index 0000000..5fcb454 --- /dev/null +++ b/ls_vec.h @@ -0,0 +1,114 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/* + * Lion's Standard (LS) ANSI C vector library. + * + * This is a vector library, i.e. a dynamically sized array. + * To get started, you have to declare your type: + * + * VEC(int) + * + * which creates a struct and the associated functions for a vec_int, + * meaning a vector of type `int`. The resulting struct is named `vec_int` + * and all associated functions are prefixed with that same name, for + * example `vec_int_init`, `vec_int_push`, etc. + * + * You can choose a name for long or complex types like this: + * + * VEC_NAMED(int*, intp) + * + * which results in vec_intp, vec_intp_push, etc. or + * + * VEC_NAMED(struct Car, car) + * + * which results in vec_car, vec_car_push, etc. + * + * The VEC and VEC_NAMED macros create both the declaration and implementation. + * If you'd like to split that, call + * + * VEC_DECL(int) + * + * to generate the declarations, and somewhere else + * + * VEC_IMPL(int) + * + * to generate the implementation. The same with VEC_NAMED_DECL + * and VEC_NAMED_IMPL. + * + * Full example: + * + * VEC(int) + * + * int main(void) { + * vec_int vec; + * vec_int_init(&vec); + * for (int i = 0; i < 10; ++i) { + * vec_int_push(&vec, i); + * } + * vec_int_clear(&vec); + * } + * + */ + +#define LS_VEC_DECL(T, name) \ + typedef struct name { \ + size_t size; \ + size_t capacity; \ + T* data; \ + } name; \ + void name##_init(name* vec); \ + void name##_clear(name* vec); \ + int name##_reserve(name* vec, size_t count); \ + int name##_push(name* vec, T value); +#define LS_VEC_IMPL(T, name) _ls_VEC_IMPL_DETAIL(T, name, ) + +#define LS_VEC_INLINE(T, name) \ + typedef struct name { \ + size_t size; \ + size_t capacity; \ + T* data; \ + } name; \ + _ls_VEC_IMPL_DETAIL(T, name, static) + +#define _ls_VEC_IMPL_DETAIL(T, name, specifier) \ + specifier void name##_init(name* vec) { memset(vec, 0, sizeof(*vec)); } \ + specifier void name##_clear(name* vec) { \ + if (vec->data) { \ + free(vec->data); \ + vec->data = NULL; \ + } \ + vec->size = 0; \ + vec->capacity = 0; \ + } \ + specifier int name##_reserve(name* vec, size_t count) { \ + if (vec->capacity < count) { \ + T* new_data; \ + size_t total; \ + if (count == 0) { \ + vec->capacity = 5; \ + } else { \ + size_t new_cap = (size_t)((float)vec->capacity * 1.6f + 1.0f); \ + vec->capacity = new_cap > count ? new_cap : count; \ + } \ + total = vec->capacity * sizeof(T); \ + if (vec->capacity != 0 && total / vec->capacity != sizeof(T)) \ + return 0; /* integer overflow */ \ + new_data = (T*)realloc(vec->data, total); \ + if (!new_data) \ + return 0; \ + vec->data = new_data; \ + } \ + return 1; \ + } \ + specifier int name##_push(name* vec, T value) { \ + if (!name##_reserve(vec, vec->size + 1)) { \ + return 0; \ + } \ + vec->data[vec->size++] = value; \ + return 1; \ + } |
