From f2fb8311d373cfd498dfbebc539982b8ad174615 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov <0x7fffff@guattari.ru> Date: Sat, 6 Aug 2022 16:32:59 +0400 Subject: input buffer, dynamic array --- source/kit/CMakeLists.txt | 11 +- source/kit/allocator.c | 18 +++ source/kit/allocator.h | 25 ++++ source/kit/array_ref.c | 41 +++++++ source/kit/array_ref.h | 61 ++++++++++ source/kit/async_function.h | 12 +- source/kit/dynamic_array.c | 48 ++++++++ source/kit/dynamic_array.h | 108 +++++++++++++++++ source/kit/input_buffer.c | 107 +++++++++++++++++ source/kit/input_buffer.h | 31 +++++ source/kit/input_stream.c | 62 ++++++++++ source/kit/input_stream.h | 32 +++++ source/kit/string_ref.c | 1 + source/kit/string_ref.h | 20 ++++ source/kit_test/test.h | 2 +- source/test/unittests/CMakeLists.txt | 3 +- source/test/unittests/array_ref.test.c | 42 +++++++ source/test/unittests/async_function.test.c | 2 +- source/test/unittests/dynamic_array.test.c | 174 ++++++++++++++++++++++++++++ source/test/unittests/input_buffer.test.c | 20 ++++ source/test/unittests/input_stream.test.c | 23 ++++ 21 files changed, 832 insertions(+), 11 deletions(-) create mode 100644 source/kit/allocator.c create mode 100644 source/kit/allocator.h create mode 100644 source/kit/array_ref.c create mode 100644 source/kit/array_ref.h create mode 100644 source/kit/dynamic_array.c create mode 100644 source/kit/dynamic_array.h create mode 100644 source/kit/input_buffer.c create mode 100644 source/kit/input_buffer.h create mode 100644 source/kit/input_stream.c create mode 100644 source/kit/input_stream.h create mode 100644 source/kit/string_ref.c create mode 100644 source/kit/string_ref.h create mode 100644 source/test/unittests/array_ref.test.c create mode 100644 source/test/unittests/dynamic_array.test.c create mode 100644 source/test/unittests/input_buffer.test.c create mode 100644 source/test/unittests/input_stream.test.c diff --git a/source/kit/CMakeLists.txt b/source/kit/CMakeLists.txt index 24d1aed..761f572 100644 --- a/source/kit/CMakeLists.txt +++ b/source/kit/CMakeLists.txt @@ -1,6 +1,13 @@ target_sources( ${KIT_LIBRARY} PRIVATE - async_function.c + input_buffer.c input_stream.c string_ref.c + async_function.c allocator.c array_ref.c dynamic_array.c PUBLIC - $) + $ + $ + $ + $ + $ + $ + $) diff --git a/source/kit/allocator.c b/source/kit/allocator.c new file mode 100644 index 0000000..fbad11f --- /dev/null +++ b/source/kit/allocator.c @@ -0,0 +1,18 @@ +#include "allocator.h" + +#include + +static void *allocate(void *_, size_t size) { + return malloc(size); +} + +static void deallocate(void *_, void *pointer) { + free(pointer); +} + +struct kit_allocator kit_alloc_default() { + struct kit_allocator alloc = { .state = NULL, + .allocate = allocate, + .deallocate = deallocate }; + return alloc; +} diff --git a/source/kit/allocator.h b/source/kit/allocator.h new file mode 100644 index 0000000..24ad5aa --- /dev/null +++ b/source/kit/allocator.h @@ -0,0 +1,25 @@ +#ifndef KIT_ALLOCATOR_H +#define KIT_ALLOCATOR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*kit_allocate_fn)(void *state, size_t size); +typedef void (*kit_deallocate_fn)(void *state, void *pointer); + +struct kit_allocator { + void *state; + kit_allocate_fn allocate; + kit_deallocate_fn deallocate; +}; + +struct kit_allocator kit_alloc_default(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit/array_ref.c b/source/kit/array_ref.c new file mode 100644 index 0000000..2e46324 --- /dev/null +++ b/source/kit/array_ref.c @@ -0,0 +1,41 @@ +#include "array_ref.h" + +#include + +_Bool ar_equal_bytes(ptrdiff_t left_element_size, ptrdiff_t left_size, + void const *left_data, + ptrdiff_t right_element_size, + ptrdiff_t right_size, void const *right_data) { + if (left_element_size != right_element_size) + return 0; + if (left_size != right_size) + return 0; + for (ptrdiff_t i = 0; i < left_size; i++) + if (memcmp((char const *) left_data + i * left_element_size, + (char const *) right_data + i * left_element_size, + left_element_size) != 0) + return 0; + return 1; +} + +int ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size, + void const *left_data, ptrdiff_t right_element_size, + ptrdiff_t right_size, void const *right_data, + ar_compare_fn compare) { + if (left_element_size < right_element_size) + return -1; + if (left_element_size > right_element_size) + return 1; + for (ptrdiff_t i = 0; i < left_size && i < right_size; i++) { + int const c = compare( + (char const *) left_data + i * left_element_size, + (char const *) right_data + i * left_element_size); + if (c != 0) + return c; + } + if (left_size < right_size) + return -1; + if (left_size > right_size) + return 1; + return 0; +} diff --git a/source/kit/array_ref.h b/source/kit/array_ref.h new file mode 100644 index 0000000..649af8b --- /dev/null +++ b/source/kit/array_ref.h @@ -0,0 +1,61 @@ +#ifndef KIT_ARRAY_REF_H +#define KIT_ARRAY_REF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*ar_compare_fn)(void const *left, void const *right); + +_Bool ar_equal_bytes(ptrdiff_t left_element_size, ptrdiff_t left_size, + void const *left_data, + ptrdiff_t right_element_size, + ptrdiff_t right_size, void const *right_data); + +int ar_compare(ptrdiff_t left_element_size, ptrdiff_t left_size, + void const *left_data, ptrdiff_t right_element_size, + ptrdiff_t right_size, void const *right_data, + ar_compare_fn compare); + +#define AR(name_, type_) \ + struct { \ + ptrdiff_t size; \ + type_ *values; \ + } name_ + +#define AR_CONST(name_, type_) \ + struct { \ + ptrdiff_t size; \ + type_ const *values; \ + } name_ + +#define AR_TYPE(name_, element_type_) \ + struct name_ { \ + ptrdiff_t size; \ + element_type_ *values; \ + } + +#define AR_TYPE_CONST(name_, element_type_) \ + struct name_ { \ + ptrdiff_t size; \ + element_type_ const *values; \ + } + +#define AR_EQUAL(left_, right_) \ + ar_equal_bytes(sizeof((left_).values[0]), (left_).size, \ + (left_).values, sizeof((right_).values[0]), \ + (right_).size, (right_).values) + +#define AR_COMPARE(left_, right_, compare_) \ + ar_compare(sizeof((left_).values[0]), (left_).size, \ + (left_).values, sizeof((right_).values[0]), \ + (right_).size, (right_).values, \ + (ar_compare_fn) (compare_)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit/async_function.h b/source/kit/async_function.h index 77a88ef..69b9453 100644 --- a/source/kit/async_function.h +++ b/source/kit/async_function.h @@ -1,15 +1,15 @@ -#ifndef AF_AF_H -#define AF_AF_H +#ifndef KIT_ASYNC_FUNCTION_H +#define KIT_ASYNC_FUNCTION_H #ifdef __cplusplus extern "C" { #endif enum af_request { - af_request_resume, - af_request_join, - af_request_resume_and_join, - af_request_execute + af_request_execute = 0, + af_request_resume = 1, + af_request_join = 2, + af_request_resume_and_join = 3 }; typedef struct { diff --git a/source/kit/dynamic_array.c b/source/kit/dynamic_array.c new file mode 100644 index 0000000..a3ba3dc --- /dev/null +++ b/source/kit/dynamic_array.c @@ -0,0 +1,48 @@ +#include "dynamic_array.h" + +#include + +void da_init(struct da_void *array, ptrdiff_t element_size, + ptrdiff_t size, struct kit_allocator alloc) { + memset(array, 0, sizeof(struct da_void)); + + if (size > 0) + array->values = alloc.allocate(alloc.state, element_size * size); + + if (array->values != NULL) { + array->capacity = size; + array->size = size; + } + + array->alloc = alloc; +} + +static ptrdiff_t eval_capacity(ptrdiff_t current_cap, + ptrdiff_t required_cap) { + if (current_cap == 0) + return required_cap; + ptrdiff_t cap = current_cap; + while (cap < required_cap) cap *= 2; + return cap; +} + +void da_resize(struct da_void *array, ptrdiff_t element_size, + ptrdiff_t size) { + if (size <= array->capacity) { + array->size = size; + } else { + ptrdiff_t capacity = eval_capacity(array->capacity, size); + + void *bytes = array->alloc.allocate(array->alloc.state, + element_size * capacity); + if (bytes != NULL) { + if (array->size > 0) + memcpy(bytes, array->values, element_size * array->size); + if (array->values != NULL) + array->alloc.deallocate(array->alloc.state, array->values); + array->capacity = capacity; + array->size = size; + array->values = bytes; + } + } +} \ No newline at end of file diff --git a/source/kit/dynamic_array.h b/source/kit/dynamic_array.h new file mode 100644 index 0000000..245da63 --- /dev/null +++ b/source/kit/dynamic_array.h @@ -0,0 +1,108 @@ +#ifndef KIT_DYNAMIC_ARRAY_H +#define KIT_DYNAMIC_ARRAY_H + +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct da_void { + ptrdiff_t capacity; + ptrdiff_t size; + void *values; + struct kit_allocator alloc; +}; + +void da_init(struct da_void *array, ptrdiff_t element_size, + ptrdiff_t size, struct kit_allocator alloc); + +void da_resize(struct da_void *array, ptrdiff_t element_size, + ptrdiff_t size); + +/* Declare dynamic array type. + */ +#define DA_TYPE(name_, element_type_) \ + struct name_ { \ + ptrdiff_t capacity; \ + ptrdiff_t size; \ + element_type_ *values; \ + struct kit_allocator alloc; \ + } + +/* Declare dynamic array. + */ +#define DA(name_, element_type_) \ + struct { \ + ptrdiff_t capacity; \ + ptrdiff_t size; \ + element_type_ *values; \ + struct kit_allocator alloc; \ + } name_ + +/* Initialize dynamic array. + */ +#define DA_INIT(array_, size_, alloc_) \ + da_init((struct da_void *) &(array_), sizeof((array_).values[0]), \ + (size_), (alloc_)) + +/* Declare and initialize dynamic array. + */ +#define DA_CREATE(name_, element_type_, size_) \ + DA(name_, element_type_); \ + DA_INIT(name_, (size_), kit_alloc_default()) + +/* Destroy dynamic array. + */ +#define DA_DESTROY(array_) \ + { \ + if ((array_).values != NULL) \ + (array_).alloc.deallocate((array_).alloc.state, \ + (array_).values); \ + } + +/* Resize dynamic array. + */ +#define DA_RESIZE(array_, size_) \ + da_resize((struct da_void *) &(array_), \ + sizeof((array_).values[0]), size_) + +/* Append a value to dynamic array. + */ +#define DA_APPEND(array_, value_) \ + { \ + ptrdiff_t const kit_index_back_ = (array_).size; \ + DA_RESIZE((array_), kit_index_back_ + 1); \ + if (kit_index_back_ < (array_).size) \ + (array_).values[kit_index_back_] = (value_); \ + } + +/* Insert a value into dynamic array. + */ +#define DA_INSERT(array_, index_, value_) \ + { \ + ptrdiff_t const kit_index_back_ = (array_).size; \ + ptrdiff_t const kit_indert_n_ = (index_); \ + DA_RESIZE((array_), kit_index_back_ + 1); \ + if (kit_index_back_ + 1 == (array_).size) { \ + for (ptrdiff_t kit_i_ = kit_index_back_; \ + kit_i_ > kit_indert_n_; kit_i_--) \ + (array_).values[kit_i_] = (array_).values[kit_i_ - 1]; \ + (array_).values[kit_indert_n_] = (value_); \ + } \ + } + +/* Erase a value from dynamic array. + */ +#define DA_ERASE(array_, index_) \ + { \ + for (ptrdiff_t i_ = (index_) + 1; i_ < (array_).size; i_++) \ + (array_).values[i_ - 1] = (array_).values[i_]; \ + DA_RESIZE((array_), (array_).size - 1); \ + } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit/input_buffer.c b/source/kit/input_buffer.c new file mode 100644 index 0000000..e1e0cea --- /dev/null +++ b/source/kit/input_buffer.c @@ -0,0 +1,107 @@ +#include "input_buffer.h" + +#include + +struct internal_buffer { + ptrdiff_t ref_count; + struct is_handle upstream; + struct kit_allocator alloc; + DA(data, char); +}; + +static struct internal_buffer *buf_init(struct is_handle upstream, + struct kit_allocator alloc) { + struct internal_buffer *buf; + buf = alloc.allocate(alloc.state, sizeof *buf); + if (buf != NULL) { + memset(buf, 0, sizeof *buf); + buf->ref_count = 1; + buf->upstream = upstream; + buf->alloc = alloc; + DA_INIT(buf->data, 0, alloc); + } + return buf; +} + +static struct kit_allocator buf_alloc(void *p) { + return ((struct internal_buffer *) p)->alloc; +} + +static void buf_acquire(void *p) { + struct internal_buffer *buf = (struct internal_buffer *) p; + buf->ref_count++; +} + +static void buf_release(void *p) { + struct internal_buffer *buf = (struct internal_buffer *) p; + if (--buf->ref_count == 0) { + DA_DESTROY(buf->data); + buf->alloc.deallocate(buf->alloc.state, buf); + } +} + +static void buf_adjust(void *p, ptrdiff_t size) { + struct internal_buffer *buf = (struct internal_buffer *) p; + ptrdiff_t offset = buf->data.size; + if (offset < size) { + DA_RESIZE(buf->data, size); + out_str destination = { .size = size - offset, + .values = buf->data.values + offset }; + ptrdiff_t n = IS_READ(buf->upstream, destination); + DA_RESIZE(buf->data, offset + n); + } +} + +static ptrdiff_t min(ptrdiff_t a, ptrdiff_t b) { + if (a < b) + return a; + return b; +} + +static ptrdiff_t buf_read(void *p, ptrdiff_t offset, + out_str destination) { + struct internal_buffer *buf = (struct internal_buffer *) p; + ptrdiff_t n = min(destination.size, buf->data.size - offset); + memcpy(destination.values, buf->data.values + offset, n); + return n; +} + +struct ib_handle ib_wrap(struct is_handle upstream, + struct kit_allocator alloc) { + struct ib_handle buf; + memset(&buf, 0, sizeof buf); + buf.error = 0; + DA_INIT(buf.data, 0, alloc); + buf.internal = buf_init(upstream, alloc); + if (buf.internal == NULL) + buf.error = 1; + return buf; +} + +struct ib_handle ib_read(struct ib_handle buf, ptrdiff_t size) { + struct ib_handle next; + memset(&next, 0, sizeof next); + if (buf.error) { + next.error = 1; + } else { + buf_acquire(buf.internal); + buf_adjust(buf.internal, buf.offset + size); + DA_INIT(next.data, size, buf_alloc(buf.internal)); + if (next.data.size != size) + next.error = 1; + out_str destination = { .size = next.data.size, + .values = next.data.values }; + ptrdiff_t n = buf_read(buf.internal, buf.offset, destination); + next.offset = buf.offset + n; + next.internal = buf.internal; + DA_RESIZE(next.data, n); + if (next.data.size != n) + next.error = 1; + } + return next; +} + +void ib_destroy(struct ib_handle buf) { + buf_release(buf.internal); + DA_DESTROY(buf.data); +} diff --git a/source/kit/input_buffer.h b/source/kit/input_buffer.h new file mode 100644 index 0000000..38ece8d --- /dev/null +++ b/source/kit/input_buffer.h @@ -0,0 +1,31 @@ +#ifndef KIT_INPUT_BUFFER_H +#define KIT_INPUT_BUFFER_H + +#include "dynamic_array.h" +#include "input_stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ib_handle { + _Bool error; + ptrdiff_t offset; + void *internal; + DA(data, char); +}; + +struct ib_handle ib_wrap(struct is_handle upstream, + struct kit_allocator alloc); + +struct ib_handle ib_read(struct ib_handle buf, ptrdiff_t size); + +void ib_destroy(struct ib_handle buf); + +#define IB_WRAP(upstream) ib_wrap(upstream, kit_alloc_default()) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit/input_stream.c b/source/kit/input_stream.c new file mode 100644 index 0000000..500e83d --- /dev/null +++ b/source/kit/input_stream.c @@ -0,0 +1,62 @@ +#include "input_stream.h" + +#include + +enum input_stream_type { input_stream_cstr }; + +struct is_state_basic { + ptrdiff_t type; + struct kit_allocator alloc; +}; + +struct is_state_cstr { + ptrdiff_t type; + struct kit_allocator alloc; + cstr string; +}; + +static _Bool check_type(void *state, ptrdiff_t type) { + struct is_state_basic *basic = (struct is_state_basic *) state; + return basic != NULL && basic->type == type; +} + +static ptrdiff_t min(ptrdiff_t a, ptrdiff_t b) { + if (a < b) + return a; + return b; +} + +static ptrdiff_t read_cstr(void *state, out_str destination) { + if (!check_type(state, input_stream_cstr)) + return 0; + struct is_state_cstr *cstr = (struct is_state_cstr *) state; + ptrdiff_t size = min(destination.size, cstr->string.size); + memcpy(destination.values, cstr->string.values, size); + cstr->string.values += size; + cstr->string.size -= size; + return size; +} + +struct is_handle is_wrap_string(cstr string, + struct kit_allocator alloc) { + struct is_handle in; + memset(&in, 0, sizeof in); + struct is_state_cstr *state = + (struct is_state_cstr *) alloc.allocate( + alloc.state, sizeof(struct is_state_cstr)); + if (state != NULL) { + memset(state, 0, sizeof *state); + state->type = input_stream_cstr; + state->string = string; + state->alloc = alloc; + in.state = state; + in.read = read_cstr; + } + return in; +} + +void is_destroy(struct is_handle in) { + struct is_state_basic *basic = (struct is_state_basic *) in.state; + if (basic != NULL) + basic->alloc.deallocate(basic->alloc.state, in.state); +} diff --git a/source/kit/input_stream.h b/source/kit/input_stream.h new file mode 100644 index 0000000..c59a720 --- /dev/null +++ b/source/kit/input_stream.h @@ -0,0 +1,32 @@ +#ifndef KIT_INPUT_STREAM_H +#define KIT_INPUT_STREAM_H + +#include "allocator.h" +#include "string_ref.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ptrdiff_t (*is_read_fn)(void *state, out_str destination); + +struct is_handle { + void *state; + is_read_fn read; +}; + +struct is_handle is_wrap_string(cstr string, + struct kit_allocator alloc); + +void is_destroy(struct is_handle in); + +#define IS_WRAP_STRING(string) \ + is_wrap_string((string), kit_alloc_default()) + +#define IS_READ(in, destination) (in).read((in).state, (destination)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit/string_ref.c b/source/kit/string_ref.c new file mode 100644 index 0000000..b7d385f --- /dev/null +++ b/source/kit/string_ref.c @@ -0,0 +1 @@ +#include "string_ref.h" diff --git a/source/kit/string_ref.h b/source/kit/string_ref.h new file mode 100644 index 0000000..d1af90f --- /dev/null +++ b/source/kit/string_ref.h @@ -0,0 +1,20 @@ +#ifndef KIT_STRING_REF_H +#define KIT_STRING_REF_H + +#include "array_ref.h" + +#ifdef __cplusplus +extern "C" { +#endif + +AR_TYPE(string_ref, char); +AR_TYPE_CONST(string_cref, char); + +typedef struct string_ref out_str; +typedef struct string_cref cstr; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit_test/test.h b/source/kit_test/test.h index da6c59b..09df7e9 100644 --- a/source/kit_test/test.h +++ b/source/kit_test/test.h @@ -10,7 +10,7 @@ extern "C" { #include #ifndef KIT_TEST_FILE -# define kit_test +# define KIT_TEST_FILE kit_test #endif #ifndef KIT_TESTS_SIZE_LIMIT diff --git a/source/test/unittests/CMakeLists.txt b/source/test/unittests/CMakeLists.txt index d5cc573..ff99c9c 100644 --- a/source/test/unittests/CMakeLists.txt +++ b/source/test/unittests/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources( ${KIT_TEST_SUITE} PRIVATE - async_function.test.c main.test.c) + async_function.test.c main.test.c array_ref.test.c + input_stream.test.c input_buffer.test.c dynamic_array.test.c) diff --git a/source/test/unittests/array_ref.test.c b/source/test/unittests/array_ref.test.c new file mode 100644 index 0000000..d8cbcec --- /dev/null +++ b/source/test/unittests/array_ref.test.c @@ -0,0 +1,42 @@ +#include "../../kit/array_ref.h" + +#define KIT_TEST_FILE array_ref +#include "../../kit_test/test.h" + +TEST("array ref equal") { + int foo[] = { 1, 2, 3, 4, 5, 6, 7 }; + int bar[] = { 3, 4, 5 }; + + AR(foo_ref, int) = { .size = 3, .values = foo + 2 }; + AR(bar_ref, int) = { .size = 3, .values = bar }; + + REQUIRE(AR_EQUAL(foo_ref, bar_ref)); +} + +static int compare(int const *left, int const *right) { + return *left - *right; +} + +TEST("array ref compare") { + int foo[] = { 1, 2, 3, 5 }; + int bar[] = { 1, 2, 4, 5 }; + + AR(foo_ref, int) = { .size = 3, .values = foo }; + AR(bar_ref, int) = { .size = 3, .values = bar }; + + REQUIRE(AR_COMPARE(foo_ref, bar_ref, compare) < 0); + REQUIRE(AR_COMPARE(bar_ref, foo_ref, compare) > 0); + REQUIRE(AR_COMPARE(foo_ref, foo_ref, compare) == 0); +} + +TEST("array ref different element sizes") { + int foo[] = { 1, 2, 3 }; + char bar[] = { 1, 2, 3 }; + + AR(foo_ref, int) = { .size = 3, .values = foo }; + AR(bar_ref, char) = { .size = 3, .values = bar }; + + REQUIRE(!AR_EQUAL(foo_ref, bar_ref)); + REQUIRE(AR_COMPARE(foo_ref, bar_ref, compare) > 0); + REQUIRE(AR_COMPARE(bar_ref, foo_ref, compare) < 0); +} diff --git a/source/test/unittests/async_function.test.c b/source/test/unittests/async_function.test.c index 1f50445..4fe2c60 100644 --- a/source/test/unittests/async_function.test.c +++ b/source/test/unittests/async_function.test.c @@ -1,6 +1,6 @@ #include "../../kit/async_function.h" -#define KIT_TEST_FILE async_function_test +#define KIT_TEST_FILE async_function #include "../../kit_test/test.h" CORO(int, test_foo) { diff --git a/source/test/unittests/dynamic_array.test.c b/source/test/unittests/dynamic_array.test.c new file mode 100644 index 0000000..fad8d6d --- /dev/null +++ b/source/test/unittests/dynamic_array.test.c @@ -0,0 +1,174 @@ +#include "../../kit/dynamic_array.h" + +#define KIT_TEST_FILE dynamic_array +#include "../../kit_test/test.h" + +TEST("dynamic array empty") { + DA_CREATE(v, char, 0); + + REQUIRE(v.size == 0); + + DA_DESTROY(v); +} + +TEST("dynamic array resize") { + DA_CREATE(v, char, 0); + DA_RESIZE(v, 10); + + REQUIRE(v.size == 10); + + DA_DESTROY(v); +} + +TEST("dynamic array grow") { + DA_CREATE(v, char, 2); + DA_RESIZE(v, 10); + + REQUIRE(v.size == 10); + + DA_DESTROY(v); +} + +TEST("dynamic array diminish") { + DA_CREATE(v, char, 10); + DA_RESIZE(v, 9); + + REQUIRE(v.size == 9); + + DA_DESTROY(v); +} + +TEST("dynamic array of chars") { + DA_CREATE(v, char, 100); + + REQUIRE(v.size == 100); + REQUIRE(v.capacity >= 100); + REQUIRE(v.values != NULL); + + DA_DESTROY(v); +} + +TEST("dynamic array push") { + DA_CREATE(v, char, 0); + DA_APPEND(v, 'x'); + + REQUIRE(v.size == 1); + REQUIRE(v.values[0] == 'x'); + + DA_DESTROY(v); +} + +TEST("dynamic array insert front") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_INSERT(v, 0, 'x'); + + REQUIRE(v.size == 4); + REQUIRE(v.values[0] == 'x'); + REQUIRE(v.values[1] == 'a'); + REQUIRE(v.values[2] == 'b'); + REQUIRE(v.values[3] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array insert back") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_INSERT(v, 3, 'x'); + + REQUIRE(v.size == 4); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'b'); + REQUIRE(v.values[2] == 'c'); + REQUIRE(v.values[3] == 'x'); + + DA_DESTROY(v); +} + +TEST("dynamic array insert middle") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_INSERT(v, 2, 'x'); + + REQUIRE(v.size == 4); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'b'); + REQUIRE(v.values[2] == 'x'); + REQUIRE(v.values[3] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array erase front") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_ERASE(v, 0); + + REQUIRE(v.size == 2); + REQUIRE(v.values[0] == 'b'); + REQUIRE(v.values[1] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array erase back") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_ERASE(v, 2); + + REQUIRE(v.size == 2); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'b'); + + DA_DESTROY(v); +} + +TEST("dynamic array erase middle") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_ERASE(v, 1); + + REQUIRE(v.size == 2); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array of ints") { + DA_CREATE(v, int, 10); + DA_RESIZE(v, 5); + v.values[4] = 42; + DA_APPEND(v, 43); + + REQUIRE(v.size == 6); + REQUIRE(v.values[4] == 42); + REQUIRE(v.values[5] == 43); + + DA_DESTROY(v); +} diff --git a/source/test/unittests/input_buffer.test.c b/source/test/unittests/input_buffer.test.c new file mode 100644 index 0000000..c7edb8f --- /dev/null +++ b/source/test/unittests/input_buffer.test.c @@ -0,0 +1,20 @@ +#include "../../kit/input_buffer.h" + +#define KIT_TEST_FILE input_buffer +#include "../../kit_test/test.h" + +TEST("input buffer") { + cstr text = { .size = 3, .values = "foo" }; + struct is_handle in = IS_WRAP_STRING(text); + struct ib_handle first = IB_WRAP(in); + + struct ib_handle second = ib_read(first, 3); + + REQUIRE(!second.error); + REQUIRE(second.data.size == 3); + REQUIRE(AR_EQUAL(text, second.data)); + + ib_destroy(second); + ib_destroy(first); + is_destroy(in); +} diff --git a/source/test/unittests/input_stream.test.c b/source/test/unittests/input_stream.test.c new file mode 100644 index 0000000..9fef47a --- /dev/null +++ b/source/test/unittests/input_stream.test.c @@ -0,0 +1,23 @@ +#include "../../kit/input_stream.h" + +#define KIT_TEST_FILE input_stream +#include "../../kit_test/test.h" + +TEST("input stream wrap string") { + char foo[] = "test"; + char bar[] = "test"; + + cstr foo_ref = { .size = sizeof(foo) - 1, .values = foo }; + cstr bar_ref = { .size = sizeof(bar) - 1, .values = bar }; + + struct is_handle in = IS_WRAP_STRING(foo_ref); + + char buf[4]; + out_str buf_ref = { .size = sizeof(buf), .values = buf }; + + REQUIRE(IS_READ(in, buf_ref) == buf_ref.size); + REQUIRE(AR_EQUAL(foo_ref, bar_ref)); + REQUIRE(AR_EQUAL(buf_ref, bar_ref)); + + is_destroy(in); +} -- cgit v1.2.3