// vim:fileencoding=utf-8:foldmethod=marker #ifndef ARRAY_H #define ARRAY_H #include "../mem/allocator/mem_allocator.h" #include "../../common/misc/misc_utils.h" #include "../../common/aliases/aliases.h" #include "../../common/platform/platform.h" #ifdef WP_PLATFORM_CPP BEGIN_C_LINKAGE #endif // !WP_PLATFORM_CPP #define WP_ARRAY_MAGIC (u64)0x57415f415252 #define _calcArrayCount(TYPE, ...) wpMiscUtilsVaArgsCount(TYPE, __VA_ARGS__) #define _calcArrayCapacity(TYPE, ...) wpMiscUtilsU64RoundUpPow2(_calcArrayCount(TYPE, __VA_ARGS__) * 2) typedef struct WpStr8 WpStr8; // NOTE (Abdelrahman): Typedefs to distinguish arrays from regular pointers typedef void *WpArray; typedef void **WpVoidPtrArray; typedef c8 *WpC8Array; typedef c16 *WpC16Array; typedef c32 *WpC32Array; typedef u8 *WpU8Array; typedef u16 *WpU16Array; typedef u32 *WpU32Array; typedef u64 *WpU64Array; typedef b8 *WpB8Array; typedef i8 *WpI8Array; typedef i16 *WpI16Array; typedef i32 *WpI32Array; typedef i64 *WpI64Array; typedef f32 *WpF32Array; typedef f64 *WpF64Array; typedef f128 *WpF128Array; typedef uptr *WpUptrArray; typedef iptr *WpIptrArray; typedef WpStr8 *WpStr8Array; typedef enum { WP_ARRAY_INIT_NONE = 0, WP_ARRAY_INIT_FILLED = 1 << 1, } WpArrayInitFlags; #ifdef WP_PLATFORM_CPP #define wpArray(TYPE, ...) ([&]() { \ u64 capacity = _calcArrayCapacity(TYPE, __VA_ARGS__); \ \ TYPE items[_calcArrayCapacity(TYPE, __VA_ARGS__)] = {__VA_ARGS__}; \ \ wp_persist u8 array[ \ sizeof(WpArrayHeader) + _calcArrayCapacity(TYPE, __VA_ARGS__) * sizeof(TYPE) \ ] = {0}; \ WpArrayHeader *header = (WpArrayHeader *)array; \ header->magic = WP_ARRAY_MAGIC; \ header->count = _calcArrayCount(TYPE, __VA_ARGS__); \ header->capacity = _calcArrayCapacity(TYPE, __VA_ARGS__); \ header->item_size = sizeof(TYPE); \ \ u8 *buf = (u8 *)(header + 1); \ memcpy(buf, items, capacity * sizeof(TYPE)); \ return (TYPE *)buf; \ }()) #define wpArrayWithCapacity(TYPE, CAPACITY, FLAGS) ([&]() { \ wp_persist u8 array[ \ sizeof(WpArrayHeader) + CAPACITY * sizeof(TYPE) \ ] = {0}; \ WpArrayHeader *header = (WpArrayHeader *)array; \ header->magic = WP_ARRAY_MAGIC; \ header->count = (FLAGS & WP_ARRAY_INIT_FILLED) ? CAPACITY : 0; \ header->capacity = CAPACITY; \ header->item_size = sizeof(TYPE); \ \ return (TYPE *)(header + 1); \ }()) #define wpArrayPop(TYPE, ARRAY) ([&]() { \ if (ARRAY == NULL || _arrayCount((WpArray)ARRAY) == 0) { \ TYPE result{}; \ return result; \ } \ \ return *((TYPE *)_arrayPop((WpArray)ARRAY, sizeof(TYPE))); \ }()) #else #define _stackArray(TYPE, SIZE) struct {WpArrayHeader header; \ TYPE items[SIZE]; \ wpMiscUtilsReservePadding(sizeof(WpArrayHeader) + \ sizeof(TYPE) * SIZE);} #define wpArray(TYPE, ...) \ ((TYPE *)( \ (_stackArray(TYPE, _calcArrayCapacity(TYPE, __VA_ARGS__))){ \ .header = { \ .magic = WP_ARRAY_MAGIC, \ .count = _calcArrayCount(TYPE, __VA_ARGS__), \ .capacity = _calcArrayCapacity(TYPE, __VA_ARGS__), \ .item_size = sizeof(TYPE), \ }, \ .items = {__VA_ARGS__}, \ }.items \ )) #define wpArrayWithCapacity(TYPE, CAPACITY, FLAGS) \ ((TYPE *)( \ (_stackArray(TYPE, CAPACITY)){ \ .header = { \ .magic = WP_ARRAY_MAGIC, \ .count = (FLAGS & WP_ARRAY_INIT_FILLED) ? CAPACITY : 0, \ .capacity = CAPACITY, \ .item_size = sizeof(TYPE), \ }, \ .items = {0}, \ }.items \ )) #define wpArrayPop(TYPE, ARRAY) \ (ARRAY == NULL || _arrayCount((WpArray)ARRAY) == 0 ? \ (TYPE){0} : \ *((TYPE *)_arrayPop((WpArray)ARRAY, sizeof(TYPE))) \ ) #endif // !WP_PLATFORM_CPP #define wpArrayCount(ARRAY) \ (_arrayCount((WpArray)ARRAY)) #define wpArrayCapacity(ARRAY) \ (_arrayCapacity((WpArray)ARRAY)) #define wpArrayItemSize(ARRAY) \ (_arrayItemSize((WpArray)ARRAY)) #define wpArraySetCount(ARRAY, COUNT) \ (_arraySetCount((WpArray)ARRAY, COUNT)) #define wpArrayGet(TYPE, ARRAY, INDEX) \ ((TYPE *)_arrayGet((WpArray)ARRAY, \ INDEX, \ sizeof(TYPE))) #define wpArraySet(TYPE, ARRAY, INDEX, VALUE_PTR) \ (_arraySet((WpArray)ARRAY, \ INDEX, \ (u8 *)VALUE_PTR, \ sizeof(TYPE))) #define wpArrayAppendCapped(TYPE, ARRAY, VALUE_PTR) \ (_arrayAppendCapped((WpArray)ARRAY, \ (u8 *)VALUE_PTR, \ sizeof(TYPE))) #define wpArrayExtendCapped(TYPE, DST_ARRAY, SRC_ARRAY) \ (_arrayExtendCappend((WpArray)DST_ARRAY, \ (WpArray)SRC_ARRAY, \ sizeof(TYPE))) #define wpArrayCopyCapped(TYPE, DST_ARRAY, SRC_ARRAY) \ (_arrayCopyCapped((WpArray)DST_ARRAY, \ (WpArray)SRC_ARRAY, \ sizeof(TYPE))) #define wpArrayAppendAlloc(TYPE, ALLOCATOR_PTR, ARRAY, VALUE_PTR, FLAGS) \ ((TYPE *)_arrayAppendAlloc(ALLOCATOR_PTR, \ (WpArray)ARRAY, \ (u8 *)VALUE_PTR, \ FLAGS, \ sizeof(TYPE))) #define wpArrayExtendAlloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \ ((TYPE *)_arrayExtendAlloc(ALLOCATOR_PTR, \ (WpArray)DST_ARRAY, \ (WpArray)SRC_ARRAY, \ FLAGS, \ sizeof(TYPE))) #define wpArrayCopyAlloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \ ((TYPE *)_arrayCopyAlloc(ALLOCATOR_PTR, \ (WpArray)DST_ARRAY, \ (WpArray)SRC_ARRAY, \ FLAGS, \ sizeof(TYPE))) #define wpArrayClear(TYPE, ARRAY) \ (_arrayClear((WpArray)ARRAY, \ sizeof(TYPE))) #define wpArrayCalcAllocSize(TYPE, CAPACITY) _arrayCalcAllocSize(CAPACITY, sizeof(TYPE)) #define wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, FLAGS) \ ((TYPE *)_arrayAllocCapacity(ALLOCATOR_PTR, CAPACITY, FLAGS, sizeof(TYPE))) #define wpArrayFromPreallcatedBuffer(TYPE, BUFFER, BUFFER_SIZE) \ ((TYPE *)_array_from_preallcated_buffer(BUFFER, BUFFER_SIZE, sizeof(TYPE))) // Only needed for allocators like malloc where each allocation has to be freed on its own. // No need to use it for allocators like Arena. #define wpArrayDealloc(TYPE, ALLOCATOR_PTR, ARRAY_DPTR) \ (_arrayDealloc(ALLOCATOR_PTR, (WpArray *)ARRAY_DPTR, sizeof(TYPE))) typedef struct WpArrayHeader WpArrayHeader; struct WpArrayHeader { u64 magic; u64 count; u64 capacity; u64 item_size; }; u64 _arrayCount(WpArray array); u64 _arrayCapacity(WpArray array); u64 _arrayItemSize(WpArray array); void _arraySetCount(WpArray array, u64 count); void *_arrayGet(WpArray array, u64 index, u64 item_size); void _arraySet(WpArray array, u64 index, void *value, u64 item_size); void _arrayAppendCapped(WpArray array, void *value, u64 item_size); void _arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size); void _arrayCopyCapped(WpArray dst, const WpArray src, u64 item_size); WpArray _arrayAppendAlloc(const WpAllocator *allocator, WpArray array, void *value, WpArrayInitFlags flags, u64 item_size); WpArray _arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src, WpArrayInitFlags flags, u64 item_size); WpArray _arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src, WpArrayInitFlags flags, u64 item_size); void *_arrayPop(WpArray array, u64 item_size); void _arrayClear(WpArray array, u64 item_size); u64 _arrayCalcAllocSize(u64 capacity, u64 item_size); WpArray _arrayAllocCapacity(const WpAllocator *allocator, u64 capacity, WpArrayInitFlags flags, u64 item_size); WpArray _arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitFlags flags, u64 item_size); void _arrayDealloc(const WpAllocator *allocator, WpArray *array, u64 item_size); #ifdef WP_PLATFORM_CPP END_C_LINKAGE #endif // !WP_PLATFORM_CPP #endif // !ARRAY_H