commit cadccc91359113f62df6778185d905eba740582e Author: Abdelrahman Date: Fri Jun 26 20:01:05 2026 +0100 INITIAL COMMIT diff --git a/src/wapp/base/array/array.c b/src/wapp/base/array/array.c new file mode 100644 index 0000000..bfb3ae8 --- /dev/null +++ b/src/wapp/base/array/array.c @@ -0,0 +1,266 @@ +// 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 + +#define _array_header(ARRAY) (WpArrayHeader *)(wpMiscUtilsOffsetPointer(ARRAY, (i64)sizeof(WpArrayHeader) * -1)) + +wp_persist inline void _array_validate(const WpArray array, u64 item_size); + +u64 _arrayCount(WpArray array) { + wpDebugAssert(array != NULL, "`array` should not be NULL"); + + WpArrayHeader *header = _array_header(array); + wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array"); + + return header->count; +} + +u64 _arrayCapacity(WpArray array) { + wpDebugAssert(array != NULL, "`array` should not be NULL"); + + WpArrayHeader *header = _array_header(array); + wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array"); + + return header->capacity; +} + +u64 _arrayItemSize(WpArray array) { + wpDebugAssert(array != NULL, "`array` should not be NULL"); + + WpArrayHeader *header = _array_header(array); + wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array"); + + return header->item_size; +} + +void _arraySetCount(WpArray array, u64 count) { + wpDebugAssert(array != NULL, "`array` should not be NULL"); + + WpArrayHeader *header = _array_header(array); + wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array"); + + header->count = count; +} + +void *_arrayGet(WpArray array, u64 index, u64 item_size) { + wpRuntimeAssert(array != NULL, "`array` should not be NULL"); + _array_validate(array, item_size); + + WpArrayHeader *header = _array_header(array); + wpRuntimeAssert(index < header->count, "`index` is out of bounds"); + + return wpMiscUtilsOffsetPointer(array, header->item_size * index); +} + +void _arraySet(WpArray array, u64 index, void *value, u64 item_size) { + void *item = _arrayGet(array, index, item_size); + + WpArrayHeader *header = _array_header(array); + memcpy(item, value, header->item_size); +} + +void _arrayAppendCapped(WpArray array, void *value, u64 item_size) { + wpRuntimeAssert(array != NULL, "`array` should not be NULL"); + _array_validate(array, item_size); + + WpArrayHeader *header = _array_header(array); + if (header->count >= header->capacity) { return; } + + u64 index = (header->count)++; + _arraySet(array, index, value, item_size); +} + +void _arrayExtendCappend(WpArray dst, const WpArray src, u64 item_size) { + wpRuntimeAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); + _array_validate(dst, item_size); + _array_validate(src, item_size); + + WpArrayHeader *src_header = _array_header(src); + WpArrayHeader *dst_header = _array_header(dst); + u64 remaining_capacity = dst_header->capacity - dst_header->count; + + u64 copy_count = src_header->count < remaining_capacity ? src_header->count : remaining_capacity; + void *dst_ptr = wpMiscUtilsOffsetPointer(dst, dst_header->count * dst_header->item_size); + memcpy(dst_ptr, src, copy_count * src_header->item_size); + dst_header->count += copy_count; +} + +void _arrayCopyCapped(WpArray dst, const WpArray src, u64 item_size) { + wpRuntimeAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); + _array_validate(dst, item_size); + _array_validate(src, item_size); + + _arrayClear(dst, item_size); + + WpArrayHeader *src_header = _array_header(src); + WpArrayHeader *dst_header = _array_header(dst); + u64 copy_count = src_header->count < dst_header->capacity ? src_header->count : dst_header->capacity; + memcpy((void *)dst, (void *)src, copy_count * src_header->item_size); + dst_header->count = copy_count; +} + +WpArray _arrayAppendAlloc(const WpAllocator *allocator, WpArray array, void *value, + WpArrayInitFlags flags, u64 item_size) { + wpRuntimeAssert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + _array_validate(array, item_size); + + WpArray output = array; + + WpArrayHeader *header = _array_header(array); + if (header->count >= header->capacity) { + u64 new_capacity = wpMiscUtilsU64RoundUpPow2(header->capacity * 2); + output = (WpArray )_arrayAllocCapacity(allocator, new_capacity, flags, + header->item_size); + if (!output) { + output = array; + goto RETURN_ARRAY_APPEND_ALLOC; + } + _arrayCopyCapped(output, array, item_size); + } + + _arrayAppendCapped(output, value, item_size); + + if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) { + _arraySetCount(output, _arrayCapacity(output)); + } + +RETURN_ARRAY_APPEND_ALLOC: + return output; +} + +WpArray _arrayExtendAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src, + WpArrayInitFlags flags, u64 item_size) { + wpRuntimeAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL"); + _array_validate(dst, item_size); + _array_validate(src, item_size); + + WpArray output = dst; + + WpArrayHeader *src_header = _array_header(src); + WpArrayHeader *dst_header = _array_header(dst); + u64 remaining_capacity = dst_header->capacity - dst_header->count; + if (src_header->count >= remaining_capacity) { + u64 new_capacity = wpMiscUtilsU64RoundUpPow2(dst_header->capacity * 2); + output = (WpArray )_arrayAllocCapacity(allocator, new_capacity, + flags, dst_header->item_size); + if (!output) { + output = dst; + goto RETURN_ARRAY_EXTEND_ALLOC; + } + _arrayCopyCapped(output, dst, item_size); + } + + _arrayExtendCappend(output, src, item_size); + + if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) { + _arraySetCount(output, _arrayCapacity(output)); + } + +RETURN_ARRAY_EXTEND_ALLOC: + return output; +} + +WpArray _arrayCopyAlloc(const WpAllocator *allocator, WpArray dst, const WpArray src, + WpArrayInitFlags flags, u64 item_size) { + wpRuntimeAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL"); + _array_validate(dst, item_size); + _array_validate(src, item_size); + + WpArray output = dst; + + WpArrayHeader *src_header = _array_header(src); + WpArrayHeader *dst_header = _array_header(dst); + if (src_header->count >= dst_header->capacity) { + u64 new_capacity = wpMiscUtilsU64RoundUpPow2(dst_header->capacity * 2); + output = (WpArray )_arrayAllocCapacity(allocator, new_capacity, + flags, src_header->item_size); + if (!output) { + output = dst; + goto RETURN_ARRAY_COPY_ALLOC; + } + } + + _arrayCopyCapped(output, src, item_size); + + if ((flags & WP_ARRAY_INIT_FILLED) == WP_ARRAY_INIT_FILLED) { + _arraySetCount(output, _arrayCapacity(output)); + } + +RETURN_ARRAY_COPY_ALLOC: + return output; +} + +void *_arrayPop(WpArray array, u64 item_size) { + wpRuntimeAssert(array != NULL, "`array` should not be NULL"); + _array_validate(array, item_size); + + WpArrayHeader *header = _array_header(array); + if (header->count == 0) { return NULL; } + + u64 index = header->count - 1; + void *out = _arrayGet(array, index, item_size); + --(header->count); + return out; +} + +void _arrayClear(WpArray array, u64 item_size) { + wpRuntimeAssert(array != NULL, "`array` should not be NULL"); + _array_validate(array, item_size); + + WpArrayHeader *header = _array_header(array); + header->count = 0; +} + +u64 _arrayCalcAllocSize(u64 capacity, u64 item_size) { + return sizeof(WpArrayHeader) + item_size * capacity; +} + +WpArray _arrayAllocCapacity(const WpAllocator *allocator, u64 capacity, WpArrayInitFlags flags, + u64 item_size) { + wpRuntimeAssert(allocator != NULL, "`allocator` should not be NULL"); + + WpArray output = NULL; + + u64 allocation_size = _arrayCalcAllocSize(capacity, item_size); + void *buffer = wpMemAllocatorAlloc(allocator, allocation_size); + if (!buffer) { + goto RETURN_ARRAY_ALLOC; + } + + output = _arrayFromPreallocatedBuffer(buffer, allocation_size, flags, item_size); + +RETURN_ARRAY_ALLOC: + return output; +} + + +WpArray _arrayFromPreallocatedBuffer(void *buffer, u64 buffer_size, WpArrayInitFlags flags, + u64 item_size) { + wpRuntimeAssert(buffer != NULL, "`buffer` should not be NULL"); + + i64 data_buffer_size = (i64)buffer_size - (i64)(sizeof(WpArrayHeader)); + if (data_buffer_size <= 0) { + return NULL; + } + + u64 item_capacity = (u64)data_buffer_size / item_size; + WpArrayHeader *header = (WpArrayHeader *)buffer; + WpArray output = (u8 *)(header + 1); + header->magic = WP_ARRAY_MAGIC; + header->count = flags & WP_ARRAY_INIT_FILLED ? item_capacity : 0; + header->capacity = item_capacity; + header->item_size = item_size; + + return output; +} + +wp_persist inline void _array_validate(const WpArray array, u64 item_size) { + WpArrayHeader *header = _array_header(array); + wpRuntimeAssert(WP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array"); + wpRuntimeAssert(item_size == header->item_size, "Invalid item type provided"); +} diff --git a/src/wapp/base/array/array.h b/src/wapp/base/array/array.h new file mode 100644 index 0000000..746a95d --- /dev/null +++ b/src/wapp/base/array/array.h @@ -0,0 +1,216 @@ +// 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))) + + +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); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !ARRAY_H diff --git a/src/wapp/base/dbl_list/dbl_list.c b/src/wapp/base/dbl_list/dbl_list.c new file mode 100644 index 0000000..43f0e80 --- /dev/null +++ b/src/wapp/base/dbl_list/dbl_list.c @@ -0,0 +1,259 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "./dbl_list.h" +#include "../mem/allocator/mem_allocator.h" +#include "../../common/assert/assert.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" +#include + +wp_intern WpDblList _node_to_list(WpDblNode *node, u64 item_size); +wp_intern inline void _dblListValidate(const WpDblList *list, u64 item_size); +wp_intern inline void _dblListNodeValidate(const WpDblList *list, const WpDblNode *node, u64 item_size); + +WpDblList *_dblListAlloc(const WpAllocator *allocator, u64 item_size) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + + WpDblList *list = wpMemAllocatorAlloc(allocator, sizeof(WpDblList)); + if (!list) { goto DBL_LIST_ALLOC_RETURN; } + + memset((void *)list, 0, sizeof(WpDblList)); + list->magic = WP_DBL_LIST_MAGIC; + list->item_size = item_size; + +DBL_LIST_ALLOC_RETURN: + return list; +} + +WpDblNode *_dblListNodeAlloc(const WpAllocator *allocator, void *item, u64 item_size) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + + WpDblNode *node = wpMemAllocatorAlloc(allocator, sizeof(WpDblNode)); + if (!node) { goto DBL_LIST_NODE_ALLOC_RETURN; } + + memset((void *)node, 0, sizeof(WpDblNode)); + node->item = item; + node->header.magic = WP_DBL_NODE_MAGIC; + node->header.item_size = item_size; + +DBL_LIST_NODE_ALLOC_RETURN: + return node; +} + +WpDblNode *_dblListGet(const WpDblList *list, u64 index, u64 item_size) { + wpDebugAssert(list != NULL, "`list` should not be NULL"); + _dblListValidate(list, item_size); + wpRuntimeAssert(index < list->node_count, "`index` is out of bounds"); + + WpDblNode *output = NULL; + WpDblNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->header.next; + } + + output = current; + + return output; +} + +void _dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size) { + wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + _dblListValidate(list, item_size); + _dblListNodeValidate(list, node, item_size); + + WpDblList node_list = _node_to_list(node, item_size); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + WpDblNode *first = list->first; + if (first) { + first->header.prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->header.next = first; +} + +void _dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size) { + wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + _dblListValidate(list, item_size); + _dblListNodeValidate(list, node, item_size); + + WpDblList node_list = _node_to_list(node, item_size); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + WpDblNode *last = list->last; + if (last) { + last->header.next = node_list.first; + } + + list->last = node_list.last; + node_list.first->header.prev = last; +} + +void _dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size) { + wpDebugAssert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + _dblListValidate(list, item_size); + _dblListNodeValidate(list, node, item_size); + + if (index == 0) { + _dblListPushFront(list, node, item_size); + return; + } else if (index == list->node_count) { + _dblListPushBack(list, node, item_size); + return; + } + + WpDblNode *dst_node = _dblListGet(list, index, item_size); + if (!dst_node) { + return; + } + + WpDblList node_list = _node_to_list(node, item_size); + + list->node_count += node_list.node_count; + + WpDblNode *prev = dst_node->header.prev; + + dst_node->header.prev = node_list.last; + prev->header.next = node_list.first; + + node_list.first->header.prev = prev; + node_list.last->header.next = dst_node; +} + +WpDblNode *_dblListPopFront(WpDblList *list, u64 item_size) { + wpDebugAssert(list != NULL, "`list` should not be NULL"); + _dblListValidate(list, item_size); + + WpDblNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (WpDblList){.magic = WP_DBL_LIST_MAGIC, .item_size = item_size}; + goto RETURN_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->header.next; + + output->header.prev = output->header.next = NULL; + +RETURN_LIST_POP_FRONT: + return output; +} + +WpDblNode *_dblListPopBack(WpDblList *list, u64 item_size) { + wpDebugAssert(list != NULL, "`list` should not be NULL"); + _dblListValidate(list, item_size); + + WpDblNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (WpDblList){.magic = WP_DBL_LIST_MAGIC, .item_size = item_size}; + goto RETURN_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->header.prev; + + output->header.prev = output->header.next = NULL; + +RETURN_LIST_POP_BACK: + return output; +} + +WpDblNode *_dblListRemove(WpDblList *list, u64 index, u64 item_size) { + wpDebugAssert(list != NULL, "`list` should not be NULL"); + _dblListValidate(list, item_size); + + WpDblNode *output = NULL; + + if (index == 0) { + output = _dblListPopFront(list, item_size); + goto RETURN_LIST_REMOVE; + } else if (index == list->node_count) { + output = _dblListPopBack(list, item_size); + goto RETURN_LIST_REMOVE; + } + + output = _dblListGet(list, index, item_size); + if (!output) { + goto RETURN_LIST_REMOVE; + } + + output->header.prev->header.next = output->header.next; + output->header.next->header.prev = output->header.prev; + + --(list->node_count); + + output->header.prev = output->header.next = NULL; + +RETURN_LIST_REMOVE: + return output; +} + +void _dblListEmpty(WpDblList *list, u64 item_size) { + wpDebugAssert(list != NULL, "`list` should not be NULL"); + _dblListValidate(list, item_size); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + _dblListPopBack(list, item_size); + } +} + +wp_intern WpDblList _node_to_list(WpDblNode *node, u64 item_size) { + WpDblList output = { + .magic = WP_DBL_LIST_MAGIC, + .first = node, + .last = node, + .node_count = 1, + .item_size = item_size, + }; + + while (output.first->header.prev != NULL) { + output.first = output.first->header.prev; + ++(output.node_count); + } + + while (output.last->header.next != NULL) { + output.last = output.last->header.next; + ++(output.node_count); + } + + return output; +} + +wp_intern inline void _dblListValidate(const WpDblList *list, u64 item_size) { + wpRuntimeAssert(list->magic == WP_DBL_LIST_MAGIC, "`list` isn't a valid wp list type"); + wpRuntimeAssert(list->item_size == item_size, "Invalid item provided"); +} + +wp_intern inline void _dblListNodeValidate(const WpDblList *list, const WpDblNode *node, u64 item_size) { + wpRuntimeAssert(node->header.magic == WP_DBL_NODE_MAGIC, "`node` isn't a valid wp node type"); + wpRuntimeAssert(list->item_size == node->header.item_size, "Mismatched `list` and `node` types"); + wpRuntimeAssert(node->header.item_size == item_size, "Invalid item provided"); +} diff --git a/src/wapp/base/dbl_list/dbl_list.h b/src/wapp/base/dbl_list/dbl_list.h new file mode 100644 index 0000000..708785e --- /dev/null +++ b/src/wapp/base/dbl_list/dbl_list.h @@ -0,0 +1,184 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef DBL_LIST_H +#define DBL_LIST_H + +#include "../mem/allocator/mem_allocator.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define WP_DBL_LIST_MAGIC (u64)0x57415f444c5354 +#define WP_DBL_NODE_MAGIC (u64)0x57415f444e44 + +typedef struct WpDblNode WpDblNode; + +typedef struct { + u64 magic; + u64 item_size; + WpDblNode *prev; + WpDblNode *next; +} WpDblNodeHeader; + +struct WpDblNode { + WpDblNodeHeader header; + void *item; +}; + +typedef struct { + u64 magic; + u64 node_count; + u64 item_size; + WpDblNode *first; + WpDblNode *last; +} WpDblList; + +// NOTE (Abdelrahman): WpDblList typedefs for readability +typedef WpDblList WpVoidPtrList; +typedef WpDblList WpC8List; +typedef WpDblList WpC16List; +typedef WpDblList WpC32List; +typedef WpDblList WpU8List; +typedef WpDblList WpU16List; +typedef WpDblList WpU32List; +typedef WpDblList WpU64List; +typedef WpDblList WpB8List; +typedef WpDblList WpI8List; +typedef WpDblList WpI16List; +typedef WpDblList WpI32List; +typedef WpDblList WpI64List; +typedef WpDblList WpF32List; +typedef WpDblList WpF64List; +typedef WpDblList WpF128List; +typedef WpDblList WpUptrList; +typedef WpDblList WpIptrList; +typedef WpDblList WpStr8List; + +// NOTE (Abdelrahman): WpDblNode typedefs for readability +typedef WpDblNode WpVoidPtrNode; +typedef WpDblNode WpC8Node; +typedef WpDblNode WpC16Node; +typedef WpDblNode WpC32Node; +typedef WpDblNode WpU8Node; +typedef WpDblNode WpU16Node; +typedef WpDblNode WpU32Node; +typedef WpDblNode WpU64Node; +typedef WpDblNode WpB8Node; +typedef WpDblNode WpI8Node; +typedef WpDblNode WpI16Node; +typedef WpDblNode WpI32Node; +typedef WpDblNode WpI64Node; +typedef WpDblNode WpF32Node; +typedef WpDblNode WpF64Node; +typedef WpDblNode WpF128Node; +typedef WpDblNode WpUptrNode; +typedef WpDblNode WpIptrNode; +typedef WpDblNode WpStr8Node; + +#ifdef WP_PLATFORM_CPP +#define wpDblList(TYPE) \ + WpDblList{WP_DBL_LIST_MAGIC, 0, sizeof(TYPE), nullptr, nullptr} +#define _dblListNode(TYPE, ITEM_PTR) ([&]() { \ + wp_persist WpDblNode node = { \ + WpDblNodeHeader{WP_DBL_NODE_MAGIC, sizeof(TYPE), nullptr, nullptr}, \ + ITEM_PTR, \ + }; \ + \ + return &node; \ +}()) +#else +#define wpDblList(TYPE) ( \ + (WpDblList){.magic = WP_DBL_LIST_MAGIC, .item_size = sizeof(TYPE)} \ +) +#define _dblListNode(TYPE, ITEM_PTR) ( \ + &((WpDblNode){.header = {.magic = WP_DBL_NODE_MAGIC, .item_size = sizeof(TYPE)}, \ + .item = ITEM_PTR}) \ +) +#endif // !WP_PLATFORM_CPP + +#define wpDblListAlloc(TYPE, ALLOCATOR) \ + (_dblListAlloc(ALLOCATOR, sizeof(TYPE))) +#define wpDblListGet(TYPE, LIST_PTR, ITEM_INDEX) \ + ((TYPE *)(_dblListGet(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item)) +#define wpDblListGetNode(TYPE, LIST_PTR, ITEM_INDEX) \ + (_dblListGet(LIST_PTR, ITEM_INDEX, sizeof(TYPE))) +#define wpDblListGetNodeItem(TYPE, NODE_PTR) \ + ((TYPE *)( \ + (NODE_PTR == NULL) ? \ + NULL : \ + (NODE_PTR)->item \ + )) +#define wpDblListPushFront(TYPE, LIST_PTR, ITEM_PTR) \ + (_dblListPushFront(LIST_PTR, _dblListNode(TYPE, ITEM_PTR), sizeof(TYPE))) +#define wpDblListPushBack(TYPE, LIST_PTR, ITEM_PTR) \ + (_dblListPushBack(LIST_PTR, _dblListNode(TYPE, ITEM_PTR), sizeof(TYPE))) +#define wpDblListInsert(TYPE, LIST_PTR, ITEM_PTR, ITEM_INDEX) \ + (_dblListInsert(LIST_PTR, _dblListNode(TYPE, ITEM_PTR), \ + ITEM_INDEX, sizeof(TYPE))) +#define wpDblListPushFrontAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \ + (_dblListPushFront(LIST_PTR, _dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \ + sizeof(TYPE))) +#define wpDblListPushBackAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \ + (_dblListPushBack(LIST_PTR, _dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \ + sizeof(TYPE))) +#define wpDblListInsertAlloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR, ITEM_INDEX) \ + (_dblListInsert(LIST_PTR, _dblListNodeAlloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \ + ITEM_INDEX, sizeof(TYPE))) +#define wpDblListPopFront(TYPE, LIST_PTR) \ + ((TYPE *)( \ + (LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \ + NULL : \ + _dblListPopFront(LIST_PTR, sizeof(TYPE))->item \ + )) +#define wpDblListPopBack(TYPE, LIST_PTR) \ + ((TYPE *)( \ + (LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \ + NULL : \ + _dblListPopBack(LIST_PTR, sizeof(TYPE))->item \ + )) +#define wpDblListRemove(TYPE, LIST_PTR, ITEM_INDEX) \ + ((TYPE *)( \ + (LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \ + NULL : \ + _dblListRemove(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item \ + )) +#define wpDblListPopFrontNode(TYPE, LIST_PTR) \ + ( \ + (LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \ + NULL : \ + _dblListPopFront(LIST_PTR, sizeof(TYPE)) \ + ) +#define wpDblListPopBackNode(TYPE, LIST_PTR) \ + ( \ + (LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \ + NULL : \ + _dblListPopBack(LIST_PTR, sizeof(TYPE)) \ + ) +#define wpDblListRemoveNode(TYPE, LIST_PTR, ITEM_INDEX) \ + ( \ + (LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \ + NULL : \ + _dblListRemove(LIST_PTR, ITEM_INDEX, sizeof(TYPE)) \ + ) +#define wpDblListEmpty(TYPE, LIST_PTR) \ + (_dblListEmpty(LIST_PTR, sizeof(TYPE))) + +WpDblList *_dblListAlloc(const WpAllocator *allocator, u64 item_size); +WpDblNode *_dblListNodeAlloc(const WpAllocator *allocator, void *item, u64 item_size); +WpDblNode *_dblListGet(const WpDblList *list, u64 index, u64 item_size); +void _dblListPushFront(WpDblList *list, WpDblNode *node, u64 item_size); +void _dblListPushBack(WpDblList *list, WpDblNode *node, u64 item_size); +void _dblListInsert(WpDblList *list, WpDblNode *node, u64 index, u64 item_size); +WpDblNode *_dblListPopFront(WpDblList *list, u64 item_size); +WpDblNode *_dblListPopBack(WpDblList *list, u64 item_size); +WpDblNode *_dblListRemove(WpDblList *list, u64 index, u64 item_size); +void _dblListEmpty(WpDblList *list, u64 item_size); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !DBL_LIST_H diff --git a/src/wapp/base/mem/allocator/mem_allocator.c b/src/wapp/base/mem/allocator/mem_allocator.c new file mode 100644 index 0000000..216d863 --- /dev/null +++ b/src/wapp/base/mem/allocator/mem_allocator.c @@ -0,0 +1,35 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_allocator.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include + +void *wpMemAllocatorAlloc(const WpAllocator *allocator, u64 size) { + wpDebugAssert(allocator != NULL && (allocator->alloc) != NULL, "`allocator` and `allocator->alloc` should not be NULL"); + return allocator->alloc(size, allocator->obj); +} + +void *wpMemAllocatorAllocAligned(const WpAllocator *allocator, u64 size, u64 alignment) { + wpDebugAssert(allocator != NULL && (allocator->alloc_aligned) != NULL, "`allocator` and `allocator->alloc_aligned` should not be NULL"); + return allocator->alloc_aligned(size, alignment, allocator->obj); +} + +void *wpMemAllocatorRealloc(const WpAllocator *allocator, void *ptr, u64 old_size, u64 new_size) { + wpDebugAssert(allocator != NULL && (allocator->realloc) != NULL, "`allocator` and `allocator->realloc` should not be NULL"); + return allocator->realloc(ptr, old_size, new_size, allocator->obj); +} + +void *wpMemAllocatorReallocAligned(const WpAllocator *allocator, void *ptr, u64 old_size, + u64 new_size, u64 alignment) { + wpDebugAssert(allocator != NULL && (allocator->realloc_aligned) != NULL, "`allocator` and `allocator->realloc_aligned` should not be NULL"); + return allocator->realloc_aligned(ptr, old_size, new_size, alignment, allocator->obj); +} + +void wpMemAllocatorFree(const WpAllocator *allocator, void **ptr, u64 size) { + if (!allocator || !(allocator->free)) { + return; + } + + allocator->free(ptr, size, allocator->obj); +} diff --git a/src/wapp/base/mem/allocator/mem_allocator.h b/src/wapp/base/mem/allocator/mem_allocator.h new file mode 100644 index 0000000..ac3940f --- /dev/null +++ b/src/wapp/base/mem/allocator/mem_allocator.h @@ -0,0 +1,50 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_ALLOCATOR_H +#define MEM_ALLOCATOR_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef void *(WpMemAllocFunc)(u64 size, void *alloc_obj); +typedef void *(WpMemAllocAlignedFunc)(u64 size, u64 alignment, void *alloc_obj); +typedef void *(WpMemReallocFunc)(void *ptr, u64 old_size, u64 new_size, void *alloc_obj); +typedef void *(WpMemReallocAlignedFunc)(void *ptr, u64 old_size, u64 new_size, u64 alignment, void *alloc_obj); +typedef void (WpMemFreeFunc)(void **ptr, u64 size, void *alloc_obj); + +typedef struct WpAllocator WpAllocator; +struct WpAllocator { + void *obj; + WpMemAllocFunc *alloc; + WpMemAllocAlignedFunc *alloc_aligned; + WpMemReallocFunc *realloc; + WpMemReallocAlignedFunc *realloc_aligned; + WpMemFreeFunc *free; +}; + +#ifdef WP_PLATFORM_CPP +#define wpMemAllocatorInvalid(ALLOCATOR) ([&]() { \ + WpAllocator alloc{}; \ + return memcmp(ALLOCATOR, &alloc, sizeof(WpAllocator)) == 0; \ +}()) +#else +#define wpMemAllocatorInvalid(ALLOCATOR) (memcmp(ALLOCATOR, &((WpAllocator){0}), sizeof(WpAllocator)) == 0) +#endif // !WP_PLATFORM_CPP + +void *wpMemAllocatorAlloc(const WpAllocator *allocator, u64 size); +void *wpMemAllocatorAllocAligned(const WpAllocator *allocator, u64 size, u64 alignment); +void *wpMemAllocatorRealloc(const WpAllocator *allocator, void *ptr, u64 old_size, u64 new_size); +void *wpMemAllocatorReallocAligned(const WpAllocator *allocator, void *ptr, u64 old_size, + u64 new_size, u64 alignment); +void wpMemAllocatorFree(const WpAllocator *allocator, void **ptr, u64 size); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_ALLOCATOR_H diff --git a/src/wapp/base/mem/utils/mem_utils.c b/src/wapp/base/mem/utils/mem_utils.c new file mode 100644 index 0000000..87bbcb4 --- /dev/null +++ b/src/wapp/base/mem/utils/mem_utils.c @@ -0,0 +1,25 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_utils.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include "../../../common/misc/misc_utils.h" +#include + +void *wpMemUtilAlignForward(void *ptr, u64 alignment) { + wpDebugAssert(ptr != NULL, "`ptr` should not be NULL"); + wpRuntimeAssert(wpMiscUtilsIsPowerOfTwo(alignment), "`alignment` value is not a power of two"); + + uptr p = (uptr)ptr; + uptr align = (uptr)alignment; + + // Similar to p % align, but it's a faster implementation that works fine + // because align is guaranteed to be a power of 2 + uptr modulo = p & (align - 1); + + if (modulo != 0) { + p += align - modulo; + } + + return (void *)p; +} diff --git a/src/wapp/base/mem/utils/mem_utils.h b/src/wapp/base/mem/utils/mem_utils.h new file mode 100644 index 0000000..9b6d4b5 --- /dev/null +++ b/src/wapp/base/mem/utils/mem_utils.h @@ -0,0 +1,19 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_UTILS_H +#define MEM_UTILS_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +void *wpMemUtilAlignForward(void *ptr, u64 alignment); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_UTILS_H diff --git a/src/wapp/base/queue/queue.c b/src/wapp/base/queue/queue.c new file mode 100644 index 0000000..a82eb32 --- /dev/null +++ b/src/wapp/base/queue/queue.c @@ -0,0 +1,108 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "queue.h" +#include "../array/array.h" +#include "../../common/assert/assert.h" +#include "../../common/misc/misc_utils.h" +#include + +void _queuePush(WpQueue *queue, void *item, u64 item_size) { + wpDebugAssert(queue != NULL, "`queue` should not be NULL"); + wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type"); + + u64 capacity = wpArrayCapacity(queue->items); + if (queue->count >= capacity) { return; } + + u64 index = (queue->back)++; + _arraySet(queue->items, index, item, item_size); + ++(queue->count); + + if (queue->back >= capacity) { + queue->back = 0; + } +} + +WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size) { + wpDebugAssert(allocator != NULL && queue != NULL && item != NULL, + "`allocator`, `queue` and `item` should not be NULL"); + wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type"); + + WpQueue *output = queue; + + u64 capacity = wpArrayCapacity(queue->items); + + // NOTE (Abdelrahman): Extracted into variable to fix MSVC error + b8 queue_full = queue->count >= capacity; + if (queue_full) { + u64 new_capacity = wpMiscUtilsU64RoundUpPow2(capacity * 2); + u64 array_size = _arrayCalcAllocSize(new_capacity, item_size); + u64 alloc_size = sizeof(WpQueue) + array_size; + void *buffer = wpMemAllocatorAlloc(allocator, alloc_size); + if (!buffer) { + goto RETURN_QUEUE_PUSH_ALLOC; + } + + memset((void *)buffer, 0, alloc_size); + + output = (WpQueue *)buffer; + output->items = _arrayFromPreallocatedBuffer((void *)(output + 1), array_size, WP_ARRAY_INIT_FILLED, item_size); + + // NOTE (Abdelrahman): When the queue is full, the front and back indices should + // always be the same + u64 front_count = capacity - queue->front; + u64 back_count = queue->back; + void *copy_boundary = (void *)((uptr)(queue->items) + (queue->front * item_size)); + + memcpy(output->items, copy_boundary, front_count * item_size); + + /** + * NOTE (Abdelrahman): Since this is a ring buffer, the elements at the beginning of the array + * aren't always the ones at the front of the queue. When that's the case, the memcpy above + * will only copy a subset of the elements. This is why we need to copy the remaining ones. + * + * Example: Take a queue that looks like this with a capacity of 5 elements + * + * 0 1 | 2 3 4 + * ---------------|----------------------- + * | * | * | * | * | * | + * ---------------|----------------------- + * | + * queue_front = 2 + * queue_back = 2 + * + * In this case, the first memcpy will only copy elements 2-4. The memcpy below will be + * responsible for copying elements 0-1. + */ + b8 items_left_to_copy = back_count > 0; + if (items_left_to_copy) { + void *back_copy_dst = (void *)((uptr)(output->items) + (front_count * item_size)); + memcpy(back_copy_dst, queue->items, back_count * item_size); + } + + output->front = 0; + output->back = front_count + back_count; + output->count = queue->count; + } + + _queuePush(output, item, item_size); + +RETURN_QUEUE_PUSH_ALLOC: + return output; +} + +void *_queuePop(WpQueue *queue, u64 item_size) { + wpDebugAssert(queue != NULL, "`queue` should not be NULL"); + wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type"); + + if (queue->count == 0) { return NULL; } + + u64 index = (queue->front)++; + --(queue->count); + + u64 capacity = wpArrayCapacity(queue->items); + if (queue->front >= capacity) { + queue->front = 0; + } + + return _arrayGet(queue->items, index, item_size); +} diff --git a/src/wapp/base/queue/queue.h b/src/wapp/base/queue/queue.h new file mode 100644 index 0000000..f04cf29 --- /dev/null +++ b/src/wapp/base/queue/queue.h @@ -0,0 +1,100 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef QUEUE_H +#define QUEUE_H + +#include "../array/array.h" +#include "../mem/allocator/mem_allocator.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef struct { + WpArray items; + u64 front; + u64 back; + u64 count; +} WpQueue; + +// NOTE (Abdelrahman): WpQueue typedefs for readability +typedef WpQueue WpVoidPtrQueue; +typedef WpQueue WpC8Queue; +typedef WpQueue WpC16Queue; +typedef WpQueue WpC32Queue; +typedef WpQueue WpU8Queue; +typedef WpQueue WpU16Queue; +typedef WpQueue WpU32Queue; +typedef WpQueue WpU64Queue; +typedef WpQueue WpB8Queue; +typedef WpQueue WpI8Queue; +typedef WpQueue WpI16Queue; +typedef WpQueue WpI32Queue; +typedef WpQueue WpI64Queue; +typedef WpQueue WpF32Queue; +typedef WpQueue WpF64Queue; +typedef WpQueue WpF128Queue; +typedef WpQueue WpUptrQueue; +typedef WpQueue WpIptrQueue; +typedef WpQueue WpStr8Queue; + +#ifdef WP_PLATFORM_CPP +#define wpQueue(TYPE, CAPACITY) ([&]() { \ + wp_persist WpArray arr = wpArrayWithCapacity(TYPE, CAPACITY, WP_ARRAY_INIT_FILLED); \ + wp_persist WpQueue queue = { \ + arr, \ + 0, \ + 0, \ + 0, \ + }; \ + \ + return queue; \ +}()) +#define wpQueueAlloc(TYPE, ALLOCATOR_PTR, CAPACITY) ([&]() { \ + wp_persist WpQueue queue = { \ + wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, WP_ARRAY_INIT_FILLED), \ + 0, \ + 0, \ + 0, \ + }; \ + \ + return queue; \ +}()) +#else +#define wpQueue(TYPE, CAPACITY) ((WpQueue){ \ + .items = wpArrayWithCapacity(TYPE, CAPACITY, WP_ARRAY_INIT_FILLED), \ + .front = 0, \ + .back = 0, \ + .count = 0, \ +}) +#define wpQueueAlloc(TYPE, ALLOCATOR_PTR, CAPACITY) ((WpQueue){ \ + .items = wpArrayAllocCapacity(TYPE, ALLOCATOR_PTR, CAPACITY, WP_ARRAY_INIT_FILLED), \ + .front = 0, \ + .back = 0, \ + .count = 0, \ +}) +#endif // !WP_PLATFORM_CPP + +#define wpQueueCapacity(QUEUE_PTR) (wpArrayCapacity((QUEUE_PTR)->items)) +#define wpQueueItemSize(QUEUE_PTR) (wpArrayItemSize((QUEUE_PTR)->items)) +#define wpQueuePush(TYPE, QUEUE_PTR, VALUE_PTR) ( \ + _queuePush(QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \ +) +#define wpQueuePushAlloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR) ( \ + _queuePushAlloc(ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \ +) +#define wpQueuePop(TYPE, QUEUE_PTR) ( \ + (TYPE *)_queuePop(QUEUE_PTR, sizeof(TYPE)) \ +) + +void _queuePush(WpQueue *queue, void *item, u64 item_size); +WpQueue *_queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size); +void *_queuePop(WpQueue *queue, u64 item_size); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !QUEUE_H diff --git a/src/wapp/base/strings/str8/str8.c b/src/wapp/base/strings/str8/str8.c new file mode 100644 index 0000000..a1e36da --- /dev/null +++ b/src/wapp/base/strings/str8/str8.c @@ -0,0 +1,480 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "str8.h" +#include "../../array/array.h" +#include "../../mem/allocator/mem_allocator.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include +#include +#include +#include +#include + +#define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(WpStr8) + sizeof(c8) * CAPACITY) + +WpStr8 *wpStr8AllocBuf(const WpAllocator *allocator, u64 capacity) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + + WpStr8 *str = wpMemAllocatorAlloc(allocator, STR8_BUF_ALLOC_SIZE(capacity)); + if (!str) { + goto RETURN_STR8; + } + + str->buf = (u8 *)str + sizeof(WpStr8); + str->size = 0; + str->capacity = capacity; + +RETURN_STR8: + return str; +} + +WpStr8 *wpStr8AllocAndFillBuf(const WpAllocator *allocator, u64 capacity) { + WpStr8 *out = wpStr8AllocBuf(allocator, capacity); + if (out) { + memset(out->buf, 0, capacity); + out->size = capacity; + } + return out; +} + +WpStr8 *wpStr8AllocCstr(const WpAllocator *allocator, const char *str) { + wpDebugAssert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); + + u64 length = strlen(str); + WpStr8 *output = wpStr8AllocBuf(allocator, length * 2); + if (!output) { + goto RETURN_ALLOC_CSTR; + } + + output->size = length; + memcpy(output->buf, str, length); + +RETURN_ALLOC_CSTR: + return output; +} + +WpStr8 *wpStr8AllocStr8(const WpAllocator *allocator, WpStr8RO *str) { + wpDebugAssert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); + + WpStr8 *output = wpStr8AllocBuf(allocator, str->capacity); + if (!output) { + goto RETURN_ALLOC_STR8; + } + + output->size = str->size; + memcpy(output->buf, str->buf, str->size); + +RETURN_ALLOC_STR8: + return output; +} + +WpStr8 *wpStr8AllocSubstr(const WpAllocator *allocator, WpStr8RO *str, u64 start, u64 end) { + wpDebugAssert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); + + WpStr8 *output = NULL; + + if (start >= str->size || start >= end) { + goto RETURN_ALLOC_SUBSTR; + } + + if (end > str->size) { + end = str->size; + } + + output = wpStr8AllocBuf(allocator, str->capacity); + if (!output) { + goto RETURN_ALLOC_SUBSTR; + } + + output->size = end - start; + memcpy(output->buf, str->buf + start, output->size); + +RETURN_ALLOC_SUBSTR: + return output; +} + +void wpStr8DeallocBuf(const WpAllocator *allocator, WpStr8 **str) { + wpDebugAssert(allocator != NULL && str != NULL && (*str) != NULL, "Either `allocator` is NULL or `str` is an invalid double pointer"); + wpMemAllocatorFree(allocator, (void **)str, STR8_BUF_ALLOC_SIZE((*str)->capacity)); +} + +c8 wpStr8Get(const WpStr8 *str, u64 index) { + if (index >= str->size) { + return '\0'; + } + + return str->buf[index]; +} + +void wpStr8Set(WpStr8 *str, u64 index, c8 c) { + if (index >= str->size) { + return; + } + + str->buf[index] = c; +} + +void wpStr8PushBack(WpStr8 *str, c8 c) { + if (!(str->size < str->capacity)) { + return; + } + + u64 index = (str->size)++; + wpStr8Set(str, index, c); +} + +b8 wpStr8Equal(WpStr8RO *s1, WpStr8RO *s2) { + if (s1->size != s2->size) { + return false; + } + + return wpStr8EqualToCount(s1, s2, s1->size); +} + +b8 wpStr8EqualToCount(WpStr8RO* s1, WpStr8RO* s2, u64 count) { + if (!s1 || !s2) { + return false; + } + + return memcmp(s1->buf, s2->buf, count) == 0; +} + +WpStr8 wpStr8Slice(WpStr8RO *str, u64 start, u64 end) { + if (start >= str->size || start >= end) { + start = str->size; + end = str->size; + } + + if (end > str->size) { + end = str->size; + } + + return (WpStr8RO){ + .capacity = end - start, + .size = end - start, + .buf = str->buf + start, + }; +} + +WpStr8 *wpStr8AllocConcat(const WpAllocator *allocator, WpStr8 *dst, WpStr8RO *src) { + wpDebugAssert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL"); + + WpStr8 *output = NULL; + u64 remaining = dst->capacity - dst->size; + if (src->size <= remaining) { + output = dst; + goto SOURCE_STRING_STR8_CONCAT; + } + + u64 capacity = dst->capacity + src->size; + + output = wpStr8AllocBuf(allocator, capacity); + if (!output) { + goto RETURN_STR8_CONCAT; + } + + wpStr8ConcatCapped(output, dst); + +SOURCE_STRING_STR8_CONCAT: + wpStr8ConcatCapped(output, src); + +RETURN_STR8_CONCAT: + return output; +} + +void wpStr8ConcatCapped(WpStr8 *dst, WpStr8RO *src) { + wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); + + u64 remaining = dst->capacity - dst->size; + u64 to_copy = remaining < src->size ? remaining : src->size; + + memcpy(dst->buf + dst->size, src->buf, to_copy); + dst->size += to_copy; +} + +void wpStr8CopyCstrCapped(WpStr8 *dst, const char *src) { + wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); + + u64 length = strlen(src); + u64 to_copy = length <= dst->capacity ? length : dst->capacity; + + memset(dst->buf, 0, dst->size); + memcpy(dst->buf, src, to_copy); + dst->size = to_copy; +} + +void wpStr8CopyStr8Capped(WpStr8 *dst, WpStr8RO *src) { + wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); + + u64 to_copy = src->size <= dst->capacity ? src->size : dst->capacity; + + memset(dst->buf, 0, dst->size); + memcpy(dst->buf, src->buf, to_copy); + dst->size = to_copy; +} + +void wpStr8CopyToCstr(char *dst, WpStr8RO *src, u64 dst_capacity) { + wpDebugAssert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); + + u64 to_copy = src->size < dst_capacity ? src->size : dst_capacity - 1; + + memset(dst, 0, dst_capacity); + memcpy(dst, src->buf, to_copy); +} + +void wpStr8Format(WpStr8 *dst, const char *format, ...) { + wpDebugAssert(dst != NULL && format != NULL, "`dst` and `format` should not be NULL"); + + va_list args1; + va_list args2; + + va_start(args1, format); + va_copy(args2, args1); + + u64 total_size = vsnprintf(NULL, 0, format, args1); + dst->size = total_size <= dst->capacity ? total_size : dst->capacity; + + vsnprintf((char *)(dst->buf), dst->capacity, format, args2); + + va_end(args1); + va_end(args2); +} + +void wpStr8ToLower(WpStr8 *dst, WpStr8RO *src) { + wpDebugAssert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL"); + wpDebugAssert(dst->capacity >= src->capacity, "`dst` does not have enough capacity"); + + dst->size = src->size; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 index = 0; + b8 running = true; + while (running) { + wpStr8Set(dst, index, (u8)tolower(wpStr8Get(src, index))); + ++index; + running = index < src->size; + } +} + +void wpStr8ToUpper(WpStr8 *dst, WpStr8RO *src) { + wpDebugAssert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL"); + wpDebugAssert(dst->capacity >= src->capacity, "`dst` does not have enough capacity"); + + dst->size = src->size; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 index = 0; + b8 running = true; + while (running) { + wpStr8Set(dst, index, (u8)toupper(wpStr8Get(src, index))); + ++index; + running = index < src->size; + } +} + +void wpStr8FromBytes(WpStr8 *dst, const WpU8Array src) { + wpDebugAssert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL"); + + u64 size = wpArrayCount(src) * wpArrayItemSize(src); + + wpDebugAssert(dst->capacity >= size, "`dst` does not have enough capacity"); + + dst->size = size; + memcpy(dst->buf, src, size); +} + +i64 wpStr8Find(WpStr8RO *str, WpStr8RO substr) { + if (!str || substr.size > str->size) { + return -1; + } + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 char_index = 0; + b8 running = char_index < str->size; + while (running) { + const c8 *sub = str->buf + char_index; + if (memcmp(sub, substr.buf, substr.size) == 0) { + return char_index; + } + + ++char_index; + running = char_index < str->size; + } + + return -1; +} + +i64 wpStr8Rfind(WpStr8RO *str, WpStr8RO substr) { + if (!str || substr.size > str->size) { + return -1; + } + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + i64 char_index = str->size - substr.size; + b8 running = char_index >= 0; + while (running) { + const c8 *sub = str->buf + char_index; + if (memcmp(sub, substr.buf, substr.size) == 0) { + return char_index; + } + + --char_index; + running = char_index >= 0; + } + + return -1; +} + +WpStr8List *wpStr8SplitWithMax(const WpAllocator *allocator, WpStr8RO *str, WpStr8RO *delimiter, i64 max_splits) { + wpDebugAssert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL"); + + WpStr8List *output = wpDblListAlloc(WpStr8, allocator); + + if (delimiter->size > str->size) { + WpStr8 *full = wpStr8AllocStr8(allocator, str); + if (full) { + wpDblListPushBackAlloc(WpStr8, allocator, output, full); + } + + goto RETURN_STR8_SPLIT; + } + + i64 start = 0; + i64 end = 0; + i64 splits = 0; + WpStr8 *rest = wpStr8AllocStr8(allocator, str); + WpStr8 *before_str; + + while ((end = wpStr8Find(rest, *delimiter)) != -1) { + if (max_splits > 0 && splits >= max_splits) { + break; + } + + before_str = wpStr8AllocSubstr(allocator, str, start, start + end); + if (before_str) { + wpDblListPushBackAlloc(WpStr8, allocator, output, before_str); + } + + wpMemAllocatorFree(allocator, (void **)&rest, sizeof(WpStr8)); + rest = wpStr8AllocSubstr(allocator, str, start + end + delimiter->size, str->size); + start += end + delimiter->size; + + ++splits; + } + + // Ensure the last part of the string after the delimiter is added to the list + rest = wpStr8AllocSubstr(allocator, str, start, str->size); + if (rest) { + wpDblListPushBackAlloc(WpStr8, allocator, output, rest); + } + +RETURN_STR8_SPLIT: + return output; +} + +WpStr8List *wpStr8RsplitWithMax(const WpAllocator *allocator, WpStr8RO *str, WpStr8RO *delimiter, i64 max_splits) { + wpDebugAssert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL"); + + WpStr8List *output = wpDblListAlloc(WpStr8, allocator); + + if (delimiter->size > str->size) { + WpStr8 *full = wpStr8AllocStr8(allocator, str); + if (full) { + wpDblListPushBackAlloc(WpStr8, allocator, output, full); + } + + goto RETURN_STR8_SPLIT; + } + + i64 end = 0; + i64 splits = 0; + WpStr8 *rest = wpStr8AllocStr8(allocator, str); + WpStr8 *after_str; + + while ((end = wpStr8Rfind(rest, *delimiter)) != -1) { + if (max_splits > 0 && splits >= max_splits) { + break; + } + + after_str = wpStr8AllocSubstr(allocator, rest, end + delimiter->size, str->size); + if (after_str) { + wpDblListPushFrontAlloc(WpStr8, allocator, output, after_str); + } + + wpMemAllocatorFree(allocator, (void **)&rest, sizeof(WpStr8)); + rest = wpStr8AllocSubstr(allocator, rest, 0, end); + + ++splits; + } + + rest = wpStr8AllocSubstr(allocator, str, 0, rest->size); + if (rest) { + wpDblListPushFrontAlloc(WpStr8, allocator, output, rest); + } + +RETURN_STR8_SPLIT: + return output; +} + +WpStr8 *wpStr8Join(const WpAllocator *allocator, const WpStr8List *list, WpStr8RO *delimiter) { + wpDebugAssert(allocator != NULL && list != NULL && delimiter != NULL, "`allocator`, `list` and `delimiter` should not be NULL"); + + u64 capacity = wpStr8ListTotalSize(list) + (delimiter->size * (list->node_count - 1)); + WpStr8 *output = wpStr8AllocBuf(allocator, capacity * 2); + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + WpStr8 *node; + u64 node_index = 0; + b8 running = node_index < list->node_count; + while (running) { + node = wpDblListGet(WpStr8, list, node_index); + if (!node) { + break; + } + + wpStr8ConcatCapped(output, node); + + // NOTE (Abdelrahman): Comparison extracted to variable to silence + // MSVC Spectre mitigation warnings + b8 not_last = node_index + 1 < list->node_count; + if (not_last) { + wpStr8ConcatCapped(output, delimiter); + } + + ++node_index; + running = node_index < list->node_count; + } + + return output; +} + +u64 wpStr8ListTotalSize(const WpStr8List *list) { + if (!list) { + return 0; + } + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + WpStr8 *node; + u64 node_index = 0; + u64 output = 0; + b8 running = node_index < list->node_count; + while (running) { + node = wpDblListGet(WpStr8, list, node_index); + if (!node) { + break; + } + + output += node->size; + ++node_index; + running = node_index < list->node_count; + } + + return output; +} diff --git a/src/wapp/base/strings/str8/str8.h b/src/wapp/base/strings/str8/str8.h new file mode 100644 index 0000000..e3c1ef0 --- /dev/null +++ b/src/wapp/base/strings/str8/str8.h @@ -0,0 +1,130 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef STR8_H +#define STR8_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include "../../../common/platform/platform.h" +#include "../../array/array.h" +#include "../../dbl_list/dbl_list.h" +#include "../../mem/allocator/mem_allocator.h" +#include + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef struct WpStr8 WpStr8; +struct WpStr8 { + u64 capacity; + u64 size; + c8 *buf; +}; + +typedef const WpStr8 WpStr8RO; + +/** + * Utilities to be used with printf functions + */ +#define WP_STR8_SPEC "%.*s" +#define wpStr8Varg(STRING) (int)((STRING).size), (STRING).buf + +/** + * WpStr8 stack buffers + */ + +#ifdef WP_PLATFORM_CPP +// Uses a lambda to achieve the same behaviour achieved by the C macro +#define wpStr8Buf(CAPACITY) ([&](){ \ + wp_persist c8 buf[CAPACITY] = {}; \ + memset(buf, 0, CAPACITY); \ + return WpStr8{CAPACITY, 0, buf}; \ +}()) + +// Uses a lambda to achieve the same behaviour achieved by the C macro +#define wpStr8Lit(STRING) ([&]() { \ + wp_persist c8 buf[sizeof(STRING) * 2] = {}; \ + memcpy(buf, STRING, sizeof(STRING)); \ + return WpStr8{(sizeof(STRING) - 1) * 2, sizeof(STRING) - 1, buf}; \ +}()) + +#define wpStr8LitRo(STRING) WpStr8RO{sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING} +#define wpStr8LitRoInitialiserList(STRING) {sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING} +#else +#define wpStr8Buf(CAPACITY) ((WpStr8){.capacity = CAPACITY, .size = 0, .buf = (c8[CAPACITY]){0}}) + +// Utilises the fact that memcpy returns pointer to dest buffer and that getting +// address of compound literals is valid in C to create a string on the stack +#define wpStr8Lit(STRING) ((WpStr8){.capacity = (sizeof(STRING) - 1) * 2, \ + .size = sizeof(STRING) - 1, \ + .buf = memcpy(&((c8 [sizeof(STRING) * 2]){0}), \ + STRING, \ + sizeof(STRING))}) +#define wpStr8LitRo(STRING) ((WpStr8RO){.capacity = sizeof(STRING) - 1, \ + .size = sizeof(STRING) - 1, \ + .buf = (c8 *)STRING}) +// To be used only when initialising a static storage variable in compilers that don't support +// initialisers with the syntax of wpStr8LitRo (e.g. gcc). Should only be used when necessary +// and only be assigned to a WpStr8RO variable to avoid any attempt at modifying the string +#define wpStr8LitRoInitialiserList(STRING) {.capacity = sizeof(STRING) - 1, \ + .size = sizeof(STRING) - 1, \ + .buf = (c8 *)STRING} +#endif // !WP_PLATFORM_CPP + +/** + * WpStr8 allocated buffers + */ +WpStr8 *wpStr8AllocBuf(const WpAllocator *allocator, u64 capacity); +WpStr8 *wpStr8AllocAndFillBuf(const WpAllocator *allocator, u64 capacity); +WpStr8 *wpStr8AllocCstr(const WpAllocator *allocator, const char *str); +WpStr8 *wpStr8AllocStr8(const WpAllocator *allocator, WpStr8RO *str); +WpStr8 *wpStr8AllocSubstr(const WpAllocator *allocator, WpStr8RO *str, u64 start, u64 end); +WpStr8 *wpStr8AllocConcat(const WpAllocator *allocator, WpStr8 *dst, WpStr8RO *src); +// 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. +void wpStr8DeallocBuf(const WpAllocator *allocator, WpStr8 **str); + +/** + * WpStr8 utilities + */ +c8 wpStr8Get(WpStr8RO *str, u64 index); +void wpStr8Set(WpStr8 *str, u64 index, c8 c); +void wpStr8PushBack(WpStr8 *str, c8 c); +b8 wpStr8Equal(WpStr8RO *s1, WpStr8RO *s2); +b8 wpStr8EqualToCount(WpStr8RO* s1, WpStr8RO* s2, u64 count); +WpStr8 wpStr8Slice(WpStr8RO *str, u64 start, u64 end); +void wpStr8ConcatCapped(WpStr8 *dst, WpStr8RO *src); +void wpStr8CopyCstrCapped(WpStr8 *dst, const char *src); +void wpStr8CopyStr8Capped(WpStr8 *dst, WpStr8RO *src); +void wpStr8CopyToCstr(char *dst, WpStr8RO *src, u64 dst_capacity); +void wpStr8Format(WpStr8 *dst, const char *format, ...); +void wpStr8ToLower(WpStr8 *dst, WpStr8RO *src); +void wpStr8ToUpper(WpStr8 *dst, WpStr8RO *src); +void wpStr8FromBytes(WpStr8 *dst, const WpU8Array src); + +/** + * WpStr8 find functions + */ +i64 wpStr8Find(WpStr8RO *str, WpStr8RO substr); +i64 wpStr8Rfind(WpStr8RO *str, WpStr8RO substr); + +/** + * WpStr8 split and join + */ +#define wpStr8Split(ALLOCATOR, STR, DELIMITER) wpStr8SplitWithMax(ALLOCATOR, STR, DELIMITER, -1) +#define wpStr8Rsplit(ALLOCATOR, STR, DELIMITER) wpStr8RsplitWithMax(ALLOCATOR, STR, DELIMITER, -1) +WpStr8List *wpStr8SplitWithMax(const WpAllocator *allocator, WpStr8RO *str, WpStr8RO *delimiter, i64 max_splits); +WpStr8List *wpStr8RsplitWithMax(const WpAllocator *allocator, WpStr8RO *str, WpStr8RO *delimiter, i64 max_splits); +WpStr8 *wpStr8Join(const WpAllocator *allocator, const WpStr8List *list, WpStr8RO *delimiter); + +/** + * WpStr8 list utilities + */ +u64 wpStr8ListTotalSize(const WpStr8List *list); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !STR8_H diff --git a/src/wapp/base/wapp_base.c b/src/wapp/base/wapp_base.c new file mode 100644 index 0000000..8f22291 --- /dev/null +++ b/src/wapp/base/wapp_base.c @@ -0,0 +1,14 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_BASE_C +#define WAPP_BASE_C + +#include "wapp_base.h" +#include "array/array.c" +#include "dbl_list/dbl_list.c" +#include "queue/queue.c" +#include "mem/allocator/mem_allocator.c" +#include "mem/utils/mem_utils.c" +#include "strings/str8/str8.c" + +#endif // !WAPP_BASE_C diff --git a/src/wapp/base/wapp_base.h b/src/wapp/base/wapp_base.h new file mode 100644 index 0000000..4c48c1d --- /dev/null +++ b/src/wapp/base/wapp_base.h @@ -0,0 +1,14 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_BASE_H +#define WAPP_BASE_H + +#include "array/array.h" +#include "dbl_list/dbl_list.h" +#include "queue/queue.h" +#include "mem/allocator/mem_allocator.h" +#include "mem/utils/mem_utils.h" +#include "strings/str8/str8.h" +#include "../common/wapp_common.h" + +#endif // !WAPP_BASE_H diff --git a/src/wapp/common/aliases/aliases.h b/src/wapp/common/aliases/aliases.h new file mode 100644 index 0000000..01d52c0 --- /dev/null +++ b/src/wapp/common/aliases/aliases.h @@ -0,0 +1,67 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef ALIASES_H +#define ALIASES_H + +#include "../platform/platform.h" +#include + +#if defined(WP_PLATFORM_C) && WP_PLATFORM_C_VERSION >= WP_PLATFORM_C11_VERSION && !defined(WP_PLATFORM_APPLE) + #include + + #if WP_PLATFORM_C_VERSION >= WP_PLATFORM_C23_VERSION + typedef char8_t c8; + #else + typedef uint8_t c8; + #endif // !WP_PLATFORM_C23_VERSION + + typedef char16_t c16; + typedef char32_t c32; +#else + typedef uint8_t c8; + typedef uint16_t c16; + typedef uint32_t c32; +#endif // !WP_PLATFORM_C + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef uint8_t b8; + +#ifndef WP_PLATFORM_CPP + +#ifndef false +#define false (b8)0 +#endif // !false + +#ifndef true +#define true (b8)1 +#endif // !true + +#endif // !WP_PLATFORM_CPP + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +typedef float f32; +typedef double f64; +typedef long double f128; + +typedef uintptr_t uptr; +typedef intptr_t iptr; + +#define wp_extern extern +#define wp_intern static +#define wp_persist static + +#ifdef WP_PLATFORM_CPP +#define wp_class_mem static +#define BEGIN_C_LINKAGE wp_extern "C" { +#define END_C_LINKAGE } +#endif // WP_PLATFORM_CPP + +#endif // !ALIASES_H diff --git a/src/wapp/common/assert/assert.h b/src/wapp/common/assert/assert.h new file mode 100644 index 0000000..ab062b6 --- /dev/null +++ b/src/wapp/common/assert/assert.h @@ -0,0 +1,61 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_ASSERT_H +#define WAPP_ASSERT_H + +#include "../aliases/aliases.h" +#include "../platform/platform.h" +#include +#include +#include + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define wpStaticAssert(EXPR, MSG) wp_extern char ASSERTION_FAILED[EXPR ? 1 : -1] + +#ifndef WP_NO_RUNTIME_ASSERT + #define wpRuntimeAssert(EXPR, MSG) _runtimeAssert(EXPR, MSG) +#else + #define wpRuntimeAssert(EXPR, MSG) +#endif + +#ifdef WP_DEBUG_ASSERT + #define wpDebugAssert(EXPR, MSG) wpRuntimeAssert(EXPR, MSG) +#else + #define wpDebugAssert(EXPR, MSG) +#endif + +#ifdef WP_PLATFORM_WINDOWS +#define _runtimeAssert(EXPR, MSG) do { \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + if (!(EXPR)) { \ + __pragma(warning(pop)) \ + _runtimeAssertFailed(EXPR, MSG); \ + } \ +} while(false) +#else +#define _runtimeAssert(EXPR, MSG) do { \ + if (!(EXPR)) { \ + _runtimeAssertFailed(EXPR, MSG); \ + } \ +} while(false) +#endif // !WP_PLATFORM_WINDOWS + +#define _runtimeAssertFailed(EXPR, MSG) do { \ + fprintf( \ + stderr, \ + "%s:%d (In function `%s`): Assertion failed (%" PRIu32 ")\nDiagnostic: %s\n\n", \ + __FILE__, __LINE__, __func__, \ + EXPR, MSG \ + ); \ + abort(); \ +} while(false) + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !WAPP_ASSERT_H diff --git a/src/wapp/common/misc/misc_utils.h b/src/wapp/common/misc/misc_utils.h new file mode 100644 index 0000000..1b9f34f --- /dev/null +++ b/src/wapp/common/misc/misc_utils.h @@ -0,0 +1,63 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MISC_UTILS_H +#define MISC_UTILS_H + +#include "../aliases/aliases.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define KiB(SIZE) (((u64)SIZE) << 10) +#define MiB(SIZE) (((u64)SIZE) << 20) +#define GiB(SIZE) (((u64)SIZE) << 30) +#define TiB(SIZE) (((u64)SIZE) << 40) +#define PiB(SIZE) (((u64)SIZE) << 50) +#define EiB(SIZE) (((u64)SIZE) << 60) + +#define KB(SIZE) (((u64)SIZE) * 1000llu) +#define MB(SIZE) (KB(SIZE) * 1000llu) +#define GB(SIZE) (MB(SIZE) * 1000llu) +#define TB(SIZE) (GB(SIZE) * 1000llu) +#define PB(SIZE) (TB(SIZE) * 1000llu) +#define EB(SIZE) (PB(SIZE) * 1000llu) + +#define wpMiscUtilsReservePadding(SIZE) u8 reserved_padding[sizeof(void *) - ((SIZE) % sizeof(void *))] + +#define U64_RSHIFT_OR_1(X) (((u64)X) | (((u64)X) >> 1)) +#define U64_RSHIFT_OR_2(X) (((u64)X) | (((u64)X) >> 2)) +#define U64_RSHIFT_OR_4(X) (((u64)X) | (((u64)X) >> 4)) +#define U64_RSHIFT_OR_8(X) (((u64)X) | (((u64)X) >> 8)) +#define U64_RSHIFT_OR_16(X) (((u64)X) | (((u64)X) >> 16)) +#define U64_RSHIFT_OR_32(X) (((u64)X) | (((u64)X) >> 32)) +#define wpMiscUtilsU64RoundUpPow2(X) ( \ + ( \ + U64_RSHIFT_OR_32( \ + U64_RSHIFT_OR_16( \ + U64_RSHIFT_OR_8( \ + U64_RSHIFT_OR_4( \ + U64_RSHIFT_OR_2( \ + U64_RSHIFT_OR_1(X - 1) \ + ) \ + ) \ + ) \ + ) \ + ) \ + ) + 1 \ +) + +#define wpMiscUtilsIsPowerOfTwo(NUM) ((NUM & (NUM - 1)) == 0) +#define wpMiscUtilsOffsetPointer(PTR, OFFSET) ((void *)((uptr)(PTR) + (OFFSET))) + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE + +#include + +#define wpMiscUtilsVaArgsCount(T, ...) (std::tuple_size::value) +#else +#define wpMiscUtilsVaArgsCount(T, ...) (sizeof((T[]){__VA_ARGS__})/sizeof(T)) +#endif // !WP_PLATFORM_CPP + +#endif // !MISC_UTILS_H diff --git a/src/wapp/common/platform/platform.h b/src/wapp/common/platform/platform.h new file mode 100644 index 0000000..a73fd8f --- /dev/null +++ b/src/wapp/common/platform/platform.h @@ -0,0 +1,114 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef PLATFORM_H +#define PLATFORM_H + +#if defined(__ANDROID__) + #define WP_PLATFORM_ANDROID + #define WP_PLATFORM_POSIX +#elif defined(__FreeBSD__) + #define WP_PLATFORM_FREE_BSD + #define WP_PLATFORM_BSD + #define WP_PLATFORM_POSIX +#elif defined(__NetBSD__) + #define WP_PLATFORM_NET_BSD + #define WP_PLATFORM_BSD + #define WP_PLATFORM_POSIX +#elif defined(__OpenBSD__) + #define WP_PLATFORM_OPEN_BSD + #define WP_PLATFORM_BSD + #define WP_PLATFORM_POSIX +#elif defined(__DragonFly__) + #define WP_PLATFORM_DRAGON_FLY + #define WP_PLATFORM_BSD + #define WP_PLATFORM_POSIX +#elif defined(__bsdi__) + #define WP_PLATFORM_BSD + #define WP_PLATFORM_POSIX +#elif defined(__linux__) || defined(linux) || defined(__linux) || defined(__gnu_linux__) + #define WP_PLATFORM_LINUX + #define WP_PLATFORM_POSIX +#elif defined(__GNU__) || defined(__gnu_hurd__) + #define WP_PLATFORM_GNU + #define WP_PLATFORM_POSIX +#elif defined(__APPLE__) || defined(__MACH__) + #include + #if TARGET_OS_IPHONE + #define WP_PLATFORM_IOS + #define WP_PLATFORM_APPLE + #define WP_PLATFORM_POSIX + #elif TARGET_OS_MAC + #define WP_PLATFORM_MACOS + #define WP_PLATFORM_APPLE + #define WP_PLATFORM_POSIX + #else + #error "Unrecognised Apple platform" + #endif +#elif defined(_WIN64) + #define WP_PLATFORM_WINDOWS64 + #define WP_PLATFORM_WINDOWS +#elif defined(_WIN32) + #define WP_PLATFORM_WINDOWS32 + #define WP_PLATFORM_WINDOWS +#elif defined(__CYGWIN__) + #define WP_PLATFORM_CYGWIN + #define WP_PLATFORM_WINDOWS +#elif defined(__unix__) || defined(__unix) + #define WP_PLATFORM_UNIX + #define WP_PLATFORM_POSIX +#else + #error "Unrecognised platform" +#endif + +#ifdef __cplusplus + #define WP_PLATFORM_CPP + #define WP_PLATFORM_CPP_VERSION __cplusplus + #define WP_PLATFORM_CPP98_VERSION 199711L + #define WP_PLATFORM_CPP11_VERSION 201103L + #define WP_PLATFORM_CPP14_VERSION 201402L + #define WP_PLATFORM_CPP17_VERSION 201703L + #define WP_PLATFORM_CPP20_VERSION 202002L + #define WP_PLATFORM_CPP23_VERSION 202302L + + #if WP_PLATFORM_CPP_VERSION == WP_PLATFORM_CPP98_VERSION + #define WP_PLATFORM_CPP98 + #elif WP_PLATFORM_CPP_VERSION == WP_PLATFORM_CPP11_VERSION + #define WP_PLATFORM_CPP11 + #elif WP_PLATFORM_CPP_VERSION == WP_PLATFORM_CPP14_VERSION + #define WP_PLATFORM_CPP14 + #elif WP_PLATFORM_CPP_VERSION == WP_PLATFORM_CPP17_VERSION + #define WP_PLATFORM_CPP17 + #elif WP_PLATFORM_CPP_VERSION == WP_PLATFORM_CPP20_VERSION + #define WP_PLATFORM_CPP20 + #elif WP_PLATFORM_CPP_VERSION == WP_PLATFORM_CPP23_VERSION + #define WP_PLATFORM_CPP23 + #else + #error "Unrecognised C++ version" + #endif +#else + #define WP_PLATFORM_C + + #if defined(__STDC_VERSION__) + #define WP_PLATFORM_C_VERSION __STDC_VERSION__ + #define WP_PLATFORM_C99_VERSION 199901L + #define WP_PLATFORM_C11_VERSION 201112L + #define WP_PLATFORM_C17_VERSION 201710L + #define WP_PLATFORM_C23_VERSION 202311L + + #if WP_PLATFORM_C_VERSION == WP_PLATFORM_C99_VERSION + #define WP_PLATFORM_C99 + #elif WP_PLATFORM_C_VERSION == WP_PLATFORM_C11_VERSION + #define WP_PLATFORM_C11 + #elif WP_PLATFORM_C_VERSION == WP_PLATFORM_C17_VERSION + #define WP_PLATFORM_C17 + #elif WP_PLATFORM_C_VERSION == WP_PLATFORM_C23_VERSION + #define WP_PLATFORM_C23 + #else + #error "Unrecognised C version" + #endif + #else + #define WP_PLATFORM_C89 + #endif +#endif // !__cplusplus + +#endif // !PLATFORM_H diff --git a/src/wapp/common/wapp_common.h b/src/wapp/common/wapp_common.h new file mode 100644 index 0000000..a126b0a --- /dev/null +++ b/src/wapp/common/wapp_common.h @@ -0,0 +1,11 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_COMMON_H +#define WAPP_COMMON_H + +#include "aliases/aliases.h" +#include "assert/assert.h" +#include "misc/misc_utils.h" +#include "platform/platform.h" + +#endif // !WAPP_COMMON_H diff --git a/src/wapp/log/log.c b/src/wapp/log/log.c new file mode 100644 index 0000000..4026c60 --- /dev/null +++ b/src/wapp/log/log.c @@ -0,0 +1,137 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "log.h" +#include "../base/strings/str8/str8.h" +#include "../common/aliases/aliases.h" +#include "../common/assert/assert.h" +#include "../common/misc/misc_utils.h" +#include "../os/file/file.h" +#include + +#define MIN_LOG_MSG_LENGTH 32 +#define TIME_BUF_CAPACITY 70 + +wp_intern WpStr8RO L_BRACKET = wpStr8LitRo("["); +wp_intern WpStr8RO R_BRACKET_SPACE = wpStr8LitRo("] "); +wp_intern WpStr8RO R_BRACKET_NEWLINE = wpStr8LitRo("]\n"); + +typedef struct { + WpFile *outlog; + WpFile *errlog; + WpLogLevel level; + + wpMiscUtilsReservePadding(2 * sizeof(WpFile *) + sizeof(WpLogLevel)); +} LogConfig; + +wp_intern LogConfig LOG_CONFIG = { + .level = WP_LOG_LEVEL_DEBUG, +}; +wp_intern WpStr8RO LOG_LEVEL_STRINGS[COUNT_LOG_LEVEL] = { + [WP_LOG_LEVEL_FATAL] = wpStr8LitRoInitialiserList("fatal "), + [WP_LOG_LEVEL_CRITICAL] = wpStr8LitRoInitialiserList("critical "), + [WP_LOG_LEVEL_ERROR] = wpStr8LitRoInitialiserList("error "), + [WP_LOG_LEVEL_WARNING] = wpStr8LitRoInitialiserList("warning "), + [WP_LOG_LEVEL_INFO] = wpStr8LitRoInitialiserList("info "), + [WP_LOG_LEVEL_DEBUG] = wpStr8LitRoInitialiserList("debug "), +}; + +wp_intern void _get_current_time_string(WpStr8 *dst); +wp_intern void _write_log_line(WpFile *fp, const WpLogger *logger, WpStr8 msg, WpLogLevel level); + +void wpLogSetLevel(WpLogLevel level) { + LOG_CONFIG.level = level; +} + +void wpLogConfigure(WpFile *outlog, WpFile *errlog, WpLogLevel level) { + LOG_CONFIG.outlog = outlog; + LOG_CONFIG.errlog = errlog; + LOG_CONFIG.level = level; +} + +WpLogger wpLogMakeLogger(WpStr8 name) { + return (WpLogger){ .name = name }; +} + +void wpLogDebug(const WpLogger *logger, WpStr8 msg) { + wpDebugAssert(logger != NULL, "`logger` should not be NULL"); + if (LOG_CONFIG.level < WP_LOG_LEVEL_DEBUG) { return; } + + WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout(); + _write_log_line(fp, logger, msg, WP_LOG_LEVEL_DEBUG); +} + +void wpLogInfo(const WpLogger *logger, WpStr8 msg) { + wpDebugAssert(logger != NULL, "`logger` should not be NULL"); + if (LOG_CONFIG.level < WP_LOG_LEVEL_INFO) { return; } + + WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout(); + _write_log_line(fp, logger, msg, WP_LOG_LEVEL_INFO); +} + +void wpLogWarning(const WpLogger *logger, WpStr8 msg) { + wpDebugAssert(logger != NULL, "`logger` should not be NULL"); + if (LOG_CONFIG.level < WP_LOG_LEVEL_WARNING) { return; } + + WpFile *fp = LOG_CONFIG.outlog != NULL ? LOG_CONFIG.outlog : wpFileStdout(); + _write_log_line(fp, logger, msg, WP_LOG_LEVEL_WARNING); +} + +void wpLogError(const WpLogger *logger, WpStr8 msg) { + wpDebugAssert(logger != NULL, "`logger` should not be NULL"); + if (LOG_CONFIG.level < WP_LOG_LEVEL_ERROR) { return; } + + WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr(); + _write_log_line(fp, logger, msg, WP_LOG_LEVEL_ERROR); +} + +void wpLogCritical(const WpLogger *logger, WpStr8 msg) { + wpDebugAssert(logger != NULL, "`logger` should not be NULL"); + if (LOG_CONFIG.level < WP_LOG_LEVEL_CRITICAL) { return; } + + WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr(); + _write_log_line(fp, logger, msg, WP_LOG_LEVEL_CRITICAL); +} + +void wpLogFatal(const WpLogger *logger, WpStr8 msg) { + wpDebugAssert(logger != NULL, "`logger` should not be NULL"); + if (LOG_CONFIG.level < WP_LOG_LEVEL_FATAL) { return; } + + WpFile *fp = LOG_CONFIG.errlog != NULL ? LOG_CONFIG.errlog : wpFileStderr(); + _write_log_line(fp, logger, msg, WP_LOG_LEVEL_FATAL); +} + +wp_intern void _get_current_time_string(WpStr8 *dst) { + // TODO (Abdelrahman): Replace with proper date/time utilities + char buf[TIME_BUF_CAPACITY]; + time_t now = time(NULL); + struct tm utc; + gmtime_r(&now, &utc); + strftime(buf, sizeof(buf), "%FT%TZ ", &utc); + wpStr8CopyCstrCapped(dst, buf); +} + +wp_intern void _write_log_line(WpFile *fp, const WpLogger *logger, WpStr8 msg, WpLogLevel level) { + WpStr8 padding = wpStr8Buf(MIN_LOG_MSG_LENGTH); + u32 padding_size = msg.size < MIN_LOG_MSG_LENGTH ? MIN_LOG_MSG_LENGTH - msg.size + 1 : 0; + wpStr8Format(&padding, "%-*s", padding_size, " "); + + WpStr8 time_str = wpStr8Buf(TIME_BUF_CAPACITY); + _get_current_time_string(&time_str); + + WpStr8RO **strings = wpArray( + WpStr8RO *, + &time_str, + &L_BRACKET, + &LOG_LEVEL_STRINGS[level], + &R_BRACKET_SPACE, + &msg, + &padding, + &L_BRACKET, + &logger->name, + &R_BRACKET_NEWLINE + ); + + for (u64 i = 0; i < wpArrayCount(strings); ++i) { + wpFileWriteStr8(strings[i], fp); + } +} diff --git a/src/wapp/log/log.h b/src/wapp/log/log.h new file mode 100644 index 0000000..3a4dbb0 --- /dev/null +++ b/src/wapp/log/log.h @@ -0,0 +1,34 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef LOG_H +#define LOG_H + +#include "../os/file/file.h" +#include "../base/strings/str8/str8.h" + +typedef enum { + WP_LOG_LEVEL_FATAL, + WP_LOG_LEVEL_CRITICAL, + WP_LOG_LEVEL_ERROR, + WP_LOG_LEVEL_WARNING, + WP_LOG_LEVEL_INFO, + WP_LOG_LEVEL_DEBUG, + + COUNT_LOG_LEVEL, +} WpLogLevel; + +typedef struct { + WpStr8 name; +} WpLogger; + +void wpLogSetLevel(WpLogLevel level); +void wpLogConfigure(WpFile *outlog, WpFile *errlog, WpLogLevel level); +WpLogger wpLogMakeLogger(WpStr8 name); +void wpLogDebug(const WpLogger *logger, WpStr8 msg); +void wpLogInfo(const WpLogger *logger, WpStr8 msg); +void wpLogWarning(const WpLogger *logger, WpStr8 msg); +void wpLogError(const WpLogger *logger, WpStr8 msg); +void wpLogCritical(const WpLogger *logger, WpStr8 msg); +void wpLogFatal(const WpLogger *logger, WpStr8 msg); + +#endif // !LOG_H diff --git a/src/wapp/log/wapp_log.c b/src/wapp/log/wapp_log.c new file mode 100644 index 0000000..64376ed --- /dev/null +++ b/src/wapp/log/wapp_log.c @@ -0,0 +1,10 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_LOG_C +#define WAPP_LOG_C + +#include "log.c" +#include "../base/wapp_base.c" +#include "../os/wapp_os.c" + +#endif // !WAPP_LOG_C diff --git a/src/wapp/log/wapp_log.h b/src/wapp/log/wapp_log.h new file mode 100644 index 0000000..a8dcdcd --- /dev/null +++ b/src/wapp/log/wapp_log.h @@ -0,0 +1,11 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_LOG_H +#define WAPP_LOG_H + +#include "log.h" +#include "../common/wapp_common.h" +#include "../base/wapp_base.h" +#include "../os/wapp_os.h" + +#endif // !WAPP_LOG_H diff --git a/src/wapp/oldnames.h b/src/wapp/oldnames.h new file mode 100644 index 0000000..1cb59bf --- /dev/null +++ b/src/wapp/oldnames.h @@ -0,0 +1,597 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// +// oldnames.h — backward-compatible #define mappings for renames in the +// wizapp-stdlib naming-conventions branch. +// +// Every public API symbol that was renamed is mapped from its old name to +// its new name so that existing code continues to compile without changes. +// +// Rename patterns applied across all modules: +// wapp_xxx() → wpXxx() +// WAPP_XXX → WP_XXX +// GenericXxx → WpXxx +// SHELL_XXX → WP_SHELL_XXX +// _xxx_yyy() → _xxxYyy() +// +// Sections: Constants → Types → Functions + +#ifndef OLDNAMES_H +#define OLDNAMES_H + +// ============================================================================ +// ===== Constants ===== +// ============================================================================ + +// --- Aliases --- + +#define WAPP_PLATFORM_CPP WP_PLATFORM_CPP +#define WAPP_PLATFORM_C WP_PLATFORM_C + +// --- Arena --- + +#define WAPP_MEM_ALLOC_RESERVE WP_MEM_ALLOC_RESERVE +#define WAPP_MEM_ALLOC_COMMIT WP_MEM_ALLOC_COMMIT + +// --- Array --- + +#define WAPP_ARRAY_MAGIC WP_ARRAY_MAGIC +#define ARRAY_INIT_NONE WP_ARRAY_INIT_NONE +#define ARRAY_INIT_FILLED WP_ARRAY_INIT_FILLED + +// --- Assert --- + +#define WAPP_NO_RUNTIME_ASSERT WP_NO_RUNTIME_ASSERT +#define WAPP_DEBUG_ASSERT WP_DEBUG_ASSERT + +// --- CPath --- + +#define WAPP_PATH_SEP WP_PATH_SEP +#define WAPP_PATH_MAX WP_PATH_MAX + +#define CPATH_JOIN_SUCCESS WP_CPATH_JOIN_RESULT_SUCCESS +#define CPATH_JOIN_INVALID_ARGS WP_CPATH_JOIN_RESULT_INVALID_ARGS +#define CPATH_JOIN_EMPTY_PARTS WP_CPATH_JOIN_RESULT_EMPTY_PARTS +#define CPATH_JOIN_INSUFFICIENT_DST_CAPACITY WP_CPATH_JOIN_RESULT_INSUFFICIENT_DST_CAPACITY + +// --- DblList --- + +#define WAPP_DBL_LIST_MAGIC WP_DBL_LIST_MAGIC +#define WAPP_DBL_NODE_MAGIC WP_DBL_NODE_MAGIC + +// --- File --- + +#define WAPP_ACCESS_READ WP_ACCESS_READ +#define WAPP_ACCESS_WRITE WP_ACCESS_WRITE +#define WAPP_ACCESS_APPEND WP_ACCESS_APPEND +#define WAPP_ACCESS_READ_EX WP_ACCESS_READ_EX +#define WAPP_ACCESS_WRITE_EX WP_ACCESS_WRITE_EX +#define WAPP_ACCESS_APPEND_EX WP_ACCESS_APPEND_EX +#define WAPP_ACCESS_WRITE_FAIL_ON_EXIST WP_ACCESS_WRITE_FAIL_ON_EXIST +#define WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX WP_ACCESS_WRITE_FAIL_ON_EXIST_EX +#define WAPP_SEEK_START WP_SEEK_START +#define WAPP_SEEK_CURRENT WP_SEEK_CURRENT +#define WAPP_SEEK_END WP_SEEK_END +#define END_OF_LINE WP_END_OF_LINE + +// --- Log --- + +#define WAPP_LOG_FATAL WP_LOG_LEVEL_FATAL +#define WAPP_LOG_CRITICAL WP_LOG_LEVEL_CRITICAL +#define WAPP_LOG_ERROR WP_LOG_LEVEL_ERROR +#define WAPP_LOG_WARNING WP_LOG_LEVEL_WARNING +#define WAPP_LOG_INFO WP_LOG_LEVEL_INFO +#define WAPP_LOG_DEBUG WP_LOG_LEVEL_DEBUG + +// --- Mem Os --- + +#define WAPP_MEM_ACCESS_NONE WP_MEM_ACCESS_NONE +#define WAPP_MEM_ACCESS_READ_ONLY WP_MEM_ACCESS_READ_ONLY +#define WAPP_MEM_ACCESS_EXEC_ONLY WP_MEM_ACCESS_EXEC_ONLY +#define WAPP_MEM_ACCESS_READ_WRITE WP_MEM_ACCESS_READ_WRITE +#define WAPP_MEM_ACCESS_READ_EXEC WP_MEM_ACCESS_READ_EXEC +#define WAPP_MEM_ACCESS_READ_WRITE_EXEC WP_MEM_ACCESS_READ_WRITE_EXEC +#define WAPP_MEM_INIT_UNINITIALISED WP_MEM_INIT_UNINITIALISED +#define WAPP_MEM_INIT_INITIALISED WP_MEM_INIT_INITIALISED + +// --- Platform --- + +#define WAPP_PLATFORM_ANDROID WP_PLATFORM_ANDROID +#define WAPP_PLATFORM_FREE_BSD WP_PLATFORM_FREE_BSD +#define WAPP_PLATFORM_NET_BSD WP_PLATFORM_NET_BSD +#define WAPP_PLATFORM_OPEN_BSD WP_PLATFORM_OPEN_BSD +#define WAPP_PLATFORM_DRAGON_FLY WP_PLATFORM_DRAGON_FLY +#define WAPP_PLATFORM_BSD WP_PLATFORM_BSD +#define WAPP_PLATFORM_POSIX WP_PLATFORM_POSIX +#define WAPP_PLATFORM_LINUX WP_PLATFORM_LINUX +#define WAPP_PLATFORM_GNU WP_PLATFORM_GNU +#define WAPP_PLATFORM_IOS WP_PLATFORM_IOS +#define WAPP_PLATFORM_APPLE WP_PLATFORM_APPLE +#define WAPP_PLATFORM_MACOS WP_PLATFORM_MACOS +#define WAPP_PLATFORM_WINDOWS64 WP_PLATFORM_WINDOWS64 +#define WAPP_PLATFORM_WINDOWS32 WP_PLATFORM_WINDOWS32 +#define WAPP_PLATFORM_WINDOWS WP_PLATFORM_WINDOWS +#define WAPP_PLATFORM_CYGWIN WP_PLATFORM_CYGWIN +#define WAPP_PLATFORM_UNIX WP_PLATFORM_UNIX +#define WAPP_PLATFORM_CPP_VERSION WP_PLATFORM_CPP_VERSION +#define WAPP_PLATFORM_CPP98_VERSION WP_PLATFORM_CPP98_VERSION +#define WAPP_PLATFORM_CPP11_VERSION WP_PLATFORM_CPP11_VERSION +#define WAPP_PLATFORM_CPP14_VERSION WP_PLATFORM_CPP14_VERSION +#define WAPP_PLATFORM_CPP17_VERSION WP_PLATFORM_CPP17_VERSION +#define WAPP_PLATFORM_CPP20_VERSION WP_PLATFORM_CPP20_VERSION +#define WAPP_PLATFORM_CPP23_VERSION WP_PLATFORM_CPP23_VERSION +#define WAPP_PLATFORM_CPP98 WP_PLATFORM_CPP98 +#define WAPP_PLATFORM_CPP11 WP_PLATFORM_CPP11 +#define WAPP_PLATFORM_CPP14 WP_PLATFORM_CPP14 +#define WAPP_PLATFORM_CPP17 WP_PLATFORM_CPP17 +#define WAPP_PLATFORM_CPP20 WP_PLATFORM_CPP20 +#define WAPP_PLATFORM_CPP23 WP_PLATFORM_CPP23 +#define WAPP_PLATFORM_C_VERSION WP_PLATFORM_C_VERSION +#define WAPP_PLATFORM_C99_VERSION WP_PLATFORM_C99_VERSION +#define WAPP_PLATFORM_C11_VERSION WP_PLATFORM_C11_VERSION +#define WAPP_PLATFORM_C17_VERSION WP_PLATFORM_C17_VERSION +#define WAPP_PLATFORM_C23_VERSION WP_PLATFORM_C23_VERSION +#define WAPP_PLATFORM_C99 WP_PLATFORM_C99 +#define WAPP_PLATFORM_C11 WP_PLATFORM_C11 +#define WAPP_PLATFORM_C17 WP_PLATFORM_C17 +#define WAPP_PLATFORM_C23 WP_PLATFORM_C23 +#define WAPP_PLATFORM_C89 WP_PLATFORM_C89 + +// --- Shell Commander --- + +#define SHELL_OUTPUT_DISCARD WP_SHELL_OUTPUT_DISCARD +#define SHELL_OUTPUT_PRINT WP_SHELL_OUTPUT_PRINT +#define SHELL_OUTPUT_CAPTURE WP_SHELL_OUTPUT_CAPTURE +#define SHELL_ERR_NO_ERROR WP_SHELL_ERR_NO_ERROR +#define SHELL_ERR_INVALID_ARGS WP_SHELL_ERR_INVALID_ARGS +#define SHELL_ERR_ALLOCATION_FAIL WP_SHELL_ERR_ALLOCATION_FAIL +#define SHELL_ERR_PROC_START_FAIL WP_SHELL_ERR_PROC_START_FAIL +#define SHELL_ERR_OUT_BUF_FULL WP_SHELL_ERR_OUT_BUF_FULL +#define SHELL_ERR_PROC_EXIT_FAIL WP_SHELL_ERR_PROC_EXIT_FAIL + +// --- Shell Termcolour --- + +#define WAPP_TERM_COLOUR_FG_BLACK WP_TERM_COLOUR_FG_BLACK +#define WAPP_TERM_COLOUR_FG_RED WP_TERM_COLOUR_FG_RED +#define WAPP_TERM_COLOUR_FG_GREEN WP_TERM_COLOUR_FG_GREEN +#define WAPP_TERM_COLOUR_FG_BLUE WP_TERM_COLOUR_FG_BLUE +#define WAPP_TERM_COLOUR_FG_CYAN WP_TERM_COLOUR_FG_CYAN +#define WAPP_TERM_COLOUR_FG_MAGENTA WP_TERM_COLOUR_FG_MAGENTA +#define WAPP_TERM_COLOUR_FG_YELLOW WP_TERM_COLOUR_FG_YELLOW +#define WAPP_TERM_COLOUR_FG_WHITE WP_TERM_COLOUR_FG_WHITE +#define WAPP_TERM_COLOUR_FG_BR_BLACK WP_TERM_COLOUR_FG_BR_BLACK +#define WAPP_TERM_COLOUR_FG_BR_RED WP_TERM_COLOUR_FG_BR_RED +#define WAPP_TERM_COLOUR_FG_BR_GREEN WP_TERM_COLOUR_FG_BR_GREEN +#define WAPP_TERM_COLOUR_FG_BR_BLUE WP_TERM_COLOUR_FG_BR_BLUE +#define WAPP_TERM_COLOUR_FG_BR_CYAN WP_TERM_COLOUR_FG_BR_CYAN +#define WAPP_TERM_COLOUR_FG_BR_MAGENTA WP_TERM_COLOUR_FG_BR_MAGENTA +#define WAPP_TERM_COLOUR_FG_BR_YELLOW WP_TERM_COLOUR_FG_BR_YELLOW +#define WAPP_TERM_COLOUR_FG_BR_WHITE WP_TERM_COLOUR_FG_BR_WHITE +#define WAPP_TERM_COLOUR_CLEAR WP_TERM_COLOUR_CLEAR + +// --- Str8 --- + +#define WAPP_STR8_SPEC WP_STR8_SPEC + +// --- UUID --- + +#define UUID_BUF_LENGTH WP_UUID_BUF_LENGTH +#define WAPP_UUID_SPEC WP_UUID_SPEC + +// ============================================================================ +// ===== Types ===== +// ============================================================================ + +// --- Aliases --- + +#define wapp_extern wp_extern +#define wapp_intern wp_intern +#define wapp_persist wp_persist +#define wapp_class_mem wp_class_mem + +// --- Arena --- + +#define Arena WpArena + +// --- Array --- + +#define GenericArray WpArray +#define VoidPtrArray WpVoidPtrArray +#define C8Array WpC8Array +#define C16Array WpC16Array +#define C32Array WpC32Array +#define U8Array WpU8Array +#define U16Array WpU16Array +#define U32Array WpU32Array +#define U64Array WpU64Array +#define B8Array WpB8Array +#define I8Array WpI8Array +#define I16Array WpI16Array +#define I32Array WpI32Array +#define I64Array WpI64Array +#define F32Array WpF32Array +#define F64Array WpF64Array +#define F128Array WpF128Array +#define UptrArray WpUptrArray +#define IptrArray WpIptrArray +#define Str8Array WpStr8Array +#define ArrayHeader WpArrayHeader +#define ArrayInitFlags WpArrayInitFlags + +// --- DblList --- + +#define GenericNode WpDblNode +#define NodeHeader WpDblNodeHeader +#define GenericList WpDblList +#define VoidPtrList WpVoidPtrList +#define C8List WpC8List +#define C16List WpC16List +#define C32List WpC32List +#define U8List WpU8List +#define U16List WpU16List +#define U32List WpU32List +#define U64List WpU64List +#define B8List WpB8List +#define I8List WpI8List +#define I16List WpI16List +#define I32List WpI32List +#define I64List WpI64List +#define F32List WpF32List +#define F64List WpF64List +#define F128List WpF128List +#define UptrList WpUptrList +#define IptrList WpIptrList +#define Str8List WpStr8List +#define VoidPtrNode WpVoidPtrNode +#define C8Node WpC8Node +#define C16Node WpC16Node +#define C32Node WpC32Node +#define U8Node WpU8Node +#define U16Node WpU16Node +#define U32Node WpU32Node +#define U64Node WpU64Node +#define B8Node WpB8Node +#define I8Node WpI8Node +#define I16Node WpI16Node +#define I32Node WpI32Node +#define I64Node WpI64Node +#define F32Node WpF32Node +#define F64Node WpF64Node +#define F128Node WpF128Node +#define UptrNode WpUptrNode +#define IptrNode WpIptrNode +#define Str8Node WpStr8Node + +// --- File --- + +#define WFile WpFile +#define FileAccessMode WpFileAccessMode +#define FileSeekOrigin WpFileSeekOrigin + +// --- Log --- + +#define LogLevel WpLogLevel +#define Logger WpLogger + +// --- Mem Allocator --- + +#define Allocator WpAllocator +#define MemAllocFunc WpMemAllocFunc +#define MemAllocAlignedFunc WpMemAllocAlignedFunc +#define MemReallocFunc WpMemReallocFunc +#define MemReallocAlignedFunc WpMemReallocAlignedFunc +#define MemFreeFunc WpMemFreeFunc + +// --- Mem Os --- + +#define MemAccess WpMemAccess +#define MemInitType WpMemInitType +#define MemAllocFlags WpMemAllocFlags + +// --- PRNG Xorshift --- + +#define XOR256State WpXor256State + +// --- Queue --- + +#define GenericQueue WpQueue +#define VoidPtrQueue WpVoidPtrQueue +#define C8Queue WpC8Queue +#define C16Queue WpC16Queue +#define C32Queue WpC32Queue +#define U8Queue WpU8Queue +#define U16Queue WpU16Queue +#define U32Queue WpU32Queue +#define U64Queue WpU64Queue +#define B8Queue WpB8Queue +#define I8Queue WpI8Queue +#define I16Queue WpI16Queue +#define I32Queue WpI32Queue +#define I64Queue WpI64Queue +#define F32Queue WpF32Queue +#define F64Queue WpF64Queue +#define F128Queue WpF128Queue +#define UptrQueue WpUptrQueue +#define IptrQueue WpIptrQueue +#define Str8Queue WpStr8Queue + +// --- Shell Commander --- + +#define CMDResult WpCmdResult +#define CMDOutHandling WpCmdOutHandling +#define CMDError WpCmdError + +// --- Shell Termcolour --- + +#define TerminalColour WpTerminalColour + +// --- Str8 --- + +#define Str8 WpStr8 +#define Str8RO WpStr8RO + +// --- Tester --- + +#define TestFuncResult WpTestFuncResult +#define TestFunc WpTestFunc + +// --- UUID --- + +#define WUUID WpUuid + +// ============================================================================ +// ===== Functions ===== +// ============================================================================ + +// --- Arena --- + +#define wapp_mem_arena_init_allocated wpMemArenaInitAllocated +#define wapp_mem_arena_init_allocated_commit wpMemArenaInitAllocatedCommit +#define wapp_mem_arena_init_allocated_zero wpMemArenaInitAllocatedZero +#define wapp_mem_arena_init_allocated_commit_and_zero wpMemArenaInitAllocatedCommitAndZero +#define wapp_mem_arena_init_allocated_custom wpMemArenaInitAllocatedCustom +#define wapp_mem_arena_init_buffer wpMemArenaInitBuffer +#define wapp_mem_arena_alloc wpMemArenaAlloc +#define wapp_mem_arena_alloc_aligned wpMemArenaAllocAligned +#define wapp_mem_arena_realloc wpMemArenaRealloc +#define wapp_mem_arena_realloc_aligned wpMemArenaReallocAligned +#define wapp_mem_arena_temp_begin wpMemArenaTempBegin +#define wapp_mem_arena_temp_end wpMemArenaTempEnd +#define wapp_mem_arena_clear wpMemArenaClear +#define wapp_mem_arena_destroy wpMemArenaDestroy + +#define wapp_mem_arena_allocator_init wpMemArenaAllocatorInit +#define wapp_mem_arena_allocator_init_commit wpMemArenaAllocatorInitCommit +#define wapp_mem_arena_allocator_init_zero wpMemArenaAllocatorInitZero +#define wapp_mem_arena_allocator_init_commit_and_zero wpMemArenaAllocatorInitCommitAndZero +#define wapp_mem_arena_allocator_init_custom wpMemArenaAllocatorInitCustom +#define wapp_mem_arena_allocator_init_with_buffer wpMemArenaAllocatorInitWithBuffer +#define wapp_mem_arena_allocator_temp_begin wpMemArenaAllocatorTempBegin +#define wapp_mem_arena_allocator_temp_end wpMemArenaAllocatorTempEnd +#define wapp_mem_arena_allocator_clear wpMemArenaAllocatorClear +#define wapp_mem_arena_allocator_destroy wpMemArenaAllocatorDestroy + +// --- Array --- + +#define wapp_array wpArray +#define wapp_array_with_capacity wpArrayWithCapacity +#define wapp_array_pop wpArrayPop +#define wapp_array_count wpArrayCount +#define wapp_array_capacity wpArrayCapacity +#define wapp_array_item_size wpArrayItemSize +#define wapp_array_set_count wpArraySetCount +#define wapp_array_get wpArrayGet +#define wapp_array_set wpArraySet +#define wapp_array_append_capped wpArrayAppendCapped +#define wapp_array_extend_capped wpArrayExtendCapped +#define wapp_array_copy_capped wpArrayCopyCapped +#define wapp_array_append_alloc wpArrayAppendAlloc +#define wapp_array_extend_alloc wpArrayExtendAlloc +#define wapp_array_copy_alloc wpArrayCopyAlloc +#define wapp_array_clear wpArrayClear +#define wapp_array_calc_alloc_size wpArrayCalcAllocSize +#define wapp_array_alloc_capacity wpArrayAllocCapacity +#define wapp_array_from_preallcated_buffer wpArrayFromPreallcatedBuffer + +// --- Assert --- + +#define wapp_static_assert wpStaticAssert +#define wapp_runtime_assert wpRuntimeAssert +#define wapp_debug_assert wpDebugAssert + +// --- CPath --- + +#define wapp_cpath_dirname wpCpathDirname +#define wapp_cpath_dirup wpCpathDirup +#define wapp_cpath_join_path wpCpathJoinPath +#define dirup _dirup + +// --- DblList --- + +#define wapp_dbl_list wpDblList +#define wapp_dbl_list_alloc wpDblListAlloc +#define wapp_dbl_list_get wpDblListGet +#define wapp_dbl_list_get_node wpDblListGetNode +#define wapp_dbl_list_get_node_item wpDblListGetNodeItem +#define wapp_dbl_list_push_front wpDblListPushFront +#define wapp_dbl_list_push_back wpDblListPushBack +#define wapp_dbl_list_insert wpDblListInsert +#define wapp_dbl_list_push_front_alloc wpDblListPushFrontAlloc +#define wapp_dbl_list_push_back_alloc wpDblListPushBackAlloc +#define wapp_dbl_list_insert_alloc wpDblListInsertAlloc +#define wapp_dbl_list_pop_front wpDblListPopFront +#define wapp_dbl_list_pop_back wpDblListPopBack +#define wapp_dbl_list_remove wpDblListRemove +#define wapp_dbl_list_pop_front_node wpDblListPopFrontNode +#define wapp_dbl_list_pop_back_node wpDblListPopBackNode +#define wapp_dbl_list_remove_node wpDblListRemoveNode +#define wapp_dbl_list_empty wpDblListEmpty + +#define _dbl_list_alloc _dblListAlloc +#define _dbl_list_node_alloc _dblListNodeAlloc +#define _dbl_list_get _dblListGet +#define _dbl_list_push_front _dblListPushFront +#define _dbl_list_push_back _dblListPushBack +#define _dbl_list_insert _dblListInsert +#define _dbl_list_pop_front _dblListPopFront +#define _dbl_list_pop_back _dblListPopBack +#define _dbl_list_remove _dblListRemove +#define _dbl_list_empty _dblListEmpty + +// --- File --- + +#define wapp_file_stdin wpFileStdin +#define wapp_file_stdout wpFileStdout +#define wapp_file_stderr wpFileStderr +#define wapp_file_open wpFileOpen +#define wapp_file_get_current_position wpFileGetCurrentPosition +#define wapp_file_seek wpFileSeek +#define wapp_file_get_length wpFileGetLength +#define wapp_file_read wpFileRead +#define wapp_file_write wpFileWrite +#define wapp_file_read_str8 wpFileReadStr8 +#define wapp_file_write_str8 wpFileWriteStr8 +#define wapp_file_read_array wpFileReadArray +#define wapp_file_write_array wpFileWriteArray +#define wapp_file_flush wpFileFlush +#define wapp_file_close wpFileClose +#define wapp_file_rename wpFileRename +#define wapp_file_remove wpFileRemove + +#define _file_open _fileOpen +#define _file_seek _fileSeek +#define _file_read _fileRead +#define _file_write _fileWrite +#define _file_flush _fileFlush +#define _file_close _fileClose +#define _file_rename _fileRename +#define _file_remove _fileRemove + +// --- Log --- + +#define wapp_log_set_level wpLogSetLevel +#define wapp_log_configure wpLogConfigure +#define wapp_log_make_logger wpLogMakeLogger +#define wapp_log_debug wpLogDebug +#define wapp_log_info wpLogInfo +#define wapp_log_warning wpLogWarning +#define wapp_log_error wpLogError +#define wapp_log_critical wpLogCritical +#define wapp_log_fatal wpLogFatal + +// --- Mem Allocator --- + +#define wapp_mem_allocator_invalid wpMemAllocatorInvalid +#define wapp_mem_allocator_alloc wpMemAllocatorAlloc +#define wapp_mem_allocator_alloc_aligned wpMemAllocatorAllocAligned +#define wapp_mem_allocator_realloc wpMemAllocatorRealloc +#define wapp_mem_allocator_realloc_aligned wpMemAllocatorReallocAligned +#define wapp_mem_allocator_free wpMemAllocatorFree + +// --- Mem Os --- + +#define wapp_os_mem_alloc wpOsMemAlloc +#define wapp_os_mem_free wpOsMemFree +#define os_mem_allocate _osMemAllocate +#define os_mem_free _osMemFree + +// --- Mem Utils --- + +#define wapp_mem_util_align_forward wpMemUtilAlignForward + +// --- Misc Utils --- + +#define wapp_misc_utils_reserve_padding wpMiscUtilsReservePadding +#define wapp_misc_utils_u64_round_up_pow2 wpMiscUtilsU64RoundUpPow2 +#define wapp_is_power_of_two wpMiscUtilsIsPowerOfTwo +#define wapp_pointer_offset wpMiscUtilsOffsetPointer +#define wapp_misc_utils_va_args_count wpMiscUtilsVaArgsCount + +// --- PRNG Xorshift --- + +#define wapp_prng_xorshift_init_state wpPrngXorshiftInit +#define wapp_prng_xorshift_256 wpPrngXorshift256 +#define wapp_prng_xorshift_256ss wpPrngXorshift256ss +#define wapp_prng_xorshift_256p wpPrngXorshift256p + +// --- Queue --- + +#define wapp_queue wpQueue +#define wapp_queue_alloc wpQueueAlloc +#define wapp_queue_capacity wpQueueCapacity +#define wapp_queue_item_size wpQueueItemSize +#define wapp_queue_push wpQueuePush +#define wapp_queue_push_alloc wpQueuePushAlloc +#define wapp_queue_pop wpQueuePop + +#define _queue_push _queuePush +#define _queue_push_alloc _queuePushAlloc +#define _queue_pop _queuePop + +// --- Shell Commander --- + +#define CMD_NO_EXIT wpCmdNoExit +#define wapp_shell_commander_execute wpShellCommanderExecute +#define get_output_status _getOutputStatus + +// --- Shell Termcolour --- + +#define wapp_shell_termcolour_print_text wpShellTermcolourPrintText +#define wapp_shell_termcolour_clear_colour wpShellTermcolourClearColour +#define print_coloured_text _printColouredText + +// --- Shell Utils --- + +#define wapp_shell_utils_popen wpShellUtilsPopen +#define wapp_shell_utils_pclose wpShellUtilsPclose + +// --- Str8 --- + +#define wapp_str8_varg wpStr8Varg +#define wapp_str8_buf wpStr8Buf +#define wapp_str8_lit wpStr8Lit +#define wapp_str8_lit_ro wpStr8LitRo +#define wapp_str8_lit_ro_initialiser_list wpStr8LitRoInitialiserList +#define wapp_str8_alloc_buf wpStr8AllocBuf +#define wapp_str8_alloc_and_fill_buf wpStr8AllocAndFillBuf +#define wapp_str8_alloc_cstr wpStr8AllocCstr +#define wapp_str8_alloc_str8 wpStr8AllocStr8 +#define wapp_str8_alloc_substr wpStr8AllocSubstr +#define wapp_str8_alloc_concat wpStr8AllocConcat +#define wapp_str8_dealloc_buf wpStr8DeallocBuf +#define wapp_str8_get wpStr8Get +#define wapp_str8_set wpStr8Set +#define wapp_str8_push_back wpStr8PushBack +#define wapp_str8_equal wpStr8Equal +#define wapp_str8_equal_to_count wpStr8EqualToCount +#define wapp_str8_slice wpStr8Slice +#define wapp_str8_concat_capped wpStr8ConcatCapped +#define wapp_str8_copy_cstr_capped wpStr8CopyCstrCapped +#define wapp_str8_copy_str8_capped wpStr8CopyStr8Capped +#define wapp_str8_copy_to_cstr wpStr8CopyToCstr +#define wapp_str8_format wpStr8Format +#define wapp_str8_to_lower wpStr8ToLower +#define wapp_str8_to_upper wpStr8ToUpper +#define wapp_str8_from_bytes wpStr8FromBytes +#define wapp_str8_find wpStr8Find +#define wapp_str8_rfind wpStr8Rfind +#define wapp_str8_split wpStr8Split +#define wapp_str8_rsplit wpStr8Rsplit +#define wapp_str8_split_with_max wpStr8SplitWithMax +#define wapp_str8_rsplit_with_max wpStr8RsplitWithMax +#define wapp_str8_join wpStr8Join +#define wapp_str8_list_total_size wpStr8ListTotalSize + +// --- Tester --- + +#define wapp_tester_result wpTesterResult +#define wapp_tester_run wpTesterRun +#define run_tests _runTests + +// --- UUID --- + +#define wapp_uuid_varg wpUuidVarg +#define wapp_uuid_gen_uuid4 wpUuidGenUuid4 +#define wapp_uuid_create wpUuidCreate +#define wapp_uuid_init_uuid4 wpUuidInitUuid4 + +#endif // !OLDNAMES_H diff --git a/src/wapp/os/allocators/arena/mem_arena.c b/src/wapp/os/allocators/arena/mem_arena.c new file mode 100644 index 0000000..35f28c6 --- /dev/null +++ b/src/wapp/os/allocators/arena/mem_arena.c @@ -0,0 +1,192 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_arena.h" +#include "../../mem/mem_os.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include "../../../common/misc/misc_utils.h" +#include "../../../base/mem/utils/mem_utils.h" +#include + +#ifndef DEFAULT_ALIGNMENT +// Why 2 * sizeof(void *) instead of sizeof(void *) +// https://handmade.network/forums/t/6860-alignment_arena_allocator +#define DEFAULT_ALIGNMENT (2 * sizeof(void *)) +#endif /* ifndef DEFAULT_ALIGNMENT */ + +#define ARENA_MINIMUM_CAPACITY KiB(16) // Allocate minimum of 4 pages + +typedef enum { + ARENA_STORAGE_TYPE_ALLOCATED, + ARENA_STORAGE_TYPE_BUFFER, +} ArenaStorageType; + +struct WpArena { + u8 *buf; + u8 *offset; + u8 *prev_offset; + u64 capacity; + ArenaStorageType type; + b8 committed; + + wpMiscUtilsReservePadding(sizeof(u8 *) * 3 + sizeof(u64) + sizeof(ArenaStorageType) + sizeof(b8)); +}; + +b8 wpMemArenaInitBuffer(WpArena **arena, u8 *buffer, u64 buffer_size) { + if (!arena || *arena || buffer_size < sizeof(WpArena)) { + return false; + } + + *arena = (WpArena *)buffer; + WpArena *arena_ptr = *arena; + + arena_ptr->buf = (u8 *)(arena_ptr + 1); + arena_ptr->offset = arena_ptr->buf; + arena_ptr->prev_offset = NULL; + arena_ptr->capacity = buffer_size - sizeof(WpArena); + arena_ptr->type = ARENA_STORAGE_TYPE_BUFFER; + arena_ptr->committed = true; + + return true; +} + +b8 wpMemArenaInitAllocatedCustom(WpArena **arena, u64 base_capacity, WpMemAllocFlags flags, b8 zero_buffer) { + if (!arena || *arena || base_capacity == 0) { + return false; + } + + u64 size = sizeof(WpArena) + (base_capacity >= ARENA_MINIMUM_CAPACITY ? base_capacity : ARENA_MINIMUM_CAPACITY); + u64 alloc_size = wpMiscUtilsU64RoundUpPow2(size); + u8 *allocated = (u8 *)wpOsMemAlloc(NULL, alloc_size, WP_MEM_ACCESS_READ_WRITE, flags, + zero_buffer ? WP_MEM_INIT_INITIALISED : WP_MEM_INIT_UNINITIALISED); + if (!allocated) { + return false; + } + + b8 committed = (flags & WP_MEM_ALLOC_COMMIT) == WP_MEM_ALLOC_COMMIT; + +#ifdef WP_PLATFORM_WINDOWS + if (!committed) { + wpOsMemAlloc(allocated, sizeof(WpArena), WP_MEM_ACCESS_READ_WRITE, WP_MEM_ALLOC_COMMIT, + WP_MEM_INIT_INITIALISED); + } +#endif // ifdef WP_PLATFORM_WINDOWS + + if (!wpMemArenaInitBuffer(arena, allocated, alloc_size)) { + wpMemArenaDestroy(arena); + return false; + } + + WpArena *arena_ptr = *arena; + arena_ptr->type = ARENA_STORAGE_TYPE_ALLOCATED; + arena_ptr->committed = committed; + + return true; +} + +void *wpMemArenaAlloc(WpArena *arena, u64 size) { + return wpMemArenaAllocAligned(arena, size, DEFAULT_ALIGNMENT); +} + +void *wpMemArenaAllocAligned(WpArena *arena, u64 size, u64 alignment) { + wpDebugAssert(arena != NULL, "`arena` should not be NULL"); + + u8 *alloc_start = arena->offset; + + u8 *output = wpMemUtilAlignForward((void *)alloc_start, alignment); + if (output + size >= arena->buf + arena->capacity) { + return NULL; + } + + arena->offset = output + size; + +#ifdef WP_PLATFORM_WINDOWS + if (arena->type == ARENA_STORAGE_TYPE_ALLOCATED && !(arena->committed)) { + wpOsMemAlloc(alloc_start, (uptr)(arena->offset) - (uptr)(alloc_start), + WP_MEM_ACCESS_READ_WRITE, WP_MEM_ALLOC_COMMIT, + WP_MEM_INIT_UNINITIALISED); + } +#endif // ifdef WP_PLATFORM_WINDOWS + + memset(output, 0, size); + + return (void *)output; +} + +void *wpMemArenaRealloc(WpArena *arena, void *ptr, u64 old_size, u64 new_size) { + wpDebugAssert(arena != NULL, "`arena` should not be NULL"); + + if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset || + arena->offset + new_size >= arena->buf + arena->capacity) { + return NULL; + } + + void *new_ptr = wpMemArenaAlloc(arena, new_size); + if (!new_ptr) { + return NULL; + } + + u64 copy_size = new_size <= old_size ? new_size : old_size; + memcpy(new_ptr, ptr, copy_size); + + return new_ptr; +} + +void *wpMemArenaReallocAligned(WpArena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment) { + wpDebugAssert(arena != NULL, "`arena` should not be NULL"); + + if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset || + arena->offset + new_size >= arena->buf + arena->capacity) { + return NULL; + } + + void *new_ptr = wpMemArenaAllocAligned(arena, new_size, alignment); + if (!new_ptr) { + return NULL; + } + + u64 copy_size = new_size <= old_size ? new_size : old_size; + memcpy(new_ptr, ptr, copy_size); + + return new_ptr; +} + +void wpMemArenaTempBegin(WpArena *arena) { + wpDebugAssert(arena != NULL, "`arena` should not be NULL"); + + if (arena->prev_offset != NULL) { + return; + } + + arena->prev_offset = arena->offset; +} + +void wpMemArenaTempEnd(WpArena *arena) { + wpDebugAssert(arena != NULL, "`arena` should not be NULL"); + + if (arena->prev_offset == NULL) { + return; + } + + arena->offset = arena->prev_offset; + arena->prev_offset = NULL; +} + +void wpMemArenaClear(WpArena *arena) { + wpDebugAssert(arena != NULL, "`arena` should not be NULL"); + + memset(arena->buf, 0, arena->offset - arena->buf); + arena->offset = arena->buf; +} + +void wpMemArenaDestroy(WpArena **arena) { + wpDebugAssert(arena != NULL && (*arena) != NULL, "`arena` double pointer is not valid"); + + WpArena *arena_ptr = *arena; + + if (arena_ptr->type == ARENA_STORAGE_TYPE_ALLOCATED) { + wpOsMemFree(*arena, sizeof(WpArena) + arena_ptr->capacity); + } + + *arena = NULL; +} diff --git a/src/wapp/os/allocators/arena/mem_arena.h b/src/wapp/os/allocators/arena/mem_arena.h new file mode 100644 index 0000000..5e4c516 --- /dev/null +++ b/src/wapp/os/allocators/arena/mem_arena.h @@ -0,0 +1,45 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_ARENA_H +#define MEM_ARENA_H + +#include "../../mem/mem_os.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef struct WpArena WpArena; + +#define wpMemArenaInitAllocated(arena_dptr, base_capacity) \ + (wpMemArenaInitAllocatedCustom(arena_dptr, base_capacity, WP_MEM_ALLOC_RESERVE, false)) +#define wpMemArenaInitAllocatedCommit(arena_dptr, base_capacity) \ + (wpMemArenaInitAllocatedCustom(arena_dptr, base_capacity, WP_MEM_ALLOC_RESERVE | WP_MEM_ALLOC_COMMIT, false)) +#define wpMemArenaInitAllocatedZero(arena_dptr, base_capacity) \ + (wpMemArenaInitAllocatedCustom(arena_dptr, base_capacity, WP_MEM_ALLOC_RESERVE, true)) +#define wpMemArenaInitAllocatedCommitAndZero(arena_dptr, base_capacity) \ + (wpMemArenaInitAllocatedCustom(arena_dptr, base_capacity, WP_MEM_ALLOC_RESERVE | WP_MEM_ALLOC_COMMIT, true)) + +/** + * WpArena initialisation function. `wpMemArenaInitAllocatedCustom` provides the most + * control over how the WpArena is initialised. Wrapper macros are provided for + * easier use. + */ +b8 wpMemArenaInitAllocatedCustom(WpArena **arena, u64 base_capacity, WpMemAllocFlags flags, b8 zero_buffer); +b8 wpMemArenaInitBuffer(WpArena **arena, u8 *buffer, u64 buffer_size); +void *wpMemArenaAlloc(WpArena *arena, u64 size); +void *wpMemArenaAllocAligned(WpArena *arena, u64 size, u64 alignment); +void *wpMemArenaRealloc(WpArena *arena, void *ptr, u64 old_size, u64 new_size); +void *wpMemArenaReallocAligned(WpArena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment); +void wpMemArenaTempBegin(WpArena *arena); +void wpMemArenaTempEnd(WpArena *arena); +void wpMemArenaClear(WpArena *arena); +void wpMemArenaDestroy(WpArena **arena); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_ARENA_H diff --git a/src/wapp/os/allocators/arena/mem_arena_allocator.c b/src/wapp/os/allocators/arena/mem_arena_allocator.c new file mode 100644 index 0000000..0d1a0f0 --- /dev/null +++ b/src/wapp/os/allocators/arena/mem_arena_allocator.c @@ -0,0 +1,87 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_arena_allocator.h" +#include "mem_arena.h" +#include "../../mem/mem_os.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" + +wp_intern void initialise_arena_allocator(WpAllocator *allocator); +wp_intern void *mem_arena_alloc(u64 size, void *alloc_obj); +wp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj); +wp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj); +wp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment, + void *alloc_obj); + +WpAllocator wpMemArenaAllocatorInitWithBuffer(u8 *buffer, u64 buffer_size) { + WpAllocator allocator = {0}; + b8 initialised = wpMemArenaInitBuffer((WpArena **)(&allocator.obj), buffer, buffer_size); + if (!initialised) { + return allocator; + } + + initialise_arena_allocator(&allocator); + + return allocator; +} + +WpAllocator wpMemArenaAllocatorInitCustom(u64 base_capacity, WpMemAllocFlags flags, b8 zero_buffer) { + WpAllocator allocator = {0}; + b8 initialised = wpMemArenaInitAllocatedCustom((WpArena **)(&allocator.obj), base_capacity, flags, zero_buffer); + if (!initialised) { + return allocator; + } + + initialise_arena_allocator(&allocator); + + return allocator; +} + +void wpMemArenaAllocatorTempBegin(const WpAllocator *allocator) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + wpMemArenaTempBegin((WpArena *)(allocator->obj)); +} + +void wpMemArenaAllocatorTempEnd(const WpAllocator *allocator) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + wpMemArenaTempEnd((WpArena *)(allocator->obj)); +} + +void wpMemArenaAllocatorClear(WpAllocator *allocator) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + wpMemArenaClear((WpArena *)(allocator->obj)); +} + +void wpMemArenaAllocatorDestroy(WpAllocator *allocator) { + wpDebugAssert(allocator != NULL, "`allocator` should not be NULL"); + wpMemArenaDestroy((WpArena **)(&(allocator->obj))); + *allocator = (WpAllocator){0}; +} + +wp_intern void initialise_arena_allocator(WpAllocator *allocator) { + allocator->alloc = mem_arena_alloc; + allocator->alloc_aligned = mem_arena_alloc_aligned; + allocator->realloc = mem_arena_realloc; + allocator->realloc_aligned = mem_arena_realloc_aligned; +} + +wp_intern void *mem_arena_alloc(u64 size, void *alloc_obj) { + WpArena *arena = (WpArena *)alloc_obj; + return wpMemArenaAlloc(arena, size); +} + +wp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj) { + WpArena *arena = (WpArena *)alloc_obj; + return wpMemArenaAllocAligned(arena, size, alignment); +} + +wp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) { + WpArena *arena = (WpArena *)alloc_obj; + return wpMemArenaRealloc(arena, ptr, old_size, new_size); +} + +wp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment, + void *alloc_obj) { + WpArena *arena = (WpArena *)alloc_obj; + return wpMemArenaReallocAligned(arena, ptr, old_size, new_size, alignment); +} diff --git a/src/wapp/os/allocators/arena/mem_arena_allocator.h b/src/wapp/os/allocators/arena/mem_arena_allocator.h new file mode 100644 index 0000000..789cbb2 --- /dev/null +++ b/src/wapp/os/allocators/arena/mem_arena_allocator.h @@ -0,0 +1,46 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_ARENA_ALLOCATOR_H +#define MEM_ARENA_ALLOCATOR_H + +#include "../../mem/mem_os.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../../base/mem/allocator/mem_allocator.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define wpMemArenaAllocatorInit(base_capacity) \ + (wpMemArenaAllocatorInitCustom(base_capacity, WP_MEM_ALLOC_RESERVE, false)) +#define wpMemArenaAllocatorInitCommit(base_capacity) \ + (wpMemArenaAllocatorInitCustom(base_capacity, WP_MEM_ALLOC_RESERVE | WP_MEM_ALLOC_COMMIT, false)) +#define wpMemArenaAllocatorInitZero(base_capacity) \ + (wpMemArenaAllocatorInitCustom(base_capacity, WP_MEM_ALLOC_RESERVE, true)) +#define wpMemArenaAllocatorInitCommitAndZero(base_capacity) \ + (wpMemArenaAllocatorInitCustom(base_capacity, WP_MEM_ALLOC_RESERVE | WP_MEM_ALLOC_COMMIT, true)) + +/** + * Wraps a WpArena in a WpAllocator object. It attempts to initialise the WpArena + * and, if successful, defines the operations supported by it to be used by the + * WpAllocator. + * + * An WpArena allocator only supports normal allocation and aligned allocation. + * Reallocation, aligned reallocation and freeing aren't implemented. + * + * The `wpMemArenaAllocatorInitCustom` provides the most control over how + * the WpArena is initialised. Wrapper macros are provided for easier use. + */ +WpAllocator wpMemArenaAllocatorInitCustom(u64 base_capacity, WpMemAllocFlags flags, b8 zero_buffer); +WpAllocator wpMemArenaAllocatorInitWithBuffer(u8 *buffer, u64 buffer_size); +void wpMemArenaAllocatorTempBegin(const WpAllocator *allocator); +void wpMemArenaAllocatorTempEnd(const WpAllocator *allocator); +void wpMemArenaAllocatorClear(WpAllocator *allocator); +void wpMemArenaAllocatorDestroy(WpAllocator *allocator); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_ARENA_ALLOCATOR_H diff --git a/src/wapp/os/cpath/cpath.c b/src/wapp/os/cpath/cpath.c new file mode 100644 index 0000000..a78d17a --- /dev/null +++ b/src/wapp/os/cpath/cpath.c @@ -0,0 +1,134 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "cpath.h" +#include "../allocators/arena/mem_arena_allocator.h" +#include "../../common/aliases/aliases.h" +#include "../../common/misc/misc_utils.h" +#include "../../base/dbl_list/dbl_list.h" +#include "../../base/mem/allocator/mem_allocator.h" +#include "../../base/strings/str8/str8.h" +#include + +u32 wpCpathJoinPath(WpStr8 *dst, const WpStr8List *parts) { + if (!dst || !parts) { + return WP_CPATH_JOIN_RESULT_INVALID_ARGS; + } + + if (parts->node_count == 0) { + return WP_CPATH_JOIN_RESULT_EMPTY_PARTS; + } + + WpStr8 separator = wpStr8Buf(4); + wpStr8PushBack(&separator, WP_PATH_SEP); + + u64 required_capacity = parts->node_count * separator.size + wpStr8ListTotalSize(parts); + if (dst->capacity < required_capacity) { + return WP_CPATH_JOIN_RESULT_INSUFFICIENT_DST_CAPACITY; + } + + // Handle first node + WpStr8 *first_node = wpDblListGet(WpStr8, parts, 0); + wpStr8CopyStr8Capped(dst, first_node); + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + WpStr8 *node = first_node; + u64 node_index = 1; + b8 running = node_index < parts->node_count; + while (running) { + node = wpDblListGet(WpStr8, parts, node_index); + if (node->size == 0) { + goto CPATH_JOIN_LOOP_END; + } + + if (dst->size > 0) { + char dst_last = wpStr8Get(dst, dst->size - 1); + char node_start = wpStr8Get(node, 0); + b8 add_path_sep = dst_last != WP_PATH_SEP && node_start != WP_PATH_SEP; + + if (add_path_sep) { + wpStr8ConcatCapped(dst, &separator); + } + } + + wpStr8ConcatCapped(dst, node); + +CPATH_JOIN_LOOP_END: + ++node_index; + running = node_index < parts->node_count; + } + + return WP_CPATH_JOIN_RESULT_SUCCESS; +} + +WpStr8 *_dirup(const WpAllocator *allocator, WpStr8RO *path, u64 levels) { + WpStr8 *output = NULL; + if (!allocator || !path) { + goto RETURN_DIRUP; + } + + b8 absolute = wpStr8Get(path, 0) == WP_PATH_SEP; + WpStr8 separator = wpStr8Buf(4); + wpStr8PushBack(&separator, WP_PATH_SEP); + + if (path->size == 0) { + output = wpStr8AllocBuf(allocator, 16); + if (!output) { + goto RETURN_DIRUP; + } + + wpStr8PushBack(output, absolute ? WP_PATH_SEP : '.'); + goto RETURN_DIRUP; + } + + if (levels < 1) { + output = wpStr8AllocStr8(allocator, path); + goto RETURN_DIRUP; + } + + WpAllocator tmp_arena = wpMemArenaAllocatorInit(MiB(8)); + if (wpMemAllocatorInvalid(&tmp_arena)) { + goto RETURN_DIRUP; + } + + WpStr8List *parts = wpStr8Split(&tmp_arena, path, &separator); + if (!parts) { + goto RETURN_DIRUP; + } + + if (levels >= parts->node_count) { + output = wpStr8AllocBuf(allocator, 16); + if (!output) { + goto LIST_CLEANUP_DIRUP; + } + + wpStr8PushBack(output, absolute ? WP_PATH_SEP : '.'); + } else { + for (u64 i = 0; i < levels; ++i) { + wpDblListPopBack(WpStr8, parts); + } + + u64 alignment = sizeof(void *) * 2; + u64 alloc_size = wpStr8ListTotalSize(parts) + parts->node_count * separator.size; + u64 modulo = alloc_size & (alignment - 1); + alloc_size += alignment - modulo; + + output = wpStr8AllocBuf(allocator, alloc_size); + if (output) { + if (absolute) { + wpStr8PushBack(output, WP_PATH_SEP); + } + + WpStr8 *joined = wpStr8Join(&tmp_arena, parts, &separator); + if (joined) { + wpStr8ConcatCapped(output, joined); + } + } + } + +LIST_CLEANUP_DIRUP: + wpMemArenaAllocatorDestroy(&tmp_arena); + +RETURN_DIRUP: + return output; +} diff --git a/src/wapp/os/cpath/cpath.h b/src/wapp/os/cpath/cpath.h new file mode 100644 index 0000000..d87506a --- /dev/null +++ b/src/wapp/os/cpath/cpath.h @@ -0,0 +1,45 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef CPATH_H +#define CPATH_H + +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" +#include "../../base/mem/allocator/mem_allocator.h" +#include "../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#ifdef WP_PLATFORM_POSIX +#include +#define WP_PATH_SEP '/' +#define WP_PATH_MAX PATH_MAX +#elif defined(WP_PLATFORM_WINDOWS) +#define WIN32_LEAN_AND_MEAN +#include +#define WP_PATH_SEP '\\' +#define WP_PATH_MAX MAX_PATH +#else +#error "Unrecognised platform" +#endif + +#define wpCpathDirname(ALLOCATOR, PATH) _dirup(ALLOCATOR, PATH, 1) +#define wpCpathDirup(ALLOCATOR, PATH, COUNT) _dirup(ALLOCATOR, PATH, COUNT) + +typedef enum { + WP_CPATH_JOIN_RESULT_SUCCESS = 0, + WP_CPATH_JOIN_RESULT_INVALID_ARGS, + WP_CPATH_JOIN_RESULT_EMPTY_PARTS, + WP_CPATH_JOIN_RESULT_INSUFFICIENT_DST_CAPACITY, +} WpCpathJoinResult; + +WpCpathJoinResult wpCpathJoinPath(WpStr8 *dst, const WpStr8List *parts); +WpStr8 *_dirup(const WpAllocator *allocator, WpStr8RO *path, u64 levels); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !CPATH_H diff --git a/src/wapp/os/file/file.c b/src/wapp/os/file/file.c new file mode 100644 index 0000000..9822620 --- /dev/null +++ b/src/wapp/os/file/file.c @@ -0,0 +1,139 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "file.h" +#include "../cpath/cpath.h" +#include "../../common/assert/assert.h" +#include "../../common/aliases/aliases.h" +#include "../../base/array/array.h" +#include "../../base/strings/str8/str8.h" + +WpFile *wpFileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) { + wpDebugAssert(allocator != NULL && filepath != NULL, "`allocator` and `filepath` should not be NULL"); + wpDebugAssert(filepath->size < WP_PATH_MAX, "`filepath` exceeds max path limit."); + return _fileOpen(allocator, filepath, mode); +} + +i64 wpFileGetCurrentPosition(WpFile *file) { + wpDebugAssert(file != NULL, "`file` should not be NULL."); + return _fileSeek(file, 0, WP_SEEK_CURRENT); +} + +i64 wpFileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) { + wpDebugAssert(file != NULL, "`file` should not be NULL."); + return _fileSeek(file, offset, origin); +} + +i64 wpFileGetLength(WpFile *file) { + wpDebugAssert(file != NULL, "`file` should not be NULL."); + + i64 current = wpFileGetCurrentPosition(file); + + _fileSeek(file, 0, WP_SEEK_END); + + i64 output = wpFileGetCurrentPosition(file); + + // Restore position + _fileSeek(file, current, WP_SEEK_START); + + return output; +} + +u64 wpFileRead(void *dst_buf, WpFile *file, u64 byte_count) { + wpDebugAssert(dst_buf != NULL && file != NULL, + "`dst_buf` and `file` should not be NULL."); + + i64 file_length = wpFileGetLength(file); + if (file_length < 0) { + return 0; + } + + return _fileRead(dst_buf, byte_count, file, file_length); +} + +i64 wpFileWrite(const void *src_buf, WpFile *file, u64 byte_count) { + wpDebugAssert(src_buf != NULL && file != NULL, + "`src_buf` and `file` should not be NULL."); + return _fileWrite(src_buf, file, byte_count); +} + +u64 wpFileReadStr8(WpStr8 *str, WpFile *file) { + wpDebugAssert(str != NULL, "`str` should not be NULL."); + return wpFileRead((void *)(str->buf), file, str->size); +} + +i64 wpFileWriteStr8(WpStr8RO *str, WpFile *file) { + wpDebugAssert(str != NULL, "`str` should not be NULL."); + return wpFileWrite((void *)(str->buf), file, str->size); +} + +u64 wpFileReadArray(WpArray dst_buf, WpFile *file, u64 item_count) { + wpDebugAssert(dst_buf != NULL && file != NULL, + "`dst_buf` and `file` should not be NULL."); + + i64 _file_length = wpFileGetLength(file); + if (_file_length < 0) { + return 0; + } + + u64 file_length = (u64)_file_length; + u64 item_size = wpArrayItemSize(dst_buf); + u64 dst_byte_capacity = wpArrayCapacity(dst_buf) * item_size; + u64 req_byte_count = item_count * item_size; + u64 copy_byte_count = 0; + + if (req_byte_count <= file_length && req_byte_count <= dst_byte_capacity) { + copy_byte_count = req_byte_count; + } else { + copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity; + } + + u64 byte_count = _fileRead(dst_buf, copy_byte_count, file, file_length); + if (byte_count == 0) { + return 0; + } + + wpArraySetCount(dst_buf, byte_count / item_size); + + return wpArrayCount(dst_buf); +} + +i64 wpFileWriteArray(const WpArray src_buf, WpFile *file, u64 item_count) { + wpDebugAssert(src_buf != NULL && file != NULL, + "`src_buf` and `file` should not be NULL."); + + u64 item_size = wpArrayItemSize(src_buf); + u64 src_byte_count = wpArrayCount(src_buf) * item_size; + u64 req_byte_count = item_count * item_size; + u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count; + + i64 bytes_written = _fileWrite(src_buf, file, to_copy); + if (bytes_written < 0) { + return 0; + } + + return (u64)bytes_written / item_size; +} + +i32 wpFileFlush(WpFile *file) { + wpDebugAssert(file != NULL, "`file` should not be NULL."); + return _fileFlush(file); +} + +i32 wpFileClose(WpFile *file) { + wpDebugAssert(file != NULL, "`file` should not be NULL."); + return _fileClose(file); +} + +i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) { + wpDebugAssert(old_filepath != NULL && new_filepath != NULL, + "`old_filepath` and `new_filepath` should not be NULL"); + wpDebugAssert(old_filepath->size < WP_PATH_MAX, "`old_filepath` exceeds max path limit."); + wpDebugAssert(new_filepath->size < WP_PATH_MAX, "`new_filepath` exceeds max path limit."); + return _fileRename(old_filepath, new_filepath); +} + +i32 wpFileRemove(WpStr8RO *filepath) { + wpDebugAssert(filepath != NULL, "`filepath` should not be NULL"); + wpDebugAssert(filepath->size < WP_PATH_MAX, "`filepath` exceeds max path limit."); + return _fileRemove(filepath); +} diff --git a/src/wapp/os/file/file.h b/src/wapp/os/file/file.h new file mode 100644 index 0000000..73f8231 --- /dev/null +++ b/src/wapp/os/file/file.h @@ -0,0 +1,77 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef FILE_H +#define FILE_H + +#include "../../base/mem/allocator/mem_allocator.h" +#include "../../common/aliases/aliases.h" +#include "../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef struct WpFile WpFile; + +typedef enum { + WP_ACCESS_READ, // Equivalent to r + WP_ACCESS_WRITE, // Equivalent to w + WP_ACCESS_APPEND, // Equivalent to a + WP_ACCESS_READ_EX, // Equivalent to r+ + WP_ACCESS_WRITE_EX, // Equivalent to w+ + WP_ACCESS_APPEND_EX, // Equivalent to a+ + WP_ACCESS_WRITE_FAIL_ON_EXIST, // Equivalent to wx + WP_ACCESS_WRITE_FAIL_ON_EXIST_EX, // Equivalent to wx+ + + COUNT_FILE_ACCESS_MODE, +} WpFileAccessMode; + +typedef enum { + WP_SEEK_START, + WP_SEEK_CURRENT, + WP_SEEK_END, + + COUNT_FILE_SEEK_ORIGIN, +} WpFileSeekOrigin; + +// Return value should not be cached as it's not guaranteed to remain the same. Always call +// wpFileStdin to get the standard input stream +wp_extern WpFile *wpFileStdin(void); + +// Return value should not be cached as it's not guaranteed to remain the same. Always call +// wpFileStdout to get the standard output stream +wp_extern WpFile *wpFileStdout(void); + +// Return value should not be cached as it's not guaranteed to remain the same. Always call +// wpFileStderr to get the standard error stream +wp_extern WpFile *wpFileStderr(void); + +WpFile *wpFileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode); +i64 wpFileGetCurrentPosition(WpFile *file); +i64 wpFileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin); +i64 wpFileGetLength(WpFile *file); +u64 wpFileRead(void *dst_buf, WpFile *file, u64 byte_count); +i64 wpFileWrite(const void *src_buf, WpFile *file, u64 byte_count); +u64 wpFileReadStr8(WpStr8 *str, WpFile *file); +i64 wpFileWriteStr8(WpStr8RO *str, WpFile *file); +u64 wpFileReadArray(WpArray dst_buf, WpFile *file, u64 item_count); +i64 wpFileWriteArray(const WpArray src_buf, WpFile *file, u64 item_count); +i32 wpFileFlush(WpFile *file); +i32 wpFileClose(WpFile *file); +i32 wpFileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath); +i32 wpFileRemove(WpStr8RO *filepath); + +wp_extern WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode); +wp_extern i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin); +wp_extern u64 _fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length); +wp_extern i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count); +wp_extern i32 _fileFlush(WpFile *file); +wp_extern i32 _fileClose(WpFile *file); +wp_extern i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath); +wp_extern i32 _fileRemove(WpStr8RO *filepath); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !FILE_H diff --git a/src/wapp/os/file/posix/file_posix.c b/src/wapp/os/file/posix/file_posix.c new file mode 100644 index 0000000..3a3fafd --- /dev/null +++ b/src/wapp/os/file/posix/file_posix.c @@ -0,0 +1,134 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "file_posix.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_POSIX + +#include "../file.h" +#include "../../cpath/cpath.h" +#include "../../../common/aliases/aliases.h" +#include "../../../base/array/array.h" +#include "../../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_APPLE +#define _FILE_OFFSET_BITS 64 +#define lseek64 lseek +#endif // !WP_PLATFORM_APPLE + +#define __USE_LARGEFILE64 +#include +#include +#include + +wp_intern i32 file_flags[COUNT_FILE_ACCESS_MODE] = { + [WP_ACCESS_READ] = O_RDONLY, + [WP_ACCESS_WRITE] = O_WRONLY | O_CREAT, + [WP_ACCESS_APPEND] = O_WRONLY | O_APPEND | O_CREAT, + [WP_ACCESS_READ_EX] = O_RDWR, + [WP_ACCESS_WRITE_EX] = O_RDWR | O_CREAT, + [WP_ACCESS_APPEND_EX] = O_RDWR | O_APPEND | O_CREAT, + [WP_ACCESS_WRITE_FAIL_ON_EXIST] = O_WRONLY | O_CREAT | O_EXCL, + [WP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = O_RDWR | O_CREAT | O_EXCL, +}; + +wp_intern mode_t file_modes[COUNT_FILE_ACCESS_MODE] = { + [WP_ACCESS_READ] = 0, + [WP_ACCESS_WRITE] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + [WP_ACCESS_APPEND] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + [WP_ACCESS_READ_EX] = 0, + [WP_ACCESS_WRITE_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + [WP_ACCESS_APPEND_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + [WP_ACCESS_WRITE_FAIL_ON_EXIST] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + [WP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, +}; + +wp_intern i32 file_seek_origins[COUNT_FILE_SEEK_ORIGIN] = { + [WP_SEEK_START] = SEEK_SET, + [WP_SEEK_CURRENT] = SEEK_CUR, + [WP_SEEK_END] = SEEK_END, +}; + +WpFile *wpFileStdin(void) { + wp_persist WpFile _stdin = { .fd = STDIN_FILENO }; + return &_stdin; +} + +WpFile *wpFileStdout(void) { + wp_persist WpFile _stdout = { .fd = STDOUT_FILENO }; + return &_stdout; +} + +WpFile *wpFileStderr(void) { + wp_persist WpFile _stderr = { .fd = STDERR_FILENO }; + return &_stderr; +} + +WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) { + wp_persist c8 tmp[WP_PATH_MAX] = {0}; + memset(tmp, 0, WP_PATH_MAX); + memcpy(tmp, filepath->buf, filepath->size); + + i32 fd = open((const char *)tmp, file_flags[mode], file_modes[mode]); + if (fd < 0) { + return NULL; + } + + WpFile *output = wpMemAllocatorAlloc(allocator, sizeof(WpFile)); + if (output) { + output->fd = fd; + } + + return output; +} + +i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) { + return lseek64(file->fd, offset, file_seek_origins[origin]); +} + +u64 _fileRead(void *dst_buf, u64 byte_count, WpFile *file, u64 file_length) { + u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count; + + i64 count = read(file->fd, dst_buf, copy_byte_count); + if (count < 0) { return 0; } + + return count; +} + +i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count) { + return write(file->fd, src_buf, byte_count); +} + +i32 _fileFlush(WpFile *file) { + return fsync(file->fd); +} + +i32 _fileClose(WpFile *file) { + return close(file->fd); +} + +i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) { + wp_persist c8 old_tmp[WP_PATH_MAX] = {0}; + wp_persist c8 new_tmp[WP_PATH_MAX] = {0}; + memset(old_tmp, 0, WP_PATH_MAX); + memcpy(old_tmp, old_filepath->buf, old_filepath->size); + memset(new_tmp, 0, WP_PATH_MAX); + memcpy(new_tmp, new_filepath->buf, new_filepath->size); + + i32 link_result = link((const char *)old_tmp, (const char *)new_tmp); + if (link_result == 0) { + _fileRemove(old_filepath); + } + + return link_result; +} + +i32 _fileRemove(WpStr8RO *filepath) { + wp_persist c8 tmp[WP_PATH_MAX] = {0}; + memset(tmp, 0, WP_PATH_MAX); + memcpy(tmp, filepath->buf, filepath->size); + + return unlink((const char *)tmp); +} + +#endif // !WP_PLATFORM_POSIX diff --git a/src/wapp/os/file/posix/file_posix.h b/src/wapp/os/file/posix/file_posix.h new file mode 100644 index 0000000..47c8036 --- /dev/null +++ b/src/wapp/os/file/posix/file_posix.h @@ -0,0 +1,27 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef FILE_POSIX_H +#define FILE_POSIX_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#ifdef WP_PLATFORM_POSIX + +#define WP_END_OF_LINE "\n" + +struct WpFile { + i32 fd; +}; + +#endif // !WP_PLATFORM_POSIX + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !FILE_POSIX_H diff --git a/src/wapp/os/file/win/file_win.c b/src/wapp/os/file/win/file_win.c new file mode 100644 index 0000000..0c4dd09 --- /dev/null +++ b/src/wapp/os/file/win/file_win.c @@ -0,0 +1,177 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "file_win.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_WINDOWS + +#include "../file.h" +#include "../../cpath/cpath.h" +#include "../../../common/aliases/aliases.h" +#include "../../../base/array/array.h" +#include "../../../base/strings/str8/str8.h" +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +wp_intern DWORD file_accesses[COUNT_FILE_ACCESS_MODE] = { + [WP_ACCESS_READ] = FILE_READ_DATA, + [WP_ACCESS_WRITE] = FILE_WRITE_DATA, + [WP_ACCESS_APPEND] = FILE_APPEND_DATA, + [WP_ACCESS_READ_EX] = FILE_READ_DATA | FILE_WRITE_DATA, + [WP_ACCESS_WRITE_EX] = FILE_READ_DATA | FILE_WRITE_DATA, + [WP_ACCESS_APPEND_EX] = FILE_READ_DATA | FILE_APPEND_DATA, + [WP_ACCESS_WRITE_FAIL_ON_EXIST] = FILE_WRITE_DATA, + [WP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = FILE_READ_DATA | FILE_WRITE_DATA, +}; + +wp_intern DWORD creation_dispositions[COUNT_FILE_ACCESS_MODE] = { + [WP_ACCESS_READ] = OPEN_EXISTING, + [WP_ACCESS_WRITE] = CREATE_ALWAYS, + [WP_ACCESS_APPEND] = OPEN_ALWAYS, + [WP_ACCESS_READ_EX] = OPEN_EXISTING, + [WP_ACCESS_WRITE_EX] = CREATE_ALWAYS, + [WP_ACCESS_APPEND_EX] = OPEN_ALWAYS, + [WP_ACCESS_WRITE_FAIL_ON_EXIST] = CREATE_NEW, + [WP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = CREATE_NEW, +}; + +wp_intern DWORD sharing_modes[COUNT_FILE_ACCESS_MODE] = { + [WP_ACCESS_READ] = FILE_SHARE_READ | FILE_SHARE_WRITE, + [WP_ACCESS_WRITE] = FILE_SHARE_READ, + [WP_ACCESS_APPEND] = FILE_SHARE_READ, + [WP_ACCESS_READ_EX] = FILE_SHARE_READ | FILE_SHARE_WRITE, + [WP_ACCESS_WRITE_EX] = FILE_SHARE_READ, + [WP_ACCESS_APPEND_EX] = FILE_SHARE_READ, + [WP_ACCESS_WRITE_FAIL_ON_EXIST] = FILE_SHARE_READ, + [WP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = FILE_SHARE_READ, +}; + +wp_intern DWORD file_seek_origins[COUNT_FILE_SEEK_ORIGIN] = { + [WP_SEEK_START] = FILE_BEGIN, + [WP_SEEK_CURRENT] = FILE_CURRENT, + [WP_SEEK_END] = FILE_END, +}; + +WpFile *wpFileStdin(void) { + wp_persist WpFile _stdin = { .fh = INVALID_HANDLE_VALUE }; + _stdin.fh = GetStdHandle(STD_INPUT_HANDLE); + return &_stdin; +} + +WpFile *wpFileStdout(void) { + wp_persist WpFile _stdout = { .fh = INVALID_HANDLE_VALUE }; + _stdout.fh = GetStdHandle(STD_OUTPUT_HANDLE); + return &_stdout; +} + +WpFile *wpFileStderr(void) { + wp_persist WpFile _stderr = { .fh = INVALID_HANDLE_VALUE }; + _stderr.fh = GetStdHandle(STD_ERROR_HANDLE); + return &_stderr; +} + +WpFile *_fileOpen(const WpAllocator *allocator, WpStr8RO *filepath, WpFileAccessMode mode) { + wp_persist c8 tmp[WP_PATH_MAX] = {0}; + memset(tmp, 0, WP_PATH_MAX); + memcpy(tmp, filepath->buf, filepath->size); + + HANDLE fh = CreateFileA((LPCSTR)tmp, + file_accesses[mode], + sharing_modes[mode], + NULL, + creation_dispositions[mode], + FILE_ATTRIBUTE_NORMAL, + NULL); + if (fh == INVALID_HANDLE_VALUE) { + return NULL; + } + + WpFile *output = wpMemAllocatorAlloc(allocator, sizeof(WpFile)); + if (output) { + output->fh = fh; + } + + return output; +} + +i64 _fileSeek(WpFile *file, i64 offset, WpFileSeekOrigin origin) { + LARGE_INTEGER distance = {0}; + LARGE_INTEGER output = {0}; + + distance.QuadPart = offset; + + if (!SetFilePointerEx(file->fh, distance, &output, file_seek_origins[origin])) { + return -1; + } + + return output.QuadPart; +} + +u64 _fileRead(void* dst_buf, u64 byte_count, WpFile* file, u64 file_length) { + u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count; + wpDebugAssert(copy_byte_count <= DWORD_MAX, "Attempting to read large number of bytes at once"); + + DWORD read_count = 0; + if (!ReadFile(file->fh, dst_buf, (DWORD)copy_byte_count, &read_count, NULL)) { + return 0; + } + + return (u64)read_count; +} + +i64 _fileWrite(const void *src_buf, WpFile *file, u64 byte_count) { + wpDebugAssert(byte_count <= DWORD_MAX, "Attempting to write large number of bytes at once"); + + DWORD write_count = 0; + if (!WriteFile(file->fh, src_buf, (DWORD)byte_count, &write_count, NULL)) { + return 0; + } + return (i64)write_count; +} + +i32 _fileFlush(WpFile *file) { + if (!FlushFileBuffers(file->fh)) { + return -1; + } + + return 0; +} + +i32 _fileClose(WpFile *file) { + if (!CloseHandle(file->fh)) { + return -1; + } + + return 0; +} + +i32 _fileRename(WpStr8RO *old_filepath, WpStr8RO *new_filepath) { + wp_persist c8 old_tmp[WP_PATH_MAX] = {0}; + wp_persist c8 new_tmp[WP_PATH_MAX] = {0}; + memset(old_tmp, 0, WP_PATH_MAX); + memcpy(old_tmp, old_filepath->buf, old_filepath->size); + memset(new_tmp, 0, WP_PATH_MAX); + memcpy(new_tmp, new_filepath->buf, new_filepath->size); + + if (!MoveFile((LPCSTR)old_tmp, (LPCSTR)new_tmp)) { + return -1; + } + + return 0; +} + +i32 _fileRemove(WpStr8RO *filepath) { + wp_persist c8 tmp[WP_PATH_MAX] = {0}; + memset(tmp, 0, WP_PATH_MAX); + memcpy(tmp, filepath->buf, filepath->size); + + if (!DeleteFile((LPCSTR)tmp)) { + return -1; + } + + return 0; +} + +#endif // !WP_PLATFORM_WINDOWS diff --git a/src/wapp/os/file/win/file_win.h b/src/wapp/os/file/win/file_win.h new file mode 100644 index 0000000..c6b2a4e --- /dev/null +++ b/src/wapp/os/file/win/file_win.h @@ -0,0 +1,31 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef FILE_WIN_H +#define FILE_WIN_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#ifdef WP_PLATFORM_WINDOWS + +#define WP_END_OF_LINE "\r\n" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +struct WpFile { + HANDLE fh; +}; + +#endif // !WP_PLATFORM_WINDOWS + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !FILE_WIN_H diff --git a/src/wapp/os/mem/mem_os.c b/src/wapp/os/mem/mem_os.c new file mode 100644 index 0000000..792addf --- /dev/null +++ b/src/wapp/os/mem/mem_os.c @@ -0,0 +1,30 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_os.h" +#include "mem_os_ops.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" +#include +#include + +#if defined(WP_PLATFORM_WINDOWS) +#include "win/mem_os_win.h" +#elif defined(WP_PLATFORM_POSIX) +#include "posix/mem_os_posix.h" +#else +#error "Unrecognised platform" +#endif + +void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) { + void *output = _osMemAllocate(addr, size, access, flags, type); + + if (type == WP_MEM_INIT_INITIALISED) { + memset(output, 0, size); + } + + return output; +} + +void wpOsMemFree(void *ptr, u64 size) { + _osMemFree(ptr, size); +} diff --git a/src/wapp/os/mem/mem_os.h b/src/wapp/os/mem/mem_os.h new file mode 100644 index 0000000..6ece5d4 --- /dev/null +++ b/src/wapp/os/mem/mem_os.h @@ -0,0 +1,33 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_OS_H +#define MEM_OS_H + +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" + +#include "mem_os_ops.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#if defined(WP_PLATFORM_WINDOWS) +#include "win/mem_os_win.h" +#elif defined(WP_PLATFORM_POSIX) +#include "posix/mem_os_posix.h" +#else +#error "Unrecognised platform" +#endif + +void *wpOsMemAlloc(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type); +void wpOsMemFree(void *ptr, u64 size); + +wp_extern void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type); +wp_extern void _osMemFree(void *ptr, u64 size); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_OS_H diff --git a/src/wapp/os/mem/mem_os_ops.h b/src/wapp/os/mem/mem_os_ops.h new file mode 100644 index 0000000..8184e38 --- /dev/null +++ b/src/wapp/os/mem/mem_os_ops.h @@ -0,0 +1,30 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_OS_OPS_H +#define MEM_OS_OPS_H + +#include "../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef enum { + WP_MEM_ACCESS_NONE, + WP_MEM_ACCESS_READ_ONLY, + WP_MEM_ACCESS_EXEC_ONLY, + WP_MEM_ACCESS_READ_WRITE, + WP_MEM_ACCESS_READ_EXEC, + WP_MEM_ACCESS_READ_WRITE_EXEC, +} WpMemAccess; + +typedef enum { + WP_MEM_INIT_UNINITIALISED, + WP_MEM_INIT_INITIALISED, +} WpMemInitType; + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_OS_OPS_H diff --git a/src/wapp/os/mem/posix/mem_os_posix.c b/src/wapp/os/mem/posix/mem_os_posix.c new file mode 100644 index 0000000..23cddda --- /dev/null +++ b/src/wapp/os/mem/posix/mem_os_posix.c @@ -0,0 +1,36 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_POSIX + +#include "mem_os_posix.h" +#include "../mem_os_ops.h" +#include + +wp_intern const i32 access_types[] = { + [WP_MEM_ACCESS_NONE] = PROT_NONE, + [WP_MEM_ACCESS_READ_ONLY] = PROT_READ, + [WP_MEM_ACCESS_EXEC_ONLY] = PROT_EXEC, + [WP_MEM_ACCESS_READ_WRITE] = PROT_READ | PROT_WRITE, + [WP_MEM_ACCESS_READ_EXEC] = PROT_READ | PROT_EXEC, + [WP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC, +}; + +void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) { + (void)type; + i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE; + +#if defined(WP_PLATFORM_LINUX) || defined(WP_PLATFORM_GNU) || defined(WP_PLATFORM_NET_BSD) + alloc_flags |= MAP_NORESERVE; +#endif + + return mmap(addr, size, access_types[access], alloc_flags, -1, 0); +} + +void _osMemFree(void *ptr, u64 size) { + munmap(ptr, size); +} + +#endif // !WP_PLATFORM_POSIX diff --git a/src/wapp/os/mem/posix/mem_os_posix.h b/src/wapp/os/mem/posix/mem_os_posix.h new file mode 100644 index 0000000..9f2805b --- /dev/null +++ b/src/wapp/os/mem/posix/mem_os_posix.h @@ -0,0 +1,35 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_OS_POSIX_H +#define MEM_OS_POSIX_H + +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#ifdef WP_PLATFORM_POSIX + +#include + +typedef enum { +#if defined(WP_PLATFORM_LINUX) || defined(WP_PLATFORM_GNU) + WP_MEM_ALLOC_RESERVE = 0, + WP_MEM_ALLOC_COMMIT = MAP_POPULATE, +#elif defined(WP_PLATFORM_FREE_BSD) + WP_MEM_ALLOC_RESERVE = 0, + WP_MEM_ALLOC_COMMIT = MAP_PREFAULT_READ, +#elif defined(WP_PLATFORM_BSD) || defined(WP_PLATFORM_UNIX) || defined(WP_PLATFORM_APPLE) + WP_MEM_ALLOC_RESERVE = 0, + WP_MEM_ALLOC_COMMIT = 0, +#endif +} WpMemAllocFlags; + +#endif // !WP_PLATFORM_POSIX + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_OS_POSIX_H diff --git a/src/wapp/os/mem/win/mem_os_win.c b/src/wapp/os/mem/win/mem_os_win.c new file mode 100644 index 0000000..a7e6e5f --- /dev/null +++ b/src/wapp/os/mem/win/mem_os_win.c @@ -0,0 +1,37 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_WINDOWS + +#include "mem_os_win.h" +#include "../mem_os_ops.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +wp_intern const i32 access_types[] = { + [WP_MEM_ACCESS_NONE] = PAGE_NOACCESS, + [WP_MEM_ACCESS_READ_ONLY] = PAGE_READONLY, + [WP_MEM_ACCESS_EXEC_ONLY] = PAGE_EXECUTE, + [WP_MEM_ACCESS_READ_WRITE] = PAGE_READWRITE, + [WP_MEM_ACCESS_READ_EXEC] = PAGE_EXECUTE_READ, + [WP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE, +}; + +void *_osMemAllocate(void *addr, u64 size, WpMemAccess access, WpMemAllocFlags flags, WpMemInitType type) { + // Ensure memory is committed if it's meant to be initialised + if (type == WP_MEM_INIT_INITIALISED) { + flags |= WP_MEM_ALLOC_COMMIT; + } + + return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]); +} + +void _osMemFree(void *ptr, u64 size) { + VirtualFree(ptr, size, MEM_RELEASE); +} + +#endif // !WP_PLATFORM_WINDOWS diff --git a/src/wapp/os/mem/win/mem_os_win.h b/src/wapp/os/mem/win/mem_os_win.h new file mode 100644 index 0000000..229caad --- /dev/null +++ b/src/wapp/os/mem/win/mem_os_win.h @@ -0,0 +1,29 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_OS_WIN_H +#define MEM_OS_WIN_H + +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#ifdef WP_PLATFORM_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#include +#include + +typedef enum { + WP_MEM_ALLOC_RESERVE = MEM_RESERVE, + WP_MEM_ALLOC_COMMIT = MEM_COMMIT, +} WpMemAllocFlags; + +#endif // !WP_PLATFORM_WINDOWS + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !MEM_OS_WIN_H diff --git a/src/wapp/os/shell/commander/commander.c b/src/wapp/os/shell/commander/commander.c new file mode 100644 index 0000000..476c202 --- /dev/null +++ b/src/wapp/os/shell/commander/commander.c @@ -0,0 +1,101 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "commander.h" +#include "commander_output.h" +#include "../utils/shell_utils.h" +#include "../../allocators/arena/mem_arena_allocator.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/misc/misc_utils.h" +#include "../../../base/dbl_list/dbl_list.h" +#include "../../../base/mem/allocator/mem_allocator.h" +#include "../../../base/strings/str8/str8.h" +#include +#include +#include +#include + +#define CMD_BUF_LEN 8192 +#define OUT_BUF_LEN 4096 + +wp_intern WpCmdResult executeCommand(WpStr8RO *cmd, WpCmdOutHandling out_handling, WpStr8 *out_buf); +wp_intern WpCmdError getCommandOutput(FILE *fp, WpCmdOutHandling out_handling, WpStr8 *out_buf); + +WpCmdResult wpShellCommanderExecute(WpCmdOutHandling out_handling, WpStr8 *out_buf, const WpStr8List *cmd) { + if (!cmd) { + return wpCmdNoExit(WP_SHELL_ERR_INVALID_ARGS); + } + + WpAllocator arena = wpMemArenaAllocatorInit(KiB(500)); + + WpStr8 *cmd_str = wpStr8Join(&arena, cmd, &wpStr8LitRo(" ")); + if (!cmd_str) { + wpMemArenaAllocatorDestroy(&arena); + return wpCmdNoExit(WP_SHELL_ERR_ALLOCATION_FAIL); + } + + // Redirect output + cmd_str = wpStr8AllocConcat(&arena, cmd_str, &wpStr8LitRo(" 2>&1")); + + WpCmdResult output = executeCommand(cmd_str, out_handling, out_buf); + + wpMemArenaAllocatorDestroy(&arena); + + return output; +} + +wp_intern WpCmdResult executeCommand(WpStr8RO *cmd, WpCmdOutHandling out_handling, WpStr8 *out_buf) { + char cmd_buf[CMD_BUF_LEN] = {0}; + wpStr8CopyToCstr(cmd_buf, cmd, CMD_BUF_LEN); + + FILE *fp = wpShellUtilsPopen(cmd_buf, "r"); + if (!fp) { + return wpCmdNoExit(WP_SHELL_ERR_PROC_START_FAIL); + } + + WpCmdResult output; + + WpCmdError err = getCommandOutput(fp, out_handling, out_buf); + if (err > WP_SHELL_ERR_NO_ERROR) { + output = wpCmdNoExit(err); + goto executeCommand_CLOSE; + } + + i32 st = EXIT_SUCCESS; + err = _getOutputStatus(fp, &st); + if (err > WP_SHELL_ERR_NO_ERROR) { + output = wpCmdNoExit(err); + goto executeCommand_CLOSE; + } + + // Process is already closed in _getOutputStatus + fp = NULL; + + output = (WpCmdResult){ + .exited = true, + .exit_code = st, + .error = WP_SHELL_ERR_NO_ERROR, + }; + +executeCommand_CLOSE: + if (fp) { + wpShellUtilsPclose(fp); + } + return output; +} + +wp_intern WpCmdError getCommandOutput(FILE *fp, WpCmdOutHandling out_handling, WpStr8 *out_buf) { + WpStr8 out = wpStr8Buf(OUT_BUF_LEN); + + out.size = fread((void *)out.buf, sizeof(c8), out.capacity, fp); + if (out_handling == WP_SHELL_OUTPUT_CAPTURE && out_buf != NULL) { + if (out.size >= out_buf->capacity) { + return WP_SHELL_ERR_OUT_BUF_FULL; + } + + wpStr8ConcatCapped(out_buf, &out); + } else if (out_handling == WP_SHELL_OUTPUT_PRINT) { + printf(WP_STR8_SPEC, wpStr8Varg(out)); + } + + return WP_SHELL_ERR_NO_ERROR; +} diff --git a/src/wapp/os/shell/commander/commander.h b/src/wapp/os/shell/commander/commander.h new file mode 100644 index 0000000..891a4f4 --- /dev/null +++ b/src/wapp/os/shell/commander/commander.h @@ -0,0 +1,29 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef COMMANDER_H +#define COMMANDER_H + +#include "commander_output.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../../base/strings/str8/str8.h" +#include +#include + +// TODO (Abdelrahman): This module needs rethinking + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define wpCmdNoExit(ERR) ((WpCmdResult){.exited = false, .exit_code = EXIT_FAILURE, .error = ERR}) + +WpCmdResult wpShellCommanderExecute(WpCmdOutHandling out_handling, WpStr8 *out_buf, const WpStr8List *cmd); + +wp_extern WpCmdError _getOutputStatus(FILE *fp, i32 *status_out); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !COMMANDER_H diff --git a/src/wapp/os/shell/commander/commander_output.h b/src/wapp/os/shell/commander/commander_output.h new file mode 100644 index 0000000..4d18d48 --- /dev/null +++ b/src/wapp/os/shell/commander/commander_output.h @@ -0,0 +1,42 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef COMMANDER_OUTPUT_H +#define COMMANDER_OUTPUT_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../../common/misc/misc_utils.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef enum { + WP_SHELL_OUTPUT_DISCARD, + WP_SHELL_OUTPUT_PRINT, + WP_SHELL_OUTPUT_CAPTURE, +} WpCmdOutHandling; + +typedef enum { + WP_SHELL_ERR_NO_ERROR, + WP_SHELL_ERR_INVALID_ARGS, + WP_SHELL_ERR_ALLOCATION_FAIL, + WP_SHELL_ERR_PROC_START_FAIL, + WP_SHELL_ERR_OUT_BUF_FULL, + WP_SHELL_ERR_PROC_EXIT_FAIL, +} WpCmdError; + +typedef struct WpCmdResult WpCmdResult; +struct WpCmdResult { + i32 exit_code; + WpCmdError error; + b8 exited; + + wpMiscUtilsReservePadding(sizeof(b8) + sizeof(i32) + sizeof(WpCmdError)); +}; + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !COMMANDER_OUTPUT_H diff --git a/src/wapp/os/shell/commander/posix/commander_posix.c b/src/wapp/os/shell/commander/posix/commander_posix.c new file mode 100644 index 0000000..0b1069c --- /dev/null +++ b/src/wapp/os/shell/commander/posix/commander_posix.c @@ -0,0 +1,25 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "../../../../common/aliases/aliases.h" +#include "../../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_POSIX + +#include "../commander_output.h" +#include "../../utils/shell_utils.h" +#include +#include + +WpCmdError _getOutputStatus(FILE *fp, i32 *status_out) { + *status_out = wpShellUtilsPclose(fp); + + if (!WIFEXITED(*status_out)) { + return WP_SHELL_ERR_PROC_EXIT_FAIL; + } + + *status_out = WEXITSTATUS(*status_out); + + return WP_SHELL_ERR_NO_ERROR; +} + +#endif // !WP_PLATFORM_POSIX diff --git a/src/wapp/os/shell/commander/win/commander_win.c b/src/wapp/os/shell/commander/win/commander_win.c new file mode 100644 index 0000000..daf764e --- /dev/null +++ b/src/wapp/os/shell/commander/win/commander_win.c @@ -0,0 +1,24 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "../../../../common/aliases/aliases.h" +#include "../../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_WINDOWS + +#include "../commander_output.h" +#include "../../utils/shell_utils.h" +#include + +WpCmdError _getOutputStatus(FILE *fp, i32 *status_out) { + if (!feof(fp)) { + // Ensure process is closed on failure + wpShellUtilsPclose(fp); + return WP_SHELL_ERR_PROC_EXIT_FAIL; + } + + *status_out = wpShellUtilsPclose(fp); + + return WP_SHELL_ERR_NO_ERROR; +} + +#endif // !WP_PLATFORM_WINDOWS diff --git a/src/wapp/os/shell/termcolour/posix/termcolour_posix.c b/src/wapp/os/shell/termcolour/posix/termcolour_posix.c new file mode 100644 index 0000000..4489d1e --- /dev/null +++ b/src/wapp/os/shell/termcolour/posix/termcolour_posix.c @@ -0,0 +1,36 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "../../../../common/aliases/aliases.h" +#include "../../../../common/platform/platform.h" +#include "../../../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_POSIX + +#include "../terminal_colours.h" +#include + +wp_intern WpStr8RO colours[COUNT_TERM_COLOUR] = { + [WP_TERM_COLOUR_FG_BLACK] = wpStr8LitRoInitialiserList("\033[30m"), + [WP_TERM_COLOUR_FG_RED] = wpStr8LitRoInitialiserList("\033[31m"), + [WP_TERM_COLOUR_FG_GREEN] = wpStr8LitRoInitialiserList("\033[32m"), + [WP_TERM_COLOUR_FG_BLUE] = wpStr8LitRoInitialiserList("\033[34m"), + [WP_TERM_COLOUR_FG_CYAN] = wpStr8LitRoInitialiserList("\033[36m"), + [WP_TERM_COLOUR_FG_MAGENTA] = wpStr8LitRoInitialiserList("\033[35m"), + [WP_TERM_COLOUR_FG_YELLOW] = wpStr8LitRoInitialiserList("\033[33m"), + [WP_TERM_COLOUR_FG_WHITE] = wpStr8LitRoInitialiserList("\033[37m"), + [WP_TERM_COLOUR_FG_BR_BLACK] = wpStr8LitRoInitialiserList("\033[90m"), + [WP_TERM_COLOUR_FG_BR_RED] = wpStr8LitRoInitialiserList("\033[91m"), + [WP_TERM_COLOUR_FG_BR_GREEN] = wpStr8LitRoInitialiserList("\033[92m"), + [WP_TERM_COLOUR_FG_BR_BLUE] = wpStr8LitRoInitialiserList("\033[94m"), + [WP_TERM_COLOUR_FG_BR_CYAN] = wpStr8LitRoInitialiserList("\033[96m"), + [WP_TERM_COLOUR_FG_BR_MAGENTA] = wpStr8LitRoInitialiserList("\033[95m"), + [WP_TERM_COLOUR_FG_BR_YELLOW] = wpStr8LitRoInitialiserList("\033[93m"), + [WP_TERM_COLOUR_FG_BR_WHITE] = wpStr8LitRoInitialiserList("\033[97m"), + [WP_TERM_COLOUR_CLEAR] = wpStr8LitRoInitialiserList("\033[0m"), +}; + +void _printColouredText(WpStr8RO *text, WpTerminalColour colour) { + printf(WP_STR8_SPEC WP_STR8_SPEC, wpStr8Varg(colours[colour]), wpStr8Varg((*text))); +} + +#endif // !WP_PLATFORM_POSIX diff --git a/src/wapp/os/shell/termcolour/termcolour.c b/src/wapp/os/shell/termcolour/termcolour.c new file mode 100644 index 0000000..a3da8fb --- /dev/null +++ b/src/wapp/os/shell/termcolour/termcolour.c @@ -0,0 +1,18 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "termcolour.h" +#include "terminal_colours.h" +#include "../../../base/strings/str8/str8.h" + +void wpShellTermcolourPrintText(WpStr8RO *text, WpTerminalColour colour) { + if (colour < WP_TERM_COLOUR_FG_BLACK || colour > WP_TERM_COLOUR_FG_BR_WHITE) { + return; + } + + _printColouredText(text, colour); +} + +void wpShellTermcolourClearColour(void) { + WpStr8RO empty = wpStr8LitRo(""); + _printColouredText(&empty, WP_TERM_COLOUR_CLEAR); +} diff --git a/src/wapp/os/shell/termcolour/termcolour.h b/src/wapp/os/shell/termcolour/termcolour.h new file mode 100644 index 0000000..9343da4 --- /dev/null +++ b/src/wapp/os/shell/termcolour/termcolour.h @@ -0,0 +1,26 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef TERM_COLOUR_H +#define TERM_COLOUR_H + +#include "terminal_colours.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +// TODO (Abdelrahman): Look into moving away from stdio in the implementation + +void wpShellTermcolourPrintText(WpStr8RO *text, WpTerminalColour colour); +void wpShellTermcolourClearColour(void); + +wp_extern void _printColouredText(WpStr8RO *text, WpTerminalColour colour); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !TERM_COLOUR_H diff --git a/src/wapp/os/shell/termcolour/terminal_colours.h b/src/wapp/os/shell/termcolour/terminal_colours.h new file mode 100644 index 0000000..6c1a328 --- /dev/null +++ b/src/wapp/os/shell/termcolour/terminal_colours.h @@ -0,0 +1,39 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef TERMINAL_COLOURS_H +#define TERMINAL_COLOURS_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef enum { + WP_TERM_COLOUR_FG_BLACK, + WP_TERM_COLOUR_FG_RED, + WP_TERM_COLOUR_FG_GREEN, + WP_TERM_COLOUR_FG_BLUE, + WP_TERM_COLOUR_FG_CYAN, + WP_TERM_COLOUR_FG_MAGENTA, + WP_TERM_COLOUR_FG_YELLOW, + WP_TERM_COLOUR_FG_WHITE, + WP_TERM_COLOUR_FG_BR_BLACK, + WP_TERM_COLOUR_FG_BR_RED, + WP_TERM_COLOUR_FG_BR_GREEN, + WP_TERM_COLOUR_FG_BR_BLUE, + WP_TERM_COLOUR_FG_BR_CYAN, + WP_TERM_COLOUR_FG_BR_MAGENTA, + WP_TERM_COLOUR_FG_BR_YELLOW, + WP_TERM_COLOUR_FG_BR_WHITE, + WP_TERM_COLOUR_CLEAR, + + COUNT_TERM_COLOUR, +} WpTerminalColour; + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !TERMINAL_COLOURS_H diff --git a/src/wapp/os/shell/termcolour/win/termcolour_win.c b/src/wapp/os/shell/termcolour/win/termcolour_win.c new file mode 100644 index 0000000..af8e911 --- /dev/null +++ b/src/wapp/os/shell/termcolour/win/termcolour_win.c @@ -0,0 +1,73 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "../../../../common/aliases/aliases.h" +#include "../../../../common/platform/platform.h" +#include "../../../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_WINDOWS + +#include "../terminal_colours.h" +#include "../../../../common/misc/misc_utils.h" +#include + +#define WIN32_LEAN_AND_MEAN +#include + +typedef struct TermcolourData TermcolourData; +struct TermcolourData { + HANDLE handle; + WORD default_colour; + WORD current_colour; + + wpMiscUtilsReservePadding(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD)); +}; + +wp_intern void init_data(TermcolourData *data); + +wp_intern WORD colours[COUNT_TERM_COLOUR] = { + [WP_TERM_COLOUR_FG_BLACK] = 0, + [WP_TERM_COLOUR_FG_RED] = FOREGROUND_RED, + [WP_TERM_COLOUR_FG_GREEN] = FOREGROUND_GREEN, + [WP_TERM_COLOUR_FG_BLUE] = FOREGROUND_BLUE, + [WP_TERM_COLOUR_FG_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE, + [WP_TERM_COLOUR_FG_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE, + [WP_TERM_COLOUR_FG_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN, + [WP_TERM_COLOUR_FG_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, + [WP_TERM_COLOUR_FG_BR_BLACK] = FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, + [WP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, +}; + +void _printColouredText(WpStr8RO *text, WpTerminalColour colour) { + wp_persist TermcolourData data = {0}; + if (data.handle == 0) { + init_data(&data); + } + + if (colour == WP_TERM_COLOUR_CLEAR) { + data.current_colour = data.default_colour; + } else { + data.current_colour = colours[colour]; + } + + SetConsoleTextAttribute(data.handle, data.current_colour); + printf(WP_STR8_SPEC, wpStr8Varg((*text))); +} + +wp_intern void init_data(TermcolourData *data) { + // create handle + data->handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // get console colour information + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(data->handle, &csbi); + data->default_colour = csbi.wAttributes; + data->current_colour = data->default_colour; +} + +#endif // !WP_PLATFORM_WINDOWS diff --git a/src/wapp/os/shell/utils/shell_utils.h b/src/wapp/os/shell/utils/shell_utils.h new file mode 100644 index 0000000..20a94ed --- /dev/null +++ b/src/wapp/os/shell/utils/shell_utils.h @@ -0,0 +1,26 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef SHELL_UTILS_H +#define SHELL_UTILS_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#ifdef WP_PLATFORM_WINDOWS + #define wpShellUtilsPopen _popen + #define wpShellUtilsPclose _pclose +#else + #define wpShellUtilsPopen popen + #define wpShellUtilsPclose pclose +#endif /* ifdef WP_PLATFORM_WINDOWS */ + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !SHELL_UTILS_H diff --git a/src/wapp/os/wapp_os.c b/src/wapp/os/wapp_os.c new file mode 100644 index 0000000..62a6bce --- /dev/null +++ b/src/wapp/os/wapp_os.c @@ -0,0 +1,24 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_OS_C +#define WAPP_OS_C + +#include "wapp_os.h" +#include "file/file.c" +#include "file/posix/file_posix.c" +#include "file/win/file_win.c" +#include "shell/termcolour/posix/termcolour_posix.c" +#include "shell/termcolour/win/termcolour_win.c" +#include "shell/termcolour/termcolour.c" +#include "shell/commander/posix/commander_posix.c" +#include "shell/commander/win/commander_win.c" +#include "shell/commander/commander.c" +#include "cpath/cpath.c" +#include "allocators/arena/mem_arena.c" +#include "allocators/arena/mem_arena_allocator.c" +#include "mem/posix/mem_os_posix.c" +#include "mem/win/mem_os_win.c" +#include "mem/mem_os.c" +#include "../base/wapp_base.c" + +#endif // !WAPP_OS_C diff --git a/src/wapp/os/wapp_os.h b/src/wapp/os/wapp_os.h new file mode 100644 index 0000000..39cb3b2 --- /dev/null +++ b/src/wapp/os/wapp_os.h @@ -0,0 +1,24 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_CORE_H +#define WAPP_CORE_H + +#include "file/file.h" +#include "file/posix/file_posix.h" +#include "file/win/file_win.h" +#include "shell/termcolour/termcolour.h" +#include "shell/termcolour/terminal_colours.h" +#include "shell/commander/commander.h" +#include "shell/commander/commander_output.h" +#include "shell/utils/shell_utils.h" +#include "cpath/cpath.h" +#include "allocators/arena/mem_arena.h" +#include "allocators/arena/mem_arena_allocator.h" +#include "mem/posix/mem_os_posix.h" +#include "mem/win/mem_os_win.h" +#include "mem/mem_os_ops.h" +#include "mem/mem_os.h" +#include "../common/wapp_common.h" +#include "../base/wapp_base.h" + +#endif // !WAPP_CORE_H diff --git a/src/wapp/prng/wapp_prng.c b/src/wapp/prng/wapp_prng.c new file mode 100644 index 0000000..e5081be --- /dev/null +++ b/src/wapp/prng/wapp_prng.c @@ -0,0 +1,8 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_PRNG_C +#define WAPP_PRNG_C + +#include "xorshift/xorshift.c" + +#endif // !WAPP_PRNG_C diff --git a/src/wapp/prng/wapp_prng.h b/src/wapp/prng/wapp_prng.h new file mode 100644 index 0000000..e64dfac --- /dev/null +++ b/src/wapp/prng/wapp_prng.h @@ -0,0 +1,9 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_PRNG_H +#define WAPP_PRNG_H + +#include "xorshift/xorshift.h" +#include "../common/wapp_common.h" + +#endif // !WAPP_PRNG_H diff --git a/src/wapp/prng/xorshift/xorshift.c b/src/wapp/prng/xorshift/xorshift.c new file mode 100644 index 0000000..b41d5c2 --- /dev/null +++ b/src/wapp/prng/xorshift/xorshift.c @@ -0,0 +1,135 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "xorshift.h" +#include "../../common/aliases/aliases.h" +#include "../../common/assert/assert.h" +#include "../../common/platform/platform.h" +#include +#include + +typedef struct SplitMix64State SplitMix64State; +struct SplitMix64State { + u64 seed; +}; + +wp_intern u64 rol64(u64 x, u64 bits); +wp_intern u64 split_mix_64(SplitMix64State *state); +wp_intern void seed_os_generator(void); +wp_intern u64 generate_random_number(void); + +WpXor256State wpPrngXorshiftInit(void) { + wp_persist b8 seeded = false; + if (!seeded) { + seeded = true; + seed_os_generator(); + } + + SplitMix64State sm64 = {.seed = generate_random_number()}; + + return (WpXor256State){ + .x = split_mix_64(&sm64), + .y = split_mix_64(&sm64), + .z = split_mix_64(&sm64), + .w = split_mix_64(&sm64), + }; +} + +u64 wpPrngXorshift256(WpXor256State *state) { + u64 t = state->x ^ (state->x << 11); + + state->x = state->y; + state->y = state->z; + state->z = state->w; + state->w = (state->w ^ (state->w >> 19)) ^ (t ^ (t >> 8)); + + return state->w; +} + +u64 wpPrngXorshift256ss(WpXor256State *state) { + const u64 result = rol64(state->z * 5, 7) * 9; + const u64 t = state->z << 17; + + state->y ^= state->w; + state->x ^= state->z; + state->z ^= state->y; + state->w ^= state->x; + + state->y ^= t; + state->x = rol64(state->x, 45); + + return result; +} + +u64 wpPrngXorshift256p(WpXor256State *state) { + const u64 result = state->w + state->x; + const u64 t = state->z << 17; + + state->y ^= state->w; + state->x ^= state->z; + state->z ^= state->y; + state->w ^= state->x; + + state->y ^= t; + state->x = rol64(state->x, 45); + + return result; +} + +wp_intern u64 rol64(u64 x, u64 bits) { + return (x << bits) | (x >> (64 - bits)); +} + +wp_intern u64 split_mix_64(SplitMix64State *state) { + state->seed += 0x9E3779B97f4A7C15; + + u64 result = state->seed; + result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; + result = (result ^ (result >> 27)) * 0x94D049BB133111EB; + + return result ^ (result >> 31); +} + +#if defined(WP_PLATFORM_C) && WP_PLATFORM_C_VERSION >= WP_PLATFORM_C11_VERSION +#ifdef WP_PLATFORM_POSIX +wp_intern void seed_os_generator(void) { + struct timespec ts = {0}; + int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + wpRuntimeAssert(result == 0, "Invalid seed value"); + + srand48(ts.tv_nsec); +} + +wp_intern u64 generate_random_number(void) { + return lrand48(); +} +#else +wp_intern void seed_os_generator(void) { + struct timespec ts = {0}; + int result = timespec_get(&ts, TIME_UTC); + wpRuntimeAssert(result != 0, "Invalid seed value"); + + srand(ts.tv_nsec); +} + +wp_intern u64 generate_random_number(void) { + i32 n1 = rand(); + i32 n2 = rand(); + + return (((u64)n1) << 32 | (u64)n2); +} +#endif // !WP_PLATFORM_POSIX +#else +wp_intern void seed_os_generator(void) { + time_t result = time(NULL); + wpRuntimeAssert(result != (time_t)(-1), "Invalid seed value"); + + srand(result); +} + +wp_intern u64 generate_random_number(void) { + i32 n1 = rand(); + i32 n2 = rand(); + + return (((u64)n1) << 32 | (u64)n2); +} +#endif // !WP_PLATFORM_C diff --git a/src/wapp/prng/xorshift/xorshift.h b/src/wapp/prng/xorshift/xorshift.h new file mode 100644 index 0000000..48258cb --- /dev/null +++ b/src/wapp/prng/xorshift/xorshift.h @@ -0,0 +1,30 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef XORSHIFT_H +#define XORSHIFT_H + +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +typedef struct WpXor256State WpXor256State; +struct WpXor256State { + u64 x; + u64 y; + u64 z; + u64 w; +}; + +WpXor256State wpPrngXorshiftInit(void); +u64 wpPrngXorshift256(WpXor256State *state); +u64 wpPrngXorshift256ss(WpXor256State *state); +u64 wpPrngXorshift256p(WpXor256State *state); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !XORSHIFT_H diff --git a/src/wapp/testing/tester/tester.c b/src/wapp/testing/tester/tester.c new file mode 100644 index 0000000..d80e534 --- /dev/null +++ b/src/wapp/testing/tester/tester.c @@ -0,0 +1,55 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "tester.h" +#include "../../common/aliases/aliases.h" +#include "../../os/shell/termcolour/termcolour.h" +#include "../../base/strings/str8/str8.h" +#include +#include +#include + +wp_intern void handleTestResult(WpTestFuncResult result); + +void _runTests(WpTestFunc *func1, ...) { + printf("\n"); + + handleTestResult(func1()); + + va_list args; + va_start(args, func1); + + WpTestFunc *func = va_arg(args, WpTestFunc *); + + while (func) { + WpTestFuncResult result = func(); + handleTestResult(result); + + func = va_arg(args, WpTestFunc *); + } + + va_end(args); + + printf("\n"); +} + +wp_intern void handleTestResult(WpTestFuncResult result) { + WpTerminalColour colour; + WpStr8 result_text = wpStr8Buf(64); + + if (result.passed) { + colour = WP_TERM_COLOUR_FG_BR_GREEN; + wpStr8CopyCstrCapped(&result_text, "PASSED"); + } else { + colour = WP_TERM_COLOUR_FG_BR_RED; + wpStr8CopyCstrCapped(&result_text, "FAILED"); + } + + printf("["); + wpShellTermcolourPrintText(&result_text, colour); + wpShellTermcolourClearColour(); + printf("] " WP_STR8_SPEC "\n", wpStr8Varg(result.name)); + + if (!result.passed) { + exit(EXIT_FAILURE); + } +} diff --git a/src/wapp/testing/tester/tester.h b/src/wapp/testing/tester/tester.h new file mode 100644 index 0000000..5ac7d8c --- /dev/null +++ b/src/wapp/testing/tester/tester.h @@ -0,0 +1,36 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef TESTER_H +#define TESTER_H + +#include "../../common/misc/misc_utils.h" +#include "../../common/platform/platform.h" +#include "../../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE + +#define wpTesterResult(PASSED) (WpTestFuncResult{wpStr8LitRo(__func__), PASSED, {}}) +#else +#define wpTesterResult(PASSED) ((WpTestFuncResult){.name = wpStr8LitRo(__func__), .passed = PASSED}) +#endif // !WP_PLATFORM_CPP + +#define wpTesterRun(...) _runTests(__VA_ARGS__, NULL) + +typedef struct WpTestFuncResult WpTestFuncResult; +struct WpTestFuncResult { + WpStr8 name; + b8 passed; + + wpMiscUtilsReservePadding(sizeof(WpStr8) + sizeof(b8)); +}; + +typedef WpTestFuncResult(WpTestFunc)(void); + +void _runTests(WpTestFunc *func1, ...); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !TESTER_H diff --git a/src/wapp/testing/wapp_testing.c b/src/wapp/testing/wapp_testing.c new file mode 100644 index 0000000..2898eea --- /dev/null +++ b/src/wapp/testing/wapp_testing.c @@ -0,0 +1,10 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_TESTING_C +#define WAPP_TESTING_C + +#include "wapp_testing.h" +#include "tester/tester.c" +#include "../os/wapp_os.c" + +#endif // !WAPP_TESTING_C diff --git a/src/wapp/testing/wapp_testing.h b/src/wapp/testing/wapp_testing.h new file mode 100644 index 0000000..1c1877f --- /dev/null +++ b/src/wapp/testing/wapp_testing.h @@ -0,0 +1,10 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_TESTING_H +#define WAPP_TESTING_H + +#include "tester/tester.h" +#include "../common/wapp_common.h" +#include "../os/wapp_os.h" + +#endif // !WAPP_TESTING_H diff --git a/src/wapp/uuid/uuid.c b/src/wapp/uuid/uuid.c new file mode 100644 index 0000000..8f50e26 --- /dev/null +++ b/src/wapp/uuid/uuid.c @@ -0,0 +1,58 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "uuid.h" +#include "../common/aliases/aliases.h" +#include "../common/assert/assert.h" +#include "../base/strings/str8/str8.h" +#include "../prng/xorshift/xorshift.h" +#include + +#define UUID_STR_FORMAT ("%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.12" PRIx64) + +typedef struct UUID4 UUID4; +struct UUID4 { + u64 high; + u64 low; +}; + +wp_intern UUID4 generate_uuid4(void); +wp_intern void uuid4_to_uuid(const UUID4* uuid4, WpUuid *uuid); + +WpUuid *wpUuidInitUuid4(WpUuid *uuid) { + wpDebugAssert(uuid != NULL, "`uuid` should not be NULL"); + + UUID4 uuid4 = generate_uuid4(); + uuid4_to_uuid(&uuid4, uuid); + + return uuid; +} + +wp_intern UUID4 generate_uuid4(void) { + wp_persist WpXor256State state = {0}; + wp_persist b8 initialised = false; + + if (!initialised) { + initialised = true; + state = wpPrngXorshiftInit(); + } + + UUID4 uuid = (UUID4){ + .high = wpPrngXorshift256(&state), + .low = wpPrngXorshift256(&state), + }; + + uuid.high = (uuid.high & 0xffffffffffff0fff) | 0x0000000000004000; + uuid.low = (uuid.low & 0x3fffffffffffffff) | 0x8000000000000000; + + return uuid; +} + +wp_intern void uuid4_to_uuid(const UUID4* uuid4, WpUuid *uuid) { + u64 group1 = uuid4->high >> 32; + u64 group2 = (uuid4->high << 32) >> 48; + u64 group3 = (uuid4->high << 48) >> 48; + u64 group4 = uuid4->low >> 48; + u64 group5 = (uuid4->low << 16) >> 16; + + wpStr8Format(&(uuid->uuid), UUID_STR_FORMAT, group1, group2, group3, group4, group5); +} diff --git a/src/wapp/uuid/uuid.h b/src/wapp/uuid/uuid.h new file mode 100644 index 0000000..51a7fdd --- /dev/null +++ b/src/wapp/uuid/uuid.h @@ -0,0 +1,50 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef UUID_H +#define UUID_H + +#include "../common/aliases/aliases.h" +#include "../common/platform/platform.h" +#include "../base/strings/str8/str8.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define WP_UUID_BUF_LENGTH 48 +#define WP_UUID_SPEC WP_STR8_SPEC +#define wpUuidVarg(WpUuid) wpStr8Varg((WpUuid).uuid) + +typedef struct WpUuid WpUuid; +struct WpUuid { + WpStr8 uuid; +}; + +// TODO (Abdelrahman): Update UUID implementation to work properly with C++ and tests for validation + +#ifdef WP_PLATFORM_CPP +#define wpUuidGenUuid4() ([&](){ \ + wp_persist WpUuid uuid = wpUuidCreate(); \ + return *(wpUuidInitUuid4(&uuid)); \ +}()) +#else +#define wpUuidGenUuid4() *(wpUuidInitUuid4(&wpUuidCreate())) +#endif + +/* Low level UUID API */ + +#ifdef WP_PLATFORM_CPP +#define wpUuidCreate() ([&](){ return WpUuid{wpStr8Buf(WP_UUID_BUF_LENGTH)}; }()) +#else +#define wpUuidCreate() ((WpUuid){.uuid = wpStr8Buf(WP_UUID_BUF_LENGTH)}) +#endif + +// Just returns the same pointer that was passed in with the UUID initialised. +// Fails when passed a NULL pointer. +WpUuid *wpUuidInitUuid4(WpUuid *uuid); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !UUID_H diff --git a/src/wapp/uuid/wapp_uuid.c b/src/wapp/uuid/wapp_uuid.c new file mode 100644 index 0000000..c2a9b00 --- /dev/null +++ b/src/wapp/uuid/wapp_uuid.c @@ -0,0 +1,10 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_UUID_C +#define WAPP_UUID_C + +#include "uuid.c" +#include "../base/wapp_base.c" +#include "../prng/wapp_prng.c" + +#endif // !WAPP_UUID_C diff --git a/src/wapp/uuid/wapp_uuid.h b/src/wapp/uuid/wapp_uuid.h new file mode 100644 index 0000000..4878499 --- /dev/null +++ b/src/wapp/uuid/wapp_uuid.h @@ -0,0 +1,11 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_UUID_H +#define WAPP_UUID_H + +#include "uuid.h" +#include "../common/wapp_common.h" +#include "../base/wapp_base.h" +#include "../prng/wapp_prng.h" + +#endif // !WAPP_UUID_H diff --git a/src/wapp/wapp.c b/src/wapp/wapp.c new file mode 100644 index 0000000..9dc22ab --- /dev/null +++ b/src/wapp/wapp.c @@ -0,0 +1,14 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_C +#define WAPP_C + +#include "wapp.h" +#include "base/wapp_base.c" +#include "os/wapp_os.c" +#include "log/wapp_log.c" +#include "prng/wapp_prng.c" +#include "uuid/wapp_uuid.c" +#include "testing/wapp_testing.c" + +#endif // !WAPP_C diff --git a/src/wapp/wapp.h b/src/wapp/wapp.h new file mode 100644 index 0000000..14957fe --- /dev/null +++ b/src/wapp/wapp.h @@ -0,0 +1,14 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_H +#define WAPP_H + +#include "common/wapp_common.h" +#include "base/wapp_base.h" +#include "os/wapp_os.h" +#include "log/wapp_log.h" +#include "prng/wapp_prng.h" +#include "uuid/wapp_uuid.h" +#include "testing/wapp_testing.h" + +#endif // !WAPP_H