summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Sibille <clements+git@lisible.xyz>2024-05-20 00:56:32 +0900
committerClement Sibille <clements+git@lisible.xyz>2024-05-20 01:28:21 +0900
commit62eb3b371fffe75e0da5393cb558a472a177f4ce (patch)
tree9bd00cc4b6042d440fa4e938d71c015bfc6285d2
parent2d813cc4c26af142bcfaabdf654371e7801f6491 (diff)
Add vec module
-rw-r--r--meson.build3
-rw-r--r--src/lisiblestd/vec.c4
-rw-r--r--src/lisiblestd/vec.h111
-rw-r--r--tests/vec.c54
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))
Go back to lisible.xyz