Reformat base

This commit is contained in:
2025-12-29 21:21:09 +00:00
parent a32ef94522
commit 31a22b74e9
8 changed files with 717 additions and 717 deletions

View File

@@ -12,162 +12,162 @@
wapp_persist inline void _array_validate(const GenericArray *array, u64 item_size); wapp_persist inline void _array_validate(const GenericArray *array, u64 item_size);
void *_array_get(GenericArray *array, u64 index, u64 item_size) { void *_array_get(GenericArray *array, u64 index, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL"); wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size); _array_validate(array, item_size);
wapp_runtime_assert(index < array->count, "`index` is out of bounds"); wapp_runtime_assert(index < array->count, "`index` is out of bounds");
return _offset_pointer(array->items, array->item_size * index); return _offset_pointer(array->items, array->item_size * index);
} }
void _array_set(GenericArray *array, u64 index, void *value, u64 item_size) { void _array_set(GenericArray *array, u64 index, void *value, u64 item_size) {
void *item = _array_get(array, index, item_size); void *item = _array_get(array, index, item_size);
memcpy(item, value, array->item_size); memcpy(item, value, array->item_size);
} }
void _array_append_capped(GenericArray *array, void *value, u64 item_size) { void _array_append_capped(GenericArray *array, void *value, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL"); wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size); _array_validate(array, item_size);
if (array->count >= array->capacity) { return; } if (array->count >= array->capacity) { return; }
u64 index = (array->count)++; u64 index = (array->count)++;
_array_set(array, index, value, item_size); _array_set(array, index, value, item_size);
} }
void _array_extend_capped(GenericArray *dst, const GenericArray *src, u64 item_size) { void _array_extend_capped(GenericArray *dst, const GenericArray *src, u64 item_size) {
wapp_runtime_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); wapp_runtime_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
_array_validate(dst, item_size); _array_validate(dst, item_size);
_array_validate(src, item_size); _array_validate(src, item_size);
u64 remaining_capacity = dst->capacity - dst->count; u64 remaining_capacity = dst->capacity - dst->count;
u64 copy_count = src->count < remaining_capacity ? src->count : remaining_capacity; u64 copy_count = src->count < remaining_capacity ? src->count : remaining_capacity;
void *dst_ptr = _offset_pointer(dst->items, dst->count * dst->item_size); void *dst_ptr = _offset_pointer(dst->items, dst->count * dst->item_size);
memcpy(dst_ptr, src->items, copy_count * src->item_size); memcpy(dst_ptr, src->items, copy_count * src->item_size);
dst->count += copy_count; dst->count += copy_count;
} }
void _array_copy_capped(GenericArray *dst, const GenericArray *src, u64 item_size) { void _array_copy_capped(GenericArray *dst, const GenericArray *src, u64 item_size) {
wapp_runtime_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); wapp_runtime_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
_array_validate(dst, item_size); _array_validate(dst, item_size);
_array_validate(src, item_size); _array_validate(src, item_size);
_array_clear(dst, item_size); _array_clear(dst, item_size);
u64 copy_count = src->count < dst->capacity ? src->count : dst->capacity; u64 copy_count = src->count < dst->capacity ? src->count : dst->capacity;
memcpy(dst->items, src->items, copy_count * src->item_size); memcpy(dst->items, src->items, copy_count * src->item_size);
dst->count = copy_count; dst->count = copy_count;
} }
GenericArray *_array_append_alloc(const Allocator *allocator, GenericArray *array, void *value, u64 item_size) { GenericArray *_array_append_alloc(const Allocator *allocator, GenericArray *array, void *value, u64 item_size) {
wapp_runtime_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); wapp_runtime_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL");
_array_validate(array, item_size); _array_validate(array, item_size);
GenericArray *output = array; GenericArray *output = array;
if (array->count >= array->capacity) { if (array->count >= array->capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2);
output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size, false); output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size, false);
if (!output) { if (!output) {
output = array; output = array;
goto RETURN_ARRAY_APPEND_ALLOC; goto RETURN_ARRAY_APPEND_ALLOC;
} }
_array_copy_capped(output, array, item_size); _array_copy_capped(output, array, item_size);
} }
_array_append_capped(output, value, item_size); _array_append_capped(output, value, item_size);
RETURN_ARRAY_APPEND_ALLOC: RETURN_ARRAY_APPEND_ALLOC:
return output; return output;
} }
GenericArray *_array_extend_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size) { GenericArray *_array_extend_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size) {
wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL"); wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
_array_validate(dst, item_size); _array_validate(dst, item_size);
_array_validate(src, item_size); _array_validate(src, item_size);
GenericArray *output = dst; GenericArray *output = dst;
u64 remaining_capacity = dst->capacity - dst->count; u64 remaining_capacity = dst->capacity - dst->count;
if (src->count >= remaining_capacity) { if (src->count >= remaining_capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2);
output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, dst->item_size, false); output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, dst->item_size, false);
if (!output) { if (!output) {
output = dst; output = dst;
goto RETURN_ARRAY_EXTEND_ALLOC; goto RETURN_ARRAY_EXTEND_ALLOC;
} }
_array_copy_capped(output, dst, item_size); _array_copy_capped(output, dst, item_size);
} }
_array_extend_capped(output, src, item_size); _array_extend_capped(output, src, item_size);
RETURN_ARRAY_EXTEND_ALLOC: RETURN_ARRAY_EXTEND_ALLOC:
return output; return output;
} }
GenericArray *_array_copy_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size) { GenericArray *_array_copy_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size) {
wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL"); wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
_array_validate(dst, item_size); _array_validate(dst, item_size);
_array_validate(src, item_size); _array_validate(src, item_size);
GenericArray *output = dst; GenericArray *output = dst;
if (src->count >= dst->capacity) { if (src->count >= dst->capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2);
output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size, false); output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size, false);
if (!output) { if (!output) {
output = dst; output = dst;
goto RETURN_ARRAY_COPY_ALLOC; goto RETURN_ARRAY_COPY_ALLOC;
} }
} }
_array_copy_capped(output, src, item_size); _array_copy_capped(output, src, item_size);
RETURN_ARRAY_COPY_ALLOC: RETURN_ARRAY_COPY_ALLOC:
return output; return output;
} }
void *_array_pop(GenericArray *array, u64 item_size) { void *_array_pop(GenericArray *array, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL"); wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size); _array_validate(array, item_size);
if (array->count == 0) { return NULL; } if (array->count == 0) { return NULL; }
u64 index = array->count - 1; u64 index = array->count - 1;
void *out = _array_get(array, index, item_size); void *out = _array_get(array, index, item_size);
--(array->count); --(array->count);
return out; return out;
} }
void _array_clear(GenericArray *array, u64 item_size) { void _array_clear(GenericArray *array, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL"); wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size); _array_validate(array, item_size);
array->count = 0; array->count = 0;
} }
GenericArray *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size, b8 fill) { GenericArray *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size, b8 fill) {
wapp_runtime_assert(allocator != NULL, "`allocator` should not be NULL"); wapp_runtime_assert(allocator != NULL, "`allocator` should not be NULL");
GenericArray *output = NULL; GenericArray *output = NULL;
u64 allocation_size = sizeof(GenericArray) + item_size * capacity; u64 allocation_size = sizeof(GenericArray) + item_size * capacity;
output = wapp_mem_allocator_alloc(allocator, allocation_size); output = wapp_mem_allocator_alloc(allocator, allocation_size);
if (!output) { if (!output) {
goto RETURN_ARRAY_ALLOC; goto RETURN_ARRAY_ALLOC;
} }
output->magic = WAPP_ARRAY_MAGIC; output->magic = WAPP_ARRAY_MAGIC;
output->count = fill ? capacity : 0; output->count = fill ? capacity : 0;
output->capacity = capacity; output->capacity = capacity;
output->item_size = item_size; output->item_size = item_size;
output->items = (void *)(output + 1); output->items = (void *)(output + 1);
RETURN_ARRAY_ALLOC: RETURN_ARRAY_ALLOC:
return output; return output;
} }
wapp_persist inline void _array_validate(const GenericArray *array, u64 item_size) { wapp_persist inline void _array_validate(const GenericArray *array, u64 item_size) {
wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array"); wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array");
wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided"); wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided");
} }

View File

@@ -12,247 +12,247 @@ wapp_intern inline void _dbl_list_validate(const GenericList *list, u64 item_siz
wapp_intern inline void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size); wapp_intern inline void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size);
GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size) { GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
GenericList *list = wapp_mem_allocator_alloc(allocator, sizeof(GenericList)); GenericList *list = wapp_mem_allocator_alloc(allocator, sizeof(GenericList));
if (!list) { goto DBL_LIST_ALLOC_RETURN; } if (!list) { goto DBL_LIST_ALLOC_RETURN; }
memset((void *)list, 0, sizeof(GenericList)); memset((void *)list, 0, sizeof(GenericList));
list->magic = WAPP_DBL_LIST_MAGIC; list->magic = WAPP_DBL_LIST_MAGIC;
list->item_size = item_size; list->item_size = item_size;
DBL_LIST_ALLOC_RETURN: DBL_LIST_ALLOC_RETURN:
return list; return list;
} }
GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size) { GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
GenericNode *node = wapp_mem_allocator_alloc(allocator, sizeof(GenericNode)); GenericNode *node = wapp_mem_allocator_alloc(allocator, sizeof(GenericNode));
if (!node) { goto DBL_LIST_NODE_ALLOC_RETURN; } if (!node) { goto DBL_LIST_NODE_ALLOC_RETURN; }
memset((void *)node, 0, sizeof(GenericNode)); memset((void *)node, 0, sizeof(GenericNode));
node->magic = WAPP_DBL_NODE_MAGIC; node->magic = WAPP_DBL_NODE_MAGIC;
node->item_size = item_size; node->item_size = item_size;
DBL_LIST_NODE_ALLOC_RETURN: DBL_LIST_NODE_ALLOC_RETURN:
return node; return node;
} }
GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size) { GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size) {
wapp_debug_assert(list != NULL, "`list` should not be NULL"); wapp_debug_assert(list != NULL, "`list` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");
GenericNode *output = NULL; GenericNode *output = NULL;
GenericNode *current = list->first; GenericNode *current = list->first;
for (u64 i = 1; i <= index; ++i) { for (u64 i = 1; i <= index; ++i) {
current = current->next; current = current->next;
} }
output = current; output = current;
return output; return output;
} }
void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size) { void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size) {
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
_dbl_list_node_validate(list, node, item_size); _dbl_list_node_validate(list, node, item_size);
GenericList node_list = _node_to_list(node, item_size); GenericList node_list = _node_to_list(node, item_size);
if (list->node_count == 0) { if (list->node_count == 0) {
*list = node_list; *list = node_list;
return; return;
} }
list->node_count += node_list.node_count; list->node_count += node_list.node_count;
GenericNode *first = list->first; GenericNode *first = list->first;
if (first) { if (first) {
first->prev = node_list.last; first->prev = node_list.last;
} }
list->first = node_list.first; list->first = node_list.first;
node_list.last->next = first; node_list.last->next = first;
} }
void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size) { void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size) {
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
_dbl_list_node_validate(list, node, item_size); _dbl_list_node_validate(list, node, item_size);
GenericList node_list = _node_to_list(node, item_size); GenericList node_list = _node_to_list(node, item_size);
if (list->node_count == 0) { if (list->node_count == 0) {
*list = node_list; *list = node_list;
return; return;
} }
list->node_count += node_list.node_count; list->node_count += node_list.node_count;
GenericNode *last = list->last; GenericNode *last = list->last;
if (last) { if (last) {
last->next = node_list.first; last->next = node_list.first;
} }
list->last = node_list.last; list->last = node_list.last;
node_list.first->prev = last; node_list.first->prev = last;
} }
void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size) { void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size) {
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
_dbl_list_node_validate(list, node, item_size); _dbl_list_node_validate(list, node, item_size);
if (index == 0) { if (index == 0) {
_dbl_list_push_front(list, node, item_size); _dbl_list_push_front(list, node, item_size);
return; return;
} else if (index == list->node_count) { } else if (index == list->node_count) {
_dbl_list_push_back(list, node, item_size); _dbl_list_push_back(list, node, item_size);
return; return;
} }
GenericNode *dst_node = _dbl_list_get(list, index, item_size); GenericNode *dst_node = _dbl_list_get(list, index, item_size);
if (!dst_node) { if (!dst_node) {
return; return;
} }
GenericList node_list = _node_to_list(node, item_size); GenericList node_list = _node_to_list(node, item_size);
list->node_count += node_list.node_count; list->node_count += node_list.node_count;
GenericNode *prev = dst_node->prev; GenericNode *prev = dst_node->prev;
dst_node->prev = node_list.last; dst_node->prev = node_list.last;
prev->next = node_list.first; prev->next = node_list.first;
node_list.first->prev = prev; node_list.first->prev = prev;
node_list.last->next = dst_node; node_list.last->next = dst_node;
} }
GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size) { GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size) {
wapp_debug_assert(list != NULL, "`list` should not be NULL"); wapp_debug_assert(list != NULL, "`list` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
GenericNode *output = NULL; GenericNode *output = NULL;
if (list->node_count == 0) { if (list->node_count == 0) {
goto RETURN_I32_LIST_POP_FRONT; goto RETURN_I32_LIST_POP_FRONT;
} }
output = list->first; output = list->first;
if (list->node_count == 1) { if (list->node_count == 1) {
*list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size}; *list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size};
goto RETURN_I32_LIST_POP_FRONT; goto RETURN_I32_LIST_POP_FRONT;
} }
--(list->node_count); --(list->node_count);
list->first = output->next; list->first = output->next;
output->prev = output->next = NULL; output->prev = output->next = NULL;
RETURN_I32_LIST_POP_FRONT: RETURN_I32_LIST_POP_FRONT:
return output; return output;
} }
GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size) { GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size) {
wapp_debug_assert(list != NULL, "`list` should not be NULL"); wapp_debug_assert(list != NULL, "`list` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
GenericNode *output = NULL; GenericNode *output = NULL;
if (list->node_count == 0) { if (list->node_count == 0) {
goto RETURN_I32_LIST_POP_BACK; goto RETURN_I32_LIST_POP_BACK;
} }
output = list->last; output = list->last;
if (list->node_count == 1) { if (list->node_count == 1) {
*list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size}; *list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size};
goto RETURN_I32_LIST_POP_BACK; goto RETURN_I32_LIST_POP_BACK;
} }
--(list->node_count); --(list->node_count);
list->last = output->prev; list->last = output->prev;
output->prev = output->next = NULL; output->prev = output->next = NULL;
RETURN_I32_LIST_POP_BACK: RETURN_I32_LIST_POP_BACK:
return output; return output;
} }
GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size) { GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size) {
wapp_debug_assert(list != NULL, "`list` should not be NULL"); wapp_debug_assert(list != NULL, "`list` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
GenericNode *output = NULL; GenericNode *output = NULL;
if (index == 0) { if (index == 0) {
output = _dbl_list_pop_front(list, item_size); output = _dbl_list_pop_front(list, item_size);
goto RETURN_I32_LIST_REMOVE; goto RETURN_I32_LIST_REMOVE;
} else if (index == list->node_count) { } else if (index == list->node_count) {
output = _dbl_list_pop_back(list, item_size); output = _dbl_list_pop_back(list, item_size);
goto RETURN_I32_LIST_REMOVE; goto RETURN_I32_LIST_REMOVE;
} }
output = _dbl_list_get(list, index, item_size); output = _dbl_list_get(list, index, item_size);
if (!output) { if (!output) {
goto RETURN_I32_LIST_REMOVE; goto RETURN_I32_LIST_REMOVE;
} }
output->prev->next = output->next; output->prev->next = output->next;
output->next->prev = output->prev; output->next->prev = output->prev;
--(list->node_count); --(list->node_count);
output->prev = output->next = NULL; output->prev = output->next = NULL;
RETURN_I32_LIST_REMOVE: RETURN_I32_LIST_REMOVE:
return output; return output;
} }
void _dbl_list_empty(GenericList *list, u64 item_size) { void _dbl_list_empty(GenericList *list, u64 item_size) {
wapp_debug_assert(list != NULL, "`list` should not be NULL"); wapp_debug_assert(list != NULL, "`list` should not be NULL");
_dbl_list_validate(list, item_size); _dbl_list_validate(list, item_size);
u64 count = list->node_count; u64 count = list->node_count;
for (u64 i = 0; i < count; ++i) { for (u64 i = 0; i < count; ++i) {
_dbl_list_pop_back(list, item_size); _dbl_list_pop_back(list, item_size);
} }
} }
wapp_intern GenericList _node_to_list(GenericNode *node, u64 item_size) { wapp_intern GenericList _node_to_list(GenericNode *node, u64 item_size) {
GenericList output = { GenericList output = {
.magic = WAPP_DBL_LIST_MAGIC, .magic = WAPP_DBL_LIST_MAGIC,
.first = node, .first = node,
.last = node, .last = node,
.node_count = 1, .node_count = 1,
.item_size = item_size, .item_size = item_size,
}; };
while (output.first->prev != NULL) { while (output.first->prev != NULL) {
output.first = output.first->prev; output.first = output.first->prev;
++(output.node_count); ++(output.node_count);
} }
while (output.last->next != NULL) { while (output.last->next != NULL) {
output.last = output.last->next; output.last = output.last->next;
++(output.node_count); ++(output.node_count);
} }
return output; return output;
} }
wapp_intern void _dbl_list_validate(const GenericList *list, u64 item_size) { wapp_intern void _dbl_list_validate(const GenericList *list, u64 item_size) {
wapp_runtime_assert(list->magic == WAPP_DBL_LIST_MAGIC, "`list` isn't a valid wapp list type"); wapp_runtime_assert(list->magic == WAPP_DBL_LIST_MAGIC, "`list` isn't a valid wapp list type");
wapp_runtime_assert(list->item_size == item_size, "Invalid item provided"); wapp_runtime_assert(list->item_size == item_size, "Invalid item provided");
} }
wapp_intern void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size) { wapp_intern void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size) {
wapp_runtime_assert(node->magic == WAPP_DBL_NODE_MAGIC, "`node` isn't a valid wapp node type"); wapp_runtime_assert(node->magic == WAPP_DBL_NODE_MAGIC, "`node` isn't a valid wapp node type");
wapp_runtime_assert(list->item_size == node->item_size, "Mismatched `list` and `node` types"); wapp_runtime_assert(list->item_size == node->item_size, "Mismatched `list` and `node` types");
wapp_runtime_assert(node->item_size == item_size, "Invalid item provided"); wapp_runtime_assert(node->item_size == item_size, "Invalid item provided");
} }

View File

@@ -14,94 +14,94 @@ BEGIN_C_LINKAGE
#define WAPP_DBL_LIST_MAGIC (u64)0x57415f444c5354 #define WAPP_DBL_LIST_MAGIC (u64)0x57415f444c5354
#define WAPP_DBL_NODE_MAGIC (u64)0x57415f444e44 #define WAPP_DBL_NODE_MAGIC (u64)0x57415f444e44
#define WAPP_DEF_DBL_LIST_TYPE(T, NODE_NAME, LIST_NAME) \ #define WAPP_DEF_DBL_LIST_TYPE(T, NODE_NAME, LIST_NAME) \
typedef struct NODE_NAME NODE_NAME; \ typedef struct NODE_NAME NODE_NAME; \
struct NODE_NAME { \ struct NODE_NAME { \
u64 magic; \ u64 magic; \
T *item; \ T *item; \
NODE_NAME *prev; \ NODE_NAME *prev; \
NODE_NAME *next; \ NODE_NAME *next; \
u64 item_size; \ u64 item_size; \
}; \ }; \
\ \
typedef struct { \ typedef struct { \
u64 magic; \ u64 magic; \
NODE_NAME *first; \ NODE_NAME *first; \
NODE_NAME *last; \ NODE_NAME *last; \
u64 node_count; \ u64 node_count; \
u64 item_size; \ u64 item_size; \
} LIST_NAME } LIST_NAME
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP
#define wapp_dbl_list(ELEM_TYPE, LIST_TYPE) \ #define wapp_dbl_list(ELEM_TYPE, LIST_TYPE) \
LIST_TYPE{WAPP_DBL_LIST_MAGIC, nullptr, nullptr, 0, sizeof(ELEM_TYPE)} LIST_TYPE{WAPP_DBL_LIST_MAGIC, nullptr, nullptr, 0, sizeof(ELEM_TYPE)}
#define wapp_dbl_list_node(ELEM_TYPE, NODE_TYPE, ELEM_PTR) \ #define wapp_dbl_list_node(ELEM_TYPE, NODE_TYPE, ELEM_PTR) \
NODE_TYPE{WAPP_DBL_NODE_MAGIC, ELEM_PTR, nullptr, nullptr, sizeof(ELEM_TYPE)} NODE_TYPE{WAPP_DBL_NODE_MAGIC, ELEM_PTR, nullptr, nullptr, sizeof(ELEM_TYPE)}
#else #else
#define wapp_dbl_list(ELEM_TYPE, LIST_TYPE) ( \ #define wapp_dbl_list(ELEM_TYPE, LIST_TYPE) ( \
(LIST_TYPE){.magic = WAPP_DBL_LIST_MAGIC, .item_size = sizeof(ELEM_TYPE)} \ (LIST_TYPE){.magic = WAPP_DBL_LIST_MAGIC, .item_size = sizeof(ELEM_TYPE)} \
) )
#define wapp_dbl_list_node(ELEM_TYPE, NODE_TYPE, ELEM_PTR) ( \ #define wapp_dbl_list_node(ELEM_TYPE, NODE_TYPE, ELEM_PTR) ( \
(NODE_TYPE){.magic = WAPP_DBL_NODE_MAGIC, .item = ELEM_PTR, .item_size = sizeof(ELEM_TYPE)} \ (NODE_TYPE){.magic = WAPP_DBL_NODE_MAGIC, .item = ELEM_PTR, .item_size = sizeof(ELEM_TYPE)} \
) )
#endif // !WAPP_PLATFORM_CPP #endif // !WAPP_PLATFORM_CPP
#define wapp_dbl_list_alloc(ELEM_TYPE, LIST_TYPE, ALLOCATOR) \ #define wapp_dbl_list_alloc(ELEM_TYPE, LIST_TYPE, ALLOCATOR) \
(LIST_TYPE *)_dbl_list_alloc(ALLOCATOR, sizeof(ELEM_TYPE)) (LIST_TYPE *)_dbl_list_alloc(ALLOCATOR, sizeof(ELEM_TYPE))
#define wapp_dbl_list_node_alloc(ELEM_TYPE, NODE_TYPE, ALLOCATOR) \ #define wapp_dbl_list_node_alloc(ELEM_TYPE, NODE_TYPE, ALLOCATOR) \
(NODE_TYPE *)_dbl_list_node_alloc(ALLOCATOR, sizeof(ELEM_TYPE)) (NODE_TYPE *)_dbl_list_node_alloc(ALLOCATOR, sizeof(ELEM_TYPE))
#define wapp_dbl_list_get(ELEM_TYPE, NODE_TYPE, LIST_PTR, ELEM_INDEX) \ #define wapp_dbl_list_get(ELEM_TYPE, NODE_TYPE, LIST_PTR, ELEM_INDEX) \
(NODE_TYPE *)_dbl_list_get((GenericList *)LIST_PTR, ELEM_INDEX, sizeof(ELEM_TYPE)) (NODE_TYPE *)_dbl_list_get((GenericList *)LIST_PTR, ELEM_INDEX, sizeof(ELEM_TYPE))
#define wapp_dbl_list_push_front(ELEM_TYPE, LIST_PTR, NODE_PTR) \ #define wapp_dbl_list_push_front(ELEM_TYPE, LIST_PTR, NODE_PTR) \
_dbl_list_push_front((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, sizeof(ELEM_TYPE)) _dbl_list_push_front((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, sizeof(ELEM_TYPE))
#define wapp_dbl_list_push_back(ELEM_TYPE, LIST_PTR, NODE_PTR) \ #define wapp_dbl_list_push_back(ELEM_TYPE, LIST_PTR, NODE_PTR) \
_dbl_list_push_back((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, sizeof(ELEM_TYPE)) _dbl_list_push_back((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, sizeof(ELEM_TYPE))
#define wapp_dbl_list_insert(ELEM_TYPE, LIST_PTR, NODE_PTR, ELEM_INDEX) \ #define wapp_dbl_list_insert(ELEM_TYPE, LIST_PTR, NODE_PTR, ELEM_INDEX) \
_dbl_list_insert((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, ELEM_INDEX, sizeof(ELEM_TYPE)) _dbl_list_insert((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, ELEM_INDEX, sizeof(ELEM_TYPE))
#define wapp_dbl_list_pop_front(ELEM_TYPE, NODE_TYPE, LIST_PTR) \ #define wapp_dbl_list_pop_front(ELEM_TYPE, NODE_TYPE, LIST_PTR) \
(NODE_TYPE *)_dbl_list_pop_front((GenericList *)LIST_PTR, sizeof(ELEM_TYPE)) (NODE_TYPE *)_dbl_list_pop_front((GenericList *)LIST_PTR, sizeof(ELEM_TYPE))
#define wapp_dbl_list_pop_back(ELEM_TYPE, NODE_TYPE, LIST_PTR) \ #define wapp_dbl_list_pop_back(ELEM_TYPE, NODE_TYPE, LIST_PTR) \
(NODE_TYPE *)_dbl_list_pop_back((GenericList *)LIST_PTR, sizeof(ELEM_TYPE)) (NODE_TYPE *)_dbl_list_pop_back((GenericList *)LIST_PTR, sizeof(ELEM_TYPE))
#define wapp_dbl_list_remove(ELEM_TYPE, NODE_TYPE, LIST_PTR, ELEM_INDEX) \ #define wapp_dbl_list_remove(ELEM_TYPE, NODE_TYPE, LIST_PTR, ELEM_INDEX) \
(NODE_TYPE *)_dbl_list_remove((GenericList *)LIST_PTR, ELEM_INDEX, sizeof(ELEM_TYPE)) (NODE_TYPE *)_dbl_list_remove((GenericList *)LIST_PTR, ELEM_INDEX, sizeof(ELEM_TYPE))
#define wapp_dbl_list_empty(ELEM_TYPE, LIST_PTR) \ #define wapp_dbl_list_empty(ELEM_TYPE, LIST_PTR) \
_dbl_list_empty((GenericList *)LIST_PTR, sizeof(ELEM_TYPE)) _dbl_list_empty((GenericList *)LIST_PTR, sizeof(ELEM_TYPE))
WAPP_DEF_DBL_LIST_TYPE(void, GenericNode, GenericList); WAPP_DEF_DBL_LIST_TYPE(void, GenericNode, GenericList);
GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size); GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size);
GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size); GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size);
GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size); GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size);
void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size); void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size);
void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size); void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size);
void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size); void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size);
GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size); GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size);
GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size); GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size);
GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size); GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size);
void _dbl_list_empty(GenericList *list, u64 item_size); void _dbl_list_empty(GenericList *list, u64 item_size);
// Base list types // Base list types
typedef struct str8 Str8; typedef struct str8 Str8;
WAPP_DEF_DBL_LIST_TYPE(void *, VoidPtrNode, VoidPtrList); WAPP_DEF_DBL_LIST_TYPE(void * , VoidPtrNode , VoidPtrList);
WAPP_DEF_DBL_LIST_TYPE(c8 , C8Node , C8List); WAPP_DEF_DBL_LIST_TYPE(c8 , C8Node , C8List);
WAPP_DEF_DBL_LIST_TYPE(c16 , C16Node , C16List); WAPP_DEF_DBL_LIST_TYPE(c16 , C16Node , C16List);
WAPP_DEF_DBL_LIST_TYPE(c32 , C32Node , C32List); WAPP_DEF_DBL_LIST_TYPE(c32 , C32Node , C32List);
WAPP_DEF_DBL_LIST_TYPE(u8 , U8Node , U8List); WAPP_DEF_DBL_LIST_TYPE(u8 , U8Node , U8List);
WAPP_DEF_DBL_LIST_TYPE(u16 , U16Node , U16List); WAPP_DEF_DBL_LIST_TYPE(u16 , U16Node , U16List);
WAPP_DEF_DBL_LIST_TYPE(u32 , U32Node , U32List); WAPP_DEF_DBL_LIST_TYPE(u32 , U32Node , U32List);
WAPP_DEF_DBL_LIST_TYPE(u64 , U64Node , U64List); WAPP_DEF_DBL_LIST_TYPE(u64 , U64Node , U64List);
WAPP_DEF_DBL_LIST_TYPE(b8 , B8Node , B8List); WAPP_DEF_DBL_LIST_TYPE(b8 , B8Node , B8List);
WAPP_DEF_DBL_LIST_TYPE(i8 , I8Node , I8List); WAPP_DEF_DBL_LIST_TYPE(i8 , I8Node , I8List);
WAPP_DEF_DBL_LIST_TYPE(i16 , I16Node , I16List); WAPP_DEF_DBL_LIST_TYPE(i16 , I16Node , I16List);
WAPP_DEF_DBL_LIST_TYPE(i32 , I32Node , I32List); WAPP_DEF_DBL_LIST_TYPE(i32 , I32Node , I32List);
WAPP_DEF_DBL_LIST_TYPE(i64 , I64Node , I64List); WAPP_DEF_DBL_LIST_TYPE(i64 , I64Node , I64List);
WAPP_DEF_DBL_LIST_TYPE(f32 , F32Node , F32List); WAPP_DEF_DBL_LIST_TYPE(f32 , F32Node , F32List);
WAPP_DEF_DBL_LIST_TYPE(f64 , F64Node , F64List); WAPP_DEF_DBL_LIST_TYPE(f64 , F64Node , F64List);
WAPP_DEF_DBL_LIST_TYPE(f128 , F128Node , F128List); WAPP_DEF_DBL_LIST_TYPE(f128 , F128Node , F128List);
WAPP_DEF_DBL_LIST_TYPE(uptr , UptrNode , UptrList); WAPP_DEF_DBL_LIST_TYPE(uptr , UptrNode , UptrList);
WAPP_DEF_DBL_LIST_TYPE(iptr , IptrNode , IptrList); WAPP_DEF_DBL_LIST_TYPE(iptr , IptrNode , IptrList);
WAPP_DEF_DBL_LIST_TYPE(Str8 , Str8Node , Str8List); WAPP_DEF_DBL_LIST_TYPE(Str8 , Str8Node , Str8List);
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE END_C_LINKAGE

View File

@@ -6,30 +6,30 @@
#include <stdlib.h> #include <stdlib.h>
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) { void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) {
wapp_debug_assert(allocator != NULL && (allocator->alloc) != NULL, "`allocator` and `allocator->alloc` should not be NULL"); wapp_debug_assert(allocator != NULL && (allocator->alloc) != NULL, "`allocator` and `allocator->alloc` should not be NULL");
return allocator->alloc(size, allocator->obj); return allocator->alloc(size, allocator->obj);
} }
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment) { void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment) {
wapp_debug_assert(allocator != NULL && (allocator->alloc_aligned) != NULL, "`allocator` and `allocator->alloc_aligned` should not be NULL"); wapp_debug_assert(allocator != NULL && (allocator->alloc_aligned) != NULL, "`allocator` and `allocator->alloc_aligned` should not be NULL");
return allocator->alloc_aligned(size, alignment, allocator->obj); return allocator->alloc_aligned(size, alignment, allocator->obj);
} }
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size) { void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size) {
wapp_debug_assert(allocator != NULL && (allocator->realloc) != NULL, "`allocator` and `allocator->realloc` should not be NULL"); wapp_debug_assert(allocator != NULL && (allocator->realloc) != NULL, "`allocator` and `allocator->realloc` should not be NULL");
return allocator->realloc(ptr, old_size, new_size, allocator->obj); return allocator->realloc(ptr, old_size, new_size, allocator->obj);
} }
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size, void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size,
u64 new_size, u64 alignment) { u64 new_size, u64 alignment) {
wapp_debug_assert(allocator != NULL && (allocator->realloc_aligned) != NULL, "`allocator` and `allocator->realloc_aligned` should not be NULL"); wapp_debug_assert(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); return allocator->realloc_aligned(ptr, old_size, new_size, alignment, allocator->obj);
} }
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size) { void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size) {
if (!allocator || !(allocator->free)) { if (!allocator || !(allocator->free)) {
return; return;
} }
allocator->free(ptr, size, allocator->obj); allocator->free(ptr, size, allocator->obj);
} }

View File

@@ -11,26 +11,26 @@
BEGIN_C_LINKAGE BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP #endif // !WAPP_PLATFORM_CPP
typedef void *(MemAllocFunc)(u64 size, void *alloc_obj); typedef void *(MemAllocFunc)(u64 size, void *alloc_obj);
typedef void *(MemAllocAlignedFunc)(u64 size, u64 alignment, void *alloc_obj); typedef void *(MemAllocAlignedFunc)(u64 size, u64 alignment, void *alloc_obj);
typedef void *(MemReallocFunc)(void *ptr, u64 old_size, u64 new_size, void *alloc_obj); typedef void *(MemReallocFunc)(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
typedef void *(MemReallocAlignedFunc)(void *ptr, u64 old_size, u64 new_size, u64 alignment, void *alloc_obj); typedef void *(MemReallocAlignedFunc)(void *ptr, u64 old_size, u64 new_size, u64 alignment, void *alloc_obj);
typedef void (MemFreeFunc)(void **ptr, u64 size, void *alloc_obj); typedef void (MemFreeFunc)(void **ptr, u64 size, void *alloc_obj);
typedef struct allocator Allocator; typedef struct allocator Allocator;
struct allocator { struct allocator {
void *obj; void *obj;
MemAllocFunc *alloc; MemAllocFunc *alloc;
MemAllocAlignedFunc *alloc_aligned; MemAllocAlignedFunc *alloc_aligned;
MemReallocFunc *realloc; MemReallocFunc *realloc;
MemReallocAlignedFunc *realloc_aligned; MemReallocAlignedFunc *realloc_aligned;
MemFreeFunc *free; MemFreeFunc *free;
}; };
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP
#define wapp_mem_allocator_invalid(ALLOCATOR) ([&]() { \ #define wapp_mem_allocator_invalid(ALLOCATOR) ([&]() { \
Allocator alloc{}; \ Allocator alloc{}; \
return memcmp(ALLOCATOR, &alloc, sizeof(Allocator)) == 0; \ return memcmp(ALLOCATOR, &alloc, sizeof(Allocator)) == 0; \
}()) }())
#else #else
#define wapp_mem_allocator_invalid(ALLOCATOR) (memcmp(ALLOCATOR, &((Allocator){0}), sizeof(Allocator)) == 0) #define wapp_mem_allocator_invalid(ALLOCATOR) (memcmp(ALLOCATOR, &((Allocator){0}), sizeof(Allocator)) == 0)
@@ -40,7 +40,7 @@ void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size);
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment); void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment);
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size); void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size);
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size, void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size,
u64 new_size, u64 alignment); u64 new_size, u64 alignment);
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size); void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size);
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP

View File

@@ -8,19 +8,19 @@
wapp_intern b8 is_power_of_two(u64 num) { return (num & (num - 1)) == 0; } wapp_intern b8 is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) { void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
wapp_debug_assert(ptr != NULL, "`ptr` should not be NULL"); wapp_debug_assert(ptr != NULL, "`ptr` should not be NULL");
wapp_runtime_assert(is_power_of_two(alignment), "`alignment` value is not a power of two"); wapp_runtime_assert(is_power_of_two(alignment), "`alignment` value is not a power of two");
uptr p = (uptr)ptr; uptr p = (uptr)ptr;
uptr align = (uptr)alignment; uptr align = (uptr)alignment;
// Similar to p % align, but it's a faster implementation that works fine // Similar to p % align, but it's a faster implementation that works fine
// because align is guaranteed to be a power of 2 // because align is guaranteed to be a power of 2
uptr modulo = p & (align - 1); uptr modulo = p & (align - 1);
if (modulo != 0) { if (modulo != 0) {
p += align - modulo; p += align - modulo;
} }
return (void *)p; return (void *)p;
} }

View File

@@ -14,479 +14,479 @@
#define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(Str8) + sizeof(c8) * CAPACITY) #define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(Str8) + sizeof(c8) * CAPACITY)
Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity) { Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
Str8 *str = wapp_mem_allocator_alloc(allocator, STR8_BUF_ALLOC_SIZE(capacity)); Str8 *str = wapp_mem_allocator_alloc(allocator, STR8_BUF_ALLOC_SIZE(capacity));
if (!str) { if (!str) {
goto RETURN_STR8; goto RETURN_STR8;
} }
str->buf = (u8 *)str + sizeof(Str8); str->buf = (u8 *)str + sizeof(Str8);
str->size = 0; str->size = 0;
str->capacity = capacity; str->capacity = capacity;
RETURN_STR8: RETURN_STR8:
return str; return str;
} }
Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity) { Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity) {
Str8 *out = wapp_str8_alloc_buf(allocator, capacity); Str8 *out = wapp_str8_alloc_buf(allocator, capacity);
if (out) { if (out) {
memset(out->buf, 0, capacity); memset(out->buf, 0, capacity);
out->size = capacity; out->size = capacity;
} }
return out; return out;
} }
Str8 *wapp_str8_alloc_cstr(const Allocator *allocator, const char *str) { Str8 *wapp_str8_alloc_cstr(const Allocator *allocator, const char *str) {
wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
u64 length = strlen(str); u64 length = strlen(str);
Str8 *output = wapp_str8_alloc_buf(allocator, length * 2); Str8 *output = wapp_str8_alloc_buf(allocator, length * 2);
if (!output) { if (!output) {
goto RETURN_ALLOC_CSTR; goto RETURN_ALLOC_CSTR;
} }
output->size = length; output->size = length;
memcpy(output->buf, str, length); memcpy(output->buf, str, length);
RETURN_ALLOC_CSTR: RETURN_ALLOC_CSTR:
return output; return output;
} }
Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str) { Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str) {
wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
Str8 *output = wapp_str8_alloc_buf(allocator, str->capacity); Str8 *output = wapp_str8_alloc_buf(allocator, str->capacity);
if (!output) { if (!output) {
goto RETURN_ALLOC_STR8; goto RETURN_ALLOC_STR8;
} }
output->size = str->size; output->size = str->size;
memcpy(output->buf, str->buf, str->size); memcpy(output->buf, str->buf, str->size);
RETURN_ALLOC_STR8: RETURN_ALLOC_STR8:
return output; return output;
} }
Str8 *wapp_str8_alloc_substr(const Allocator *allocator, Str8RO *str, u64 start, u64 end) { Str8 *wapp_str8_alloc_substr(const Allocator *allocator, Str8RO *str, u64 start, u64 end) {
wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
Str8 *output = NULL; Str8 *output = NULL;
if (start >= str->size || start >= end) { if (start >= str->size || start >= end) {
goto RETURN_ALLOC_SUBSTR; goto RETURN_ALLOC_SUBSTR;
} }
if (end > str->size) { if (end > str->size) {
end = str->size; end = str->size;
} }
output = wapp_str8_alloc_buf(allocator, str->capacity); output = wapp_str8_alloc_buf(allocator, str->capacity);
if (!output) { if (!output) {
goto RETURN_ALLOC_SUBSTR; goto RETURN_ALLOC_SUBSTR;
} }
output->size = end - start; output->size = end - start;
memcpy(output->buf, str->buf + start, output->size); memcpy(output->buf, str->buf + start, output->size);
RETURN_ALLOC_SUBSTR: RETURN_ALLOC_SUBSTR:
return output; return output;
} }
void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str) { void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str) {
wapp_debug_assert(allocator != NULL && str != NULL && (*str) != NULL, "Either `allocator` is NULL or `str` is an invalid double pointer"); wapp_debug_assert(allocator != NULL && str != NULL && (*str) != NULL, "Either `allocator` is NULL or `str` is an invalid double pointer");
wapp_mem_allocator_free(allocator, (void **)str, STR8_BUF_ALLOC_SIZE((*str)->capacity)); wapp_mem_allocator_free(allocator, (void **)str, STR8_BUF_ALLOC_SIZE((*str)->capacity));
} }
c8 wapp_str8_get(const Str8 *str, u64 index) { c8 wapp_str8_get(const Str8 *str, u64 index) {
if (index >= str->size) { if (index >= str->size) {
return '\0'; return '\0';
} }
return str->buf[index]; return str->buf[index];
} }
void wapp_str8_set(Str8 *str, u64 index, c8 c) { void wapp_str8_set(Str8 *str, u64 index, c8 c) {
if (index >= str->size) { if (index >= str->size) {
return; return;
} }
str->buf[index] = c; str->buf[index] = c;
} }
void wapp_str8_push_back(Str8 *str, c8 c) { void wapp_str8_push_back(Str8 *str, c8 c) {
if (!(str->size < str->capacity)) { if (!(str->size < str->capacity)) {
return; return;
} }
u64 index = (str->size)++; u64 index = (str->size)++;
wapp_str8_set(str, index, c); wapp_str8_set(str, index, c);
} }
b8 wapp_str8_equal(Str8RO *s1, Str8RO *s2) { b8 wapp_str8_equal(Str8RO *s1, Str8RO *s2) {
if (s1->size != s2->size) { if (s1->size != s2->size) {
return false; return false;
} }
return wapp_str8_equal_to_count(s1, s2, s1->size); return wapp_str8_equal_to_count(s1, s2, s1->size);
} }
b8 wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count) { b8 wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count) {
if (!s1 || !s2) { if (!s1 || !s2) {
return false; return false;
} }
return memcmp(s1->buf, s2->buf, count) == 0; return memcmp(s1->buf, s2->buf, count) == 0;
} }
Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end) { Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end) {
if (start >= str->size || start >= end) { if (start >= str->size || start >= end) {
start = str->size; start = str->size;
end = str->size; end = str->size;
} }
if (end > str->size) { if (end > str->size) {
end = str->size; end = str->size;
} }
return (Str8RO){ return (Str8RO){
.capacity = end - start, .capacity = end - start,
.size = end - start, .size = end - start,
.buf = str->buf + start, .buf = str->buf + start,
}; };
} }
Str8 *wapp_str8_alloc_concat(const Allocator *allocator, Str8 *dst, Str8RO *src) { Str8 *wapp_str8_alloc_concat(const Allocator *allocator, Str8 *dst, Str8RO *src) {
wapp_debug_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL"); wapp_debug_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
Str8 *output = NULL; Str8 *output = NULL;
u64 remaining = dst->capacity - dst->size; u64 remaining = dst->capacity - dst->size;
if (src->size <= remaining) { if (src->size <= remaining) {
output = dst; output = dst;
goto SOURCE_STRING_STR8_CONCAT; goto SOURCE_STRING_STR8_CONCAT;
} }
u64 capacity = dst->capacity + src->size; u64 capacity = dst->capacity + src->size;
output = wapp_str8_alloc_buf(allocator, capacity); output = wapp_str8_alloc_buf(allocator, capacity);
if (!output) { if (!output) {
goto RETURN_STR8_CONCAT; goto RETURN_STR8_CONCAT;
} }
wapp_str8_concat_capped(output, dst); wapp_str8_concat_capped(output, dst);
SOURCE_STRING_STR8_CONCAT: SOURCE_STRING_STR8_CONCAT:
wapp_str8_concat_capped(output, src); wapp_str8_concat_capped(output, src);
RETURN_STR8_CONCAT: RETURN_STR8_CONCAT:
return output; return output;
} }
void wapp_str8_concat_capped(Str8 *dst, Str8RO *src) { void wapp_str8_concat_capped(Str8 *dst, Str8RO *src) {
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
u64 remaining = dst->capacity - dst->size; u64 remaining = dst->capacity - dst->size;
u64 to_copy = remaining < src->size ? remaining : src->size; u64 to_copy = remaining < src->size ? remaining : src->size;
memcpy(dst->buf + dst->size, src->buf, to_copy); memcpy(dst->buf + dst->size, src->buf, to_copy);
dst->size += to_copy; dst->size += to_copy;
} }
void wapp_str8_copy_cstr_capped(Str8 *dst, const char *src) { void wapp_str8_copy_cstr_capped(Str8 *dst, const char *src) {
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
u64 length = strlen(src); u64 length = strlen(src);
u64 to_copy = length <= dst->capacity ? length : dst->capacity; u64 to_copy = length <= dst->capacity ? length : dst->capacity;
memset(dst->buf, 0, dst->size); memset(dst->buf, 0, dst->size);
memcpy(dst->buf, src, to_copy); memcpy(dst->buf, src, to_copy);
dst->size = to_copy; dst->size = to_copy;
} }
void wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src) { void wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src) {
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
u64 to_copy = src->size <= dst->capacity ? src->size : dst->capacity; u64 to_copy = src->size <= dst->capacity ? src->size : dst->capacity;
memset(dst->buf, 0, dst->size); memset(dst->buf, 0, dst->size);
memcpy(dst->buf, src->buf, to_copy); memcpy(dst->buf, src->buf, to_copy);
dst->size = to_copy; dst->size = to_copy;
} }
void wapp_str8_copy_to_cstr(char *dst, Str8RO *src, u64 dst_capacity) { void wapp_str8_copy_to_cstr(char *dst, Str8RO *src, u64 dst_capacity) {
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
u64 to_copy = src->size < dst_capacity ? src->size : dst_capacity - 1; u64 to_copy = src->size < dst_capacity ? src->size : dst_capacity - 1;
memset(dst, 0, dst_capacity); memset(dst, 0, dst_capacity);
memcpy(dst, src->buf, to_copy); memcpy(dst, src->buf, to_copy);
} }
void wapp_str8_format(Str8 *dst, const char *format, ...) { void wapp_str8_format(Str8 *dst, const char *format, ...) {
wapp_debug_assert(dst != NULL && format != NULL, "`dst` and `format` should not be NULL"); wapp_debug_assert(dst != NULL && format != NULL, "`dst` and `format` should not be NULL");
va_list args1; va_list args1;
va_list args2; va_list args2;
va_start(args1, format); va_start(args1, format);
va_copy(args2, args1); va_copy(args2, args1);
u64 total_size = vsnprintf(NULL, 0, format, args1); u64 total_size = vsnprintf(NULL, 0, format, args1);
dst->size = total_size <= dst->capacity ? total_size : dst->capacity; dst->size = total_size <= dst->capacity ? total_size : dst->capacity;
vsnprintf((char *)(dst->buf), dst->capacity, format, args2); vsnprintf((char *)(dst->buf), dst->capacity, format, args2);
va_end(args1); va_end(args1);
va_end(args2); va_end(args2);
} }
void wapp_str8_to_lower(Str8 *dst, Str8RO *src) { void wapp_str8_to_lower(Str8 *dst, Str8RO *src) {
wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
wapp_debug_assert(dst->capacity >= src->capacity, "`dst` does not have enough capacity"); wapp_debug_assert(dst->capacity >= src->capacity, "`dst` does not have enough capacity");
dst->size = src->size; dst->size = src->size;
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
u64 index = 0; u64 index = 0;
b8 running = true; b8 running = true;
while (running) { while (running) {
wapp_str8_set(dst, index, (u8)tolower(wapp_str8_get(src, index))); wapp_str8_set(dst, index, (u8)tolower(wapp_str8_get(src, index)));
++index; ++index;
running = index < src->size; running = index < src->size;
} }
} }
void wapp_str8_to_upper(Str8 *dst, Str8RO *src) { void wapp_str8_to_upper(Str8 *dst, Str8RO *src) {
wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
wapp_debug_assert(dst->capacity >= src->capacity, "`dst` does not have enough capacity"); wapp_debug_assert(dst->capacity >= src->capacity, "`dst` does not have enough capacity");
dst->size = src->size; dst->size = src->size;
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
u64 index = 0; u64 index = 0;
b8 running = true; b8 running = true;
while (running) { while (running) {
wapp_str8_set(dst, index, (u8)toupper(wapp_str8_get(src, index))); wapp_str8_set(dst, index, (u8)toupper(wapp_str8_get(src, index)));
++index; ++index;
running = index < src->size; running = index < src->size;
} }
} }
void wapp_str8_from_bytes(Str8 *dst, const U8Array *src) { void wapp_str8_from_bytes(Str8 *dst, const U8Array *src) {
wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL"); wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
u64 size = src->count * src->item_size; u64 size = src->count * src->item_size;
wapp_debug_assert(dst->capacity >= size, "`dst` does not have enough capacity"); wapp_debug_assert(dst->capacity >= size, "`dst` does not have enough capacity");
dst->size = size; dst->size = size;
memcpy(dst->buf, src->items, size); memcpy(dst->buf, src->items, size);
} }
i64 wapp_str8_find(Str8RO *str, Str8RO substr) { i64 wapp_str8_find(Str8RO *str, Str8RO substr) {
if (!str || substr.size > str->size) { if (!str || substr.size > str->size) {
return -1; return -1;
} }
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
u64 char_index = 0; u64 char_index = 0;
b8 running = char_index < str->size; b8 running = char_index < str->size;
while (running) { while (running) {
const c8 *sub = str->buf + char_index; const c8 *sub = str->buf + char_index;
if (memcmp(sub, substr.buf, substr.size) == 0) { if (memcmp(sub, substr.buf, substr.size) == 0) {
return char_index; return char_index;
} }
++char_index; ++char_index;
running = char_index < str->size; running = char_index < str->size;
} }
return -1; return -1;
} }
i64 wapp_str8_rfind(Str8RO *str, Str8RO substr) { i64 wapp_str8_rfind(Str8RO *str, Str8RO substr) {
if (!str || substr.size > str->size) { if (!str || substr.size > str->size) {
return -1; return -1;
} }
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
i64 char_index = str->size - substr.size; i64 char_index = str->size - substr.size;
b8 running = char_index >= 0; b8 running = char_index >= 0;
while (running) { while (running) {
const c8 *sub = str->buf + char_index; const c8 *sub = str->buf + char_index;
if (memcmp(sub, substr.buf, substr.size) == 0) { if (memcmp(sub, substr.buf, substr.size) == 0) {
return char_index; return char_index;
} }
--char_index; --char_index;
running = char_index >= 0; running = char_index >= 0;
} }
return -1; return -1;
} }
Str8List *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) { Str8List *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) {
wapp_debug_assert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL"); wapp_debug_assert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL");
Str8List *output = wapp_dbl_list_alloc(Str8, Str8List, allocator); Str8List *output = wapp_dbl_list_alloc(Str8, Str8List, allocator);
if (delimiter->size > str->size) { if (delimiter->size > str->size) {
Str8 *full = wapp_str8_alloc_str8(allocator, str); Str8 *full = wapp_str8_alloc_str8(allocator, str);
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator); Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
if (node) { if (node) {
node->item = full; node->item = full;
wapp_dbl_list_push_back(Str8, output, node); wapp_dbl_list_push_back(Str8, output, node);
} }
goto RETURN_STR8_SPLIT; goto RETURN_STR8_SPLIT;
} }
i64 start = 0; i64 start = 0;
i64 end = 0; i64 end = 0;
i64 splits = 0; i64 splits = 0;
Str8 *rest = wapp_str8_alloc_str8(allocator, str); Str8 *rest = wapp_str8_alloc_str8(allocator, str);
Str8 *before_str; Str8 *before_str;
while ((end = wapp_str8_find(rest, *delimiter)) != -1) { while ((end = wapp_str8_find(rest, *delimiter)) != -1) {
if (max_splits > 0 && splits >= max_splits) { if (max_splits > 0 && splits >= max_splits) {
break; break;
} }
before_str = wapp_str8_alloc_substr(allocator, str, start, start + end); before_str = wapp_str8_alloc_substr(allocator, str, start, start + end);
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator); Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
if (node && before_str) { if (node && before_str) {
node->item = before_str; node->item = before_str;
wapp_dbl_list_push_back(Str8, output, node); wapp_dbl_list_push_back(Str8, output, node);
} }
wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8)); wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8));
rest = wapp_str8_alloc_substr(allocator, str, start + end + delimiter->size, str->size); rest = wapp_str8_alloc_substr(allocator, str, start + end + delimiter->size, str->size);
start += end + delimiter->size; start += end + delimiter->size;
++splits; ++splits;
} }
// Ensure the last part of the string after the delimiter is added to the list // Ensure the last part of the string after the delimiter is added to the list
rest = wapp_str8_alloc_substr(allocator, str, start, str->size); rest = wapp_str8_alloc_substr(allocator, str, start, str->size);
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator); Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
if (node && rest) { if (node && rest) {
node->item = rest; node->item = rest;
wapp_dbl_list_push_back(Str8, output, node); wapp_dbl_list_push_back(Str8, output, node);
} }
RETURN_STR8_SPLIT: RETURN_STR8_SPLIT:
return output; return output;
} }
Str8List *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) { Str8List *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) {
wapp_debug_assert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL"); wapp_debug_assert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL");
Str8List *output = wapp_dbl_list_alloc(Str8, Str8List, allocator); Str8List *output = wapp_dbl_list_alloc(Str8, Str8List, allocator);
if (delimiter->size > str->size) { if (delimiter->size > str->size) {
Str8 *full = wapp_str8_alloc_str8(allocator, str); Str8 *full = wapp_str8_alloc_str8(allocator, str);
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator); Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
if (node && full) { if (node && full) {
node->item = full; node->item = full;
wapp_dbl_list_push_back(Str8, output, node); wapp_dbl_list_push_back(Str8, output, node);
} }
goto RETURN_STR8_SPLIT; goto RETURN_STR8_SPLIT;
} }
i64 end = 0; i64 end = 0;
i64 splits = 0; i64 splits = 0;
Str8 *rest = wapp_str8_alloc_str8(allocator, str); Str8 *rest = wapp_str8_alloc_str8(allocator, str);
Str8 *after_str; Str8 *after_str;
while ((end = wapp_str8_rfind(rest, *delimiter)) != -1) { while ((end = wapp_str8_rfind(rest, *delimiter)) != -1) {
if (max_splits > 0 && splits >= max_splits) { if (max_splits > 0 && splits >= max_splits) {
break; break;
} }
after_str = wapp_str8_alloc_substr(allocator, rest, end + delimiter->size, str->size); after_str = wapp_str8_alloc_substr(allocator, rest, end + delimiter->size, str->size);
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator); Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
if (node) { if (node) {
node->item = after_str; node->item = after_str;
wapp_dbl_list_push_front(Str8, output, node); wapp_dbl_list_push_front(Str8, output, node);
} }
wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8)); wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8));
rest = wapp_str8_alloc_substr(allocator, rest, 0, end); rest = wapp_str8_alloc_substr(allocator, rest, 0, end);
++splits; ++splits;
} }
rest = wapp_str8_alloc_substr(allocator, str, 0, rest->size); rest = wapp_str8_alloc_substr(allocator, str, 0, rest->size);
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator); Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
if (node && rest) { if (node && rest) {
node->item = rest; node->item = rest;
wapp_dbl_list_push_front(Str8, output, node); wapp_dbl_list_push_front(Str8, output, node);
} }
RETURN_STR8_SPLIT: RETURN_STR8_SPLIT:
return output; return output;
} }
Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter) { Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter) {
wapp_debug_assert(allocator != NULL && list != NULL && delimiter != NULL, "`allocator`, `list` and `delimiter` should not be NULL"); wapp_debug_assert(allocator != NULL && list != NULL && delimiter != NULL, "`allocator`, `list` and `delimiter` should not be NULL");
u64 capacity = wapp_str8_list_total_size(list) + (delimiter->size * (list->node_count - 1)); u64 capacity = wapp_str8_list_total_size(list) + (delimiter->size * (list->node_count - 1));
Str8 *output = wapp_str8_alloc_buf(allocator, capacity * 2); Str8 *output = wapp_str8_alloc_buf(allocator, capacity * 2);
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
Str8Node *node; Str8Node *node;
u64 node_index = 0; u64 node_index = 0;
b8 running = node_index < list->node_count; b8 running = node_index < list->node_count;
while (running) { while (running) {
node = wapp_dbl_list_get(Str8, Str8Node, list, node_index); node = wapp_dbl_list_get(Str8, Str8Node, list, node_index);
if (!node) { if (!node) {
break; break;
} }
wapp_str8_concat_capped(output, node->item); wapp_str8_concat_capped(output, node->item);
// NOTE (Abdelrahman): Comparison extracted to variable to silence // NOTE (Abdelrahman): Comparison extracted to variable to silence
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
b8 not_last = node_index + 1 < list->node_count; b8 not_last = node_index + 1 < list->node_count;
if (not_last) { if (not_last) {
wapp_str8_concat_capped(output, delimiter); wapp_str8_concat_capped(output, delimiter);
} }
++node_index; ++node_index;
running = node_index < list->node_count; running = node_index < list->node_count;
} }
return output; return output;
} }
u64 wapp_str8_list_total_size(const Str8List *list) { u64 wapp_str8_list_total_size(const Str8List *list) {
if (!list) { if (!list) {
return 0; return 0;
} }
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings // MSVC Spectre mitigation warnings
Str8Node* node; Str8Node* node;
u64 node_index = 0; u64 node_index = 0;
u64 output = 0; u64 output = 0;
b8 running = node_index < list->node_count; b8 running = node_index < list->node_count;
while (running) { while (running) {
node = wapp_dbl_list_get(Str8, Str8Node, list, node_index); node = wapp_dbl_list_get(Str8, Str8Node, list, node_index);
if (!node) { if (!node) {
break; break;
} }
output += node->item->size; output += node->item->size;
++node_index; ++node_index;
running = node_index < list->node_count; running = node_index < list->node_count;
} }
return output; return output;
} }

View File

@@ -17,9 +17,9 @@ BEGIN_C_LINKAGE
typedef struct str8 Str8; typedef struct str8 Str8;
struct str8 { struct str8 {
u64 capacity; u64 capacity;
u64 size; u64 size;
c8 *buf; c8 *buf;
}; };
typedef const Str8 Str8RO; typedef const Str8 Str8RO;
@@ -36,17 +36,17 @@ typedef const Str8 Str8RO;
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP
// Uses a lambda to achieve the same behaviour achieved by the C macro // Uses a lambda to achieve the same behaviour achieved by the C macro
#define wapp_str8_buf(CAPACITY) ([&](){ \ #define wapp_str8_buf(CAPACITY) ([&](){ \
wapp_persist c8 buf[CAPACITY] = {}; \ wapp_persist c8 buf[CAPACITY] = {}; \
memset(buf, 0, CAPACITY); \ memset(buf, 0, CAPACITY); \
return Str8{CAPACITY, 0, buf}; \ return Str8{CAPACITY, 0, buf}; \
}()) }())
// Uses a lambda to achieve the same behaviour achieved by the C macro // Uses a lambda to achieve the same behaviour achieved by the C macro
#define wapp_str8_lit(STRING) ([&]() { \ #define wapp_str8_lit(STRING) ([&]() { \
wapp_persist c8 buf[sizeof(STRING) * 2] = {}; \ wapp_persist c8 buf[sizeof(STRING) * 2] = {}; \
memcpy(buf, STRING, sizeof(STRING)); \ memcpy(buf, STRING, sizeof(STRING)); \
return Str8{(sizeof(STRING) - 1) * 2, sizeof(STRING) - 1, buf}; \ return Str8{(sizeof(STRING) - 1) * 2, sizeof(STRING) - 1, buf}; \
}()) }())
#define wapp_str8_lit_ro(STRING) Str8RO{sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING} #define wapp_str8_lit_ro(STRING) Str8RO{sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING}
@@ -56,29 +56,29 @@ typedef const Str8 Str8RO;
// Utilises the fact that memcpy returns pointer to dest buffer and that getting // 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 // address of compound literals is valid in C to create a string on the stack
#define wapp_str8_lit(STRING) ((Str8){.capacity = (sizeof(STRING) - 1) * 2, \ #define wapp_str8_lit(STRING) ((Str8){.capacity = (sizeof(STRING) - 1) * 2, \
.size = sizeof(STRING) - 1, \ .size = sizeof(STRING) - 1, \
.buf = memcpy(&((c8 [sizeof(STRING) * 2]){0}), STRING, sizeof(STRING))}) .buf = memcpy(&((c8 [sizeof(STRING) * 2]){0}), STRING, sizeof(STRING))})
#define wapp_str8_lit_ro(STRING) ((Str8RO){.capacity = sizeof(STRING) - 1, \ #define wapp_str8_lit_ro(STRING) ((Str8RO){.capacity = sizeof(STRING) - 1, \
.size = sizeof(STRING) - 1, \ .size = sizeof(STRING) - 1, \
.buf = (c8 *)STRING}) .buf = (c8 *)STRING})
// To be used only when initialising a static storage variable in compilers that don't support // To be used only when initialising a static storage variable in compilers that don't support
// initialisers with the syntax of wapp_str8_lit_ro (e.g. gcc). Should only be used when necessary // initialisers with the syntax of wapp_str8_lit_ro (e.g. gcc). Should only be used when necessary
// and only be assigned to a Str8RO variable to avoid any attempt at modifying the string // and only be assigned to a Str8RO variable to avoid any attempt at modifying the string
#define wapp_str8_lit_ro_initialiser_list(STRING) {.capacity = sizeof(STRING) - 1, \ #define wapp_str8_lit_ro_initialiser_list(STRING) {.capacity = sizeof(STRING) - 1, \
.size = sizeof(STRING) - 1, \ .size = sizeof(STRING) - 1, \
.buf = (c8 *)STRING} .buf = (c8 *)STRING}
#endif // !WAPP_PLATFORM_CPP #endif // !WAPP_PLATFORM_CPP
/** /**
* Str8 allocated buffers * Str8 allocated buffers
*/ */
Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity); Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity);
Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity); Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity);
Str8 *wapp_str8_alloc_cstr(const Allocator *allocator, const char *str); Str8 *wapp_str8_alloc_cstr(const Allocator *allocator, const char *str);
Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str); Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str);
Str8 *wapp_str8_alloc_substr(const Allocator *allocator, Str8RO *str, u64 start, u64 end); Str8 *wapp_str8_alloc_substr(const Allocator *allocator, Str8RO *str, u64 start, u64 end);
Str8 *wapp_str8_alloc_concat(const Allocator *allocator, Str8 *dst, Str8RO *src); Str8 *wapp_str8_alloc_concat(const Allocator *allocator, Str8 *dst, Str8RO *src);
// Only needed for allocators like malloc where each allocation has to be freed on its own. // 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. // No need to use it for allocators like Arena.
void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str); void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str);
@@ -86,20 +86,20 @@ void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str);
/** /**
* Str8 utilities * Str8 utilities
*/ */
c8 wapp_str8_get(Str8RO *str, u64 index); c8 wapp_str8_get(Str8RO *str, u64 index);
void wapp_str8_set(Str8 *str, u64 index, c8 c); void wapp_str8_set(Str8 *str, u64 index, c8 c);
void wapp_str8_push_back(Str8 *str, c8 c); void wapp_str8_push_back(Str8 *str, c8 c);
b8 wapp_str8_equal(Str8RO *s1, Str8RO *s2); b8 wapp_str8_equal(Str8RO *s1, Str8RO *s2);
b8 wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count); b8 wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count);
Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end); Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end);
void wapp_str8_concat_capped(Str8 *dst, Str8RO *src); void wapp_str8_concat_capped(Str8 *dst, Str8RO *src);
void wapp_str8_copy_cstr_capped(Str8 *dst, const char *src); void wapp_str8_copy_cstr_capped(Str8 *dst, const char *src);
void wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src); void wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src);
void wapp_str8_copy_to_cstr(char *dst, Str8RO *src, u64 dst_capacity); void wapp_str8_copy_to_cstr(char *dst, Str8RO *src, u64 dst_capacity);
void wapp_str8_format(Str8 *dst, const char *format, ...); void wapp_str8_format(Str8 *dst, const char *format, ...);
void wapp_str8_to_lower(Str8 *dst, Str8RO *src); void wapp_str8_to_lower(Str8 *dst, Str8RO *src);
void wapp_str8_to_upper(Str8 *dst, Str8RO *src); void wapp_str8_to_upper(Str8 *dst, Str8RO *src);
void wapp_str8_from_bytes(Str8 *dst, const U8Array *src); void wapp_str8_from_bytes(Str8 *dst, const U8Array *src);
/** /**
* Str8 find functions * Str8 find functions
@@ -112,9 +112,9 @@ i64 wapp_str8_rfind(Str8RO *str, Str8RO substr);
*/ */
#define wapp_str8_split(ALLOCATOR, STR, DELIMITER) wapp_str8_split_with_max(ALLOCATOR, STR, DELIMITER, -1) #define wapp_str8_split(ALLOCATOR, STR, DELIMITER) wapp_str8_split_with_max(ALLOCATOR, STR, DELIMITER, -1)
#define wapp_str8_rsplit(ALLOCATOR, STR, DELIMITER) wapp_str8_rsplit_with_max(ALLOCATOR, STR, DELIMITER, -1) #define wapp_str8_rsplit(ALLOCATOR, STR, DELIMITER) wapp_str8_rsplit_with_max(ALLOCATOR, STR, DELIMITER, -1)
Str8List *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits); Str8List *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits);
Str8List *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits); Str8List *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits);
Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter); Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter);
/** /**
* Str8 list utilities * Str8 list utilities
@@ -128,18 +128,18 @@ END_C_LINKAGE
template <typename T> template <typename T>
constexpr bool is_lvalue(T&&) { constexpr bool is_lvalue(T&&) {
return std::is_lvalue_reference<T>{}; return std::is_lvalue_reference<T>{};
} }
#define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node(Str8, Str8Node, [&]() { \ #define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node(Str8, Str8Node, [&]() { \
wapp_persist Str8 str = wapp_str8_lit(STRING); \ wapp_persist Str8 str = wapp_str8_lit(STRING); \
return &str; \ return &str; \
}()) }())
#define wapp_str8_node_from_str8(STRING) wapp_dbl_list_node(Str8, Str8Node, [&]() { \ #define wapp_str8_node_from_str8(STRING) wapp_dbl_list_node(Str8, Str8Node, [&]() { \
if (is_lvalue(STRING)) { return &STRING; } \ if (is_lvalue(STRING)) { return &STRING; } \
\ \
wapp_persist Str8 str = STRING; \ wapp_persist Str8 str = STRING; \
return &str; \ return &str; \
}()) }())
#else #else
#define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node(Str8, Str8Node, &wapp_str8_lit(STRING)) #define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node(Str8, Str8Node, &wapp_str8_lit(STRING))