diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-20 13:59:29 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-03-21 11:03:34 -0400 |
| commit | 153d9b600a11025fe653a45cb4f845c0dff0b145 (patch) | |
| tree | df055c68a0a9e9044c4c9c3364fed7ce2dc419f3 | |
| parent | 9cd55867de91013bdbfe0d73112df504eb7963ba (diff) | |
pkarr: add c++ template + bump version to 0.4.2
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | pk.h.in | 11 | ||||
| -rw-r--r-- | pkarr.h | 92 | ||||
| -rw-r--r-- | test/pkarr.cpp | 113 |
4 files changed, 206 insertions, 12 deletions
@@ -1,5 +1,5 @@ # pk.h version -VERSION = 0.4.1 +VERSION = 0.4.2 # paths PREFIX = /usr/local @@ -144,6 +144,7 @@ * * Initialize `stride`, `alignment`, and `bkt` (optional) members * *before* calling any `pk_arr_*` methods. +* Alternatively, if using c++, use the template ctor. * * Examples: * ``` c @@ -154,6 +155,11 @@ * pk_arr_reserve(&arr, 10); // optional * pk_arr_append(&arr, &obj); * ``` +* ``` c++ +* struct pk_arr<some_type> arr(bkt); +* pk_arr_reserve(&arr, 10); // optional +* pk_arr_append(&arr, &obj); +* ``` * ``` c * struct pk_arr arr = {0}; * arr.stride = sizeof(obj); // required @@ -163,6 +169,11 @@ * obj* d = (obj*)arr->data; * d[0] = ...; * ``` +* ``` c++ +* struct pk_arr_t<some_type> arr(); +* pk_arr_resize(&arr, 10); +* arr[0] = {}; +* ``` * ******************************************************************************** * pkstn.h: def PK_IMPL_STN before including pk.h to enable ad-hoc. @@ -22,8 +22,82 @@ void pk_arr_resize(struct pk_arr *arr, uint32_t count); void pk_arr_move_to_back(struct pk_arr *arr, uint32_t index); void pk_arr_append(struct pk_arr *arr, void *data); 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); +#if defined(__cplusplus) +template<typename T> +struct pk_arr_t : public pk_arr { + pk_arr_t(); + pk_arr_t(struct pk_membucket *bkt); + pk_arr_t(const pk_arr_t<T> &other); + pk_arr_t(pk_arr_t<T> &&other); + pk_arr_t &operator=(const pk_arr_t<T> &other); + pk_arr_t &operator=(pk_arr_t<T> &&other); + ~pk_arr_t(); + T &operator[](size_t index); +}; +template<typename T> +pk_arr_t<T>::pk_arr_t() { + this->next = 0; + this->reserved = 0; + this->stride = sizeof(T); + this->alignment = alignof(T); + this->bkt = NULL; + this->data = NULL; +} +template<typename T> +pk_arr_t<T>::pk_arr_t(struct pk_membucket *bkt) : pk_arr_t<T>() { + this->bkt = bkt; +} +template<typename T> +pk_arr_t<T>::pk_arr_t(const pk_arr_t<T> &other) { + // copy ctor + pk_arr_clone(static_cast<struct pk_arr_t *>(&const_cast<pk_arr_t<T>&>(other)), this); +} +template<typename T> +pk_arr_t<T>::pk_arr_t(pk_arr_t<T> &&other) { + // move ctor + pk_arr_swap(this, &other); + other.data = NULL; +} +template<typename T> +pk_arr_t<T> & +pk_arr_t<T>::operator=(const pk_arr_t<T> &other) { + // copy assignment + if (this->data != NULL) { + pk_arr_reset(this); + } + pk_arr_clone(static_cast<struct pk_arr_t *>(&const_cast<pk_arr_t<T>&>(other)), this); + return *this; +} +template<typename T> +pk_arr_t<T> & +pk_arr_t<T>::operator=(pk_arr_t<T> &&other) { + // move assignment + if (this->data != NULL) { + pk_arr_reset(this); + } + pk_arr_swap(this, &other); + other.data = NULL; + return *this; +} +template<typename T> +pk_arr_t<T>::~pk_arr_t() { + if (this->data != NULL) pk_delete(this->data, this->stride * this->reserved, this->bkt); +} +template<typename T> +T &pk_arr_t<T>::operator[](size_t index) { + if(index >= this->next) throw "pk_arr_t<T>::operator[] out of range"; + return reinterpret_cast<T*>(this->data)[index]; +} +template<typename T> +void pk_arr_append_t(pk_arr_t<T> *arr, const T &item) { + pk_arr_append(arr, &const_cast<T&>(item)); +} +#endif + #endif /* PK_PKARR_H */ #ifdef PK_IMPL_ARR @@ -194,6 +268,24 @@ pk_arr_remove_at(struct pk_arr *arr, uint32_t index) arr->next -= 1; } +void +pk_arr_clone(struct pk_arr *lhs, struct pk_arr *rhs) { + size_t sz; + *rhs = *lhs; + if (lhs->data == NULL) return; + sz = lhs->stride * lhs->reserved; + rhs->data = pk_new(sz, lhs->alignment, lhs->bkt); + memcpy(rhs->data, lhs->data, sz); +} + +void +pk_arr_swap(struct pk_arr *lhs, struct pk_arr *rhs) +{ + struct pk_arr tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; +} + uint32_t pk_arr_find_first_index(struct pk_arr *arr, void *user_data, pk_arr_item_compare *fn) { diff --git a/test/pkarr.cpp b/test/pkarr.cpp index caed839..bc8e3be 100644 --- a/test/pkarr.cpp +++ b/test/pkarr.cpp @@ -1,53 +1,144 @@ #include <cstring> +#include <utility> #include "../pkarr.h" +// TODO might be able to define a "test" class that inherits from a given +// `pk_arr_t<T>` to make some of this testing more streamlined. +// Spinup in ctor, check bkt in dtor, log fn calls, etc. + void -test_spinup(struct pk_arr *arr, struct pk_membucket **bkt) +test_spinup(struct pk_membucket **bkt) { - memset(arr, 0, sizeof(struct pk_arr)); *bkt = pk_bucket_create("test", 1024 * 1024, false); - arr->bkt = *bkt; } void -test_teardown(struct pk_arr *arr, struct pk_membucket **bkt) +test_teardown(struct pk_membucket **bkt) { pk_bucket_destroy(*bkt); *bkt = NULL; - arr->data = NULL; } int main(int argc, char *argv[]) { (void)argc; (void)argv; - struct pk_arr arr = {}; struct pk_membucket *bkt = {}; + uint8_t val1 = 69; + uint8_t val2 = 117; /* template { - test_spinup(&arr, &bkt); + test_spinup(&bkt); test_teardown(&arr, &bkt); } */ + fprintf(stdout, "[%s] Begin\n\n", __FILE__); + + fprintf(stdout, "[%s] Starting append test\n", __FILE__); + test_spinup(&bkt); { - test_spinup(&arr, &bkt); - arr.stride = sizeof(uint8_t); + pk_arr_t<uint8_t> arr(bkt); uint8_t c = 255; - pk_arr_append(&arr, &c); + pk_arr_append_t(&arr, c); if (arr.bkt == NULL) exit(1); if (arr.data == NULL) exit(1); if (arr.reserved == 0) exit(1); + if (arr.stride != sizeof(uint8_t)) exit(1); + if (arr.alignment != alignof(uint8_t)) exit(1); if (arr.next != 1) exit(1); + if (arr[0] != c) exit(1); - test_teardown(&arr, &bkt); + fprintf(stdout, "[%s] parameterized bkt ctor + operator[]\n", __FILE__); + } + if (bkt->allocs != 0) exit(1); + fprintf(stdout, "[%s] dtor called.\n", __FILE__); + fprintf(stdout, "[%s] Ending append test\n\n", __FILE__); + test_teardown(&bkt); + + // copy ctor + fprintf(stdout, "[%s] Starting copy ctor test\n", __FILE__); + test_spinup(&bkt); + { + pk_arr_t<uint8_t> arr1(bkt); + pk_arr_append_t(&arr1, val1); + + // copy + pk_arr_t<uint8_t> arr2{arr1}; + + if (arr1[0] != val1) exit(1); + if (arr2[0] != val1) exit(1); + } + if (bkt->allocs != 0) exit(1); + fprintf(stdout, "[%s] dtor called.\n", __FILE__); + fprintf(stdout, "[%s] Ending copy ctor test\n\n", __FILE__); + test_teardown(&bkt); + + // move ctor + fprintf(stdout, "[%s] Starting move ctor test\n", __FILE__); + test_spinup(&bkt); + { + pk_arr_t<uint8_t> arr1(bkt); + pk_arr_append_t(&arr1, val1); + + // move + pk_arr_t<uint8_t> arr2{std::move(arr1)}; + + // if (arr1[0] == val1) exit(1); + if (arr2[0] != val1) exit(1); + } + if (bkt->allocs != 0) exit(1); + fprintf(stdout, "[%s] dtor called.\n", __FILE__); + fprintf(stdout, "[%s] Ending move ctor test\n\n", __FILE__); + test_teardown(&bkt); + + // copy assignment + fprintf(stdout, "[%s] Starting copy assignment test\n", __FILE__); + test_spinup(&bkt); + { + pk_arr_t<uint8_t> arr1(bkt); + pk_arr_append_t(&arr1, val1); + pk_arr_t<uint8_t> arr2(bkt); + pk_arr_append_t(&arr2, val2); + + // copy + arr1 = arr2; + + if (arr1[0] != val2) exit(1); + if (arr2[0] != val2) exit(1); } + if (bkt->allocs != 0) exit(1); + fprintf(stdout, "[%s] dtor called.\n", __FILE__); + fprintf(stdout, "[%s] Ending copy assignment test\n\n", __FILE__); + test_teardown(&bkt); + + // move assignment + fprintf(stdout, "[%s] Starting move assignment test\n", __FILE__); + test_spinup(&bkt); + { + pk_arr_t<uint8_t> arr1(bkt); + pk_arr_append_t(&arr1, val1); + pk_arr_t<uint8_t> arr2(bkt); + pk_arr_append_t(&arr2, val2); + + // move + arr1 = std::move(arr2); + + if (arr1[0] != val2) exit(1); + // if (arr2[0] != val1) exit(1); + } + if (bkt->allocs != 0) exit(1); + fprintf(stdout, "[%s] dtor called.\n", __FILE__); + fprintf(stdout, "[%s] Ending move assignment test\n\n", __FILE__); + test_teardown(&bkt); + + fprintf(stdout, "[%s] End\n", __FILE__); return 0; } |
