diff options
| author | Lion Kortlepel <[email protected]> | 2026-02-01 16:22:14 +0000 |
|---|---|---|
| committer | Lion Kortlepel <[email protected]> | 2026-02-01 16:22:14 +0000 |
| commit | f3b0599ff94a5bf5e13dba78281b0a3c7078c6b2 (patch) | |
| tree | 26932d75abe3285331d5f33d9a68307210116b94 | |
| parent | 48302d5ce9bbf54610a41418449be3879d218d5a (diff) | |
| download | vec-f3b0599ff94a5bf5e13dba78281b0a3c7078c6b2.tar.zst vec-f3b0599ff94a5bf5e13dba78281b0a3c7078c6b2.zip | |
feat!: breaking rename _clear to _freev2.0
this simply makes more sense, as _clear does not keep the capacity which
would be expected.
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | examples/simple.c | 4 | ||||
| -rw-r--r-- | ls_vec.h | 40 | ||||
| -rw-r--r-- | tests/ls_test.h | 50 | ||||
| -rw-r--r-- | tests/tests.c | 67 |
5 files changed, 128 insertions, 35 deletions
@@ -34,7 +34,7 @@ Minimal, single-header dynamic array (vector) for C. } // Access elements via vec.data[i] // Check size via vec.size - int_vector_clear(&vec); + int_vector_free(&vec); ``` See [`ls_vec.h`](ls_vec.h) for detailed documentation and usage patterns. diff --git a/examples/simple.c b/examples/simple.c index 74a8750..aa9c656 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -3,9 +3,11 @@ LS_VEC_INLINE(int, int_vec) int main(void) { + int v; int_vec vec; int_vec_init(&vec); int_vec_push(&vec, 12); - int_vec_clear(&vec); + int_vec_pop(&vec, &v); + int_vec_free(&vec); return 0; } @@ -1,6 +1,6 @@ /* Lion's Standard (LS) type-safe ANSI C vector. * - * Version: 1.0 + * Version: 2.0 * Website: https://libls.org * Repo: https://github.com/libls/vec * SPDX-License-Identifier: MIT @@ -41,7 +41,7 @@ * int_vector_init(&vec); * int_vector_push(&vec, 42); * // use vec.data, vec.size, etc. - * int_vector_clear(&vec); + * int_vector_free(&vec); * * Alternative example with decl and impl split: * @@ -58,7 +58,7 @@ * // handle allocation failure * } * // access elements via vec.data[i] - * int_vector_clear(&vec); + * int_vector_free(&vec); * * You can configure a custom memory allocator by defining the macros LS_REALLOC * and LS_FREE globally. These are the only allocation functions required, and @@ -115,7 +115,7 @@ T* data; \ } name; \ void name##_init(name* vec); \ - void name##_clear(name* vec); \ + void name##_free(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, ) @@ -130,7 +130,7 @@ #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) { \ + specifier void name##_free(name* vec) { \ if (vec->data) { \ LS_FREE(vec->data); \ vec->data = NULL; \ @@ -141,19 +141,20 @@ 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; \ + size_t max_items = SIZE_MAX / sizeof(T); \ + size_t new_cap = vec->capacity + vec->capacity / 2 + 8; \ + if (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*)LS_REALLOC(vec->data, total); \ - if (!new_data) \ + /* overflow check */ \ + if (new_cap > max_items) { \ return 0; \ + } \ + new_data = (T*)LS_REALLOC(vec->data, new_cap * sizeof(T)); \ + if (new_data == NULL) { \ + return 0; \ + } \ + vec->capacity = new_cap; \ vec->data = new_data; \ } \ return 1; \ @@ -164,4 +165,11 @@ } \ vec->data[vec->size++] = value; \ return 1; \ + } \ + specifier int name##_pop(name* vec, T* out_value) { \ + if (vec->size == 0) { \ + return 0; \ + } \ + *out_value = vec->data[--vec->size]; \ + return 1; \ } diff --git a/tests/ls_test.h b/tests/ls_test.h index 5dda4aa..2077477 100644 --- a/tests/ls_test.h +++ b/tests/ls_test.h @@ -1,6 +1,6 @@ /* Lion's Standard (LS) test harness. * - * Version: 1.1 + * Version: 1.3 * Website: https://libls.org * Repo: https://github.com/libls/test * SPDX-License-Identifier: MIT @@ -20,6 +20,8 @@ * you use asserts other than `ASSERT` (e.g. ASSERT_EQ), and the constructor * attribute __attribute__((destructor)) for automatic test registration. * + * Supports string comparisons using ASSERT_STR_EQ and ASSERT_STR_NEQ. + * * ==== 2. HOW TO USE ==== * * 1. Copy this file into your project and include it: @@ -96,6 +98,8 @@ _func += 6; \ fprintf(stderr, "%s: FAILED: %s (%s:%d)\n", _func, #cond, \ __FILE__, __LINE__); \ + ++lst_fail; \ + return 1; \ } \ } while (0) @@ -115,7 +119,38 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ + } while (0) + +#define ASSERT_STR_EQ(a, b) \ + do { \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + if (strcmp(_a, _b) != 0) { \ + const char* _func = __func__; \ + if (strncmp(_func, "lst_t_", 6) == 0) \ + _func += 6; \ + fprintf(stderr, \ + "%s: FAILED: %s == %s (actual: \"%s\" != \"%s\") (%s:%d)\n", \ + _func, #a, #b, _a, _b, __FILE__, __LINE__); \ + ++lst_fail; \ + return 1; \ + } \ + } while (0) + +#define ASSERT_STR_NEQ(a, b) \ + do { \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + if (strcmp(_a, _b) == 0) { \ + const char* _func = __func__; \ + if (strncmp(_func, "lst_t_", 6) == 0) \ + _func += 6; \ + fprintf(stderr, \ + "%s: FAILED: %s != %s (actual: \"%s\" == \"%s\") (%s:%d)\n", \ + _func, #a, #b, _a, _b, __FILE__, __LINE__); \ + ++lst_fail; \ + return 1; \ + } \ } while (0) #define ASSERT_NEQ(a, b, fmt) \ @@ -132,7 +167,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_LT(a, b, fmt) \ @@ -149,7 +183,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_LE(a, b, fmt) \ @@ -166,7 +199,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_GT(a, b, fmt) \ @@ -183,7 +215,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define ASSERT_GE(a, b, fmt) \ @@ -200,7 +231,6 @@ ++lst_fail; \ return 1; \ } \ - ++lst_ok; \ } while (0) #define LS_CAT2(a, b) a##b #define LS_CAT(a, b) LS_CAT2(a, b) @@ -217,7 +247,6 @@ extern lst_func* lst_funcs; extern int lst_n; extern int lst_cap; extern int lst_fail; -extern int lst_ok; void lst_reg(lst_func f); @@ -229,7 +258,6 @@ lst_func* lst_funcs; int lst_n; int lst_cap; int lst_fail = 0; -int lst_ok = 0; void lst_reg(lst_func f) { if (lst_n == lst_cap) { @@ -276,8 +304,8 @@ static int ls_test_main(int argc, char** argv) { } end: - fprintf(stderr, "%d succeeded, %d failed, %d total\n", lst_ok, lst_fail, - lst_ok + lst_fail); + fprintf(stderr, "%d succeeded, %d failed, %d total\n", lst_n - lst_fail, + lst_fail, lst_n); free(lst_funcs); if (lst_fail > 0) { diff --git a/tests/tests.c b/tests/tests.c index b679a3e..6d074a6 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -1,22 +1,77 @@ #define LS_TEST_IMPLEMENTATION -#include "ls_test.h" #include "../ls_vec.h" +#include "ls_test.h" LS_VEC_INLINE(int, vec_int) -TEST_CASE(vec_init_clear) { +TEST_CASE(vec_init_free) { vec_int v; vec_int_init(&v); ASSERT_EQ(v.size, 0, "%zu"); ASSERT_EQ(v.capacity, 0, "%zu"); ASSERT_EQ(v.data, NULL, "%p"); - vec_int_clear(&v); + vec_int_free(&v); ASSERT_EQ(v.size, 0, "%zu"); ASSERT_EQ(v.capacity, 0, "%zu"); ASSERT_EQ(v.data, NULL, "%p"); return 0; } +TEST_CASE(vec_push_pop_1000) { + int i; + vec_int v; + vec_int_init(&v); + + // Push 1000 items + for (i = 0; i < 1000; ++i) { + ASSERT_EQ(vec_int_push(&v, i), 1, "%d"); + } + ASSERT_EQ(v.size, 1000, "%zu"); + + // Pop 1000 items and check values + for (i = 999; i >= 0; --i) { + int val; + ASSERT_EQ(vec_int_pop(&v, &val), 1, "%d"); + ASSERT_EQ(val, i, "%d"); + } + ASSERT_EQ(v.size, 0, "%zu"); + + vec_int_free(&v); + return 0; +} + +TEST_CASE(vec_reserve) { + vec_int v; + vec_int_init(&v); + ASSERT_EQ(vec_int_reserve(&v, 10), 1, "%d"); + ASSERT_EQ(v.capacity, 10, "%zu"); + vec_int_free(&v); + return 0; +} + +TEST_CASE(vec_free) { + vec_int v; + int i = 0; + vec_int_init(&v); + for (i = 0; i < 100; ++i) { + vec_int_push(&v, i); + } + vec_int_free(&v); + ASSERT_EQ(v.size, 0, "%zu"); + ASSERT_EQ(v.capacity, 0, "%zu"); + ASSERT_EQ(v.data, NULL, "%p"); + return 0; +} + +TEST_CASE(vec_reserve_large) { + vec_int v; + vec_int_init(&v); + ASSERT_EQ(vec_int_reserve(&v, 10000), 1, "%d"); + ASSERT_EQ(v.capacity, 10000, "%zu"); + vec_int_free(&v); + return 0; +} + TEST_CASE(vec_push_and_access) { int i; vec_int v; @@ -26,7 +81,7 @@ TEST_CASE(vec_push_and_access) { ASSERT_EQ(v.size, 10, "%zu"); for (i = 0; i < 10; ++i) ASSERT_EQ(v.data[i], i, "%d"); - vec_int_clear(&v); + vec_int_free(&v); return 0; } @@ -35,7 +90,7 @@ TEST_CASE(vec_reserve_grow) { vec_int_init(&v); ASSERT_EQ(vec_int_reserve(&v, 20), 1, "%d"); ASSERT_GE(v.capacity, 20, "%zu"); - vec_int_clear(&v); + vec_int_free(&v); return 0; } @@ -46,7 +101,7 @@ TEST_CASE(vec_push_overflow) { v.size = v.capacity; int ret = vec_int_push(&v, 123); ASSERT_EQ(ret, 0, "%d"); - vec_int_clear(&v); + vec_int_free(&v); return 0; } |
