diff --git a/include/DArray.h b/include/DArray.h index 45e68b5..393b1bd 100644 --- a/include/DArray.h +++ b/include/DArray.h @@ -6,7 +6,7 @@ #include // IWYU pragma: keep #include -#include "scufcont.h" +#include "scufcont.h" // IWYU pragma: keep // #define SCUFCONT_BOUNDS_CHECK @@ -18,21 +18,27 @@ #define SCDARRAY_EXPANDER(macro, type, type_name, func_name) macro(type, SCDArray_##type_name, SCDArray_##type_name##_##func_name) -#define SCDARRAY_IMPL(type, type_name) \ - SCDARRAY_EXPANDER(SCDARRAY_ALLOC, type, type_name, alloc) \ - SCDARRAY_EXPANDER(SCDARRAY_IS_NULL, type, type_name, is_null) \ - SCDARRAY_EXPANDER(SCDARRAY_PUSH_BACK, type, type_name, push_back) \ - SCDARRAY_EXPANDER(SCDARRAY_AT, type, type_name, at) +#define SCDARRAY_IMPL(type, type_name) \ + SCDARRAY_EXPANDER(SCDARRAY_ALLOC, type, type_name, alloc) \ + SCDARRAY_EXPANDER(SCDARRAY_FREE, type, type_name, free) \ + SCDARRAY_EXPANDER(SCDARRAY_IS_NULL, type, type_name, is_null) \ + SCDARRAY_EXPANDER(SCDARRAY_PUSH_BACK, type, type_name, push_back) \ + SCDARRAY_EXPANDER(SCDARRAY_PUSH_BACK_MULTIPLE, type, type_name, push_back_multiple) \ + SCDARRAY_EXPANDER(SCDARRAY_AT, type, type_name, at) \ + SCDARRAY_EXPANDER(SCDARRAY_REMOVE, type, type_name, remove) #define SCDARRAY_HEADER(type, type_name) \ SCDARRAY_STRUCT(type, type_name) \ SCDARRAY_SIGS(type, type_name) -#define SCDARRAY_SIGS(type, type_name) \ - SCDARRAY_EXPANDER(SCDARRAY_ALLOC_SIG, type, type_name, alloc); \ - SCDARRAY_EXPANDER(SCDARRAY_IS_NULL_SIG, type, type_name, is_null); \ - SCDARRAY_EXPANDER(SCDARRAY_PUSH_BACK_SIG, type, type_name, push_back); \ - SCDARRAY_EXPANDER(SCDARRAY_AT_SIG, type, type_name, at); +#define SCDARRAY_SIGS(type, type_name) \ + SCDARRAY_EXPANDER(SCDARRAY_ALLOC_SIG, type, type_name, alloc); \ + SCDARRAY_EXPANDER(SCDARRAY_FREE_SIG, type, type_name, free); \ + SCDARRAY_EXPANDER(SCDARRAY_IS_NULL_SIG, type, type_name, is_null); \ + SCDARRAY_EXPANDER(SCDARRAY_PUSH_BACK_SIG, type, type_name, push_back); \ + SCDARRAY_EXPANDER(SCDARRAY_PUSH_BACK_MULTIPLE_SIG, type, type_name, push_back_multiple); \ + SCDARRAY_EXPANDER(SCDARRAY_AT_SIG, type, type_name, at); \ + SCDARRAY_EXPANDER(SCDARRAY_REMOVE_SIG, type, type_name, remove); // SCDARRAY_ALLOC_SIG(type, SCDArray_##type_name, SCDArray_##type_name##_alloc); \ // SCDARRAY_PUSH_BACK_SIG(type, SCDArray_##type_name, SCDArray_##type_name##_push_back); @@ -59,6 +65,13 @@ return SCUFCONT_SUCCESS; \ } +#define SCDARRAY_FREE_SIG(type, type_name, func_name) void func_name(type_name* darr) + +#define SCDARRAY_FREE(type, type_name, func_name) \ + SCDARRAY_FREE_SIG(type, type_name, func_name) { \ + free(darr->data); \ + } + #define SCDARRAY_IS_NULL_SIG(type, type_name, func_name) bool func_name(const type_name* darr) #define SCDARRAY_IS_NULL(type, type_name, func_name) \ @@ -68,22 +81,40 @@ // SCDARRAY_ALLOC(int, SCDArray_int, SCDArray_int_alloc); -#define SCDARRAY_PUSH_BACK_SIG(type, type_name, func_name) int func_name(type_name* darr, const type* new_elem) +#define SCDARRAY_PUSH_BACK_SIG(type, type_name, func_name) ScufContResult func_name(type_name* darr, const type* new_elem) -#define SCDARRAY_PUSH_BACK(type, type_name, func_name) \ - SCDARRAY_PUSH_BACK_SIG(type, type_name, func_name) { \ - if (darr->len + 1 > darr->capacity) { \ - darr->capacity *= 2; \ - darr->data = (type*) realloc(darr->data, darr->capacity * sizeof(type)); \ - if (darr->data == NULL) { \ - return -1; \ - } \ - } \ - memcpy(darr->data + darr->len, new_elem, sizeof(type)); \ - darr->len++; \ - return 1; \ +#define SCDARRAY_PUSH_BACK(type, type_name, func_name) \ + SCDARRAY_PUSH_BACK_SIG(type, type_name, func_name) { \ + if (darr->len + 1 > darr->capacity) { \ + darr->capacity *= 2; \ + darr->data = (type*) realloc(darr->data, darr->capacity * sizeof(*new_elem)); \ + if (darr->data == NULL) { \ + return SCUFCONT_OUT_OF_MEMORY; \ + } \ + } \ + memcpy(darr->data + darr->len, new_elem, sizeof(*new_elem)); \ + darr->len++; \ + return SCUFCONT_SUCCESS; \ } +#define SCDARRAY_PUSH_BACK_MULTIPLE_SIG(type, type_name, func_name) ScufContResult func_name(type_name* darr, const type* new_elems, const size_t new_elems_n) + +#define SCDARRAY_PUSH_BACK_MULTIPLE(type, type_name, func_name) \ + SCDARRAY_PUSH_BACK_MULTIPLE_SIG(type, type_name, func_name) { \ + if (darr->len + new_elems_n > darr->capacity) { \ + darr->data = (type*) realloc(darr->data, (darr->capacity + new_elems_n) * sizeof(type)); \ + if (darr->data == NULL) { \ + return SCUFCONT_OUT_OF_MEMORY; \ + } \ + darr->capacity += new_elems_n; \ + } \ + memcpy(darr->data + darr->len, new_elems, sizeof(type) * new_elems_n); \ + darr->len += new_elems_n; \ + return SCUFCONT_SUCCESS; \ + } + +// SCDARRAY_PUSH_BACK_MULTIPLE(int, SCDArray_int, SCDArray_int_push_back_multiple) + #define SCDARRAY_AT_SIG(type, type_name, func_name) type* func_name(type_name* darr, const size_t i) // SCDARRAY_PUSH_BACK(int, SCDArray_int, SCDArray_int_push_back); @@ -111,4 +142,14 @@ // SCDARRAY_AT(char*, SCDArray_charp, SCDArray_charp_at) +#define SCDARRAY_REMOVE_SIG(type, type_name, func_name) void func_name(type_name* darr, const size_t i) + +#define SCDARRAY_REMOVE(type, type_name, func_name) \ + SCDARRAY_REMOVE_SIG(type, type_name, func_name) { \ + memmove(darr->data + i, darr->data + i + 1, (darr->len - i) * sizeof(type)); \ + darr->len--; \ + } + +// SCDARRAY_REMOVE(char*, SCDArray_charp, SCDArray_charp_remove) + #endif // SCUFCONT_DARRAY_H_ diff --git a/tests/cmocka/DArray_tests.c b/tests/cmocka/DArray_tests.c index c741a9c..3916e61 100644 --- a/tests/cmocka/DArray_tests.c +++ b/tests/cmocka/DArray_tests.c @@ -1,11 +1,12 @@ #include #include "DArray.h" +#include "scufcont.h" SCDARRAY_HEADER(int, int) SCDARRAY_IMPL(int, int) -void DArray_alloc_test(void** state) { +void test_DArray_alloc(void** state) { (void) state; SCDArray_int arr; @@ -13,5 +14,126 @@ void DArray_alloc_test(void** state) { assert_non_null(arr.data); assert_uint_equal(arr.len, 0u); assert_uint_equal(arr.capacity, 1u); + + SCDArray_int_free(&arr); } +void test_DArray_push_back(void** state) { + (void) state; + + SCDArray_int arr; + SCDArray_int_alloc(&arr); + + assert_true(SCDArray_int_push_back(&arr, &(int){7}) == SCUFCONT_SUCCESS); + assert_true(arr.data[0] == 7); + + assert_true(SCDArray_int_push_back(&arr, &(int){10}) == SCUFCONT_SUCCESS); + assert_true(arr.data[0] == 7); + assert_true(arr.data[1] == 10); + + SCDArray_int_free(&arr); +} + +void test_DArray_at(void** state) { + (void) state; + + SCDArray_int arr; + SCDArray_int_alloc(&arr); + + assert_true(SCDArray_int_push_back(&arr, &(int){7}) == SCUFCONT_SUCCESS); + assert_int_equal(*SCDArray_int_at(&arr, 0), 7); + + assert_true(SCDArray_int_push_back(&arr, &(int){10}) == SCUFCONT_SUCCESS); + assert_int_equal(*SCDArray_int_at(&arr, 0), 7); + assert_int_equal(*SCDArray_int_at(&arr, 1), 10); + + SCDArray_int_free(&arr); +} + +void test_DArray_push_back_multiple(void** state) { + (void) state; + + SCDArray_int arr; + SCDArray_int_alloc(&arr); + + int nums[] = { 1, 2, 3, 4, 5 }; + const size_t nums_len = sizeof(nums) / sizeof(nums[0]); + assert_true(SCDArray_int_push_back_multiple(&arr, nums, sizeof(nums) / sizeof(nums[0])) == SCUFCONT_SUCCESS); + for (size_t i = 0; i < arr.len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i), nums[i]); + } + int nums2[] = { 6, 7, 8 }; + const size_t nums2_len = sizeof(nums2) / sizeof(nums2[0]); + assert_true(SCDArray_int_push_back_multiple(&arr, nums2, sizeof(nums2) / sizeof(nums2[0])) == SCUFCONT_SUCCESS); + for (size_t i = 0; i < nums_len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i), nums[i]); + } + for (size_t i = 0; i < nums2_len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i + nums_len), nums2[i]); + } + + SCDArray_int_free(&arr); +} + +void test_DArray_remove(void** state) { + (void) state; + + SCDArray_int arr; + SCDArray_int_alloc(&arr); + + int nums[] = { 1, 2, 3, 4, 5 }; + SCDArray_int_push_back_multiple(&arr, nums, sizeof(nums) / sizeof(nums[0])); + for (size_t i = 0; i < arr.len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i), nums[i]); + } + + // Remove last + { + const size_t old_len = arr.len; + SCDArray_int_remove(&arr, arr.len - 1); + assert_uint_equal(arr.len, old_len - 1); + int new_nums[] = { 1, 2, 3, 4 }; + assert_uint_equal(arr.len, sizeof(new_nums) / sizeof(new_nums[0])); + for (size_t i = 0; i < arr.len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i), new_nums[i]); + } + } + + // Remove from middle + { + const size_t old_len = arr.len; + SCDArray_int_remove(&arr, 1); + assert_uint_equal(arr.len, old_len - 1); + int new_nums[] = { 1, 3, 4 }; + assert_uint_equal(arr.len, sizeof(new_nums) / sizeof(new_nums[0])); + for (size_t i = 0; i < arr.len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i), new_nums[i]); + } + } + + // Remove first + { + const size_t old_len = arr.len; + SCDArray_int_remove(&arr, 0); + assert_uint_equal(arr.len, old_len - 1); + int new_nums[] = { 3, 4 }; + assert_uint_equal(arr.len, sizeof(new_nums) / sizeof(new_nums[0])); + for (size_t i = 0; i < arr.len; i++) { + assert_int_equal(*SCDArray_int_at(&arr, i), new_nums[i]); + } + } + + SCDArray_int_free(&arr); +} + +int DArray_tests_run(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_DArray_alloc), + cmocka_unit_test(test_DArray_push_back), + cmocka_unit_test(test_DArray_at), + cmocka_unit_test(test_DArray_push_back_multiple), + cmocka_unit_test(test_DArray_remove), + }; + + return cmocka_run_group_tests_name("DArray", tests, NULL, NULL); +} diff --git a/tests/cmocka/main.c b/tests/cmocka/main.c index 1029b4b..377b7fb 100644 --- a/tests/cmocka/main.c +++ b/tests/cmocka/main.c @@ -1,11 +1,19 @@ #include int DString_tests_run(void); +int DArray_tests_run(void); int main(void) { int failed = 0; failed = DString_tests_run(); + if (failed) { + return failed; + } + failed = DArray_tests_run(); + if (failed) { + return failed; + } return failed; } diff --git a/tests/cmocka/meson.build b/tests/cmocka/meson.build index 892c279..a83b276 100644 --- a/tests/cmocka/meson.build +++ b/tests/cmocka/meson.build @@ -1,5 +1,6 @@ cmocka_tests = executable( 'cmocka_tests', + 'DArray_tests.c', 'DString_tests.c', 'main.c', include_directories: [