// vim:fileencoding=utf-8:foldmethod=marker #include "./array.h" #include "../../common/assert/assert.h" #include "../mem_allocator/mem_allocator.h" #include "../../common/misc/misc_utils.h" #include "../../common/aliases/aliases.h" #include "../../common/platform/platform.h" #include #define _array_header(DATA_PTR) (ArrayHeader *)((u8 *)DATA_PTR - sizeof(ArrayHeader)) u64 _array_count(u8 *array, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); return arr_header->count; } u64 _array_capacity(u8 *array, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); return arr_header->capacity; } u64 _array_item_size(u8 *array, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); return arr_header->item_size; } u8 *_array_get(u8 *array, u64 index, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); wapp_runtime_assert(index < arr_header->count, "`index` is out of bounds"); return array + arr_header->item_size * index; } void _array_set(u8 *array, u64 index, u8 *value, u64 item_size) { u8 *item = _array_get(array, index, item_size); ArrayHeader *arr_header = _array_header(array); memcpy((void *)item, (void *)value, arr_header->item_size); } void _array_append_capped(u8 *array, u8 *value, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); if (arr_header->count >= arr_header->capacity) { return; } u64 index = (arr_header->count)++; _array_set(array, index, value, item_size); } void _array_extend_capped(u8 *dst_array, const u8 *src_array, u64 item_size) { wapp_debug_assert(dst_array != NULL && src_array != NULL, "`dst_array` and `src_array` should not be NULL"); ArrayHeader *dst_header = _array_header(dst_array); ArrayHeader *src_header = _array_header(src_array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst_header->magic, "`dst_array` is not a valid wapp array"); wapp_runtime_assert(WAPP_ARRAY_MAGIC == src_header->magic, "`src_array` is not a valid wapp array"); wapp_runtime_assert(item_size == dst_header->item_size && item_size == src_header->item_size, "Invalid item type provided"); u64 remaining_capacity = dst_header->capacity - dst_header->count; u64 copy_count = src_header->count < remaining_capacity ? src_header->count : remaining_capacity; u8 *dst_ptr = dst_array + dst_header->count * dst_header->item_size; memcpy((void *)dst_ptr, (const void *)src_array, copy_count * src_header->item_size); dst_header->count += copy_count; } void _array_copy_capped(u8 *dst_array, const u8 *src_array, u64 item_size) { wapp_debug_assert(dst_array != NULL && src_array != NULL, "`dst_array` and `src_array` should not be NULL"); ArrayHeader *dst_header = _array_header(dst_array); ArrayHeader *src_header = _array_header(src_array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst_header->magic, "`dst_array` is not a valid wapp array"); wapp_runtime_assert(WAPP_ARRAY_MAGIC == src_header->magic, "`src_array` is not a valid wapp array"); wapp_runtime_assert(item_size == dst_header->item_size && item_size == src_header->item_size, "Invalid item type provided"); _array_clear(dst_array, item_size); u64 copy_count = src_header->count < dst_header->capacity ? src_header->count : dst_header->capacity; memcpy((void *)dst_array, (const void *)src_array, copy_count * src_header->item_size); dst_header->count = copy_count; } u8 *_array_append_alloc(const Allocator *allocator, u8 *array, u8 *value, u64 item_size) { wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); u8 *output = array; if (arr_header->count >= arr_header->capacity) { u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(arr_header->capacity * 2); output = (u8 *)_array_alloc_capacity(allocator, new_capacity, arr_header->item_size); if (!output) { output = array; goto RETURN_ARRAY_APPEND_ALLOC; } _array_copy_capped(output, array, item_size); } _array_append_capped(output, value, item_size); RETURN_ARRAY_APPEND_ALLOC: return output; } u8 *_array_extend_alloc(const Allocator *allocator, u8 *dst_array, const u8 *src_array, u64 item_size) { wapp_debug_assert(allocator != NULL && dst_array != NULL && src_array != NULL, "`allocator`, `dst_array` and `src_array` should not be NULL"); ArrayHeader *dst_header = _array_header(dst_array); ArrayHeader *src_header = _array_header(src_array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst_header->magic, "`dst_array` is not a valid wapp array"); wapp_runtime_assert(WAPP_ARRAY_MAGIC == src_header->magic, "`src_array` is not a valid wapp array"); wapp_runtime_assert(item_size == dst_header->item_size && item_size == src_header->item_size, "Invalid item type provided"); u8 *output = dst_array; u64 remaining_capacity = dst_header->capacity - dst_header->count; if (src_header->count >= remaining_capacity) { u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst_header->capacity * 2); output = (u8 *)_array_alloc_capacity(allocator, new_capacity, dst_header->item_size); if (!output) { output = dst_array; goto RETURN_ARRAY_EXTEND_ALLOC; } _array_copy_capped(output, dst_array, item_size); } _array_extend_capped(output, src_array, item_size); RETURN_ARRAY_EXTEND_ALLOC: return output; } u8 *_array_copy_alloc(const Allocator *allocator, u8 *dst_array, const u8 *src_array, u64 item_size) { wapp_debug_assert(allocator != NULL && dst_array != NULL && src_array != NULL, "`allocator`, `dst_array` and `src_array` should not be NULL"); ArrayHeader *dst_header = _array_header(dst_array); ArrayHeader *src_header = _array_header(src_array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst_header->magic, "`dst_array` is not a valid wapp array"); wapp_runtime_assert(WAPP_ARRAY_MAGIC == src_header->magic, "`src_array` is not a valid wapp array"); wapp_runtime_assert(item_size == dst_header->item_size && item_size == src_header->item_size, "Invalid item type provided"); u8 *output = dst_array; if (src_header->count >= dst_header->capacity) { u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst_header->capacity * 2); output = (u8 *)_array_alloc_capacity(allocator, new_capacity, src_header->item_size); if (!output) { output = dst_array; goto RETURN_ARRAY_COPY_ALLOC; } } _array_copy_capped(output, src_array, item_size); RETURN_ARRAY_COPY_ALLOC: return output; } u8 *_array_pop(u8 *array, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); if (arr_header->count == 0) { return NULL; } u64 index = arr_header->count - 1; u8 *out = _array_get(array, index, item_size); --(arr_header->count); return out; } void _array_clear(u8 *array, u64 item_size) { wapp_debug_assert(array != NULL, "`array` should not be NULL"); ArrayHeader *arr_header = _array_header(array); wapp_runtime_assert(WAPP_ARRAY_MAGIC == arr_header->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(item_size == arr_header->item_size, "Invalid item type provided"); arr_header->count = 0; } u8 *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size) { wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); u8 *output = NULL; u64 allocation_size = sizeof(ArrayHeader) + item_size * capacity; ArrayHeader *header = wapp_mem_allocator_alloc(allocator, allocation_size); if (!header) { goto RETURN_ARRAY_ALLOC; } output = (u8 *)(header + 1); header->magic = WAPP_ARRAY_MAGIC; header->count = 0; header->capacity = capacity; header->item_size = item_size; RETURN_ARRAY_ALLOC: return output; }