diff options
| author | Clement Sibille <clements+git@lisible.xyz> | 2024-05-20 00:56:32 +0900 |
|---|---|---|
| committer | Clement Sibille <clements+git@lisible.xyz> | 2024-05-20 01:28:21 +0900 |
| commit | 62eb3b371fffe75e0da5393cb558a472a177f4ce (patch) | |
| tree | 9bd00cc4b6042d440fa4e938d71c015bfc6285d2 | |
| parent | 2d813cc4c26af142bcfaabdf654371e7801f6491 (diff) | |
Add vec module
| -rw-r--r-- | meson.build | 3 | ||||
| -rw-r--r-- | src/lisiblestd/vec.c | 4 | ||||
| -rw-r--r-- | src/lisiblestd/vec.h | 111 | ||||
| -rw-r--r-- | tests/vec.c | 54 |
4 files changed, 171 insertions, 1 deletions
diff --git a/meson.build b/meson.build index b07c672..b640bf1 100644 --- a/meson.build +++ b/meson.build @@ -5,7 +5,8 @@ lisiblestd_lib = library('lisiblestd', 'src/lisiblestd/log.c', 'src/lisiblestd/memory.c', 'src/lisiblestd/string.c', - 'src/lisiblestd/bytes.c' + 'src/lisiblestd/bytes.c', + 'src/lisiblestd/vec.c' ) lisiblestd_dep = declare_dependency(include_directories: lisiblestd_incdir, link_with: [lisiblestd_lib]) diff --git a/src/lisiblestd/vec.c b/src/lisiblestd/vec.c new file mode 100644 index 0000000..2569e4b --- /dev/null +++ b/src/lisiblestd/vec.c @@ -0,0 +1,4 @@ +#include "vec.h" + +DEF_VEC(char *, StringVec, 256) +DEF_VEC(u8, u8vec, 1024) diff --git a/src/lisiblestd/vec.h b/src/lisiblestd/vec.h new file mode 100644 index 0000000..6592bc4 --- /dev/null +++ b/src/lisiblestd/vec.h @@ -0,0 +1,111 @@ +#ifndef LSTD_VEC_H +#define LSTD_VEC_H + +#include "assert.h" +#include "memory.h" +#include "types.h" +#include <stdlib.h> +#include <string.h> + +#define DECL_VEC(T, name) \ + struct name { \ + Allocator *allocator; \ + T *data; \ + size_t length; \ + size_t capacity; \ + }; \ + typedef struct name name; \ + void name##_init(Allocator *allocator, name *vec); \ + void name##_deinit(name *vec); \ + void name##_reserve(name *vec, size_t length_to_reserve); \ + void name##_push_back(name *vec, T value); \ + T name##_pop_back(name *vec); \ + void name##_append(name *vec, const T *values, size_t count); \ + void name##_clear(name *vec); \ + size_t name##_length(name *vec); \ + size_t name##_capacity(name *vec); + +#define DEF_VEC(T, name, initial_capacity) \ + void name##_init(Allocator *allocator, name *vec) { \ + LSTD_ASSERT(vec != NULL); \ + vec->allocator = allocator; \ + vec->capacity = initial_capacity; \ + vec->data = Allocator_allocate(allocator, vec->capacity * sizeof(T)); \ + vec->length = 0; \ + } \ + void name##_deinit(name *vec) { \ + LSTD_ASSERT(vec != NULL); \ + Allocator_free(vec->allocator, vec->data); \ + vec->data = NULL; \ + vec->capacity = 0; \ + vec->length = 0; \ + } \ + void name##_reserve(name *vec, size_t length_to_reserve) { \ + LSTD_ASSERT(vec != NULL); \ + if (vec->length + length_to_reserve < vec->capacity) { \ + /* No need to reallocate as there is still enough capacity */ \ + return; \ + } \ + \ + size_t new_capacity = vec->capacity * 2; \ + if (vec->length + length_to_reserve > new_capacity) { \ + new_capacity = vec->length + length_to_reserve; \ + } \ + \ + vec->data = Allocator_reallocate(vec->allocator, vec->data, \ + vec->capacity * sizeof(T), \ + new_capacity * sizeof(T)); \ + if (!vec->data) { \ + /* TODO maybe improve that error handling? */ \ + LOG0_ERROR("Vec reallocation failed, no memory left"); \ + abort(); \ + } \ + vec->capacity = new_capacity; \ + } \ + void name##_push_back(name *vec, T value) { \ + LSTD_ASSERT(vec != NULL); \ + name##_reserve(vec, vec->length + 1); \ + vec->data[vec->length] = value; \ + vec->length++; \ + } \ + T name##_pop_back(name *vec) { \ + LSTD_ASSERT(vec != NULL); \ + vec->length--; \ + return vec->data[vec->length]; \ + } \ + void name##_append(name *vec, const T *values, size_t count) { \ + LSTD_ASSERT(vec != NULL); \ + LSTD_ASSERT(values != NULL); \ + name##_reserve(vec, vec->length + count); \ + memmove(&vec->data[vec->length], values, count * sizeof(T)); \ + vec->length += count; \ + } \ + void name##_clear(name *vec) { \ + LSTD_ASSERT(vec != NULL); \ + vec->length = 0; \ + } \ + size_t name##_length(name *vec) { \ + LSTD_ASSERT(vec != NULL); \ + return vec->length; \ + } \ + size_t name##_capacity(name *vec) { \ + LSTD_ASSERT(vec != NULL); \ + return vec->capacity; \ + } + +#define VEC_IMPL(T, name, initial_capacity) \ + DECL_VEC(T, name) \ + DEF_VEC(T, name, initial_capacity) + +#define VEC_FOR_EACH(vec, elt_identifier, T, ...) \ + do { \ + for (size_t i = 0; i < (vec)->length; i++) { \ + T *elt_identifier = &(vec)->data[i]; \ + __VA_ARGS__ \ + } \ + } while (0); + +DECL_VEC(char *, StringVec) +DECL_VEC(u8, u8vec) + +#endif // LSTD_VEC_H diff --git a/tests/vec.c b/tests/vec.c new file mode 100644 index 0000000..6ad973f --- /dev/null +++ b/tests/vec.c @@ -0,0 +1,54 @@ +#include "test.h" +#include <lisiblestd/log.h> +#include <lisiblestd/vec.h> +#include <memory.h> + +VEC_IMPL(int, intvec, 128) + +void t_vec_init(void) { + intvec vec = {0}; + intvec_init(&system_allocator, &vec); + T_ASSERT(intvec_length(&vec) == 0); + T_ASSERT(intvec_capacity(&vec) == 128); + intvec_deinit(&vec); +} + +void t_vec_push_back(void) { + intvec vec = {0}; + intvec_init(&system_allocator, &vec); + T_ASSERT(intvec_length(&vec) == 0); + intvec_push_back(&vec, 10); + T_ASSERT(intvec_length(&vec) == 1); + intvec_push_back(&vec, 13); + intvec_push_back(&vec, 15); + T_ASSERT(intvec_length(&vec) == 3); + T_ASSERT(vec.data[0] == 10); + T_ASSERT(vec.data[1] == 13); + T_ASSERT(vec.data[2] == 15); + intvec_deinit(&vec); +} +void t_vec_append(void) { + intvec vec = {0}; + intvec_init(&system_allocator, &vec); + T_ASSERT(intvec_length(&vec) == 0); + intvec_push_back(&vec, 10); + intvec_append(&vec, (int[]){11, 12, 13}, 3); + T_ASSERT(intvec_length(&vec) == 4); + T_ASSERT(vec.data[0] == 10); + T_ASSERT(vec.data[1] == 11); + T_ASSERT(vec.data[2] == 12); + T_ASSERT(vec.data[3] == 13); + intvec_deinit(&vec); +} + +void t_vec_u8_append_1(void) { + u8vec vec; + u8vec_init(&system_allocator, &vec); + u8 v = 1; + for (size_t i = 0; i < 1000; i++) + u8vec_append(&vec, &v, 1); + u8vec_deinit(&vec); +} + +TEST_SUITE(TEST(t_vec_init), TEST(t_vec_push_back), TEST(t_vec_append), + TEST(t_vec_u8_append_1)) |
