diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-08-26 13:23:37 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-08-26 13:23:37 -0400 |
| commit | 78956339691db1fb0de02e63823dc9100c0cd7e7 (patch) | |
| tree | bf8aef0abcbe2b55d19a3ba04e809c571a2c995e | |
| parent | 488ee1d60e32502645d4fce9a8261b012ec1ba6a (diff) | |
pkiter: add iterator for pkarr and pkbktarr
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | pk.h.in | 3 | ||||
| -rw-r--r-- | pkarr.h | 53 | ||||
| -rw-r--r-- | pkbktarr.h | 110 | ||||
| -rw-r--r-- | pkiter.h | 28 | ||||
| -rw-r--r-- | test/pkarr.c | 101 | ||||
| -rw-r--r-- | test/pkarr.cpp | 87 | ||||
| -rw-r--r-- | test/pkbktarr.c | 133 | ||||
| -rw-r--r-- | test/pkbktarr.cpp | 140 |
10 files changed, 657 insertions, 7 deletions
@@ -11,6 +11,7 @@ SRC = \ pkmem.h \ pkstr.h \ pkev.h \ + pkiter.h \ pkarr.h \ pkstn.h \ pkuuid.h \ @@ -49,6 +50,7 @@ all: options .WAIT clean .WAIT \ pkmem \ pkstr \ pkev \ + pkiter \ pkarr \ pkstn \ pktmr \ @@ -99,6 +101,8 @@ pkstr: pkmacros pkstr.gch pkstr.gchpp pkev: pkev.gch pkev.gchpp +pkiter: pkiter.gch pkiter.gchpp + pkarr: pkmem pkarr.gch pkarr.gchpp pkstn: pkstn.gch pkstn.gchpp @@ -118,6 +122,7 @@ build: pkmem-types build: pkmem build: pkstr build: pkev +build: pkiter build: pkarr build: pkstn build: pktmr @@ -132,6 +137,7 @@ build: pkfuncinstr pkmem.h \ pkstr.h \ pkev.h \ + pkiter.h \ pkarr.h \ pkstn.h \ pktmr.h \ @@ -214,6 +220,7 @@ test: pkmem-types test/test-pkmem-types test/test-pkmem-types-cpp test: pkmem test/test-pkmem test/test-pkmem-cpp test: pkstr test/test-pkstr test/test-pkstr-cpp test: pkev test/test-pkev test/test-pkev-cpp +test: pkiter test: pkarr test/test-pkarr test/test-pkarr-cpp test: pkstn test/test-pkstn test/test-pkstn-cpp test: pktmr test/test-pktmr test/test-pktmr-cpp @@ -1,5 +1,5 @@ # pk.h version -VERSION = 0.7.0 +VERSION = 0.7.1 # paths PREFIX = /usr/local @@ -305,6 +305,9 @@ # ifndef PK_IMPL_EV # define PK_IMPL_EV # endif +# ifndef PK_IMPL_ITER +# define PK_IMPL_ITER +# endif # ifndef PK_IMPL_ARR # define PK_IMPL_ARR # endif @@ -25,6 +25,13 @@ void pk_arr_remove_at(struct pk_arr *arr, uint32_t index); void pk_arr_clone(struct pk_arr *lhs, struct pk_arr *rhs); void pk_arr_swap(struct pk_arr *lhs, struct pk_arr *rhs); uint32_t pk_arr_find_first_index(struct pk_arr *arr, void *user_data, pk_arr_item_compare *fn); +#ifdef PK_IMPL_ITER +#include "pkiter.h" /*deleteme*/ +bool pk_arr_iter_begin(struct pk_arr *arr, struct pk_iter *it); +bool pk_arr_iter_end(struct pk_arr *arr, struct pk_iter *it); +bool pk_arr_iter_increment(struct pk_arr *arr, struct pk_iter *it); +bool pk_arr_iter_decrement(struct pk_arr *arr, struct pk_iter *it); +#endif /* PK_IMPL_ITER */ #if defined(__cplusplus) template<typename T> @@ -294,4 +301,50 @@ pk_arr_find_first_index(struct pk_arr *arr, void *user_data, pk_arr_item_compare return -1; } +#ifdef PK_IMPL_ITER + +bool +pk_arr_iter_begin(struct pk_arr *arr, struct pk_iter *it) { + it->data = nullptr; + it->id.arr.i = 0; + if (arr->data != nullptr && arr->data != CAFE_BABE(void)) { + it->data = arr->data; + return true; + } + return false; +} + +bool pk_arr_iter_end(struct pk_arr *arr, struct pk_iter *it) { + it->data = nullptr; + it->id.arr.i = 0; + if (arr->data != nullptr && arr->data != CAFE_BABE(void)) { + it->id.arr.i = arr->next - 1; + it->data = (void *)((char*)arr->data + (arr->stride * it->id.arr.i)); + return true; + } + return false; +} + +bool +pk_arr_iter_increment(struct pk_arr *arr, struct pk_iter *it) { + if (it->id.arr.i + 1 >= arr->next) { + return false; + } + it->id.arr.i += 1; + it->data = (void *)((char*)arr->data + (arr->stride * it->id.arr.i)); + return true; +} + +bool +pk_arr_iter_decrement(struct pk_arr *arr, struct pk_iter *it) { + if (it->id.arr.i == 0) { + return false; + } + it->id.arr.i -= 1; + it->data = (void *)((char*)arr->data + (arr->stride * it->id.arr.i)); + return true; +} + +#endif /* PK_IMPL_ITER */ + #endif /* PK_IMPL_ARR */ @@ -53,6 +53,7 @@ enum PK_BKT_ARR_HANDLE_VALIDATION pk_bkt_arr_handle_validate(struct pk_bkt_arr * void pk_bkt_arr_init(struct pk_bkt_arr *bkt_arr, unsigned long stride, unsigned long alignment, struct pk_bkt_arr_handle limits, struct pk_membucket *bkt_buckets, struct pk_membucket *bkt_data); void pk_bkt_arr_clear(struct pk_bkt_arr *bkt_arr); +void pk_bkt_arr_reserve(struct pk_bkt_arr *bkt_arr, size_t count); struct pk_bkt_arr_handle pk_bkt_arr_find_first_handle(struct pk_bkt_arr *bkt_arr, pk_bkt_arr_compare_fn fn, void *user_data, const void *user_obj_data); void pk_bkt_arr_iterate(struct pk_bkt_arr *bkt_arr, pk_bkt_arr_iterate_fn fn, void *user_data); void pk_bkt_arr_teardown(struct pk_bkt_arr *bkt_arr); @@ -62,6 +63,14 @@ int pk_bkt_arr_handle_compare(struct pk_bkt_arr_handle lhs, struct pk_bkt_arr_ha struct pk_bkt_arr_handle pk_bkt_arr_handle_increment(struct pk_bkt_arr *arr, struct pk_bkt_arr_handle h); struct pk_bkt_arr_handle pk_bkt_arr_handle_decrement(struct pk_bkt_arr *arr, struct pk_bkt_arr_handle h); +#ifdef PK_IMPL_ITER +#include "pkiter.h" /*deleteme*/ +bool pk_bkt_arr_iter_begin(struct pk_bkt_arr *arr, struct pk_iter *it); +bool pk_bkt_arr_iter_end(struct pk_bkt_arr *arr, struct pk_iter *it); +bool pk_bkt_arr_iter_increment(struct pk_bkt_arr *arr, struct pk_iter *it); +bool pk_bkt_arr_iter_decrement(struct pk_bkt_arr *arr, struct pk_iter *it); +#endif + #if defined (__cplusplus) #include "pktmpln.h" /*deleteme*/ #include <assert.h> @@ -90,7 +99,7 @@ T &pk_bkt_arr_t<T>::operator[](struct pk_bkt_arr_handle handle) { assert(this->bucketed_data != nullptr); assert(handle.b <= this->limits.b); assert(handle.i <= this->limits.i); - assert(handle.b != this->head_r.b || handle.i < this->head_r.i); + assert(handle.b != this->head_r.b || handle.i <= this->head_r.i); T** two_star_programmer = reinterpret_cast<T**>(this->bucketed_data); return two_star_programmer[handle.b][handle.i]; } @@ -108,9 +117,10 @@ enum PK_BKT_ARR_HANDLE_VALIDATION pk_bkt_arr_handle_validate(struct pk_bkt_arr * if (handle.b >= bkt_arr->reserved_buckets || handle.b >= bkt_arr->limits.b) { ret |= PK_BKT_ARR_HANDLE_VALIDATION_BUCKET_INDEX_TOO_HIGH; } - if (handle.b == bkt_arr->reserved_buckets-1 && handle.i > bkt_arr->head_r.i) { + if (handle.i >= bkt_arr->limits.i) { ret |= PK_BKT_ARR_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH; - } else if (handle.b < bkt_arr->reserved_buckets-1 && handle.i > bkt_arr->limits.i) { + } + if (handle.b == bkt_arr->head_r.b && handle.i > bkt_arr->head_r.i) { ret |= PK_BKT_ARR_HANDLE_VALIDATION_ITEM_INDEX_TOO_HIGH; } return (enum PK_BKT_ARR_HANDLE_VALIDATION)ret; @@ -149,6 +159,26 @@ void pk_bkt_arr_clear(struct pk_bkt_arr *bkt_arr) { } } +void pk_bkt_arr_reserve(struct pk_bkt_arr *bkt_arr, size_t count) { + size_t bucket_count = count / bkt_arr->limits.i; + if (bkt_arr->reserved_buckets >= bucket_count) return; + unsigned long long *new_idx_unused = (unsigned long long *)pk_new(sizeof(unsigned long long) * bucket_count, alignof(uint64_t), bkt_arr->bkt_buckets); + void **new_bucketed_data = (void **)pk_new(sizeof(void *) * bucket_count, alignof(void *), bkt_arr->bkt_buckets); + if (bkt_arr->reserved_buckets > 0) { + memcpy(new_idx_unused, bkt_arr->idx_unused, sizeof(unsigned long long) * bkt_arr->reserved_buckets); + memcpy(new_bucketed_data, bkt_arr->bucketed_data, sizeof(void *) * bkt_arr->reserved_buckets); + pk_delete_bkt(bkt_arr->bucketed_data, sizeof(void *) * bkt_arr->reserved_buckets, bkt_arr->bkt_buckets); + pk_delete_bkt(bkt_arr->idx_unused, sizeof(unsigned long long) * bkt_arr->reserved_buckets, bkt_arr->bkt_buckets); + } + for (unsigned int i = bkt_arr->reserved_buckets; i < bucket_count; ++i) { + new_idx_unused[i] = PK_BKT_ARR_ALL_UNUSED_VAL; + new_bucketed_data[i] = pk_new(bkt_arr->stride * bkt_arr->limits.i, bkt_arr->alignment, bkt_arr->bkt_data); + } + bkt_arr->idx_unused = new_idx_unused; + bkt_arr->bucketed_data = new_bucketed_data; + bkt_arr->reserved_buckets = bucket_count; +} + struct pk_bkt_arr_handle pk_bkt_arr_find_first_handle(struct pk_bkt_arr *bkt_arr, pk_bkt_arr_compare_fn fn, void *user_data, const void *user_obj_data) { assert(bkt_arr != NULL); assert(fn != NULL); @@ -179,7 +209,7 @@ void pk_bkt_arr_iterate(struct pk_bkt_arr *bkt_arr, pk_bkt_arr_iterate_fn fn, vo unsigned int b, i, ii; for (b = 0; b < bkt_arr->reserved_buckets; ++b) { char *arr = ((char**)(bkt_arr->bucketed_data))[b]; - ii = b == bkt_arr->reserved_buckets-1 ? bkt_arr->head_r.i : bkt_arr->limits.i; + ii = b == bkt_arr->head_r.b ? bkt_arr->head_r.i : bkt_arr->limits.i; for (i = 0; i < ii; ++i) { if (PK_HAS_FLAG(bkt_arr->idx_unused[b], 1ull << i)) { continue; @@ -306,4 +336,76 @@ struct pk_bkt_arr_handle pk_bkt_arr_handle_decrement(struct pk_bkt_arr *arr, str return h; } +#ifdef PK_IMPL_ITER + +bool pk_bkt_arr_iter_begin(struct pk_bkt_arr *arr, struct pk_iter *it) { + it->data = nullptr; + it->id.bkt.b = 0; + it->id.bkt.i = 0; + if ((arr->idx_unused[it->id.bkt.b] & (1ull << it->id.bkt.i)) != 0) return false; + it->data = arr->bucketed_data[0]; + return true; +} + +bool pk_bkt_arr_iter_end(struct pk_bkt_arr *arr, struct pk_iter *it) { + it->data = nullptr; + it->id.bkt.b = 0; + it->id.bkt.i = 0; + if (arr->head_r.b == 0 && arr->head_r.i == 0) return false; + do { + struct pk_bkt_arr_handle handle = arr->head_r; + for (;;) { + if ((arr->idx_unused[handle.b] & (1ull << handle.i)) == 0) break; + if (handle.b == 0 && handle.i == 0) return false; + handle = pk_bkt_arr_handle_decrement(arr, handle); + } + it->id.bkt.b = handle.b; + it->id.bkt.i = handle.i; + break; + } while (true); + if (arr->bucketed_data != nullptr && arr->bucketed_data[it->id.bkt.b] != nullptr) { + it->data = (char*)(arr->bucketed_data[it->id.bkt.b]) + (arr->stride * it->id.bkt.i); + return true; + } + return false; +} + +bool pk_bkt_arr_iter_increment(struct pk_bkt_arr *arr, struct pk_iter *it) { + struct pk_bkt_arr_handle handle = { + .b = it->id.bkt.b, + .i = it->id.bkt.i, + }; + if (it->id.bkt.b == arr->limits.b-1 && it->id.bkt.i == arr->limits.i-1) return false; + for (;;) { + handle = pk_bkt_arr_handle_increment(arr, handle); + if ((arr->idx_unused[handle.b] & (1ull << handle.i)) == 0) break; + } + it->id.bkt.b = handle.b; + it->id.bkt.i = handle.i; + if (handle.b >= arr->reserved_buckets) return false; + if ((arr->idx_unused[it->id.bkt.b] & (1ull << it->id.bkt.i)) != 0) return false; + it->data = (char*)(arr->bucketed_data[it->id.bkt.b]) + (arr->stride * it->id.bkt.i); + return true; +} + +bool pk_bkt_arr_iter_decrement(struct pk_bkt_arr *arr, struct pk_iter *it) { + struct pk_bkt_arr_handle handle = { + .b = it->id.bkt.b, + .i = it->id.bkt.i, + }; + for (;;) { + handle = pk_bkt_arr_handle_decrement(arr, handle); + if ((arr->idx_unused[handle.b] & (1ull << handle.i)) == 0) break; + if (handle.b == 0 && handle.i == 0) break; + } + if (it->id.bkt.b == handle.b && it->id.bkt.i == handle.i) return false; + it->id.bkt.b = handle.b; + it->id.bkt.i = handle.i; + if ((arr->idx_unused[it->id.bkt.b] & (1ull << it->id.bkt.i)) != 0) return false; + it->data = ((char*)(arr->bucketed_data[it->id.bkt.b])) + (arr->stride * it->id.bkt.i); + return true; +} + +#endif /* PK_IMPL_ITER */ + #endif /* PK_IMPL_BKTARR */ diff --git a/pkiter.h b/pkiter.h new file mode 100644 index 0000000..db7f451 --- /dev/null +++ b/pkiter.h @@ -0,0 +1,28 @@ +#ifndef PK_PKITER_H +#define PK_PKITER_H + +union pk_iter_id { + struct pk_iter_bkt_handle { + unsigned int b : 24; + unsigned int i : 8; + } bkt; + struct pk_iter_arr_idx { + unsigned int i : 32; + } arr; +}; + +struct pk_iter { + void *data; + union pk_iter_id id; +}; + +#if defined (__cplusplus) +template <typename T> +struct pk_iter_t : public pk_iter { + operator T&() { + return *reinterpret_cast<T*>(this->data); + } +}; +#endif + +#endif /* PK_PKITER_H */ diff --git a/test/pkarr.c b/test/pkarr.c index 74ff27d..25ae171 100644 --- a/test/pkarr.c +++ b/test/pkarr.c @@ -1,6 +1,7 @@ // NOTE: only intended for performance testing // TODO: move flag to compiler and run tests more than once for full coverage +#define PK_IMPL_ITER #define PK_ARR_MOVE_IN_PLACE #define PK_IMPL_MEM #define PK_IMPL_ARR @@ -13,8 +14,8 @@ * When compiling with `-O3`, one (or maybe more?) of the tests fails * The issue is resolved now; leaving this for testing purposes. */ -#undef PK_LOGV_INF -#define PK_LOGV_INF(str, ...) (void)str +// #undef PK_LOGV_INF +// #define PK_LOGV_INF(str, ...) (void)str struct some_complex_struct { char uhh; @@ -307,5 +308,101 @@ int main(int argc, char *argv[]) } PK_LOGV_INF("%s", "[init via append, soft clear] end\n\n"); + PK_LOGV_INF("%s", "[iter forward] begin\n"); + { + bool res; + test_spinup(&arr, &bkt); + arr.stride = sizeof(uint8_t); + arr.alignment = alignof(uint8_t); + + for (i = 4; i > 0; --i) { + uint8_t u = (uint8_t)i - 1; + pk_arr_append(&arr, &u); + } + + struct pk_iter it; + res = pk_arr_iter_begin(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 0) exit(1); + if (*(uint8_t*)it.data != 3) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 1) exit(1); + if (*(uint8_t*)it.data != 2) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 2) exit(1); + if (*(uint8_t*)it.data != 1) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 3) exit(1); + if (*(uint8_t*)it.data != 0) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == true) exit(1); + + test_teardown(&arr, &bkt); + } + PK_LOGV_INF("%s", "[iter forward] end\n\n"); + + PK_LOGV_INF("%s", "[iter reverse] begin\n"); + { + bool res; + test_spinup(&arr, &bkt); + arr.stride = sizeof(uint8_t); + arr.alignment = alignof(uint8_t); + + for (i = 4; i > 0; --i) { + uint8_t u = (uint8_t)i - 1; + pk_arr_append(&arr, &u); + } + + struct pk_iter it; + res = pk_arr_iter_end(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 3) exit(1); + if (*(uint8_t*)it.data != 0) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 2) exit(1); + if (*(uint8_t*)it.data != 1) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 1) exit(1); + if (*(uint8_t*)it.data != 2) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.arr.i != 0) exit(1); + if (*(uint8_t*)it.data != 3) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == true) exit(1); + + test_teardown(&arr, &bkt); + } + PK_LOGV_INF("%s", "[iter reverse] end\n\n"); + return 0; } diff --git a/test/pkarr.cpp b/test/pkarr.cpp index 4b03922..db42ad8 100644 --- a/test/pkarr.cpp +++ b/test/pkarr.cpp @@ -1,4 +1,5 @@ +#define PK_IMPL_ITER #define PK_IMPL_MEM #define PK_IMPL_ARR @@ -155,6 +156,92 @@ int main(int argc, char *argv[]) fprintf(stdout, "[%s] Ending move assignment test\n\n", __FILE__); test_teardown(&bkt); + test_spinup(&bkt); + fprintf(stdout, "[%s] Starting iter forward test\n", __FILE__); + { + bool res; + uint8_t u, u2; + pk_arr_t<uint8_t> arr(bkt); + for (u = 4; u > 0; --u) { + u2 = u - 1; + pk_arr_append_t(&arr, u2); + } + + struct pk_iter_t<uint8_t> it; + res = pk_arr_iter_begin(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 0) exit(1); + if (it != 3) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 1) exit(1); + if (it != 2) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 2) exit(1); + if (it != 1) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 3) exit(1); + if (it != 0) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_increment(&arr, &it); + if (res == true) exit(1); + + } + fprintf(stdout, "[%s] Ending iter forward test\n\n", __FILE__); + test_teardown(&bkt); + + test_spinup(&bkt); + fprintf(stdout, "[%s] Starting iter reverse test\n", __FILE__); + { + bool res; + uint8_t u, u2; + pk_arr_t<uint8_t> arr(bkt); + for (u = 4; u > 0; --u) { + u2 = u - 1; + pk_arr_append_t(&arr, u2); + } + + struct pk_iter_t<uint8_t> it; + res = pk_arr_iter_end(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 3) exit(1); + if (it != 0) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 2) exit(1); + if (it != 1) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 1) exit(1); + if (it != 2) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == false) exit(1); + if (it.id.arr.i != 0) exit(1); + if (it != 3) exit(1); + PK_LOGV_INF("iter.data: %p iter.val: %i\n", it.data, *(uint8_t*)it.data); + + res = pk_arr_iter_decrement(&arr, &it); + if (res == true) exit(1); + + } + fprintf(stdout, "[%s] Ending iter reverse test\n\n", __FILE__); + test_teardown(&bkt); + fprintf(stdout, "[%s] End\n", __FILE__); return 0; diff --git a/test/pkbktarr.c b/test/pkbktarr.c index 6767cbc..012bc90 100644 --- a/test/pkbktarr.c +++ b/test/pkbktarr.c @@ -1,5 +1,6 @@ #include "../pkmem.h" +#define PK_IMPL_ITER #define PK_IMPL_MEM #define PK_IMPL_BKTARR #include "../pkbktarr.h" @@ -470,6 +471,138 @@ int main(int argc, char *argv[]) while (false); test_teardown(&bkt_buckets, &bkt_data); + fprintf(stdout, "[%s] test iter forwards w/ empty slot begin\n", __FILE__); + test_spinup(&bkt_buckets, &bkt_data); + { + assert(bkt_buckets != nullptr); + assert(bkt_data != nullptr); + uint8_t u; + bool b; + struct pk_bkt_arr arr = {0}; + struct pk_bkt_arr_handle h; + struct pk_bkt_arr_handle limits; + limits.b = 1; + limits.i = 5; + + pk_bkt_arr_init(&arr, sizeof(uint8_t), alignof(uint8_t), limits, bkt_buckets, bkt_data); + + for (u = 0; u < 5; ++u) { + h = pk_bkt_arr_new_handle(&arr); + uint8_t *typed_arr = (uint8_t*)arr.bucketed_data[h.b]; + typed_arr[h.i] = u; + } + + h.b = 0; + h.i = 2; + pk_bkt_arr_free_handle(&arr, h); + + struct pk_iter it; + b = pk_bkt_arr_iter_begin(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 0) exit(1); + if (*(uint8_t*)it.data != 0) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_increment(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 1) exit(1); + if (*(uint8_t*)it.data != 1) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_increment(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 3) exit(1); + if (*(uint8_t*)it.data != 3) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_increment(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 4) exit(1); + if (*(uint8_t*)it.data != 4) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_increment(&arr, &it); + if (b == true) exit(1); + + pk_bkt_arr_teardown(&arr); + } + fprintf(stdout, "[%s] test iter forwards w/ empty slot end\n\n", __FILE__); + test_teardown(&bkt_buckets, &bkt_data); + + fprintf(stdout, "[%s] test iter reverse w/ empty slot begin\n", __FILE__); + test_spinup(&bkt_buckets, &bkt_data); + { + assert(bkt_buckets != nullptr); + assert(bkt_data != nullptr); + uint8_t u; + bool b; + struct pk_bkt_arr arr = {0}; + struct pk_bkt_arr_handle h; + struct pk_bkt_arr_handle limits; + limits.b = 1; + limits.i = 5; + + pk_bkt_arr_init(&arr, sizeof(uint8_t), alignof(uint8_t), limits, bkt_buckets, bkt_data); + + for (u = 0; u < 5; ++u) { + h = pk_bkt_arr_new_handle(&arr); + uint8_t *typed_arr = (uint8_t*)arr.bucketed_data[h.b]; + typed_arr[h.i] = u; + } + + h.b = 0; + h.i = 2; + pk_bkt_arr_free_handle(&arr, h); + + struct pk_iter it; + b = pk_bkt_arr_iter_end(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 4) exit(1); + if (*(uint8_t*)it.data != 4) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_decrement(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 3) exit(1); + if (*(uint8_t*)it.data != 3) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_decrement(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 1) exit(1); + if (*(uint8_t*)it.data != 1) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_decrement(&arr, &it); + if (b == false) exit(1); + if (it.data == nullptr) exit(1); + if (it.id.bkt.b != 0) exit(1); + if (it.id.bkt.i != 0) exit(1); + if (*(uint8_t*)it.data != 0) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + + b = pk_bkt_arr_iter_decrement(&arr, &it); + if (b == true) exit(1); + + pk_bkt_arr_teardown(&arr); + } + test_teardown(&bkt_buckets, &bkt_data); + fprintf(stdout, "[%s] test iter reverse w/ empty slot end\n\n", __FILE__); + return 0; uncaught_err: PK_LOGV_ERR("%s: failed to catch err.\n", __FILE__); diff --git a/test/pkbktarr.cpp b/test/pkbktarr.cpp index 23a7132..db30e56 100644 --- a/test/pkbktarr.cpp +++ b/test/pkbktarr.cpp @@ -1,6 +1,7 @@ #include "../pkmem.h" #include "../pktmpln.h" +#define PK_IMPL_ITER #define PK_IMPL_MEM #define PK_IMPL_BKTARR #include "../pkbktarr.h" @@ -135,4 +136,143 @@ int main(int argc, char *argv[]) if (bkt_data->alloc_count != 0) exit(1); } test_teardown(&bkt_buckets, &bkt_data); + + // test pointers + test_spinup(&bkt_buckets, &bkt_data); + { + assert(bkt_buckets != nullptr); + assert(bkt_data != nullptr); + const int base_array_len = 16; + int i; + struct pk_bkt_arr_t<int *> arr(pk_bkt_arr_handle_MAX_constexpr, bkt_buckets, bkt_data); + + for (i = 0; i < base_array_len; ++i) { + auto handle = pk_bkt_arr_new_handle(&arr); + arr[handle] = new int{i}; + } + + pk_bkt_arr_t<int*>::FN_Iter cb_wrapper{}; + i = 0; + cb_wrapper.func = [&i](int **lhs) + { + int *val_ptr = *lhs; + int val = *val_ptr; + if (val != i) { + fprintf(stderr, "[pkbktarr.cpp] int pointer did not match, expected: %i, got: %i", i, val); + exit(1); + } + i += 1; + return; + }; + pk_bkt_arr_iterate(&arr, &pk_bkt_arr_t<int>::FN_Iter::invoke, &cb_wrapper); + + arr.~pk_bkt_arr_t<int*>(); + if (bkt_buckets->alloc_count != 0) exit(1); + if (bkt_data->alloc_count != 0) exit(1); + } + test_teardown(&bkt_buckets, &bkt_data); + + fprintf(stdout, "[%s] test iter forwards w/ empty slot begin\n", __FILE__); + test_spinup(&bkt_buckets, &bkt_data); + { + assert(bkt_buckets != nullptr); + assert(bkt_data != nullptr); + uint8_t u, uu; + bool b; + struct pk_bkt_arr_handle h; + struct pk_bkt_arr_handle limits; + limits.b = 2; + limits.i = 5; + struct pk_bkt_arr_t<uint8_t> arr(limits, bkt_buckets, bkt_data); + + for (u = 0; u < limits.b; ++u) { + for (uu = 0; uu < limits.i; ++uu) { + h = pk_bkt_arr_new_handle(&arr); + arr[h] = uu; + } + } + + h.b = 0; + h.i = 2; + pk_bkt_arr_free_handle(&arr, h); + h.b = 1; + pk_bkt_arr_free_handle(&arr, h); + + struct pk_iter_t<uint8_t> it; + + for (u = 0; u < limits.b; ++u) { + for (uu = 0; uu < limits.i; ++uu) { + if (uu == 2) continue; + if (u == 0 && uu == 0) { + b = pk_bkt_arr_iter_begin(&arr, &it); + } else { + b = pk_bkt_arr_iter_increment(&arr, &it); + } + if (b == false) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + if (it.id.bkt.b != u) exit(1); + if (it.id.bkt.i != uu) exit(1); + if (it != uu) exit(1); + } + } + + b = pk_bkt_arr_iter_increment(&arr, &it); + if (b == true) exit(1); + + pk_bkt_arr_teardown(&arr); + } + fprintf(stdout, "[%s] test iter forwards w/ empty slot end\n\n", __FILE__); + test_teardown(&bkt_buckets, &bkt_data); + + fprintf(stdout, "[%s] test iter reverse w/ empty slot begin\n", __FILE__); + test_spinup(&bkt_buckets, &bkt_data); + { + assert(bkt_buckets != nullptr); + assert(bkt_data != nullptr); + uint8_t u, uu; + bool b; + struct pk_bkt_arr_handle h; + struct pk_bkt_arr_handle limits; + limits.b = 2; + limits.i = 5; + pk_bkt_arr_t<uint8_t> arr(limits, bkt_buckets, bkt_data); + + for (u = 0; u < 5; ++u) { + for (uu = 0; uu < 5; ++uu) { + h = pk_bkt_arr_new_handle(&arr); + arr[h] = uu; + } + } + + h.b = 0; + h.i = 2; + pk_bkt_arr_free_handle(&arr, h); + h.b = 1; + pk_bkt_arr_free_handle(&arr, h); + + struct pk_iter_t<uint8_t> it; + + for (u = limits.b; u > 0; --u) { + for (uu = limits.i; uu > 0; --uu) { + if (uu-1 == 2) continue; + if (u == limits.b && uu == limits.i) { + b = pk_bkt_arr_iter_end(&arr, &it); + } else { + b = pk_bkt_arr_iter_decrement(&arr, &it); + } + if (b == false) exit(1); + fprintf(stdout, "it.data: %p, val: %i\n", it.data, *(uint8_t*)it.data); + if (it.id.bkt.b != u-1) exit(1); + if (it.id.bkt.i != uu-1) exit(1); + if (it != uu-1) exit(1); + } + } + + b = pk_bkt_arr_iter_decrement(&arr, &it); + if (b == true) exit(1); + + pk_bkt_arr_teardown(&arr); + } + test_teardown(&bkt_buckets, &bkt_data); + fprintf(stdout, "[%s] test iter reverse w/ empty slot end\n\n", __FILE__); } |
