summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-08-26 13:23:37 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-08-26 13:23:37 -0400
commit78956339691db1fb0de02e63823dc9100c0cd7e7 (patch)
treebf8aef0abcbe2b55d19a3ba04e809c571a2c995e
parent488ee1d60e32502645d4fce9a8261b012ec1ba6a (diff)
pkiter: add iterator for pkarr and pkbktarr
-rw-r--r--Makefile7
-rw-r--r--config.mk2
-rw-r--r--pk.h.in3
-rw-r--r--pkarr.h53
-rw-r--r--pkbktarr.h110
-rw-r--r--pkiter.h28
-rw-r--r--test/pkarr.c101
-rw-r--r--test/pkarr.cpp87
-rw-r--r--test/pkbktarr.c133
-rw-r--r--test/pkbktarr.cpp140
10 files changed, 657 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index 4e00c62..1f80c2a 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/config.mk b/config.mk
index 8d8bdc2..fdd9cfa 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
# pk.h version
-VERSION = 0.7.0
+VERSION = 0.7.1
# paths
PREFIX = /usr/local
diff --git a/pk.h.in b/pk.h.in
index 7e95dd7..52246f9 100644
--- a/pk.h.in
+++ b/pk.h.in
@@ -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
diff --git a/pkarr.h b/pkarr.h
index 88c6ac6..83db8ef 100644
--- a/pkarr.h
+++ b/pkarr.h
@@ -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 */
diff --git a/pkbktarr.h b/pkbktarr.h
index 29613ae..4f146e4 100644
--- a/pkbktarr.h
+++ b/pkbktarr.h
@@ -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__);
}