From 3c81feedbb659e316acf3eaad44e6eee9e24a3da Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 19 Sep 2026 22:41:10 +0100 Subject: [PATCH] Add wpArrayRemoveSwapEnd --- CHANGELOG.md | 1 + src/base/array/array.c | 27 ++++++++++++++++++++++++--- src/base/array/array.h | 2 ++ tests/array/test_i32_array.c | 13 +++++++++++++ tests/array/test_i32_array.cc | 13 +++++++++++++ tests/array/test_i32_array.h | 1 + tests/wapptest.c | 1 + tests/wapptest.cc | 1 + 8 files changed, 56 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d737eca..8278c8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `wpPrngSplitmix64Init`, `wpPrngSplitmix64InitWithSeed`, `wpPrngSplitmix64`, `wpPrngSplitmix64InRange`, `wpPrngSplitmix64Choice` - `wpStr8Clear` - `wpArrayZero` to zero all elements in an array without setting the count to 0 +- `wpArrayRemoveSwapEnd` to remove an array element using its index and swap the last element in ### Changed diff --git a/src/base/array/array.c b/src/base/array/array.c index 8e4fb65..d8c20c4 100644 --- a/src/base/array/array.c +++ b/src/base/array/array.c @@ -9,7 +9,8 @@ #define arrayHeader(ARRAY) (WpArrayHeader *)(wpMiscUtilsOffsetPointer(ARRAY, (i64)sizeof(WpArrayHeader) * -1)) -wp_persist inline void arrayValidate(const WpArray array, u64 item_size); +wp_persist inline void arrayValidate(const WpArray array, u64 item_size); +wp_persist inline void *arrayGetItemWithOffset(const WpArray array, u64 offset); u64 arrayCount(WpArray array) { wpDebugAssert(array != NULL, "`array` should not be NULL"); @@ -54,7 +55,7 @@ void *arrayGet(WpArray array, u64 index, u64 item_size) { WpArrayHeader *header = arrayHeader(array); wpRuntimeAssert(index < header->count, "`index` is out of bounds"); - return wpMiscUtilsOffsetPointer(array, header->item_size * index); + return arrayGetItemWithOffset(array, header->item_size * index); } void arraySet(WpArray array, u64 index, void *value, u64 item_size) { @@ -195,6 +196,22 @@ RETURN_ARRAY_COPY_ALLOC: return output; } +void arrayRemoveSwapEnd(WpArray array, u64 index, u64 item_size) { + wpRuntimeAssert(array != NULL, "`array` should not be NULL"); + arrayValidate(array, item_size); + + WpArrayHeader *header = arrayHeader(array); + if (header->count == 0 || index > header->count) { return; } + + u64 last_item_index = header->count - 1; + void *cur_item = arrayGetItemWithOffset(array, header->item_size * index); + void *last_item = arrayGetItemWithOffset(array, header->item_size * last_item_index); + + memcpy(cur_item, last_item, header->item_size); + memset(last_item, 0, header->item_size); + --(header->count); +} + void *arrayPop(WpArray array, u64 item_size) { wpRuntimeAssert(array != NULL, "`array` should not be NULL"); arrayValidate(array, item_size); @@ -203,7 +220,7 @@ void *arrayPop(WpArray array, u64 item_size) { if (header->count == 0) { return NULL; } u64 index = header->count - 1; - void *out = arrayGet(array, index, item_size); + void *out = arrayGetItemWithOffset(array, header->item_size * index); --(header->count); return out; } @@ -283,3 +300,7 @@ wp_persist inline void arrayValidate(const WpArray array, u64 item_size) { wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array"); wpRuntimeAssert(item_size == header->item_size, "Invalid item type provided"); } + +wp_persist inline void *arrayGetItemWithOffset(const WpArray array, u64 offset) { + return wpMiscUtilsOffsetPointer(array, offset); +} diff --git a/src/base/array/array.h b/src/base/array/array.h index 14d949d..a49374e 100644 --- a/src/base/array/array.h +++ b/src/base/array/array.h @@ -168,6 +168,7 @@ typedef enum WpArrayInitFlags { (WpArray)SRC_ARRAY, \ FLAGS, \ sizeof(TYPE))) +#define wpArrayRemoveSwapEnd(TYPE, ARRAY, INDEX) arrayRemoveSwapEnd(ARRAY, INDEX, sizeof(TYPE)) #define wpArrayZero(TYPE, ARRAY) (arrayZero((WpArray)ARRAY, sizeof(TYPE))) #define wpArrayClear(TYPE, ARRAY) (arrayClear((WpArray)ARRAY, sizeof(TYPE))) #define wpArrayCalcAllocSize(TYPE, CAPACITY) arrayCalcAllocSize(CAPACITY, sizeof(TYPE)) @@ -204,6 +205,7 @@ WpArray arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArra WpArrayInitFlags flags, u64 item_size); WpArray arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src, WpArrayInitFlags flags, u64 item_size); +void arrayRemoveSwapEnd(WpArray array, u64 index, u64 item_size); void *arrayPop(WpArray array, u64 item_size); void arrayZero(WpArray array, u64 item_size); void arrayClear(WpArray array, u64 item_size); diff --git a/tests/array/test_i32_array.c b/tests/array/test_i32_array.c index 66ab702..c98e3de 100644 --- a/tests/array/test_i32_array.c +++ b/tests/array/test_i32_array.c @@ -245,6 +245,19 @@ WpTestFuncResult test_i32_array_copy_alloc(void) { return wpTesterResult(result); } +WpTestFuncResult test_i32_array_remove_swap_end(void) { + b8 result; + + WpI32Array array = wpArray(i32, 0, 1, 2, 3, 4, 5, 6, 7, 8); + result = wpArrayCount(array) == 9 && array[4] == 4; + + wpArrayRemoveSwapEnd(i32, array, 4); + + result = result && wpArrayCount(array) == 8 && array[4] == 8; + + return wpTesterResult(result); +} + WpTestFuncResult test_i32_array_pop(void) { b8 result; diff --git a/tests/array/test_i32_array.cc b/tests/array/test_i32_array.cc index d15ca21..9d3e818 100644 --- a/tests/array/test_i32_array.cc +++ b/tests/array/test_i32_array.cc @@ -261,6 +261,19 @@ WpTestFuncResult test_i32_array_clear(void) { return wpTesterResult(result); } +WpTestFuncResult test_i32_array_remove_swap_end(void) { + b8 result; + + WpI32Array array = wpArray(i32, 0, 1, 2, 3, 4, 5, 6, 7, 8); + result = wpArrayCount(array) == 9 && array[4] == 4; + + wpArrayRemoveSwapEnd(i32, array, 4); + + result = result && wpArrayCount(array) == 8 && array[4] == 8; + + return wpTesterResult(result); +} + WpTestFuncResult test_i32_array_pop(void) { b8 result; diff --git a/tests/array/test_i32_array.h b/tests/array/test_i32_array.h index 05a932a..95f9918 100644 --- a/tests/array/test_i32_array.h +++ b/tests/array/test_i32_array.h @@ -14,6 +14,7 @@ WpTestFuncResult test_i32_array_alloc_capacity(void); WpTestFuncResult test_i32_array_append_alloc(void); WpTestFuncResult test_i32_array_extend_alloc(void); WpTestFuncResult test_i32_array_copy_alloc(void); +WpTestFuncResult test_i32_array_remove_swap_end(void); WpTestFuncResult test_i32_array_pop(void); WpTestFuncResult test_i32_array_clear(void); diff --git a/tests/wapptest.c b/tests/wapptest.c index ea44e46..8ab9311 100644 --- a/tests/wapptest.c +++ b/tests/wapptest.c @@ -44,6 +44,7 @@ int main(void) { test_i32_array_append_alloc, test_i32_array_extend_alloc, test_i32_array_copy_alloc, + test_i32_array_remove_swap_end, test_i32_array_pop, test_i32_array_clear, test_queue_push, diff --git a/tests/wapptest.cc b/tests/wapptest.cc index ea44e46..8ab9311 100644 --- a/tests/wapptest.cc +++ b/tests/wapptest.cc @@ -44,6 +44,7 @@ int main(void) { test_i32_array_append_alloc, test_i32_array_extend_alloc, test_i32_array_copy_alloc, + test_i32_array_remove_swap_end, test_i32_array_pop, test_i32_array_clear, test_queue_push,