commit e90d14344eaa3420bd830e975f138adf829b701d Author: Abdelrahman Date: Sun Aug 10 23:30:27 2025 +0100 Recreate base64 project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec0d909 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +b64 diff --git a/README.md b/README.md new file mode 100644 index 0000000..5021f2a --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# C testing projects + +Recreating the projects from [intro-to-zig](https://git.thewizardapprentice.com/abdelrahman/intro-to-zig) in C diff --git a/base64/base64.c b/base64/base64.c new file mode 100644 index 0000000..546f01a --- /dev/null +++ b/base64/base64.c @@ -0,0 +1,140 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "base64.h" +#include "../wapp/wapp.h" +#include + +internal Str8RO alphabet = wapp_str8_lit_ro("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); + +internal c8 char_at(u8 index); +internal u8 char_index(c8 c); +internal u64 calc_encode_length(Str8RO *input); +internal u64 calc_decode_length(Str8RO *input); + +Str8 *encode(Allocator *allocator, Str8RO *input) { + if (input->size == 0) { + return NULL; + } + + u64 n_out = calc_encode_length(input); + Str8 *out = wapp_str8_alloc_and_fill_buf(allocator, n_out); + if (!out) return NULL; + + u8 buf[3] = {0}; + u8 count = 0; + u64 iout = 0; + + + for (u64 i = 0; i < input->size; ++i) { + buf[count] = wapp_str8_get(input, i); + count += 1; + if (count == 3) { + wapp_str8_set(out, iout, char_at(buf[0] >> 2)); + wapp_str8_set(out, iout + 1, char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4))); + wapp_str8_set(out, iout + 2, char_at(((buf[1] & 0x0f) << 2) + (buf[2] >> 6))); + wapp_str8_set(out, iout + 3, char_at(buf[2] & 0x3f)); + + iout += 4; + count = 0; + } + } + + if (count == 1) { + wapp_str8_set(out, iout, char_at(buf[0] >> 2)); + wapp_str8_set(out, iout + 1, char_at((buf[0] & 0x03) << 4)); + wapp_str8_set(out, iout + 2, '='); + wapp_str8_set(out, iout + 3, '='); + } + + if (count == 2) { + wapp_str8_set(out, iout, char_at(buf[0] >> 2)); + wapp_str8_set(out, iout + 1, char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4))); + wapp_str8_set(out, iout + 2, char_at((buf[1] & 0x0f) << 2)); + wapp_str8_set(out, iout + 3, '='); + + iout += 4; + } + + return out; +} + +Str8 *decode(Allocator *allocator, Str8RO *input) { + if (input->size == 0) { + return NULL; + } + + u64 n_out = calc_decode_length(input); + Str8 *out = wapp_str8_alloc_and_fill_buf(allocator, n_out); + if (!out) return NULL; + + u8 buf[4] = {0}; + u8 count = 0; + u64 iout = 0; + + for (u64 i = 0; i < input->size; ++i) { + buf[count] = char_index(wapp_str8_get(input, i)); + count += 1; + if (count == 4) { + wapp_str8_set(out, iout, (buf[0] << 2) + (buf[1] >> 4)); + if (buf[2] != 64) { + wapp_str8_set(out, iout + 1, (buf[1] << 4) + (buf[2] >> 2)); + } + if (buf[3] != 64) { + wapp_str8_set(out, iout + 2, (buf[2] << 6) + buf[3]); + } + + iout += 3; + count = 0; + } + } + + return out; +} + +internal c8 char_at(u8 index) { + return wapp_str8_get(&alphabet, index); +} + +internal u8 char_index(c8 c) { + if (c == '=') { + return 64; + } + + u8 index = 0; + for (u8 i = 0; i < 63; ++i) { + if (char_at(i) == c) { + break; + } + index += 1; + } + + return index; +} + +internal u64 calc_encode_length(Str8RO *input) { + if (input->size < 3) { + return 4; + } + + u64 n_groups = (u64)(ceilf((f32)input->size / 3.0f)); + + return n_groups * 4; +} + +internal u64 calc_decode_length(Str8RO *input) { + if (input->size < 4) { + return 3; + } + + u64 n_groups = (u64)(floorf((f32)input->size / 4.0f)); + + u64 groups = n_groups * 3; + + for (u64 i = input->size; i > 0; --i) { + if (wapp_str8_get(input, i) == '=') { + groups -= 1; + } + } + + return groups; +} diff --git a/base64/base64.h b/base64/base64.h new file mode 100644 index 0000000..693676f --- /dev/null +++ b/base64/base64.h @@ -0,0 +1,11 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef BASE64_H +#define BASE64_H + +#include "../wapp/wapp.h" + +Str8 *encode(Allocator *allocator, Str8RO *input); +Str8 *decode(Allocator *allocator, Str8RO *input); + +#endif // !BASE64_H diff --git a/base64/build b/base64/build new file mode 100755 index 0000000..b371c6b --- /dev/null +++ b/base64/build @@ -0,0 +1,5 @@ +#!/bin/bash + +script_dir="$(dirname $0)" + +clang $script_dir/*.c $script_dir/../wapp/wapp.c -lm -o b64 diff --git a/base64/main.c b/base64/main.c new file mode 100644 index 0000000..e2bae14 --- /dev/null +++ b/base64/main.c @@ -0,0 +1,23 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "base64.h" +#include "../wapp/wapp.h" +#include + +int main(void) { + Allocator allocator = wapp_mem_arena_allocator_init(MB(10)); + + Str8RO text = wapp_str8_lit_ro("Testing some more stuff"); + Str8RO etext = wapp_str8_lit_ro("VGVzdGluZyBzb21lIG1vcmUgc3R1ZmY="); + + Str8 *encoded_text = encode(&allocator, &text); + Str8 *decoded_text = decode(&allocator, &etext); + wapp_runtime_assert(encoded_text != NULL && decoded_text != NULL, "Failed to allocate strings"); + + printf("Encoded text: " WAPP_STR8_SPEC "\n", wapp_str8_varg(*encoded_text)); + printf("Decoded text: " WAPP_STR8_SPEC "\n", wapp_str8_varg(*decoded_text)); + + wapp_mem_arena_allocator_destroy(&allocator); + + return 0; +} diff --git a/wapp/common/aliases/aliases.h b/wapp/common/aliases/aliases.h new file mode 100644 index 0000000..0534834 --- /dev/null +++ b/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 WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C11_VERSION && !defined(WAPP_PLATFORM_APPLE) + #include + + #if WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C23_VERSION + #define c8 char8_t + #else + #define c8 uint8_t + #endif // !WAPP_PLATFORM_C23_VERSION + + #define c16 char16_t + #define c32 char32_t +#else + #define c8 uint8_t + #define c16 uint16_t + #define c32 uint32_t +#endif // !WAPP_PLATFORM_C11_VERSION + +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +#define b32 uint32_t + +#ifndef WAPP_PLATFORM_CPP + +#ifndef false +#define false (b32)0 +#endif // !false + +#ifndef true +#define true (b32)1 +#endif // !true + +#endif // !WAPP_PLATFORM_CPP + +#define i8 int8_t +#define i16 int16_t +#define i32 int32_t +#define i64 int64_t + +#define f32 float +#define f64 double +#define f128 long double + +#define uptr uintptr_t +#define iptr intptr_t + +#define external extern +#define internal static +#define persistent static + +#ifdef WAPP_PLATFORM_CPP +#define class_mem static +#define BEGIN_C_LINKAGE extern "C" { +#define END_C_LINKAGE } +#endif // WAPP_PLATFORM_CPP + +#endif // !ALIASES_H diff --git a/wapp/common/assert/assert.h b/wapp/common/assert/assert.h new file mode 100644 index 0000000..ae98975 --- /dev/null +++ b/wapp/common/assert/assert.h @@ -0,0 +1,41 @@ +// 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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#define wapp_static_assert(EXPR, MSG) extern char ASSERTION_FAILED[EXPR ? 1 : -1] +#define wapp_runtime_assert(EXPR, MSG) __wapp_runtime_assert(EXPR, MSG) + +#ifdef WAPP_DEBUG_ASSERT + #define wapp_debug_assert(EXPR, MSG) wapp_runtime_assert(EXPR, MSG) +#else + #define wapp_debug_assert(EXPR, MSG) +#endif + +#define __wapp_runtime_assert(EXPR, MSG) do { \ + if (!(EXPR)) { \ + fprintf( \ + stderr, \ + "%s:%d (In function `%s`): Assertion failed (%" PRIu32 ")\nDiagnostic: %s\n\n", \ + __FILE__, __LINE__, __func__, \ + EXPR, MSG \ + ); \ + abort(); \ + } \ +} while(false) + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !WAPP_ASSERT_H diff --git a/wapp/common/misc/misc_utils.h b/wapp/common/misc/misc_utils.h new file mode 100644 index 0000000..27c0074 --- /dev/null +++ b/wapp/common/misc/misc_utils.h @@ -0,0 +1,56 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MISC_UTILS_H +#define MISC_UTILS_H + +#include "../aliases/aliases.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#define KB(SIZE) (SIZE * 1024ull) +#define MB(SIZE) (KB(SIZE) * 1024) +#define GB(SIZE) (MB(SIZE) * 1024) +#define TB(SIZE) (GB(SIZE) * 1024) + +#define wapp_misc_utils_padding_size(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 wapp_misc_utils_u64_round_up_pow2(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 \ +) + +#ifdef WAPP_PLATFORM_CPP +#define wapp_misc_utils_va_args_count(T, ...) va_args_count(__VA_ARGS__) +#else +#define wapp_misc_utils_va_args_count(T, ...) (sizeof((T[]){__VA_ARGS__})/sizeof(T)) +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE + +template +constexpr u64 va_args_count(Args&&...) { + return sizeof...(Args); +} +#endif // !WAPP_PLATFORM_CPP + +#endif // !MISC_UTILS_H diff --git a/wapp/common/platform/platform.h b/wapp/common/platform/platform.h new file mode 100644 index 0000000..9891f86 --- /dev/null +++ b/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 WAPP_PLATFORM_ANDROID + #define WAPP_PLATFORM_POSIX +#elif defined(__FreeBSD__) + #define WAPP_PLATFORM_FREE_BSD + #define WAPP_PLATFORM_BSD + #define WAPP_PLATFORM_POSIX +#elif defined(__NetBSD__) + #define WAPP_PLATFORM_NET_BSD + #define WAPP_PLATFORM_BSD + #define WAPP_PLATFORM_POSIX +#elif defined(__OpenBSD__) + #define WAPP_PLATFORM_OPEN_BSD + #define WAPP_PLATFORM_BSD + #define WAPP_PLATFORM_POSIX +#elif defined(__DragonFly__) + #define WAPP_PLATFORM_DRAGON_FLY + #define WAPP_PLATFORM_BSD + #define WAPP_PLATFORM_POSIX +#elif defined(__bsdi__) + #define WAPP_PLATFORM_BSD + #define WAPP_PLATFORM_POSIX +#elif defined(__linux__) || defined(linux) || defined(__linux) || defined(__gnu_linux__) + #define WAPP_PLATFORM_LINUX + #define WAPP_PLATFORM_POSIX +#elif defined(__GNU__) || defined(__gnu_hurd__) + #define WAPP_PLATFORM_GNU + #define WAPP_PLATFORM_POSIX +#elif defined(__APPLE__) || defined(__MACH__) + #include + #if TARGET_OS_IPHONE + #define WAPP_PLATFORM_IOS + #define WAPP_PLATFORM_APPLE + #define WAPP_PLATFORM_POSIX + #elif TARGET_OS_MAC + #define WAPP_PLATFORM_MACOS + #define WAPP_PLATFORM_APPLE + #define WAPP_PLATFORM_POSIX + #else + #error "Unrecognised Apple platform" + #endif +#elif defined(_WIN64) + #define WAPP_PLATFORM_WINDOWS64 + #define WAPP_PLATFORM_WINDOWS +#elif defined(_WIN32) + #define WAPP_PLATFORM_WINDOWS32 + #define WAPP_PLATFORM_WINDOWS +#elif defined(__CYGWIN__) + #define WAPP_PLATFORM_CYGWIN + #define WAPP_PLATFORM_WINDOWS +#elif defined(__unix__) || defined(__unix) + #define WAPP_PLATFORM_UNIX + #define WAPP_PLATFORM_POSIX +#else + #error "Unrecognised platform" +#endif + +#ifdef __cplusplus + #define WAPP_PLATFORM_CPP + #define WAPP_PLATFORM_CPP_VERSION __cplusplus + #define WAPP_PLATFORM_CPP98_VERSION 199711L + #define WAPP_PLATFORM_CPP11_VERSION 201103L + #define WAPP_PLATFORM_CPP14_VERSION 201402L + #define WAPP_PLATFORM_CPP17_VERSION 201703L + #define WAPP_PLATFORM_CPP20_VERSION 202002L + #define WAPP_PLATFORM_CPP23_VERSION 202302L + + #if WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP98_VERSION + #define WAPP_PLATFORM_CPP98 + #elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP11_VERSION + #define WAPP_PLATFORM_CPP11 + #elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP14_VERSION + #define WAPP_PLATFORM_CPP14 + #elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP17_VERSION + #define WAPP_PLATFORM_CPP17 + #elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP20_VERSION + #define WAPP_PLATFORM_CPP20 + #elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP23_VERSION + #define WAPP_PLATFORM_CPP23 + #else + #error "Unrecognised C++ version" + #endif +#else + #define WAPP_PLATFORM_C + + #if defined(__STDC_VERSION__) + #define WAPP_PLATFORM_C_VERSION __STDC_VERSION__ + #define WAPP_PLATFORM_C99_VERSION 199901L + #define WAPP_PLATFORM_C11_VERSION 201112L + #define WAPP_PLATFORM_C17_VERSION 201710L + #define WAPP_PLATFORM_C23_VERSION 202311L + + #if WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C99_VERSION + #define WAPP_PLATFORM_C99 + #elif WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C11_VERSION + #define WAPP_PLATFORM_C11 + #elif WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C17_VERSION + #define WAPP_PLATFORM_C17 + #elif WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C23_VERSION + #define WAPP_PLATFORM_C23 + #else + #error "Unrecognised C version" + #endif + #else + #define WAPP_PLATFORM_C89 + #endif +#endif // !__cplusplus + +#endif // !PLATFORM_H diff --git a/wapp/common/wapp_common.h b/wapp/common/wapp_common.h new file mode 100644 index 0000000..a126b0a --- /dev/null +++ b/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/wapp/core/mem/arena/mem_arena.c b/wapp/core/mem/arena/mem_arena.c new file mode 100644 index 0000000..aa8d9fe --- /dev/null +++ b/wapp/core/mem/arena/mem_arena.c @@ -0,0 +1,147 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_arena.h" +#include "../utils/mem_utils.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include "../../../common/misc/misc_utils.h" +#include "../../os/mem/mem_os.h" +#include +#include +#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 KB(16) // Allocate minimum of 4 pages + +struct arena { + u8 *buf; + u8 *offset; + u64 capacity; + bool committed; + +#ifdef WAPP_PLATFORM_WINDOWS + wapp_misc_utils_padding_size(sizeof(u8 *) * 2 + sizeof(u64) + sizeof(bool)); +#endif // ifdef WAPP_PLATFORM_WINDOWS +}; + +bool wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, bool zero_buffer) { + if (!arena || *arena || base_capacity == 0) { + return false; + } + + *arena = (Arena *)calloc(1, sizeof(Arena)); + Arena *arena_ptr = *arena; + if (!arena_ptr) { + return false; + } + + u64 arena_capacity = wapp_misc_utils_u64_round_up_pow2( + base_capacity >= ARENA_MINIMUM_CAPACITY ? + base_capacity : + ARENA_MINIMUM_CAPACITY + ); + + arena_ptr->buf = (u8 *)wapp_mem_util_alloc(NULL, arena_capacity, WAPP_MEM_ACCESS_READ_WRITE, flags, + zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED); + + if (!(arena_ptr->buf)) { + wapp_mem_arena_destroy(arena); + return false; + } + + arena_ptr->capacity = arena_capacity; + arena_ptr->offset = arena_ptr->buf; + arena_ptr->committed = (flags & WAPP_MEM_ALLOC_COMMIT) == WAPP_MEM_ALLOC_COMMIT; + + return true; +} + +void *wapp_mem_arena_alloc(Arena *arena, u64 size) { + return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT); +} + +void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) { + wapp_debug_assert(arena != NULL, "`arena` should not be NULL"); + + u8 *alloc_start = arena->offset; + + u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment); + if (output + size >= arena->buf + arena->capacity) { + return NULL; + } + + arena->offset = output + size; + +#ifdef WAPP_PLATFORM_WINDOWS + if (!(arena->committed)) { + wapp_mem_util_alloc(alloc_start, (uptr)(arena->offset) - (uptr)(alloc_start), + WAPP_MEM_ACCESS_READ_WRITE, WAPP_MEM_ALLOC_COMMIT, + WAPP_MEM_INIT_UNINITIALISED); + } +#endif // ifdef WAPP_PLATFORM_WINDOWS + + memset(output, 0, size); + + return (void *)output; +} + +void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 old_size, u64 new_size) { + if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset || + arena->offset + new_size >= arena->buf + arena->capacity) { + return NULL; + } + + void *new_ptr = wapp_mem_arena_alloc(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 *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment) { + if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset || + arena->offset + new_size >= arena->buf + arena->capacity) { + return NULL; + } + + void *new_ptr = wapp_mem_arena_alloc_aligned(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 wapp_mem_arena_clear(Arena *arena) { + wapp_debug_assert(arena != NULL, "`arena` should not be NULL"); + + memset(arena->buf, 0, arena->offset - arena->buf); + arena->offset = arena->buf; +} + +void wapp_mem_arena_destroy(Arena **arena) { + wapp_debug_assert(arena != NULL && (*arena) != NULL, "`arena` double pointer is not valid"); + + Arena *arena_ptr = *arena; + if (arena_ptr->buf) { + wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity); + } + + arena_ptr->buf = arena_ptr->offset = NULL; + arena_ptr->capacity = 0; + + free(*arena); + *arena = NULL; +} diff --git a/wapp/core/mem/arena/mem_arena.h b/wapp/core/mem/arena/mem_arena.h new file mode 100644 index 0000000..ec05f32 --- /dev/null +++ b/wapp/core/mem/arena/mem_arena.h @@ -0,0 +1,43 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_ARENA_H +#define MEM_ARENA_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../os/mem/mem_os.h" +#include + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef struct arena Arena; + +#define wapp_mem_arena_init(arena_dptr, base_capacity) \ + (wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, false)) +#define wapp_mem_arena_init_commit(arena_dptr, base_capacity) \ + (wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false)) +#define wapp_mem_arena_init_zero(arena_dptr, base_capacity) \ + (wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, true)) +#define wapp_mem_arena_init_commit_and_zero(arena_dptr, base_capacity) \ + (wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true)) + +/** + * Arena initialisation function. `wapp_mem_arena_init_custom` provides the most + * control over how the Arena is initialised. Wrapper macros are provided for + * easier use. + */ +bool wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, bool zero_buffer); +void *wapp_mem_arena_alloc(Arena *arena, u64 size); +void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment); +void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 old_size, u64 new_size); +void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment); +void wapp_mem_arena_clear(Arena *arena); +void wapp_mem_arena_destroy(Arena **arena); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_ARENA_H diff --git a/wapp/core/mem/arena/mem_arena_allocator.c b/wapp/core/mem/arena/mem_arena_allocator.c new file mode 100644 index 0000000..4ac0a29 --- /dev/null +++ b/wapp/core/mem/arena/mem_arena_allocator.c @@ -0,0 +1,59 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_arena_allocator.h" +#include "mem_arena.h" +#include "../../../common/aliases/aliases.h" +#include "../../os/mem/mem_os.h" + +internal inline void *mem_arena_alloc(u64 size, void *alloc_obj); +internal inline void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj); +internal inline void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj); +internal inline void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment, + void *alloc_obj); + + +Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, bool zero_buffer) { + Allocator allocator = {0}; + bool initialised = wapp_mem_arena_init_custom((Arena **)(&allocator.obj), base_capacity, flags, zero_buffer); + if (!initialised) { + return 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; + + return allocator; +} + +void wapp_mem_arena_allocator_clear(Allocator *allocator) { + wapp_mem_arena_clear((Arena *)(allocator->obj)); +} + +void wapp_mem_arena_allocator_destroy(Allocator *allocator) { + wapp_mem_arena_destroy((Arena **)(&(allocator->obj))); + *allocator = (Allocator){0}; +} + + +internal inline void *mem_arena_alloc(u64 size, void *alloc_obj) { + Arena *arena = (Arena *)alloc_obj; + return wapp_mem_arena_alloc(arena, size); +} + +internal inline void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj) { + Arena *arena = (Arena *)alloc_obj; + return wapp_mem_arena_alloc_aligned(arena, size, alignment); +} + +internal inline void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) { + Arena *arena = (Arena *)alloc_obj; + return wapp_mem_arena_realloc(arena, ptr, old_size, new_size); +} + +internal inline void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment, + void *alloc_obj) { + Arena *arena = (Arena *)alloc_obj; + return wapp_mem_arena_realloc_aligned(arena, ptr, old_size, new_size, alignment); +} diff --git a/wapp/core/mem/arena/mem_arena_allocator.h b/wapp/core/mem/arena/mem_arena_allocator.h new file mode 100644 index 0000000..f0bd4c3 --- /dev/null +++ b/wapp/core/mem/arena/mem_arena_allocator.h @@ -0,0 +1,44 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef MEM_ARENA_ALLOCATOR_H +#define MEM_ARENA_ALLOCATOR_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../../primitives/mem_allocator/mem_allocator.h" +#include "../../os/mem/mem_os.h" +#include + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#define wapp_mem_arena_allocator_init(base_capacity) \ + (wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE, false)) +#define wapp_mem_arena_allocator_init_commit(base_capacity) \ + (wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false)) +#define wapp_mem_arena_allocator_init_zero(base_capacity) \ + (wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE, true)) +#define wapp_mem_arena_allocator_init_commit_and_zero(base_capacity) \ + (wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true)) + +/** + * Wraps an Arena in an Allocator object. It attempts to initialise the Arena + * and, if successful, defines the operations supported by it to be used by the + * Allocator. + * + * An Arena allocator only supports normal allocation and aligned allocation. + * Reallocation, aligned reallocation and freeing aren't implemented. + * + * The `wapp_mem_arena_allocator_init_custom` provides the most control over how + * the Arena is initialised. Wrapper macros are provided for easier use. + */ +Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, bool zero_buffer); +void wapp_mem_arena_allocator_clear(Allocator *allocator); +void wapp_mem_arena_allocator_destroy(Allocator *allocator); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_ARENA_ALLOCATOR_H diff --git a/wapp/core/mem/utils/mem_utils.c b/wapp/core/mem/utils/mem_utils.c new file mode 100644 index 0000000..01a07ce --- /dev/null +++ b/wapp/core/mem/utils/mem_utils.c @@ -0,0 +1,27 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "mem_utils.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include +#include + +internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; } + +void *wapp_mem_util_align_forward(void *ptr, u64 alignment) { + 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"); + + 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/wapp/core/mem/utils/mem_utils.h b/wapp/core/mem/utils/mem_utils.h new file mode 100644 index 0000000..ca7f781 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +void *wapp_mem_util_align_forward(void *ptr, u64 alignment); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_UTILS_H diff --git a/wapp/core/os/cpath/cpath.c b/wapp/core/os/cpath/cpath.c new file mode 100644 index 0000000..dd895b5 --- /dev/null +++ b/wapp/core/os/cpath/cpath.c @@ -0,0 +1,136 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "cpath.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/misc/misc_utils.h" +#include "../../mem/arena/mem_arena_allocator.h" +#include "../../../primitives/dbl_list/dbl_list.h" +#include "../../../primitives/mem_allocator/mem_allocator.h" +#include "../../../primitives/strings/str8/str8.h" +#include +#include +#include +#include + +u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts) { + if (!dst || !parts) { + return CPATH_JOIN_INVALID_ARGS; + } + + if (parts->node_count == 0) { + return CPATH_JOIN_EMPTY_PARTS; + } + + Str8 separator = wapp_str8_buf(4); + wapp_str8_push_back(&separator, PATH_SEP); + + u64 required_capacity = parts->node_count * separator.size + wapp_str8_list_total_size(parts); + if (dst->capacity < required_capacity) { + return CPATH_JOIN_INSUFFICIENT_DST_CAPACITY; + } + + // Handle first node + const Str8Node *first_node = wapp_str8_list_get(parts, 0); + wapp_str8_copy_str8_capped(dst, first_node->item); + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + const Str8Node *node = first_node; + u64 node_index = 1; + bool running = node_index < parts->node_count; + while (running && node->next) { + node = node->next; + if (node->item->size == 0) { + continue; + } + + if (dst->size > 0) { + char dst_last = wapp_str8_get(dst, dst->size - 1); + char node_start = wapp_str8_get(node->item, 0); + bool add_path_sep = dst_last != PATH_SEP && node_start != PATH_SEP; + + if (add_path_sep) { + wapp_str8_concat_capped(dst, &separator); + } + } + + wapp_str8_concat_capped(dst, node->item); + + ++node_index; + running = node_index < parts->node_count; + } + + return CPATH_JOIN_SUCCESS; +} + +Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels) { + Str8 *output = NULL; + if (!allocator || !path) { + goto RETURN_DIRUP; + } + + bool absolute = wapp_str8_get(path, 0) == PATH_SEP; + Str8 separator = wapp_str8_buf(4); + wapp_str8_push_back(&separator, PATH_SEP); + + if (path->size == 0) { + output = wapp_str8_alloc_buf(allocator, 16); + if (!output) { + goto RETURN_DIRUP; + } + + wapp_str8_push_back(output, absolute ? PATH_SEP : '.'); + goto RETURN_DIRUP; + } + + if (levels < 1) { + output = wapp_str8_alloc_str8(allocator, path); + goto RETURN_DIRUP; + } + + Allocator tmp_arena = wapp_mem_arena_allocator_init(MB(8)); + if (wapp_mem_allocator_invalid(&tmp_arena)) { + goto RETURN_DIRUP; + } + + Str8List *parts = wapp_str8_split(&tmp_arena, path, &separator); + if (!parts) { + goto RETURN_DIRUP; + } + + if (levels >= parts->node_count) { + output = wapp_str8_alloc_buf(allocator, 16); + if (!output) { + goto LIST_CLEANUP_DIRUP; + } + + wapp_str8_push_back(output, absolute ? PATH_SEP : '.'); + } else { + for (u64 i = 0; i < levels; ++i) { + wapp_str8_list_pop_back(parts); + } + + u64 alignment = sizeof(void *) * 2; + u64 alloc_size = wapp_str8_list_total_size(parts) + parts->node_count * separator.size; + u64 modulo = alloc_size & (alignment - 1); + alloc_size += alignment - modulo; + + output = wapp_str8_alloc_buf(allocator, alloc_size); + if (output) { + if (absolute) { + wapp_str8_push_back(output, PATH_SEP); + } + + Str8 *joined = wapp_str8_join(&tmp_arena, parts, &separator); + if (joined) { + wapp_str8_concat_capped(output, joined); + } + } + } + +LIST_CLEANUP_DIRUP: + wapp_mem_arena_allocator_destroy(&tmp_arena); + +RETURN_DIRUP: + return output; +} diff --git a/wapp/core/os/cpath/cpath.h b/wapp/core/os/cpath/cpath.h new file mode 100644 index 0000000..f8363d5 --- /dev/null +++ b/wapp/core/os/cpath/cpath.h @@ -0,0 +1,40 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef CPATH_H +#define CPATH_H + +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" +#include "../../../primitives/mem_allocator/mem_allocator.h" +#include "../../../primitives/strings/str8/str8.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_POSIX +#define PATH_SEP '/' +#elif defined(WAPP_PLATFORM_WINDOWS) +#define PATH_SEP '\\' +#else +#error "Unrecognised platform" +#endif + +#define wapp_cpath_dirname(ALLOCATOR, PATH) dirup(ALLOCATOR, PATH, 1) +#define wapp_cpath_dirup(ALLOCATOR, PATH, COUNT) dirup(ALLOCATOR, PATH, COUNT) + +enum { + CPATH_JOIN_SUCCESS = 0, + CPATH_JOIN_INVALID_ARGS, + CPATH_JOIN_EMPTY_PARTS, + CPATH_JOIN_INSUFFICIENT_DST_CAPACITY, +}; + +u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts); +Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !CPATH_H diff --git a/wapp/core/os/mem/mem_os.c b/wapp/core/os/mem/mem_os.c new file mode 100644 index 0000000..9e3ee04 --- /dev/null +++ b/wapp/core/os/mem/mem_os.c @@ -0,0 +1,31 @@ +// 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 +#include + +#if defined(WAPP_PLATFORM_WINDOWS) +#include "win/mem_os_win.h" +#elif defined(WAPP_PLATFORM_POSIX) +#include "posix/mem_os_posix.h" +#else +#error "Unrecognised platform" +#endif + +void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) { + void *output = mem_util_allocate(addr, size, access, flags, type); + + if (type == WAPP_MEM_INIT_INITIALISED) { + memset(output, 0, size); + } + + return output; +} + +void wapp_mem_util_free(void *ptr, u64 size) { + mem_util_free(ptr, size); +} diff --git a/wapp/core/os/mem/mem_os.h b/wapp/core/os/mem/mem_os.h new file mode 100644 index 0000000..451485c --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#if defined(WAPP_PLATFORM_WINDOWS) +#include "win/mem_os_win.h" +#elif defined(WAPP_PLATFORM_POSIX) +#include "posix/mem_os_posix.h" +#else +#error "Unrecognised platform" +#endif + +void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type); +void wapp_mem_util_free(void *ptr, u64 size); + +external void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type); +external void mem_util_free(void *ptr, u64 size); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_OS_H diff --git a/wapp/core/os/mem/mem_os_ops.h b/wapp/core/os/mem/mem_os_ops.h new file mode 100644 index 0000000..460c9a8 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef enum mem_access { + WAPP_MEM_ACCESS_NONE, + WAPP_MEM_ACCESS_READ_ONLY, + WAPP_MEM_ACCESS_EXEC_ONLY, + WAPP_MEM_ACCESS_READ_WRITE, + WAPP_MEM_ACCESS_READ_EXEC, + WAPP_MEM_ACCESS_READ_WRITE_EXEC, +} MemAccess; + +typedef enum mem_init_type { + WAPP_MEM_INIT_UNINITIALISED, + WAPP_MEM_INIT_INITIALISED, +} MemInitType; + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_OS_OPS_H diff --git a/wapp/core/os/mem/posix/mem_os_posix.c b/wapp/core/os/mem/posix/mem_os_posix.c new file mode 100644 index 0000000..ad51372 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_POSIX + +#include "mem_os_posix.h" +#include "../mem_os_ops.h" +#include + +internal const i32 access_types[] = { + [WAPP_MEM_ACCESS_NONE] = PROT_NONE, + [WAPP_MEM_ACCESS_READ_ONLY] = PROT_READ, + [WAPP_MEM_ACCESS_EXEC_ONLY] = PROT_EXEC, + [WAPP_MEM_ACCESS_READ_WRITE] = PROT_READ | PROT_WRITE, + [WAPP_MEM_ACCESS_READ_EXEC] = PROT_READ | PROT_EXEC, + [WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC, +}; + +void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) { + (void)type; + i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE; + +#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU) || defined(WAPP_PLATFORM_NET_BSD) + alloc_flags |= MAP_NORESERVE; +#endif + + return mmap(addr, size, access_types[access], alloc_flags, -1, 0); +} + +void mem_util_free(void *ptr, u64 size) { + munmap(ptr, size); +} + +#endif // !WAPP_PLATFORM_POSIX diff --git a/wapp/core/os/mem/posix/mem_os_posix.h b/wapp/core/os/mem/posix/mem_os_posix.h new file mode 100644 index 0000000..1d3c013 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_POSIX + +#include + +typedef enum mem_alloc_flags { +#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU) + WAPP_MEM_ALLOC_RESERVE = 0, + WAPP_MEM_ALLOC_COMMIT = MAP_POPULATE, +#elif defined(WAPP_PLATFORM_FREE_BSD) + WAPP_MEM_ALLOC_RESERVE = 0, + WAPP_MEM_ALLOC_COMMIT = MAP_PREFAULT_READ, +#elif defined(WAPP_PLATFORM_BSD) || defined(WAPP_PLATFORM_UNIX) || defined(WAPP_PLATFORM_APPLE) + WAPP_MEM_ALLOC_RESERVE = 0, + WAPP_MEM_ALLOC_COMMIT = 0, +#endif +} MemAllocFlags; + +#endif // !WAPP_PLATFORM_POSIX + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_OS_POSIX_H diff --git a/wapp/core/os/mem/win/mem_os_win.c b/wapp/core/os/mem/win/mem_os_win.c new file mode 100644 index 0000000..78ce0c9 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_WINDOWS + +#include "mem_os_win.h" +#include "../mem_os_ops.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +internal const i32 access_types[] = { + [WAPP_MEM_ACCESS_NONE] = PAGE_NOACCESS, + [WAPP_MEM_ACCESS_READ_ONLY] = PAGE_READONLY, + [WAPP_MEM_ACCESS_EXEC_ONLY] = PAGE_EXECUTE, + [WAPP_MEM_ACCESS_READ_WRITE] = PAGE_READWRITE, + [WAPP_MEM_ACCESS_READ_EXEC] = PAGE_EXECUTE_READ, + [WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE, +}; + +void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) { + // Ensure memory is committed if it's meant to be initialised + if (type == WAPP_MEM_INIT_INITIALISED) { + flags |= WAPP_MEM_ALLOC_COMMIT; + } + + return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]); +} + +void mem_util_free(void *ptr, u64 size) { + VirtualFree(ptr, size, MEM_RELEASE); +} + +#endif // !WAPP_PLATFORM_WINDOWS diff --git a/wapp/core/os/mem/win/mem_os_win.h b/wapp/core/os/mem/win/mem_os_win.h new file mode 100644 index 0000000..31f826e --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_WINDOWS + +#define WIN32_LEAN_AND_MEAN +#include +#include + +typedef enum mem_alloc_flags { + WAPP_MEM_ALLOC_RESERVE = MEM_RESERVE, + WAPP_MEM_ALLOC_COMMIT = MEM_COMMIT, +} MemAllocFlags; + +#endif // !WAPP_PLATFORM_WINDOWS + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_OS_WIN_H diff --git a/wapp/core/os/shell/commander/commander.c b/wapp/core/os/shell/commander/commander.c new file mode 100644 index 0000000..3420582 --- /dev/null +++ b/wapp/core/os/shell/commander/commander.c @@ -0,0 +1,102 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "commander.h" +#include "commander_output.h" +#include "../utils/shell_utils.h" +#include "../../../mem/arena/mem_arena_allocator.h" +#include "../../../../common/aliases/aliases.h" +#include "../../../../common/misc/misc_utils.h" +#include "../../../../primitives/dbl_list/dbl_list.h" +#include "../../../../primitives/mem_allocator/mem_allocator.h" +#include "../../../../primitives/strings/str8/str8.h" +#include +#include +#include +#include +#include + +#define CMD_BUF_LEN 8192 +#define OUT_BUF_LEN 4096 + +internal inline CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf); +internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf); + +CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd) { + if (!cmd) { + return CMD_NO_EXIT(SHELL_ERR_INVALID_ARGS); + } + + Allocator arena = wapp_mem_arena_allocator_init(KB(500)); + + Str8 *cmd_str = wapp_str8_join(&arena, cmd, &wapp_str8_lit_ro(" ")); + if (!cmd_str) { + wapp_mem_arena_allocator_destroy(&arena); + return CMD_NO_EXIT(SHELL_ERR_ALLOCATION_FAIL); + } + + // Redirect output + cmd_str = wapp_str8_alloc_concat(&arena, cmd_str, &wapp_str8_lit_ro(" 2>&1")); + + CMDResult output = execute_command(cmd_str, out_handling, out_buf); + + wapp_mem_arena_allocator_destroy(&arena); + + return output; +} + +internal inline CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf) { + char cmd_buf[CMD_BUF_LEN] = {0}; + wapp_str8_copy_to_cstr(cmd_buf, cmd, CMD_BUF_LEN); + + FILE *fp = wapp_shell_utils_popen(cmd_buf, "r"); + if (!fp) { + return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL); + } + + CMDResult output; + + CMDError err = get_command_output(fp, out_handling, out_buf); + if (err > SHELL_ERR_NO_ERROR) { + output = CMD_NO_EXIT(err); + goto EXECUTE_COMMAND_CLOSE; + } + + i32 st = EXIT_SUCCESS; + err = get_output_status(fp, &st); + if (err > SHELL_ERR_NO_ERROR) { + output = CMD_NO_EXIT(err); + goto EXECUTE_COMMAND_CLOSE; + } + + // Process is already closed in get_output_status + fp = NULL; + + output = (CMDResult){ + .exited = true, + .exit_code = st, + .error = SHELL_ERR_NO_ERROR, + }; + +EXECUTE_COMMAND_CLOSE: + if (fp) { + wapp_shell_utils_pclose(fp); + } + return output; +} + +internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf) { + Str8 out = wapp_str8_buf(OUT_BUF_LEN); + + out.size = fread((void *)out.buf, sizeof(u8), out.capacity, fp); + if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) { + if (out.size >= out_buf->capacity) { + return SHELL_ERR_OUT_BUF_FULL; + } + + wapp_str8_concat_capped(out_buf, &out); + } else if (out_handling == SHELL_OUTPUT_PRINT) { + printf(WAPP_STR8_SPEC, wapp_str8_varg(out)); + } + + return SHELL_ERR_NO_ERROR; +} diff --git a/wapp/core/os/shell/commander/commander.h b/wapp/core/os/shell/commander/commander.h new file mode 100644 index 0000000..3a54657 --- /dev/null +++ b/wapp/core/os/shell/commander/commander.h @@ -0,0 +1,28 @@ +// 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 "../../../../primitives/strings/str8/str8.h" +#include +#include +#include + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#define CMD_NO_EXIT(ERR) ((CMDResult){.exited = false, .exit_code = EXIT_FAILURE, .error = ERR}) + +CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd); + +external CMDError get_output_status(FILE *fp, i32 *status_out); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !COMMANDER_H diff --git a/wapp/core/os/shell/commander/commander_output.h b/wapp/core/os/shell/commander/commander_output.h new file mode 100644 index 0000000..32b2b12 --- /dev/null +++ b/wapp/core/os/shell/commander/commander_output.h @@ -0,0 +1,45 @@ +// 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 + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef enum { + SHELL_OUTPUT_DISCARD, + SHELL_OUTPUT_PRINT, + SHELL_OUTPUT_CAPTURE, +} CMDOutHandling; + +typedef enum { + SHELL_ERR_NO_ERROR, + SHELL_ERR_INVALID_ARGS, + SHELL_ERR_ALLOCATION_FAIL, + SHELL_ERR_PROC_START_FAIL, + SHELL_ERR_OUT_BUF_FULL, + SHELL_ERR_PROC_EXIT_FAIL, +} CMDError; + +typedef struct commander_result CMDResult; +struct commander_result { + i32 exit_code; + CMDError error; + bool exited; + +#ifdef WAPP_PLATFORM_WINDOWS + #include "../../../../common/misc/misc_utils.h" + wapp_misc_utils_padding_size(sizeof(bool) + sizeof(i32) + sizeof(CMDError)); +#endif // !WAPP_PLATFORM_WINDOWS +}; + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !COMMANDER_OUTPUT_H diff --git a/wapp/core/os/shell/commander/posix/commander_posix.c b/wapp/core/os/shell/commander/posix/commander_posix.c new file mode 100644 index 0000000..77452f8 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_POSIX + +#include "../commander_output.h" +#include "../../utils/shell_utils.h" +#include +#include + +CMDError get_output_status(FILE *fp, i32 *status_out) { + *status_out = wapp_shell_utils_pclose(fp); + + if (!WIFEXITED(*status_out)) { + return SHELL_ERR_PROC_EXIT_FAIL; + } + + *status_out = WEXITSTATUS(*status_out); + + return SHELL_ERR_NO_ERROR; +} + +#endif // !WAPP_PLATFORM_POSIX diff --git a/wapp/core/os/shell/commander/win/commander_win.c b/wapp/core/os/shell/commander/win/commander_win.c new file mode 100644 index 0000000..78ad793 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_WINDOWS + +#include "../commander_output.h" +#include "../../utils/shell_utils.h" +#include + +CMDError get_output_status(FILE *fp, i32 *status_out) { + if (!feof(fp)) { + // Ensure process is closed on failure + wapp_shell_utils_pclose(fp); + return SHELL_ERR_PROC_EXIT_FAIL; + } + + *status_out = wapp_shell_utils_pclose(fp); + + return SHELL_ERR_NO_ERROR; +} + +#endif // !WAPP_PLATFORM_WINDOWS diff --git a/wapp/core/os/shell/termcolour/posix/termcolour_posix.c b/wapp/core/os/shell/termcolour/posix/termcolour_posix.c new file mode 100644 index 0000000..349cfd3 --- /dev/null +++ b/wapp/core/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 "../../../../../primitives/strings/str8/str8.h" + +#ifdef WAPP_PLATFORM_POSIX + +#include "../terminal_colours.h" +#include + +internal Str8RO colours[COUNT_TERM_COLOUR] = { + [WAPP_TERM_COLOUR_FG_BLACK] = wapp_str8_lit_ro_initialiser_list("\033[30m"), + [WAPP_TERM_COLOUR_FG_RED] = wapp_str8_lit_ro_initialiser_list("\033[31m"), + [WAPP_TERM_COLOUR_FG_GREEN] = wapp_str8_lit_ro_initialiser_list("\033[32m"), + [WAPP_TERM_COLOUR_FG_BLUE] = wapp_str8_lit_ro_initialiser_list("\033[34m"), + [WAPP_TERM_COLOUR_FG_CYAN] = wapp_str8_lit_ro_initialiser_list("\033[36m"), + [WAPP_TERM_COLOUR_FG_MAGENTA] = wapp_str8_lit_ro_initialiser_list("\033[35m"), + [WAPP_TERM_COLOUR_FG_YELLOW] = wapp_str8_lit_ro_initialiser_list("\033[33m"), + [WAPP_TERM_COLOUR_FG_WHITE] = wapp_str8_lit_ro_initialiser_list("\033[37m"), + [WAPP_TERM_COLOUR_FG_BR_BLACK] = wapp_str8_lit_ro_initialiser_list("\033[90m"), + [WAPP_TERM_COLOUR_FG_BR_RED] = wapp_str8_lit_ro_initialiser_list("\033[91m"), + [WAPP_TERM_COLOUR_FG_BR_GREEN] = wapp_str8_lit_ro_initialiser_list("\033[92m"), + [WAPP_TERM_COLOUR_FG_BR_BLUE] = wapp_str8_lit_ro_initialiser_list("\033[94m"), + [WAPP_TERM_COLOUR_FG_BR_CYAN] = wapp_str8_lit_ro_initialiser_list("\033[96m"), + [WAPP_TERM_COLOUR_FG_BR_MAGENTA] = wapp_str8_lit_ro_initialiser_list("\033[95m"), + [WAPP_TERM_COLOUR_FG_BR_YELLOW] = wapp_str8_lit_ro_initialiser_list("\033[93m"), + [WAPP_TERM_COLOUR_FG_BR_WHITE] = wapp_str8_lit_ro_initialiser_list("\033[97m"), + [WAPP_TERM_COLOUR_CLEAR] = wapp_str8_lit_ro_initialiser_list("\033[0m"), +}; + +void print_coloured_text(Str8RO *text, TerminalColour colour) { + printf(WAPP_STR8_SPEC WAPP_STR8_SPEC, wapp_str8_varg(colours[colour]), wapp_str8_varg((*text))); +} + +#endif // !WAPP_PLATFORM_POSIX diff --git a/wapp/core/os/shell/termcolour/termcolour.c b/wapp/core/os/shell/termcolour/termcolour.c new file mode 100644 index 0000000..846151f --- /dev/null +++ b/wapp/core/os/shell/termcolour/termcolour.c @@ -0,0 +1,18 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "termcolour.h" +#include "terminal_colours.h" +#include "../../../../primitives/strings/str8/str8.h" + +void wapp_shell_termcolour_print_text(Str8RO *text, TerminalColour colour) { + if (colour < WAPP_TERM_COLOUR_FG_BLACK || colour > WAPP_TERM_COLOUR_FG_BR_WHITE) { + return; + } + + print_coloured_text(text, colour); +} + +void wapp_shell_termcolour_clear_colour(void) { + Str8RO empty = wapp_str8_lit_ro(""); + print_coloured_text(&empty, WAPP_TERM_COLOUR_CLEAR); +} diff --git a/wapp/core/os/shell/termcolour/termcolour.h b/wapp/core/os/shell/termcolour/termcolour.h new file mode 100644 index 0000000..e720092 --- /dev/null +++ b/wapp/core/os/shell/termcolour/termcolour.h @@ -0,0 +1,24 @@ +// 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 "../../../../primitives/strings/str8/str8.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +void wapp_shell_termcolour_print_text(Str8RO *text, TerminalColour colour); +void wapp_shell_termcolour_clear_colour(void); + +external void print_coloured_text(Str8RO *text, TerminalColour colour); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !TERM_COLOUR_H diff --git a/wapp/core/os/shell/termcolour/terminal_colours.h b/wapp/core/os/shell/termcolour/terminal_colours.h new file mode 100644 index 0000000..c2c7ff2 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef enum { + WAPP_TERM_COLOUR_FG_BLACK, + WAPP_TERM_COLOUR_FG_RED, + WAPP_TERM_COLOUR_FG_GREEN, + WAPP_TERM_COLOUR_FG_BLUE, + WAPP_TERM_COLOUR_FG_CYAN, + WAPP_TERM_COLOUR_FG_MAGENTA, + WAPP_TERM_COLOUR_FG_YELLOW, + WAPP_TERM_COLOUR_FG_WHITE, + WAPP_TERM_COLOUR_FG_BR_BLACK, + WAPP_TERM_COLOUR_FG_BR_RED, + WAPP_TERM_COLOUR_FG_BR_GREEN, + WAPP_TERM_COLOUR_FG_BR_BLUE, + WAPP_TERM_COLOUR_FG_BR_CYAN, + WAPP_TERM_COLOUR_FG_BR_MAGENTA, + WAPP_TERM_COLOUR_FG_BR_YELLOW, + WAPP_TERM_COLOUR_FG_BR_WHITE, + WAPP_TERM_COLOUR_CLEAR, + + COUNT_TERM_COLOUR, +} TerminalColour; + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !TERMINAL_COLOURS_H diff --git a/wapp/core/os/shell/termcolour/win/termcolour_win.c b/wapp/core/os/shell/termcolour/win/termcolour_win.c new file mode 100644 index 0000000..7b2ee97 --- /dev/null +++ b/wapp/core/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 "../../../../../primitives/strings/str8/str8.h" + +#ifdef WAPP_PLATFORM_WINDOWS + +#include "../terminal_colours.h" +#include "../../../../../common/misc/misc_utils.h" +#include + +#define WIN32_LEAN_AND_MEAN +#include + +typedef struct termcolour_data TermcolourData; +struct termcolour_data { + HANDLE handle; + WORD default_colour; + WORD current_colour; + + wapp_misc_utils_padding_size(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD)); +}; + +internal void init_data(TermcolourData *data); + +internal WORD colours[COUNT_TERM_COLOUR] = { + [WAPP_TERM_COLOUR_FG_BLACK] = 0, + [WAPP_TERM_COLOUR_FG_RED] = FOREGROUND_RED, + [WAPP_TERM_COLOUR_FG_GREEN] = FOREGROUND_GREEN, + [WAPP_TERM_COLOUR_FG_BLUE] = FOREGROUND_BLUE, + [WAPP_TERM_COLOUR_FG_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE, + [WAPP_TERM_COLOUR_FG_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE, + [WAPP_TERM_COLOUR_FG_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN, + [WAPP_TERM_COLOUR_FG_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, + [WAPP_TERM_COLOUR_FG_BR_BLACK] = FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, + [WAPP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, +}; + +void print_coloured_text(Str8RO *text, TerminalColour colour) { + persistent TermcolourData data = {0}; + if (data.handle == 0) { + init_data(&data); + } + + if (colour == WAPP_TERM_COLOUR_CLEAR) { + data.current_colour = data.default_colour; + } else { + data.current_colour = colours[colour]; + } + + SetConsoleTextAttribute(data.handle, data.current_colour); + printf(WAPP_STR8_SPEC, wapp_str8_varg((*text))); +} + +internal 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 // !WAPP_PLATFORM_WINDOWS diff --git a/wapp/core/os/shell/utils/shell_utils.h b/wapp/core/os/shell/utils/shell_utils.h new file mode 100644 index 0000000..7148ca7 --- /dev/null +++ b/wapp/core/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_WINDOWS + #define wapp_shell_utils_popen _popen + #define wapp_shell_utils_pclose _pclose +#else + #define wapp_shell_utils_popen popen + #define wapp_shell_utils_pclose pclose +#endif /* ifdef WAPP_PLATFORM_WINDOWS */ + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !SHELL_UTILS_H diff --git a/wapp/core/wapp_core.c b/wapp/core/wapp_core.c new file mode 100644 index 0000000..34d8bcb --- /dev/null +++ b/wapp/core/wapp_core.c @@ -0,0 +1,22 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_CORE_C +#define WAPP_CORE_C + +#include "wapp_core.h" +#include "os/shell/termcolour/posix/termcolour_posix.c" +#include "os/shell/termcolour/win/termcolour_win.c" +#include "os/shell/termcolour/termcolour.c" +#include "os/shell/commander/posix/commander_posix.c" +#include "os/shell/commander/win/commander_win.c" +#include "os/shell/commander/commander.c" +#include "os/cpath/cpath.c" +#include "os/mem/posix/mem_os_posix.c" +#include "os/mem/win/mem_os_win.c" +#include "os/mem/mem_os.c" +#include "mem/utils/mem_utils.c" +#include "mem/arena/mem_arena.c" +#include "mem/arena/mem_arena_allocator.c" +#include "../primitives/wapp_primitives.c" + +#endif // !WAPP_CORE_C diff --git a/wapp/core/wapp_core.h b/wapp/core/wapp_core.h new file mode 100644 index 0000000..54320cd --- /dev/null +++ b/wapp/core/wapp_core.h @@ -0,0 +1,22 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_CORE_H +#define WAPP_CORE_H + +#include "os/shell/termcolour/termcolour.h" +#include "os/shell/termcolour/terminal_colours.h" +#include "os/shell/commander/commander.h" +#include "os/shell/commander/commander_output.h" +#include "os/shell/utils/shell_utils.h" +#include "os/cpath/cpath.h" +#include "os/mem/posix/mem_os_posix.h" +#include "os/mem/win/mem_os_win.h" +#include "os/mem/mem_os_ops.h" +#include "os/mem/mem_os.h" +#include "mem/utils/mem_utils.h" +#include "mem/arena/mem_arena_allocator.h" +#include "mem/arena/mem_arena.h" +#include "../common/wapp_common.h" +#include "../primitives/wapp_primitives.h" + +#endif // !WAPP_CORE_H diff --git a/wapp/primitives/array/array.c b/wapp/primitives/array/array.c new file mode 100644 index 0000000..207e8f1 --- /dev/null +++ b/wapp/primitives/array/array.c @@ -0,0 +1,3011 @@ +/** + * THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN + */ + +#include "./array.h" +#include "../../common/assert/assert.h" +#include "../../common/aliases/aliases.h" +#include "../mem_allocator/mem_allocator.h" +#include "../../common/misc/misc_utils.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" +#include + +Str8 *wapp_str8_array_get(const Str8Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (Str8 *)ptr; +} + +void wapp_str8_array_set(Str8Array *array, u64 index, Str8 *item) { + Str8 *ptr = wapp_str8_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_str8_array_append_capped(Str8Array *array, Str8 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_str8_array_set(array, index, item); +} + +void wapp_str8_array_extend_capped(Str8Array *array, const Str8Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + Str8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_str8_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_str8_array_append_capped(array, item); + } +} + +void wapp_str8_array_clear(Str8Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_str8_array_copy_capped(const Str8Array *src, Str8Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_str8_array_clear(dst); + + Str8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_str8_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_str8_array_append_capped(dst, item); + } +} + +Str8Array *wapp_str8_array_append_alloc(const Allocator *allocator, Str8Array *array, Str8 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + Str8Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (Str8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_STR8_ARRAY_APPEND_ALLOC; + } + wapp_str8_array_copy_capped(array, output); + } + + wapp_str8_array_append_capped(output, item); + +RETURN_STR8_ARRAY_APPEND_ALLOC: + return output; +} + +Str8Array *wapp_str8_array_extend_alloc(const Allocator *allocator, Str8Array *array, const Str8Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + Str8Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (Str8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_STR8_ARRAY_EXTEND_ALLOC; + } + wapp_str8_array_copy_capped(array, output); + } + + wapp_str8_array_extend_capped(output, other); + +RETURN_STR8_ARRAY_EXTEND_ALLOC: + return output; +} + +Str8Array *wapp_str8_array_copy_alloc(const Allocator *allocator, const Str8Array *src, Str8Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + Str8Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (Str8Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_STR8_ARRAY_COPY_ALLOC; + } + } + + wapp_str8_array_clear(output); + wapp_str8_array_copy_capped(src, output); + +RETURN_STR8_ARRAY_COPY_ALLOC: + return output; +} + +Str8 *_str8_array_pop(Str8Array *array) { + u64 index = array->count - 1; + Str8 *out = wapp_str8_array_get(array, index); + --(array->count); + return out; +} + +void * *wapp_void_ptr_array_get(const VoidPArray *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (void * *)ptr; +} + +void wapp_void_ptr_array_set(VoidPArray *array, u64 index, void * *item) { + void * *ptr = wapp_void_ptr_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_void_ptr_array_append_capped(VoidPArray *array, void * *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_void_ptr_array_set(array, index, item); +} + +void wapp_void_ptr_array_extend_capped(VoidPArray *array, const VoidPArray *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + void * *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_void_ptr_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_void_ptr_array_append_capped(array, item); + } +} + +void wapp_void_ptr_array_clear(VoidPArray *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_void_ptr_array_copy_capped(const VoidPArray *src, VoidPArray *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_void_ptr_array_clear(dst); + + void * *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_void_ptr_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_void_ptr_array_append_capped(dst, item); + } +} + +VoidPArray *wapp_void_ptr_array_append_alloc(const Allocator *allocator, VoidPArray *array, void * *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + VoidPArray *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (VoidPArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_VOID_PTR_ARRAY_APPEND_ALLOC; + } + wapp_void_ptr_array_copy_capped(array, output); + } + + wapp_void_ptr_array_append_capped(output, item); + +RETURN_VOID_PTR_ARRAY_APPEND_ALLOC: + return output; +} + +VoidPArray *wapp_void_ptr_array_extend_alloc(const Allocator *allocator, VoidPArray *array, const VoidPArray *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + VoidPArray *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (VoidPArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_VOID_PTR_ARRAY_EXTEND_ALLOC; + } + wapp_void_ptr_array_copy_capped(array, output); + } + + wapp_void_ptr_array_extend_capped(output, other); + +RETURN_VOID_PTR_ARRAY_EXTEND_ALLOC: + return output; +} + +VoidPArray *wapp_void_ptr_array_copy_alloc(const Allocator *allocator, const VoidPArray *src, VoidPArray *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + VoidPArray *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (VoidPArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_VOID_PTR_ARRAY_COPY_ALLOC; + } + } + + wapp_void_ptr_array_clear(output); + wapp_void_ptr_array_copy_capped(src, output); + +RETURN_VOID_PTR_ARRAY_COPY_ALLOC: + return output; +} + +void * *_void_ptr_array_pop(VoidPArray *array) { + u64 index = array->count - 1; + void * *out = wapp_void_ptr_array_get(array, index); + --(array->count); + return out; +} + +b32 *wapp_b32_array_get(const B32Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (b32 *)ptr; +} + +void wapp_b32_array_set(B32Array *array, u64 index, b32 *item) { + b32 *ptr = wapp_b32_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_b32_array_append_capped(B32Array *array, b32 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_b32_array_set(array, index, item); +} + +void wapp_b32_array_extend_capped(B32Array *array, const B32Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + b32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_b32_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_b32_array_append_capped(array, item); + } +} + +void wapp_b32_array_clear(B32Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_b32_array_copy_capped(const B32Array *src, B32Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_b32_array_clear(dst); + + b32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_b32_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_b32_array_append_capped(dst, item); + } +} + +B32Array *wapp_b32_array_append_alloc(const Allocator *allocator, B32Array *array, b32 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + B32Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (B32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_B32_ARRAY_APPEND_ALLOC; + } + wapp_b32_array_copy_capped(array, output); + } + + wapp_b32_array_append_capped(output, item); + +RETURN_B32_ARRAY_APPEND_ALLOC: + return output; +} + +B32Array *wapp_b32_array_extend_alloc(const Allocator *allocator, B32Array *array, const B32Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + B32Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (B32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_B32_ARRAY_EXTEND_ALLOC; + } + wapp_b32_array_copy_capped(array, output); + } + + wapp_b32_array_extend_capped(output, other); + +RETURN_B32_ARRAY_EXTEND_ALLOC: + return output; +} + +B32Array *wapp_b32_array_copy_alloc(const Allocator *allocator, const B32Array *src, B32Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + B32Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (B32Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_B32_ARRAY_COPY_ALLOC; + } + } + + wapp_b32_array_clear(output); + wapp_b32_array_copy_capped(src, output); + +RETURN_B32_ARRAY_COPY_ALLOC: + return output; +} + +b32 *_b32_array_pop(B32Array *array) { + u64 index = array->count - 1; + b32 *out = wapp_b32_array_get(array, index); + --(array->count); + return out; +} + +char *wapp_char_array_get(const CharArray *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (char *)ptr; +} + +void wapp_char_array_set(CharArray *array, u64 index, char *item) { + char *ptr = wapp_char_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_char_array_append_capped(CharArray *array, char *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_char_array_set(array, index, item); +} + +void wapp_char_array_extend_capped(CharArray *array, const CharArray *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + char *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_char_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_char_array_append_capped(array, item); + } +} + +void wapp_char_array_clear(CharArray *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_char_array_copy_capped(const CharArray *src, CharArray *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_char_array_clear(dst); + + char *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_char_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_char_array_append_capped(dst, item); + } +} + +CharArray *wapp_char_array_append_alloc(const Allocator *allocator, CharArray *array, char *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + CharArray *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (CharArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_CHAR_ARRAY_APPEND_ALLOC; + } + wapp_char_array_copy_capped(array, output); + } + + wapp_char_array_append_capped(output, item); + +RETURN_CHAR_ARRAY_APPEND_ALLOC: + return output; +} + +CharArray *wapp_char_array_extend_alloc(const Allocator *allocator, CharArray *array, const CharArray *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + CharArray *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (CharArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_CHAR_ARRAY_EXTEND_ALLOC; + } + wapp_char_array_copy_capped(array, output); + } + + wapp_char_array_extend_capped(output, other); + +RETURN_CHAR_ARRAY_EXTEND_ALLOC: + return output; +} + +CharArray *wapp_char_array_copy_alloc(const Allocator *allocator, const CharArray *src, CharArray *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + CharArray *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (CharArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_CHAR_ARRAY_COPY_ALLOC; + } + } + + wapp_char_array_clear(output); + wapp_char_array_copy_capped(src, output); + +RETURN_CHAR_ARRAY_COPY_ALLOC: + return output; +} + +char *_char_array_pop(CharArray *array) { + u64 index = array->count - 1; + char *out = wapp_char_array_get(array, index); + --(array->count); + return out; +} + +c8 *wapp_c8_array_get(const C8Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (c8 *)ptr; +} + +void wapp_c8_array_set(C8Array *array, u64 index, c8 *item) { + c8 *ptr = wapp_c8_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_c8_array_append_capped(C8Array *array, c8 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_c8_array_set(array, index, item); +} + +void wapp_c8_array_extend_capped(C8Array *array, const C8Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + c8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_c8_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_c8_array_append_capped(array, item); + } +} + +void wapp_c8_array_clear(C8Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_c8_array_copy_capped(const C8Array *src, C8Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_c8_array_clear(dst); + + c8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_c8_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_c8_array_append_capped(dst, item); + } +} + +C8Array *wapp_c8_array_append_alloc(const Allocator *allocator, C8Array *array, c8 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + C8Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (C8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_C8_ARRAY_APPEND_ALLOC; + } + wapp_c8_array_copy_capped(array, output); + } + + wapp_c8_array_append_capped(output, item); + +RETURN_C8_ARRAY_APPEND_ALLOC: + return output; +} + +C8Array *wapp_c8_array_extend_alloc(const Allocator *allocator, C8Array *array, const C8Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + C8Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (C8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_C8_ARRAY_EXTEND_ALLOC; + } + wapp_c8_array_copy_capped(array, output); + } + + wapp_c8_array_extend_capped(output, other); + +RETURN_C8_ARRAY_EXTEND_ALLOC: + return output; +} + +C8Array *wapp_c8_array_copy_alloc(const Allocator *allocator, const C8Array *src, C8Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + C8Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (C8Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_C8_ARRAY_COPY_ALLOC; + } + } + + wapp_c8_array_clear(output); + wapp_c8_array_copy_capped(src, output); + +RETURN_C8_ARRAY_COPY_ALLOC: + return output; +} + +c8 *_c8_array_pop(C8Array *array) { + u64 index = array->count - 1; + c8 *out = wapp_c8_array_get(array, index); + --(array->count); + return out; +} + +c16 *wapp_c16_array_get(const C16Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (c16 *)ptr; +} + +void wapp_c16_array_set(C16Array *array, u64 index, c16 *item) { + c16 *ptr = wapp_c16_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_c16_array_append_capped(C16Array *array, c16 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_c16_array_set(array, index, item); +} + +void wapp_c16_array_extend_capped(C16Array *array, const C16Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + c16 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_c16_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_c16_array_append_capped(array, item); + } +} + +void wapp_c16_array_clear(C16Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_c16_array_copy_capped(const C16Array *src, C16Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_c16_array_clear(dst); + + c16 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_c16_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_c16_array_append_capped(dst, item); + } +} + +C16Array *wapp_c16_array_append_alloc(const Allocator *allocator, C16Array *array, c16 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + C16Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (C16Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_C16_ARRAY_APPEND_ALLOC; + } + wapp_c16_array_copy_capped(array, output); + } + + wapp_c16_array_append_capped(output, item); + +RETURN_C16_ARRAY_APPEND_ALLOC: + return output; +} + +C16Array *wapp_c16_array_extend_alloc(const Allocator *allocator, C16Array *array, const C16Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + C16Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (C16Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_C16_ARRAY_EXTEND_ALLOC; + } + wapp_c16_array_copy_capped(array, output); + } + + wapp_c16_array_extend_capped(output, other); + +RETURN_C16_ARRAY_EXTEND_ALLOC: + return output; +} + +C16Array *wapp_c16_array_copy_alloc(const Allocator *allocator, const C16Array *src, C16Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + C16Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (C16Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_C16_ARRAY_COPY_ALLOC; + } + } + + wapp_c16_array_clear(output); + wapp_c16_array_copy_capped(src, output); + +RETURN_C16_ARRAY_COPY_ALLOC: + return output; +} + +c16 *_c16_array_pop(C16Array *array) { + u64 index = array->count - 1; + c16 *out = wapp_c16_array_get(array, index); + --(array->count); + return out; +} + +c32 *wapp_c32_array_get(const C32Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (c32 *)ptr; +} + +void wapp_c32_array_set(C32Array *array, u64 index, c32 *item) { + c32 *ptr = wapp_c32_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_c32_array_append_capped(C32Array *array, c32 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_c32_array_set(array, index, item); +} + +void wapp_c32_array_extend_capped(C32Array *array, const C32Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + c32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_c32_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_c32_array_append_capped(array, item); + } +} + +void wapp_c32_array_clear(C32Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_c32_array_copy_capped(const C32Array *src, C32Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_c32_array_clear(dst); + + c32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_c32_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_c32_array_append_capped(dst, item); + } +} + +C32Array *wapp_c32_array_append_alloc(const Allocator *allocator, C32Array *array, c32 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + C32Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (C32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_C32_ARRAY_APPEND_ALLOC; + } + wapp_c32_array_copy_capped(array, output); + } + + wapp_c32_array_append_capped(output, item); + +RETURN_C32_ARRAY_APPEND_ALLOC: + return output; +} + +C32Array *wapp_c32_array_extend_alloc(const Allocator *allocator, C32Array *array, const C32Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + C32Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (C32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_C32_ARRAY_EXTEND_ALLOC; + } + wapp_c32_array_copy_capped(array, output); + } + + wapp_c32_array_extend_capped(output, other); + +RETURN_C32_ARRAY_EXTEND_ALLOC: + return output; +} + +C32Array *wapp_c32_array_copy_alloc(const Allocator *allocator, const C32Array *src, C32Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + C32Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (C32Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_C32_ARRAY_COPY_ALLOC; + } + } + + wapp_c32_array_clear(output); + wapp_c32_array_copy_capped(src, output); + +RETURN_C32_ARRAY_COPY_ALLOC: + return output; +} + +c32 *_c32_array_pop(C32Array *array) { + u64 index = array->count - 1; + c32 *out = wapp_c32_array_get(array, index); + --(array->count); + return out; +} + +i8 *wapp_i8_array_get(const I8Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (i8 *)ptr; +} + +void wapp_i8_array_set(I8Array *array, u64 index, i8 *item) { + i8 *ptr = wapp_i8_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_i8_array_append_capped(I8Array *array, i8 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_i8_array_set(array, index, item); +} + +void wapp_i8_array_extend_capped(I8Array *array, const I8Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + i8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i8_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_i8_array_append_capped(array, item); + } +} + +void wapp_i8_array_clear(I8Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_i8_array_copy_capped(const I8Array *src, I8Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_i8_array_clear(dst); + + i8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i8_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_i8_array_append_capped(dst, item); + } +} + +I8Array *wapp_i8_array_append_alloc(const Allocator *allocator, I8Array *array, i8 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + I8Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I8_ARRAY_APPEND_ALLOC; + } + wapp_i8_array_copy_capped(array, output); + } + + wapp_i8_array_append_capped(output, item); + +RETURN_I8_ARRAY_APPEND_ALLOC: + return output; +} + +I8Array *wapp_i8_array_extend_alloc(const Allocator *allocator, I8Array *array, const I8Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + I8Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I8_ARRAY_EXTEND_ALLOC; + } + wapp_i8_array_copy_capped(array, output); + } + + wapp_i8_array_extend_capped(output, other); + +RETURN_I8_ARRAY_EXTEND_ALLOC: + return output; +} + +I8Array *wapp_i8_array_copy_alloc(const Allocator *allocator, const I8Array *src, I8Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + I8Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (I8Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_I8_ARRAY_COPY_ALLOC; + } + } + + wapp_i8_array_clear(output); + wapp_i8_array_copy_capped(src, output); + +RETURN_I8_ARRAY_COPY_ALLOC: + return output; +} + +i8 *_i8_array_pop(I8Array *array) { + u64 index = array->count - 1; + i8 *out = wapp_i8_array_get(array, index); + --(array->count); + return out; +} + +i16 *wapp_i16_array_get(const I16Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (i16 *)ptr; +} + +void wapp_i16_array_set(I16Array *array, u64 index, i16 *item) { + i16 *ptr = wapp_i16_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_i16_array_append_capped(I16Array *array, i16 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_i16_array_set(array, index, item); +} + +void wapp_i16_array_extend_capped(I16Array *array, const I16Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + i16 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i16_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_i16_array_append_capped(array, item); + } +} + +void wapp_i16_array_clear(I16Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_i16_array_copy_capped(const I16Array *src, I16Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_i16_array_clear(dst); + + i16 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i16_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_i16_array_append_capped(dst, item); + } +} + +I16Array *wapp_i16_array_append_alloc(const Allocator *allocator, I16Array *array, i16 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + I16Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I16Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I16_ARRAY_APPEND_ALLOC; + } + wapp_i16_array_copy_capped(array, output); + } + + wapp_i16_array_append_capped(output, item); + +RETURN_I16_ARRAY_APPEND_ALLOC: + return output; +} + +I16Array *wapp_i16_array_extend_alloc(const Allocator *allocator, I16Array *array, const I16Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + I16Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I16Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I16_ARRAY_EXTEND_ALLOC; + } + wapp_i16_array_copy_capped(array, output); + } + + wapp_i16_array_extend_capped(output, other); + +RETURN_I16_ARRAY_EXTEND_ALLOC: + return output; +} + +I16Array *wapp_i16_array_copy_alloc(const Allocator *allocator, const I16Array *src, I16Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + I16Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (I16Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_I16_ARRAY_COPY_ALLOC; + } + } + + wapp_i16_array_clear(output); + wapp_i16_array_copy_capped(src, output); + +RETURN_I16_ARRAY_COPY_ALLOC: + return output; +} + +i16 *_i16_array_pop(I16Array *array) { + u64 index = array->count - 1; + i16 *out = wapp_i16_array_get(array, index); + --(array->count); + return out; +} + +i32 *wapp_i32_array_get(const I32Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (i32 *)ptr; +} + +void wapp_i32_array_set(I32Array *array, u64 index, i32 *item) { + i32 *ptr = wapp_i32_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_i32_array_append_capped(I32Array *array, i32 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_i32_array_set(array, index, item); +} + +void wapp_i32_array_extend_capped(I32Array *array, const I32Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + i32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i32_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_i32_array_append_capped(array, item); + } +} + +void wapp_i32_array_clear(I32Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_i32_array_copy_capped(const I32Array *src, I32Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_i32_array_clear(dst); + + i32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i32_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_i32_array_append_capped(dst, item); + } +} + +I32Array *wapp_i32_array_append_alloc(const Allocator *allocator, I32Array *array, i32 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + I32Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I32_ARRAY_APPEND_ALLOC; + } + wapp_i32_array_copy_capped(array, output); + } + + wapp_i32_array_append_capped(output, item); + +RETURN_I32_ARRAY_APPEND_ALLOC: + return output; +} + +I32Array *wapp_i32_array_extend_alloc(const Allocator *allocator, I32Array *array, const I32Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + I32Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I32_ARRAY_EXTEND_ALLOC; + } + wapp_i32_array_copy_capped(array, output); + } + + wapp_i32_array_extend_capped(output, other); + +RETURN_I32_ARRAY_EXTEND_ALLOC: + return output; +} + +I32Array *wapp_i32_array_copy_alloc(const Allocator *allocator, const I32Array *src, I32Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + I32Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (I32Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_I32_ARRAY_COPY_ALLOC; + } + } + + wapp_i32_array_clear(output); + wapp_i32_array_copy_capped(src, output); + +RETURN_I32_ARRAY_COPY_ALLOC: + return output; +} + +i32 *_i32_array_pop(I32Array *array) { + u64 index = array->count - 1; + i32 *out = wapp_i32_array_get(array, index); + --(array->count); + return out; +} + +i64 *wapp_i64_array_get(const I64Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (i64 *)ptr; +} + +void wapp_i64_array_set(I64Array *array, u64 index, i64 *item) { + i64 *ptr = wapp_i64_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_i64_array_append_capped(I64Array *array, i64 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_i64_array_set(array, index, item); +} + +void wapp_i64_array_extend_capped(I64Array *array, const I64Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + i64 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i64_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_i64_array_append_capped(array, item); + } +} + +void wapp_i64_array_clear(I64Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_i64_array_copy_capped(const I64Array *src, I64Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_i64_array_clear(dst); + + i64 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_i64_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_i64_array_append_capped(dst, item); + } +} + +I64Array *wapp_i64_array_append_alloc(const Allocator *allocator, I64Array *array, i64 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + I64Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I64Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I64_ARRAY_APPEND_ALLOC; + } + wapp_i64_array_copy_capped(array, output); + } + + wapp_i64_array_append_capped(output, item); + +RETURN_I64_ARRAY_APPEND_ALLOC: + return output; +} + +I64Array *wapp_i64_array_extend_alloc(const Allocator *allocator, I64Array *array, const I64Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + I64Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (I64Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_I64_ARRAY_EXTEND_ALLOC; + } + wapp_i64_array_copy_capped(array, output); + } + + wapp_i64_array_extend_capped(output, other); + +RETURN_I64_ARRAY_EXTEND_ALLOC: + return output; +} + +I64Array *wapp_i64_array_copy_alloc(const Allocator *allocator, const I64Array *src, I64Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + I64Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (I64Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_I64_ARRAY_COPY_ALLOC; + } + } + + wapp_i64_array_clear(output); + wapp_i64_array_copy_capped(src, output); + +RETURN_I64_ARRAY_COPY_ALLOC: + return output; +} + +i64 *_i64_array_pop(I64Array *array) { + u64 index = array->count - 1; + i64 *out = wapp_i64_array_get(array, index); + --(array->count); + return out; +} + +u8 *wapp_u8_array_get(const U8Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (u8 *)ptr; +} + +void wapp_u8_array_set(U8Array *array, u64 index, u8 *item) { + u8 *ptr = wapp_u8_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_u8_array_append_capped(U8Array *array, u8 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_u8_array_set(array, index, item); +} + +void wapp_u8_array_extend_capped(U8Array *array, const U8Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + u8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u8_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_u8_array_append_capped(array, item); + } +} + +void wapp_u8_array_clear(U8Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_u8_array_copy_capped(const U8Array *src, U8Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_u8_array_clear(dst); + + u8 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u8_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_u8_array_append_capped(dst, item); + } +} + +U8Array *wapp_u8_array_append_alloc(const Allocator *allocator, U8Array *array, u8 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + U8Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U8_ARRAY_APPEND_ALLOC; + } + wapp_u8_array_copy_capped(array, output); + } + + wapp_u8_array_append_capped(output, item); + +RETURN_U8_ARRAY_APPEND_ALLOC: + return output; +} + +U8Array *wapp_u8_array_extend_alloc(const Allocator *allocator, U8Array *array, const U8Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + U8Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U8Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U8_ARRAY_EXTEND_ALLOC; + } + wapp_u8_array_copy_capped(array, output); + } + + wapp_u8_array_extend_capped(output, other); + +RETURN_U8_ARRAY_EXTEND_ALLOC: + return output; +} + +U8Array *wapp_u8_array_copy_alloc(const Allocator *allocator, const U8Array *src, U8Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + U8Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (U8Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_U8_ARRAY_COPY_ALLOC; + } + } + + wapp_u8_array_clear(output); + wapp_u8_array_copy_capped(src, output); + +RETURN_U8_ARRAY_COPY_ALLOC: + return output; +} + +u8 *_u8_array_pop(U8Array *array) { + u64 index = array->count - 1; + u8 *out = wapp_u8_array_get(array, index); + --(array->count); + return out; +} + +u16 *wapp_u16_array_get(const U16Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (u16 *)ptr; +} + +void wapp_u16_array_set(U16Array *array, u64 index, u16 *item) { + u16 *ptr = wapp_u16_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_u16_array_append_capped(U16Array *array, u16 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_u16_array_set(array, index, item); +} + +void wapp_u16_array_extend_capped(U16Array *array, const U16Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + u16 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u16_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_u16_array_append_capped(array, item); + } +} + +void wapp_u16_array_clear(U16Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_u16_array_copy_capped(const U16Array *src, U16Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_u16_array_clear(dst); + + u16 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u16_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_u16_array_append_capped(dst, item); + } +} + +U16Array *wapp_u16_array_append_alloc(const Allocator *allocator, U16Array *array, u16 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + U16Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U16Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U16_ARRAY_APPEND_ALLOC; + } + wapp_u16_array_copy_capped(array, output); + } + + wapp_u16_array_append_capped(output, item); + +RETURN_U16_ARRAY_APPEND_ALLOC: + return output; +} + +U16Array *wapp_u16_array_extend_alloc(const Allocator *allocator, U16Array *array, const U16Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + U16Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U16Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U16_ARRAY_EXTEND_ALLOC; + } + wapp_u16_array_copy_capped(array, output); + } + + wapp_u16_array_extend_capped(output, other); + +RETURN_U16_ARRAY_EXTEND_ALLOC: + return output; +} + +U16Array *wapp_u16_array_copy_alloc(const Allocator *allocator, const U16Array *src, U16Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + U16Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (U16Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_U16_ARRAY_COPY_ALLOC; + } + } + + wapp_u16_array_clear(output); + wapp_u16_array_copy_capped(src, output); + +RETURN_U16_ARRAY_COPY_ALLOC: + return output; +} + +u16 *_u16_array_pop(U16Array *array) { + u64 index = array->count - 1; + u16 *out = wapp_u16_array_get(array, index); + --(array->count); + return out; +} + +u32 *wapp_u32_array_get(const U32Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (u32 *)ptr; +} + +void wapp_u32_array_set(U32Array *array, u64 index, u32 *item) { + u32 *ptr = wapp_u32_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_u32_array_append_capped(U32Array *array, u32 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_u32_array_set(array, index, item); +} + +void wapp_u32_array_extend_capped(U32Array *array, const U32Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + u32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u32_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_u32_array_append_capped(array, item); + } +} + +void wapp_u32_array_clear(U32Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_u32_array_copy_capped(const U32Array *src, U32Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_u32_array_clear(dst); + + u32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u32_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_u32_array_append_capped(dst, item); + } +} + +U32Array *wapp_u32_array_append_alloc(const Allocator *allocator, U32Array *array, u32 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + U32Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U32_ARRAY_APPEND_ALLOC; + } + wapp_u32_array_copy_capped(array, output); + } + + wapp_u32_array_append_capped(output, item); + +RETURN_U32_ARRAY_APPEND_ALLOC: + return output; +} + +U32Array *wapp_u32_array_extend_alloc(const Allocator *allocator, U32Array *array, const U32Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + U32Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U32_ARRAY_EXTEND_ALLOC; + } + wapp_u32_array_copy_capped(array, output); + } + + wapp_u32_array_extend_capped(output, other); + +RETURN_U32_ARRAY_EXTEND_ALLOC: + return output; +} + +U32Array *wapp_u32_array_copy_alloc(const Allocator *allocator, const U32Array *src, U32Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + U32Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (U32Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_U32_ARRAY_COPY_ALLOC; + } + } + + wapp_u32_array_clear(output); + wapp_u32_array_copy_capped(src, output); + +RETURN_U32_ARRAY_COPY_ALLOC: + return output; +} + +u32 *_u32_array_pop(U32Array *array) { + u64 index = array->count - 1; + u32 *out = wapp_u32_array_get(array, index); + --(array->count); + return out; +} + +u64 *wapp_u64_array_get(const U64Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (u64 *)ptr; +} + +void wapp_u64_array_set(U64Array *array, u64 index, u64 *item) { + u64 *ptr = wapp_u64_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_u64_array_append_capped(U64Array *array, u64 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_u64_array_set(array, index, item); +} + +void wapp_u64_array_extend_capped(U64Array *array, const U64Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + u64 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u64_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_u64_array_append_capped(array, item); + } +} + +void wapp_u64_array_clear(U64Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_u64_array_copy_capped(const U64Array *src, U64Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_u64_array_clear(dst); + + u64 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_u64_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_u64_array_append_capped(dst, item); + } +} + +U64Array *wapp_u64_array_append_alloc(const Allocator *allocator, U64Array *array, u64 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + U64Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U64Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U64_ARRAY_APPEND_ALLOC; + } + wapp_u64_array_copy_capped(array, output); + } + + wapp_u64_array_append_capped(output, item); + +RETURN_U64_ARRAY_APPEND_ALLOC: + return output; +} + +U64Array *wapp_u64_array_extend_alloc(const Allocator *allocator, U64Array *array, const U64Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + U64Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (U64Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_U64_ARRAY_EXTEND_ALLOC; + } + wapp_u64_array_copy_capped(array, output); + } + + wapp_u64_array_extend_capped(output, other); + +RETURN_U64_ARRAY_EXTEND_ALLOC: + return output; +} + +U64Array *wapp_u64_array_copy_alloc(const Allocator *allocator, const U64Array *src, U64Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + U64Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (U64Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_U64_ARRAY_COPY_ALLOC; + } + } + + wapp_u64_array_clear(output); + wapp_u64_array_copy_capped(src, output); + +RETURN_U64_ARRAY_COPY_ALLOC: + return output; +} + +u64 *_u64_array_pop(U64Array *array) { + u64 index = array->count - 1; + u64 *out = wapp_u64_array_get(array, index); + --(array->count); + return out; +} + +f32 *wapp_f32_array_get(const F32Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (f32 *)ptr; +} + +void wapp_f32_array_set(F32Array *array, u64 index, f32 *item) { + f32 *ptr = wapp_f32_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_f32_array_append_capped(F32Array *array, f32 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_f32_array_set(array, index, item); +} + +void wapp_f32_array_extend_capped(F32Array *array, const F32Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + f32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_f32_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_f32_array_append_capped(array, item); + } +} + +void wapp_f32_array_clear(F32Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_f32_array_copy_capped(const F32Array *src, F32Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_f32_array_clear(dst); + + f32 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_f32_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_f32_array_append_capped(dst, item); + } +} + +F32Array *wapp_f32_array_append_alloc(const Allocator *allocator, F32Array *array, f32 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + F32Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (F32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_F32_ARRAY_APPEND_ALLOC; + } + wapp_f32_array_copy_capped(array, output); + } + + wapp_f32_array_append_capped(output, item); + +RETURN_F32_ARRAY_APPEND_ALLOC: + return output; +} + +F32Array *wapp_f32_array_extend_alloc(const Allocator *allocator, F32Array *array, const F32Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + F32Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (F32Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_F32_ARRAY_EXTEND_ALLOC; + } + wapp_f32_array_copy_capped(array, output); + } + + wapp_f32_array_extend_capped(output, other); + +RETURN_F32_ARRAY_EXTEND_ALLOC: + return output; +} + +F32Array *wapp_f32_array_copy_alloc(const Allocator *allocator, const F32Array *src, F32Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + F32Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (F32Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_F32_ARRAY_COPY_ALLOC; + } + } + + wapp_f32_array_clear(output); + wapp_f32_array_copy_capped(src, output); + +RETURN_F32_ARRAY_COPY_ALLOC: + return output; +} + +f32 *_f32_array_pop(F32Array *array) { + u64 index = array->count - 1; + f32 *out = wapp_f32_array_get(array, index); + --(array->count); + return out; +} + +f64 *wapp_f64_array_get(const F64Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (f64 *)ptr; +} + +void wapp_f64_array_set(F64Array *array, u64 index, f64 *item) { + f64 *ptr = wapp_f64_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_f64_array_append_capped(F64Array *array, f64 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_f64_array_set(array, index, item); +} + +void wapp_f64_array_extend_capped(F64Array *array, const F64Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + f64 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_f64_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_f64_array_append_capped(array, item); + } +} + +void wapp_f64_array_clear(F64Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_f64_array_copy_capped(const F64Array *src, F64Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_f64_array_clear(dst); + + f64 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_f64_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_f64_array_append_capped(dst, item); + } +} + +F64Array *wapp_f64_array_append_alloc(const Allocator *allocator, F64Array *array, f64 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + F64Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (F64Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_F64_ARRAY_APPEND_ALLOC; + } + wapp_f64_array_copy_capped(array, output); + } + + wapp_f64_array_append_capped(output, item); + +RETURN_F64_ARRAY_APPEND_ALLOC: + return output; +} + +F64Array *wapp_f64_array_extend_alloc(const Allocator *allocator, F64Array *array, const F64Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + F64Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (F64Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_F64_ARRAY_EXTEND_ALLOC; + } + wapp_f64_array_copy_capped(array, output); + } + + wapp_f64_array_extend_capped(output, other); + +RETURN_F64_ARRAY_EXTEND_ALLOC: + return output; +} + +F64Array *wapp_f64_array_copy_alloc(const Allocator *allocator, const F64Array *src, F64Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + F64Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (F64Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_F64_ARRAY_COPY_ALLOC; + } + } + + wapp_f64_array_clear(output); + wapp_f64_array_copy_capped(src, output); + +RETURN_F64_ARRAY_COPY_ALLOC: + return output; +} + +f64 *_f64_array_pop(F64Array *array) { + u64 index = array->count - 1; + f64 *out = wapp_f64_array_get(array, index); + --(array->count); + return out; +} + +f128 *wapp_f128_array_get(const F128Array *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (f128 *)ptr; +} + +void wapp_f128_array_set(F128Array *array, u64 index, f128 *item) { + f128 *ptr = wapp_f128_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_f128_array_append_capped(F128Array *array, f128 *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_f128_array_set(array, index, item); +} + +void wapp_f128_array_extend_capped(F128Array *array, const F128Array *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + f128 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_f128_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_f128_array_append_capped(array, item); + } +} + +void wapp_f128_array_clear(F128Array *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_f128_array_copy_capped(const F128Array *src, F128Array *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_f128_array_clear(dst); + + f128 *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_f128_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_f128_array_append_capped(dst, item); + } +} + +F128Array *wapp_f128_array_append_alloc(const Allocator *allocator, F128Array *array, f128 *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + F128Array *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (F128Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_F128_ARRAY_APPEND_ALLOC; + } + wapp_f128_array_copy_capped(array, output); + } + + wapp_f128_array_append_capped(output, item); + +RETURN_F128_ARRAY_APPEND_ALLOC: + return output; +} + +F128Array *wapp_f128_array_extend_alloc(const Allocator *allocator, F128Array *array, const F128Array *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + F128Array *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (F128Array *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_F128_ARRAY_EXTEND_ALLOC; + } + wapp_f128_array_copy_capped(array, output); + } + + wapp_f128_array_extend_capped(output, other); + +RETURN_F128_ARRAY_EXTEND_ALLOC: + return output; +} + +F128Array *wapp_f128_array_copy_alloc(const Allocator *allocator, const F128Array *src, F128Array *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + F128Array *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (F128Array *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_F128_ARRAY_COPY_ALLOC; + } + } + + wapp_f128_array_clear(output); + wapp_f128_array_copy_capped(src, output); + +RETURN_F128_ARRAY_COPY_ALLOC: + return output; +} + +f128 *_f128_array_pop(F128Array *array) { + u64 index = array->count - 1; + f128 *out = wapp_f128_array_get(array, index); + --(array->count); + return out; +} + +iptr *wapp_iptr_array_get(const IptrArray *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (iptr *)ptr; +} + +void wapp_iptr_array_set(IptrArray *array, u64 index, iptr *item) { + iptr *ptr = wapp_iptr_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_iptr_array_append_capped(IptrArray *array, iptr *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_iptr_array_set(array, index, item); +} + +void wapp_iptr_array_extend_capped(IptrArray *array, const IptrArray *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + iptr *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_iptr_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_iptr_array_append_capped(array, item); + } +} + +void wapp_iptr_array_clear(IptrArray *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_iptr_array_copy_capped(const IptrArray *src, IptrArray *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_iptr_array_clear(dst); + + iptr *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_iptr_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_iptr_array_append_capped(dst, item); + } +} + +IptrArray *wapp_iptr_array_append_alloc(const Allocator *allocator, IptrArray *array, iptr *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + IptrArray *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (IptrArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_IPTR_ARRAY_APPEND_ALLOC; + } + wapp_iptr_array_copy_capped(array, output); + } + + wapp_iptr_array_append_capped(output, item); + +RETURN_IPTR_ARRAY_APPEND_ALLOC: + return output; +} + +IptrArray *wapp_iptr_array_extend_alloc(const Allocator *allocator, IptrArray *array, const IptrArray *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + IptrArray *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (IptrArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_IPTR_ARRAY_EXTEND_ALLOC; + } + wapp_iptr_array_copy_capped(array, output); + } + + wapp_iptr_array_extend_capped(output, other); + +RETURN_IPTR_ARRAY_EXTEND_ALLOC: + return output; +} + +IptrArray *wapp_iptr_array_copy_alloc(const Allocator *allocator, const IptrArray *src, IptrArray *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + IptrArray *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (IptrArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_IPTR_ARRAY_COPY_ALLOC; + } + } + + wapp_iptr_array_clear(output); + wapp_iptr_array_copy_capped(src, output); + +RETURN_IPTR_ARRAY_COPY_ALLOC: + return output; +} + +iptr *_iptr_array_pop(IptrArray *array) { + u64 index = array->count - 1; + iptr *out = wapp_iptr_array_get(array, index); + --(array->count); + return out; +} + +uptr *wapp_uptr_array_get(const UptrArray *array, u64 index) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(index < array->count, "`index` is out of bounds"); + + u8 *ptr = (u8 *)(array->items) + (array->item_size * index); + return (uptr *)ptr; +} + +void wapp_uptr_array_set(UptrArray *array, u64 index, uptr *item) { + uptr *ptr = wapp_uptr_array_get(array, index); + + memcpy((void *)ptr, (void *)item, array->item_size); +} + +void wapp_uptr_array_append_capped(UptrArray *array, uptr *item) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + wapp_runtime_assert(array->count < array->capacity, "`array` is full"); + + u64 index = (array->count)++; + wapp_uptr_array_set(array, index, item); +} + +void wapp_uptr_array_extend_capped(UptrArray *array, const UptrArray *other) { + wapp_debug_assert(array != NULL && other != NULL, "`array` and `other` should not be NULL"); + + u64 remaining_capacity = array->capacity - array->count; + wapp_runtime_assert(other->count < remaining_capacity, "`array` does not have enough capacity"); + + uptr *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 items_to_add = other->count; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_uptr_array_get(other, item_index); + ++item_index; + running = item_index < items_to_add; + + if (!item) { + continue; + } + + wapp_uptr_array_append_capped(array, item); + } +} + +void wapp_uptr_array_clear(UptrArray *array) { + wapp_debug_assert(array != NULL, "`array` should not be NULL"); + array->count = 0; +} + +void wapp_uptr_array_copy_capped(const UptrArray *src, UptrArray *dst) { + wapp_debug_assert(src != NULL && dst != NULL, "`src` and `dst` should not be NULL"); + + wapp_uptr_array_clear(dst); + + uptr *item; + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + u64 to_copy = src->count < dst->capacity ? src->count : dst->capacity; + u64 item_index = 0; + b32 running = true; + while (running) { + item = wapp_uptr_array_get(src, item_index); + ++item_index; + running = item_index < to_copy; + + if (!item) { + continue; + } + + wapp_uptr_array_append_capped(dst, item); + } +} + +UptrArray *wapp_uptr_array_append_alloc(const Allocator *allocator, UptrArray *array, uptr *item) { + wapp_debug_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL"); + + UptrArray *output = array; + + if (array->count >= array->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (UptrArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_UPTR_ARRAY_APPEND_ALLOC; + } + wapp_uptr_array_copy_capped(array, output); + } + + wapp_uptr_array_append_capped(output, item); + +RETURN_UPTR_ARRAY_APPEND_ALLOC: + return output; +} + +UptrArray *wapp_uptr_array_extend_alloc(const Allocator *allocator, UptrArray *array, const UptrArray *other) { + wapp_debug_assert(allocator != NULL && array != NULL && other != NULL, "`allocator`, `array` and `other` should not be NULL"); + + UptrArray *output = array; + + u64 remaining_capacity = array->capacity - array->count; + if (other->count >= remaining_capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2); + output = (UptrArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size); + if (!output) { + output = array; + goto RETURN_UPTR_ARRAY_EXTEND_ALLOC; + } + wapp_uptr_array_copy_capped(array, output); + } + + wapp_uptr_array_extend_capped(output, other); + +RETURN_UPTR_ARRAY_EXTEND_ALLOC: + return output; +} + +UptrArray *wapp_uptr_array_copy_alloc(const Allocator *allocator, const UptrArray *src, UptrArray *dst) { + wapp_debug_assert(allocator != NULL && src != NULL && dst != NULL, "`allocator`, `src` and `dst` should not be NULL"); + + UptrArray *output = dst; + + if (src->count >= dst->capacity) { + u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2); + output = (UptrArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size); + if (!output) { + output = dst; + goto RETURN_UPTR_ARRAY_COPY_ALLOC; + } + } + + wapp_uptr_array_clear(output); + wapp_uptr_array_copy_capped(src, output); + +RETURN_UPTR_ARRAY_COPY_ALLOC: + return output; +} + +uptr *_uptr_array_pop(UptrArray *array) { + u64 index = array->count - 1; + uptr *out = wapp_uptr_array_get(array, index); + --(array->count); + return out; +} + +VoidPArray *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size) { + wapp_debug_assert(allocator != NULL, "`array` should not be NULL"); + + u64 allocation_size = sizeof(VoidPArray) + item_size * capacity; + VoidPArray *array = wapp_mem_allocator_alloc(allocator, allocation_size); + if (!array) { + goto RETURN_GENERIC_ARRAY_ALLOC; + } + + array->items = (void * *)((u8 *)array + sizeof(VoidPArray)); + array->count = 0; + array->capacity = capacity; + array->item_size = item_size; + +RETURN_GENERIC_ARRAY_ALLOC: + return array; +} + diff --git a/wapp/primitives/array/array.h b/wapp/primitives/array/array.h new file mode 100644 index 0000000..a786faa --- /dev/null +++ b/wapp/primitives/array/array.h @@ -0,0 +1,971 @@ +/** + * THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN + */ + +#ifndef ARRAY_H +#define ARRAY_H + +#include "../../common/aliases/aliases.h" +#include "../mem_allocator/mem_allocator.h" +#include "../../common/misc/misc_utils.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#define wapp_str8_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((Str8Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(Str8))) +#define wapp_void_ptr_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((VoidPArray *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(void *))) +#define wapp_b32_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((B32Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(b32))) +#define wapp_char_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((CharArray *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(char))) +#define wapp_c8_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((C8Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(c8))) +#define wapp_c16_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((C16Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(c16))) +#define wapp_c32_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((C32Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(c32))) +#define wapp_i8_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((I8Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(i8))) +#define wapp_i16_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((I16Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(i16))) +#define wapp_i32_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((I32Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(i32))) +#define wapp_i64_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((I64Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(i64))) +#define wapp_u8_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((U8Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(u8))) +#define wapp_u16_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((U16Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(u16))) +#define wapp_u32_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((U32Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(u32))) +#define wapp_u64_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((U64Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(u64))) +#define wapp_f32_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((F32Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(f32))) +#define wapp_f64_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((F64Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(f64))) +#define wapp_f128_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((F128Array *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(f128))) +#define wapp_iptr_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((IptrArray *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(iptr))) +#define wapp_uptr_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY) ((UptrArray *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(uptr))) + +#ifdef WAPP_PLATFORM_CPP +#define wapp_str8_array(...) ([&]() { \ + persistent Str8 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(Str8, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return Str8Array{ \ + buf, \ + wapp_misc_utils_va_args_count(Str8, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(Str8, __VA_ARGS__) * 2), \ + sizeof(Str8) \ + }; \ +}()) +#define wapp_str8_array_with_capacity(CAPACITY) ([&]() { \ + persistent Str8 buf[CAPACITY] = {}; \ + return Str8Array{buf, 0, CAPACITY, sizeof(Str8)}; \ +}()) +#define wapp_str8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_str8_array_pop(ARRAY_PTR) : \ + Str8{} \ +) +#define wapp_void_ptr_array(...) ([&]() { \ + persistent void * buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(void *, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return VoidPArray{ \ + buf, \ + wapp_misc_utils_va_args_count(void *, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(void *, __VA_ARGS__) * 2), \ + sizeof(void *) \ + }; \ +}()) +#define wapp_void_ptr_array_with_capacity(CAPACITY) ([&]() { \ + persistent void * buf[CAPACITY] = {}; \ + return VoidPArray{buf, 0, CAPACITY, sizeof(void *)}; \ +}()) +#define wapp_void_ptr_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_void_ptr_array_pop(ARRAY_PTR) : \ + void *{} \ +) +#define wapp_b32_array(...) ([&]() { \ + persistent b32 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(b32, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return B32Array{ \ + buf, \ + wapp_misc_utils_va_args_count(b32, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(b32, __VA_ARGS__) * 2), \ + sizeof(b32) \ + }; \ +}()) +#define wapp_b32_array_with_capacity(CAPACITY) ([&]() { \ + persistent b32 buf[CAPACITY] = {}; \ + return B32Array{buf, 0, CAPACITY, sizeof(b32)}; \ +}()) +#define wapp_b32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_b32_array_pop(ARRAY_PTR) : \ + b32{} \ +) +#define wapp_char_array(...) ([&]() { \ + persistent char buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(char, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return CharArray{ \ + buf, \ + wapp_misc_utils_va_args_count(char, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(char, __VA_ARGS__) * 2), \ + sizeof(char) \ + }; \ +}()) +#define wapp_char_array_with_capacity(CAPACITY) ([&]() { \ + persistent char buf[CAPACITY] = {}; \ + return CharArray{buf, 0, CAPACITY, sizeof(char)}; \ +}()) +#define wapp_char_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_char_array_pop(ARRAY_PTR) : \ + char{} \ +) +#define wapp_c8_array(...) ([&]() { \ + persistent c8 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c8, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return C8Array{ \ + buf, \ + wapp_misc_utils_va_args_count(c8, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c8, __VA_ARGS__) * 2), \ + sizeof(c8) \ + }; \ +}()) +#define wapp_c8_array_with_capacity(CAPACITY) ([&]() { \ + persistent c8 buf[CAPACITY] = {}; \ + return C8Array{buf, 0, CAPACITY, sizeof(c8)}; \ +}()) +#define wapp_c8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_c8_array_pop(ARRAY_PTR) : \ + c8{} \ +) +#define wapp_c16_array(...) ([&]() { \ + persistent c16 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c16, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return C16Array{ \ + buf, \ + wapp_misc_utils_va_args_count(c16, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c16, __VA_ARGS__) * 2), \ + sizeof(c16) \ + }; \ +}()) +#define wapp_c16_array_with_capacity(CAPACITY) ([&]() { \ + persistent c16 buf[CAPACITY] = {}; \ + return C16Array{buf, 0, CAPACITY, sizeof(c16)}; \ +}()) +#define wapp_c16_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_c16_array_pop(ARRAY_PTR) : \ + c16{} \ +) +#define wapp_c32_array(...) ([&]() { \ + persistent c32 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c32, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return C32Array{ \ + buf, \ + wapp_misc_utils_va_args_count(c32, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c32, __VA_ARGS__) * 2), \ + sizeof(c32) \ + }; \ +}()) +#define wapp_c32_array_with_capacity(CAPACITY) ([&]() { \ + persistent c32 buf[CAPACITY] = {}; \ + return C32Array{buf, 0, CAPACITY, sizeof(c32)}; \ +}()) +#define wapp_c32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_c32_array_pop(ARRAY_PTR) : \ + c32{} \ +) +#define wapp_i8_array(...) ([&]() { \ + persistent i8 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i8, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return I8Array{ \ + buf, \ + wapp_misc_utils_va_args_count(i8, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i8, __VA_ARGS__) * 2), \ + sizeof(i8) \ + }; \ +}()) +#define wapp_i8_array_with_capacity(CAPACITY) ([&]() { \ + persistent i8 buf[CAPACITY] = {}; \ + return I8Array{buf, 0, CAPACITY, sizeof(i8)}; \ +}()) +#define wapp_i8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i8_array_pop(ARRAY_PTR) : \ + i8{} \ +) +#define wapp_i16_array(...) ([&]() { \ + persistent i16 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i16, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return I16Array{ \ + buf, \ + wapp_misc_utils_va_args_count(i16, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i16, __VA_ARGS__) * 2), \ + sizeof(i16) \ + }; \ +}()) +#define wapp_i16_array_with_capacity(CAPACITY) ([&]() { \ + persistent i16 buf[CAPACITY] = {}; \ + return I16Array{buf, 0, CAPACITY, sizeof(i16)}; \ +}()) +#define wapp_i16_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i16_array_pop(ARRAY_PTR) : \ + i16{} \ +) +#define wapp_i32_array(...) ([&]() { \ + persistent i32 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i32, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return I32Array{ \ + buf, \ + wapp_misc_utils_va_args_count(i32, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i32, __VA_ARGS__) * 2), \ + sizeof(i32) \ + }; \ +}()) +#define wapp_i32_array_with_capacity(CAPACITY) ([&]() { \ + persistent i32 buf[CAPACITY] = {}; \ + return I32Array{buf, 0, CAPACITY, sizeof(i32)}; \ +}()) +#define wapp_i32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i32_array_pop(ARRAY_PTR) : \ + i32{} \ +) +#define wapp_i64_array(...) ([&]() { \ + persistent i64 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i64, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return I64Array{ \ + buf, \ + wapp_misc_utils_va_args_count(i64, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i64, __VA_ARGS__) * 2), \ + sizeof(i64) \ + }; \ +}()) +#define wapp_i64_array_with_capacity(CAPACITY) ([&]() { \ + persistent i64 buf[CAPACITY] = {}; \ + return I64Array{buf, 0, CAPACITY, sizeof(i64)}; \ +}()) +#define wapp_i64_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i64_array_pop(ARRAY_PTR) : \ + i64{} \ +) +#define wapp_u8_array(...) ([&]() { \ + persistent u8 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u8, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return U8Array{ \ + buf, \ + wapp_misc_utils_va_args_count(u8, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u8, __VA_ARGS__) * 2), \ + sizeof(u8) \ + }; \ +}()) +#define wapp_u8_array_with_capacity(CAPACITY) ([&]() { \ + persistent u8 buf[CAPACITY] = {}; \ + return U8Array{buf, 0, CAPACITY, sizeof(u8)}; \ +}()) +#define wapp_u8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u8_array_pop(ARRAY_PTR) : \ + u8{} \ +) +#define wapp_u16_array(...) ([&]() { \ + persistent u16 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u16, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return U16Array{ \ + buf, \ + wapp_misc_utils_va_args_count(u16, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u16, __VA_ARGS__) * 2), \ + sizeof(u16) \ + }; \ +}()) +#define wapp_u16_array_with_capacity(CAPACITY) ([&]() { \ + persistent u16 buf[CAPACITY] = {}; \ + return U16Array{buf, 0, CAPACITY, sizeof(u16)}; \ +}()) +#define wapp_u16_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u16_array_pop(ARRAY_PTR) : \ + u16{} \ +) +#define wapp_u32_array(...) ([&]() { \ + persistent u32 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u32, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return U32Array{ \ + buf, \ + wapp_misc_utils_va_args_count(u32, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u32, __VA_ARGS__) * 2), \ + sizeof(u32) \ + }; \ +}()) +#define wapp_u32_array_with_capacity(CAPACITY) ([&]() { \ + persistent u32 buf[CAPACITY] = {}; \ + return U32Array{buf, 0, CAPACITY, sizeof(u32)}; \ +}()) +#define wapp_u32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u32_array_pop(ARRAY_PTR) : \ + u32{} \ +) +#define wapp_u64_array(...) ([&]() { \ + persistent u64 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u64, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return U64Array{ \ + buf, \ + wapp_misc_utils_va_args_count(u64, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u64, __VA_ARGS__) * 2), \ + sizeof(u64) \ + }; \ +}()) +#define wapp_u64_array_with_capacity(CAPACITY) ([&]() { \ + persistent u64 buf[CAPACITY] = {}; \ + return U64Array{buf, 0, CAPACITY, sizeof(u64)}; \ +}()) +#define wapp_u64_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u64_array_pop(ARRAY_PTR) : \ + u64{} \ +) +#define wapp_f32_array(...) ([&]() { \ + persistent f32 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f32, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return F32Array{ \ + buf, \ + wapp_misc_utils_va_args_count(f32, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f32, __VA_ARGS__) * 2), \ + sizeof(f32) \ + }; \ +}()) +#define wapp_f32_array_with_capacity(CAPACITY) ([&]() { \ + persistent f32 buf[CAPACITY] = {}; \ + return F32Array{buf, 0, CAPACITY, sizeof(f32)}; \ +}()) +#define wapp_f32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_f32_array_pop(ARRAY_PTR) : \ + f32{} \ +) +#define wapp_f64_array(...) ([&]() { \ + persistent f64 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f64, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return F64Array{ \ + buf, \ + wapp_misc_utils_va_args_count(f64, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f64, __VA_ARGS__) * 2), \ + sizeof(f64) \ + }; \ +}()) +#define wapp_f64_array_with_capacity(CAPACITY) ([&]() { \ + persistent f64 buf[CAPACITY] = {}; \ + return F64Array{buf, 0, CAPACITY, sizeof(f64)}; \ +}()) +#define wapp_f64_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_f64_array_pop(ARRAY_PTR) : \ + f64{} \ +) +#define wapp_f128_array(...) ([&]() { \ + persistent f128 buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f128, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return F128Array{ \ + buf, \ + wapp_misc_utils_va_args_count(f128, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f128, __VA_ARGS__) * 2), \ + sizeof(f128) \ + }; \ +}()) +#define wapp_f128_array_with_capacity(CAPACITY) ([&]() { \ + persistent f128 buf[CAPACITY] = {}; \ + return F128Array{buf, 0, CAPACITY, sizeof(f128)}; \ +}()) +#define wapp_f128_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_f128_array_pop(ARRAY_PTR) : \ + f128{} \ +) +#define wapp_iptr_array(...) ([&]() { \ + persistent iptr buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(iptr, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return IptrArray{ \ + buf, \ + wapp_misc_utils_va_args_count(iptr, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(iptr, __VA_ARGS__) * 2), \ + sizeof(iptr) \ + }; \ +}()) +#define wapp_iptr_array_with_capacity(CAPACITY) ([&]() { \ + persistent iptr buf[CAPACITY] = {}; \ + return IptrArray{buf, 0, CAPACITY, sizeof(iptr)}; \ +}()) +#define wapp_iptr_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_iptr_array_pop(ARRAY_PTR) : \ + iptr{} \ +) +#define wapp_uptr_array(...) ([&]() { \ + persistent uptr buf[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(uptr, __VA_ARGS__) * 2)] = {__VA_ARGS__}; \ + return UptrArray{ \ + buf, \ + wapp_misc_utils_va_args_count(uptr, __VA_ARGS__), \ + wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(uptr, __VA_ARGS__) * 2), \ + sizeof(uptr) \ + }; \ +}()) +#define wapp_uptr_array_with_capacity(CAPACITY) ([&]() { \ + persistent uptr buf[CAPACITY] = {}; \ + return UptrArray{buf, 0, CAPACITY, sizeof(uptr)}; \ +}()) +#define wapp_uptr_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_uptr_array_pop(ARRAY_PTR) : \ + uptr{} \ +) +#else +#define wapp_str8_array(...) ((Str8Array){ \ + .items = (Str8[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(Str8, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(Str8, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(Str8, __VA_ARGS__) * 2), \ + .item_size = sizeof(Str8) \ +}) +#define wapp_str8_array_with_capacity(CAPACITY) ((Str8Array){.items = (Str8[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(Str8)}) +#define wapp_str8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_str8_array_pop(ARRAY_PTR) : \ + (Str8){0} \ +) +#define wapp_void_ptr_array(...) ((VoidPArray){ \ + .items = (void *[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(void *, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(void *, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(void *, __VA_ARGS__) * 2), \ + .item_size = sizeof(void *) \ +}) +#define wapp_void_ptr_array_with_capacity(CAPACITY) ((VoidPArray){.items = (void *[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(void *)}) +#define wapp_void_ptr_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_void_ptr_array_pop(ARRAY_PTR) : \ + (void *){0} \ +) +#define wapp_b32_array(...) ((B32Array){ \ + .items = (b32[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(b32, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(b32, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(b32, __VA_ARGS__) * 2), \ + .item_size = sizeof(b32) \ +}) +#define wapp_b32_array_with_capacity(CAPACITY) ((B32Array){.items = (b32[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(b32)}) +#define wapp_b32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_b32_array_pop(ARRAY_PTR) : \ + (b32){0} \ +) +#define wapp_char_array(...) ((CharArray){ \ + .items = (char[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(char, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(char, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(char, __VA_ARGS__) * 2), \ + .item_size = sizeof(char) \ +}) +#define wapp_char_array_with_capacity(CAPACITY) ((CharArray){.items = (char[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(char)}) +#define wapp_char_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_char_array_pop(ARRAY_PTR) : \ + (char){0} \ +) +#define wapp_c8_array(...) ((C8Array){ \ + .items = (c8[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c8, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(c8, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c8, __VA_ARGS__) * 2), \ + .item_size = sizeof(c8) \ +}) +#define wapp_c8_array_with_capacity(CAPACITY) ((C8Array){.items = (c8[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(c8)}) +#define wapp_c8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_c8_array_pop(ARRAY_PTR) : \ + (c8){0} \ +) +#define wapp_c16_array(...) ((C16Array){ \ + .items = (c16[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c16, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(c16, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c16, __VA_ARGS__) * 2), \ + .item_size = sizeof(c16) \ +}) +#define wapp_c16_array_with_capacity(CAPACITY) ((C16Array){.items = (c16[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(c16)}) +#define wapp_c16_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_c16_array_pop(ARRAY_PTR) : \ + (c16){0} \ +) +#define wapp_c32_array(...) ((C32Array){ \ + .items = (c32[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c32, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(c32, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(c32, __VA_ARGS__) * 2), \ + .item_size = sizeof(c32) \ +}) +#define wapp_c32_array_with_capacity(CAPACITY) ((C32Array){.items = (c32[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(c32)}) +#define wapp_c32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_c32_array_pop(ARRAY_PTR) : \ + (c32){0} \ +) +#define wapp_i8_array(...) ((I8Array){ \ + .items = (i8[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i8, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(i8, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i8, __VA_ARGS__) * 2), \ + .item_size = sizeof(i8) \ +}) +#define wapp_i8_array_with_capacity(CAPACITY) ((I8Array){.items = (i8[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(i8)}) +#define wapp_i8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i8_array_pop(ARRAY_PTR) : \ + (i8){0} \ +) +#define wapp_i16_array(...) ((I16Array){ \ + .items = (i16[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i16, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(i16, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i16, __VA_ARGS__) * 2), \ + .item_size = sizeof(i16) \ +}) +#define wapp_i16_array_with_capacity(CAPACITY) ((I16Array){.items = (i16[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(i16)}) +#define wapp_i16_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i16_array_pop(ARRAY_PTR) : \ + (i16){0} \ +) +#define wapp_i32_array(...) ((I32Array){ \ + .items = (i32[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i32, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(i32, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i32, __VA_ARGS__) * 2), \ + .item_size = sizeof(i32) \ +}) +#define wapp_i32_array_with_capacity(CAPACITY) ((I32Array){.items = (i32[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(i32)}) +#define wapp_i32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i32_array_pop(ARRAY_PTR) : \ + (i32){0} \ +) +#define wapp_i64_array(...) ((I64Array){ \ + .items = (i64[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i64, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(i64, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(i64, __VA_ARGS__) * 2), \ + .item_size = sizeof(i64) \ +}) +#define wapp_i64_array_with_capacity(CAPACITY) ((I64Array){.items = (i64[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(i64)}) +#define wapp_i64_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_i64_array_pop(ARRAY_PTR) : \ + (i64){0} \ +) +#define wapp_u8_array(...) ((U8Array){ \ + .items = (u8[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u8, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(u8, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u8, __VA_ARGS__) * 2), \ + .item_size = sizeof(u8) \ +}) +#define wapp_u8_array_with_capacity(CAPACITY) ((U8Array){.items = (u8[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(u8)}) +#define wapp_u8_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u8_array_pop(ARRAY_PTR) : \ + (u8){0} \ +) +#define wapp_u16_array(...) ((U16Array){ \ + .items = (u16[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u16, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(u16, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u16, __VA_ARGS__) * 2), \ + .item_size = sizeof(u16) \ +}) +#define wapp_u16_array_with_capacity(CAPACITY) ((U16Array){.items = (u16[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(u16)}) +#define wapp_u16_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u16_array_pop(ARRAY_PTR) : \ + (u16){0} \ +) +#define wapp_u32_array(...) ((U32Array){ \ + .items = (u32[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u32, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(u32, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u32, __VA_ARGS__) * 2), \ + .item_size = sizeof(u32) \ +}) +#define wapp_u32_array_with_capacity(CAPACITY) ((U32Array){.items = (u32[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(u32)}) +#define wapp_u32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u32_array_pop(ARRAY_PTR) : \ + (u32){0} \ +) +#define wapp_u64_array(...) ((U64Array){ \ + .items = (u64[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u64, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(u64, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(u64, __VA_ARGS__) * 2), \ + .item_size = sizeof(u64) \ +}) +#define wapp_u64_array_with_capacity(CAPACITY) ((U64Array){.items = (u64[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(u64)}) +#define wapp_u64_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_u64_array_pop(ARRAY_PTR) : \ + (u64){0} \ +) +#define wapp_f32_array(...) ((F32Array){ \ + .items = (f32[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f32, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(f32, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f32, __VA_ARGS__) * 2), \ + .item_size = sizeof(f32) \ +}) +#define wapp_f32_array_with_capacity(CAPACITY) ((F32Array){.items = (f32[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(f32)}) +#define wapp_f32_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_f32_array_pop(ARRAY_PTR) : \ + (f32){0} \ +) +#define wapp_f64_array(...) ((F64Array){ \ + .items = (f64[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f64, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(f64, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f64, __VA_ARGS__) * 2), \ + .item_size = sizeof(f64) \ +}) +#define wapp_f64_array_with_capacity(CAPACITY) ((F64Array){.items = (f64[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(f64)}) +#define wapp_f64_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_f64_array_pop(ARRAY_PTR) : \ + (f64){0} \ +) +#define wapp_f128_array(...) ((F128Array){ \ + .items = (f128[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f128, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(f128, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(f128, __VA_ARGS__) * 2), \ + .item_size = sizeof(f128) \ +}) +#define wapp_f128_array_with_capacity(CAPACITY) ((F128Array){.items = (f128[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(f128)}) +#define wapp_f128_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_f128_array_pop(ARRAY_PTR) : \ + (f128){0} \ +) +#define wapp_iptr_array(...) ((IptrArray){ \ + .items = (iptr[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(iptr, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(iptr, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(iptr, __VA_ARGS__) * 2), \ + .item_size = sizeof(iptr) \ +}) +#define wapp_iptr_array_with_capacity(CAPACITY) ((IptrArray){.items = (iptr[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(iptr)}) +#define wapp_iptr_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_iptr_array_pop(ARRAY_PTR) : \ + (iptr){0} \ +) +#define wapp_uptr_array(...) ((UptrArray){ \ + .items = (uptr[wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(uptr, __VA_ARGS__) * 2)]){__VA_ARGS__}, \ + .count = wapp_misc_utils_va_args_count(uptr, __VA_ARGS__), \ + .capacity = wapp_misc_utils_u64_round_up_pow2(wapp_misc_utils_va_args_count(uptr, __VA_ARGS__) * 2), \ + .item_size = sizeof(uptr) \ +}) +#define wapp_uptr_array_with_capacity(CAPACITY) ((UptrArray){.items = (uptr[CAPACITY]){0}, .count = 0, .capacity = CAPACITY, .item_size = sizeof(uptr)}) +#define wapp_uptr_array_pop(ARRAY_PTR) (ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \ + *_uptr_array_pop(ARRAY_PTR) : \ + (uptr){0} \ +) +#endif // !WAPP_PLATFORM_CPP + +typedef struct str8 Str8; + +typedef struct Str8Array Str8Array; +struct Str8Array { + Str8 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct VoidPArray VoidPArray; +struct VoidPArray { + void * *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct B32Array B32Array; +struct B32Array { + b32 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct CharArray CharArray; +struct CharArray { + char *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct C8Array C8Array; +struct C8Array { + c8 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct C16Array C16Array; +struct C16Array { + c16 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct C32Array C32Array; +struct C32Array { + c32 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct I8Array I8Array; +struct I8Array { + i8 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct I16Array I16Array; +struct I16Array { + i16 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct I32Array I32Array; +struct I32Array { + i32 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct I64Array I64Array; +struct I64Array { + i64 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct U8Array U8Array; +struct U8Array { + u8 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct U16Array U16Array; +struct U16Array { + u16 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct U32Array U32Array; +struct U32Array { + u32 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct U64Array U64Array; +struct U64Array { + u64 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct F32Array F32Array; +struct F32Array { + f32 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct F64Array F64Array; +struct F64Array { + f64 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct F128Array F128Array; +struct F128Array { + f128 *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct IptrArray IptrArray; +struct IptrArray { + iptr *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +typedef struct UptrArray UptrArray; +struct UptrArray { + uptr *items; + u64 count; + u64 capacity; + u64 item_size; +}; + +Str8 *wapp_str8_array_get(const Str8Array *array, u64 index); +void wapp_str8_array_set(Str8Array *array, u64 index, Str8 *item); +void wapp_str8_array_append_capped(Str8Array *array, Str8 *item); +void wapp_str8_array_extend_capped(Str8Array *array, const Str8Array *other); +void wapp_str8_array_clear(Str8Array *array); +void wapp_str8_array_copy_capped(const Str8Array *src, Str8Array *dst); +Str8Array *wapp_str8_array_append_alloc(const Allocator *allocator, Str8Array *array, Str8 *item); +Str8Array *wapp_str8_array_extend_alloc(const Allocator *allocator, Str8Array *array, const Str8Array *other); +Str8Array *wapp_str8_array_copy_alloc(const Allocator *allocator, const Str8Array *src, Str8Array *dst); +Str8 *_str8_array_pop(Str8Array *array); +void * *wapp_void_ptr_array_get(const VoidPArray *array, u64 index); +void wapp_void_ptr_array_set(VoidPArray *array, u64 index, void * *item); +void wapp_void_ptr_array_append_capped(VoidPArray *array, void * *item); +void wapp_void_ptr_array_extend_capped(VoidPArray *array, const VoidPArray *other); +void wapp_void_ptr_array_clear(VoidPArray *array); +void wapp_void_ptr_array_copy_capped(const VoidPArray *src, VoidPArray *dst); +VoidPArray *wapp_void_ptr_array_append_alloc(const Allocator *allocator, VoidPArray *array, void * *item); +VoidPArray *wapp_void_ptr_array_extend_alloc(const Allocator *allocator, VoidPArray *array, const VoidPArray *other); +VoidPArray *wapp_void_ptr_array_copy_alloc(const Allocator *allocator, const VoidPArray *src, VoidPArray *dst); +void * *_void_ptr_array_pop(VoidPArray *array); +b32 *wapp_b32_array_get(const B32Array *array, u64 index); +void wapp_b32_array_set(B32Array *array, u64 index, b32 *item); +void wapp_b32_array_append_capped(B32Array *array, b32 *item); +void wapp_b32_array_extend_capped(B32Array *array, const B32Array *other); +void wapp_b32_array_clear(B32Array *array); +void wapp_b32_array_copy_capped(const B32Array *src, B32Array *dst); +B32Array *wapp_b32_array_append_alloc(const Allocator *allocator, B32Array *array, b32 *item); +B32Array *wapp_b32_array_extend_alloc(const Allocator *allocator, B32Array *array, const B32Array *other); +B32Array *wapp_b32_array_copy_alloc(const Allocator *allocator, const B32Array *src, B32Array *dst); +b32 *_b32_array_pop(B32Array *array); +char *wapp_char_array_get(const CharArray *array, u64 index); +void wapp_char_array_set(CharArray *array, u64 index, char *item); +void wapp_char_array_append_capped(CharArray *array, char *item); +void wapp_char_array_extend_capped(CharArray *array, const CharArray *other); +void wapp_char_array_clear(CharArray *array); +void wapp_char_array_copy_capped(const CharArray *src, CharArray *dst); +CharArray *wapp_char_array_append_alloc(const Allocator *allocator, CharArray *array, char *item); +CharArray *wapp_char_array_extend_alloc(const Allocator *allocator, CharArray *array, const CharArray *other); +CharArray *wapp_char_array_copy_alloc(const Allocator *allocator, const CharArray *src, CharArray *dst); +char *_char_array_pop(CharArray *array); +c8 *wapp_c8_array_get(const C8Array *array, u64 index); +void wapp_c8_array_set(C8Array *array, u64 index, c8 *item); +void wapp_c8_array_append_capped(C8Array *array, c8 *item); +void wapp_c8_array_extend_capped(C8Array *array, const C8Array *other); +void wapp_c8_array_clear(C8Array *array); +void wapp_c8_array_copy_capped(const C8Array *src, C8Array *dst); +C8Array *wapp_c8_array_append_alloc(const Allocator *allocator, C8Array *array, c8 *item); +C8Array *wapp_c8_array_extend_alloc(const Allocator *allocator, C8Array *array, const C8Array *other); +C8Array *wapp_c8_array_copy_alloc(const Allocator *allocator, const C8Array *src, C8Array *dst); +c8 *_c8_array_pop(C8Array *array); +c16 *wapp_c16_array_get(const C16Array *array, u64 index); +void wapp_c16_array_set(C16Array *array, u64 index, c16 *item); +void wapp_c16_array_append_capped(C16Array *array, c16 *item); +void wapp_c16_array_extend_capped(C16Array *array, const C16Array *other); +void wapp_c16_array_clear(C16Array *array); +void wapp_c16_array_copy_capped(const C16Array *src, C16Array *dst); +C16Array *wapp_c16_array_append_alloc(const Allocator *allocator, C16Array *array, c16 *item); +C16Array *wapp_c16_array_extend_alloc(const Allocator *allocator, C16Array *array, const C16Array *other); +C16Array *wapp_c16_array_copy_alloc(const Allocator *allocator, const C16Array *src, C16Array *dst); +c16 *_c16_array_pop(C16Array *array); +c32 *wapp_c32_array_get(const C32Array *array, u64 index); +void wapp_c32_array_set(C32Array *array, u64 index, c32 *item); +void wapp_c32_array_append_capped(C32Array *array, c32 *item); +void wapp_c32_array_extend_capped(C32Array *array, const C32Array *other); +void wapp_c32_array_clear(C32Array *array); +void wapp_c32_array_copy_capped(const C32Array *src, C32Array *dst); +C32Array *wapp_c32_array_append_alloc(const Allocator *allocator, C32Array *array, c32 *item); +C32Array *wapp_c32_array_extend_alloc(const Allocator *allocator, C32Array *array, const C32Array *other); +C32Array *wapp_c32_array_copy_alloc(const Allocator *allocator, const C32Array *src, C32Array *dst); +c32 *_c32_array_pop(C32Array *array); +i8 *wapp_i8_array_get(const I8Array *array, u64 index); +void wapp_i8_array_set(I8Array *array, u64 index, i8 *item); +void wapp_i8_array_append_capped(I8Array *array, i8 *item); +void wapp_i8_array_extend_capped(I8Array *array, const I8Array *other); +void wapp_i8_array_clear(I8Array *array); +void wapp_i8_array_copy_capped(const I8Array *src, I8Array *dst); +I8Array *wapp_i8_array_append_alloc(const Allocator *allocator, I8Array *array, i8 *item); +I8Array *wapp_i8_array_extend_alloc(const Allocator *allocator, I8Array *array, const I8Array *other); +I8Array *wapp_i8_array_copy_alloc(const Allocator *allocator, const I8Array *src, I8Array *dst); +i8 *_i8_array_pop(I8Array *array); +i16 *wapp_i16_array_get(const I16Array *array, u64 index); +void wapp_i16_array_set(I16Array *array, u64 index, i16 *item); +void wapp_i16_array_append_capped(I16Array *array, i16 *item); +void wapp_i16_array_extend_capped(I16Array *array, const I16Array *other); +void wapp_i16_array_clear(I16Array *array); +void wapp_i16_array_copy_capped(const I16Array *src, I16Array *dst); +I16Array *wapp_i16_array_append_alloc(const Allocator *allocator, I16Array *array, i16 *item); +I16Array *wapp_i16_array_extend_alloc(const Allocator *allocator, I16Array *array, const I16Array *other); +I16Array *wapp_i16_array_copy_alloc(const Allocator *allocator, const I16Array *src, I16Array *dst); +i16 *_i16_array_pop(I16Array *array); +i32 *wapp_i32_array_get(const I32Array *array, u64 index); +void wapp_i32_array_set(I32Array *array, u64 index, i32 *item); +void wapp_i32_array_append_capped(I32Array *array, i32 *item); +void wapp_i32_array_extend_capped(I32Array *array, const I32Array *other); +void wapp_i32_array_clear(I32Array *array); +void wapp_i32_array_copy_capped(const I32Array *src, I32Array *dst); +I32Array *wapp_i32_array_append_alloc(const Allocator *allocator, I32Array *array, i32 *item); +I32Array *wapp_i32_array_extend_alloc(const Allocator *allocator, I32Array *array, const I32Array *other); +I32Array *wapp_i32_array_copy_alloc(const Allocator *allocator, const I32Array *src, I32Array *dst); +i32 *_i32_array_pop(I32Array *array); +i64 *wapp_i64_array_get(const I64Array *array, u64 index); +void wapp_i64_array_set(I64Array *array, u64 index, i64 *item); +void wapp_i64_array_append_capped(I64Array *array, i64 *item); +void wapp_i64_array_extend_capped(I64Array *array, const I64Array *other); +void wapp_i64_array_clear(I64Array *array); +void wapp_i64_array_copy_capped(const I64Array *src, I64Array *dst); +I64Array *wapp_i64_array_append_alloc(const Allocator *allocator, I64Array *array, i64 *item); +I64Array *wapp_i64_array_extend_alloc(const Allocator *allocator, I64Array *array, const I64Array *other); +I64Array *wapp_i64_array_copy_alloc(const Allocator *allocator, const I64Array *src, I64Array *dst); +i64 *_i64_array_pop(I64Array *array); +u8 *wapp_u8_array_get(const U8Array *array, u64 index); +void wapp_u8_array_set(U8Array *array, u64 index, u8 *item); +void wapp_u8_array_append_capped(U8Array *array, u8 *item); +void wapp_u8_array_extend_capped(U8Array *array, const U8Array *other); +void wapp_u8_array_clear(U8Array *array); +void wapp_u8_array_copy_capped(const U8Array *src, U8Array *dst); +U8Array *wapp_u8_array_append_alloc(const Allocator *allocator, U8Array *array, u8 *item); +U8Array *wapp_u8_array_extend_alloc(const Allocator *allocator, U8Array *array, const U8Array *other); +U8Array *wapp_u8_array_copy_alloc(const Allocator *allocator, const U8Array *src, U8Array *dst); +u8 *_u8_array_pop(U8Array *array); +u16 *wapp_u16_array_get(const U16Array *array, u64 index); +void wapp_u16_array_set(U16Array *array, u64 index, u16 *item); +void wapp_u16_array_append_capped(U16Array *array, u16 *item); +void wapp_u16_array_extend_capped(U16Array *array, const U16Array *other); +void wapp_u16_array_clear(U16Array *array); +void wapp_u16_array_copy_capped(const U16Array *src, U16Array *dst); +U16Array *wapp_u16_array_append_alloc(const Allocator *allocator, U16Array *array, u16 *item); +U16Array *wapp_u16_array_extend_alloc(const Allocator *allocator, U16Array *array, const U16Array *other); +U16Array *wapp_u16_array_copy_alloc(const Allocator *allocator, const U16Array *src, U16Array *dst); +u16 *_u16_array_pop(U16Array *array); +u32 *wapp_u32_array_get(const U32Array *array, u64 index); +void wapp_u32_array_set(U32Array *array, u64 index, u32 *item); +void wapp_u32_array_append_capped(U32Array *array, u32 *item); +void wapp_u32_array_extend_capped(U32Array *array, const U32Array *other); +void wapp_u32_array_clear(U32Array *array); +void wapp_u32_array_copy_capped(const U32Array *src, U32Array *dst); +U32Array *wapp_u32_array_append_alloc(const Allocator *allocator, U32Array *array, u32 *item); +U32Array *wapp_u32_array_extend_alloc(const Allocator *allocator, U32Array *array, const U32Array *other); +U32Array *wapp_u32_array_copy_alloc(const Allocator *allocator, const U32Array *src, U32Array *dst); +u32 *_u32_array_pop(U32Array *array); +u64 *wapp_u64_array_get(const U64Array *array, u64 index); +void wapp_u64_array_set(U64Array *array, u64 index, u64 *item); +void wapp_u64_array_append_capped(U64Array *array, u64 *item); +void wapp_u64_array_extend_capped(U64Array *array, const U64Array *other); +void wapp_u64_array_clear(U64Array *array); +void wapp_u64_array_copy_capped(const U64Array *src, U64Array *dst); +U64Array *wapp_u64_array_append_alloc(const Allocator *allocator, U64Array *array, u64 *item); +U64Array *wapp_u64_array_extend_alloc(const Allocator *allocator, U64Array *array, const U64Array *other); +U64Array *wapp_u64_array_copy_alloc(const Allocator *allocator, const U64Array *src, U64Array *dst); +u64 *_u64_array_pop(U64Array *array); +f32 *wapp_f32_array_get(const F32Array *array, u64 index); +void wapp_f32_array_set(F32Array *array, u64 index, f32 *item); +void wapp_f32_array_append_capped(F32Array *array, f32 *item); +void wapp_f32_array_extend_capped(F32Array *array, const F32Array *other); +void wapp_f32_array_clear(F32Array *array); +void wapp_f32_array_copy_capped(const F32Array *src, F32Array *dst); +F32Array *wapp_f32_array_append_alloc(const Allocator *allocator, F32Array *array, f32 *item); +F32Array *wapp_f32_array_extend_alloc(const Allocator *allocator, F32Array *array, const F32Array *other); +F32Array *wapp_f32_array_copy_alloc(const Allocator *allocator, const F32Array *src, F32Array *dst); +f32 *_f32_array_pop(F32Array *array); +f64 *wapp_f64_array_get(const F64Array *array, u64 index); +void wapp_f64_array_set(F64Array *array, u64 index, f64 *item); +void wapp_f64_array_append_capped(F64Array *array, f64 *item); +void wapp_f64_array_extend_capped(F64Array *array, const F64Array *other); +void wapp_f64_array_clear(F64Array *array); +void wapp_f64_array_copy_capped(const F64Array *src, F64Array *dst); +F64Array *wapp_f64_array_append_alloc(const Allocator *allocator, F64Array *array, f64 *item); +F64Array *wapp_f64_array_extend_alloc(const Allocator *allocator, F64Array *array, const F64Array *other); +F64Array *wapp_f64_array_copy_alloc(const Allocator *allocator, const F64Array *src, F64Array *dst); +f64 *_f64_array_pop(F64Array *array); +f128 *wapp_f128_array_get(const F128Array *array, u64 index); +void wapp_f128_array_set(F128Array *array, u64 index, f128 *item); +void wapp_f128_array_append_capped(F128Array *array, f128 *item); +void wapp_f128_array_extend_capped(F128Array *array, const F128Array *other); +void wapp_f128_array_clear(F128Array *array); +void wapp_f128_array_copy_capped(const F128Array *src, F128Array *dst); +F128Array *wapp_f128_array_append_alloc(const Allocator *allocator, F128Array *array, f128 *item); +F128Array *wapp_f128_array_extend_alloc(const Allocator *allocator, F128Array *array, const F128Array *other); +F128Array *wapp_f128_array_copy_alloc(const Allocator *allocator, const F128Array *src, F128Array *dst); +f128 *_f128_array_pop(F128Array *array); +iptr *wapp_iptr_array_get(const IptrArray *array, u64 index); +void wapp_iptr_array_set(IptrArray *array, u64 index, iptr *item); +void wapp_iptr_array_append_capped(IptrArray *array, iptr *item); +void wapp_iptr_array_extend_capped(IptrArray *array, const IptrArray *other); +void wapp_iptr_array_clear(IptrArray *array); +void wapp_iptr_array_copy_capped(const IptrArray *src, IptrArray *dst); +IptrArray *wapp_iptr_array_append_alloc(const Allocator *allocator, IptrArray *array, iptr *item); +IptrArray *wapp_iptr_array_extend_alloc(const Allocator *allocator, IptrArray *array, const IptrArray *other); +IptrArray *wapp_iptr_array_copy_alloc(const Allocator *allocator, const IptrArray *src, IptrArray *dst); +iptr *_iptr_array_pop(IptrArray *array); +uptr *wapp_uptr_array_get(const UptrArray *array, u64 index); +void wapp_uptr_array_set(UptrArray *array, u64 index, uptr *item); +void wapp_uptr_array_append_capped(UptrArray *array, uptr *item); +void wapp_uptr_array_extend_capped(UptrArray *array, const UptrArray *other); +void wapp_uptr_array_clear(UptrArray *array); +void wapp_uptr_array_copy_capped(const UptrArray *src, UptrArray *dst); +UptrArray *wapp_uptr_array_append_alloc(const Allocator *allocator, UptrArray *array, uptr *item); +UptrArray *wapp_uptr_array_extend_alloc(const Allocator *allocator, UptrArray *array, const UptrArray *other); +UptrArray *wapp_uptr_array_copy_alloc(const Allocator *allocator, const UptrArray *src, UptrArray *dst); +uptr *_uptr_array_pop(UptrArray *array); +VoidPArray *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !ARRAY_H diff --git a/wapp/primitives/dbl_list/dbl_list.c b/wapp/primitives/dbl_list/dbl_list.c new file mode 100644 index 0000000..9578b7f --- /dev/null +++ b/wapp/primitives/dbl_list/dbl_list.c @@ -0,0 +1,3813 @@ +/** + * THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN + */ + +#include "./dbl_list.h" +#include "../../common/assert/assert.h" +#include "../../common/aliases/aliases.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" +#include +#include + +internal Str8List str8_node_to_list(Str8Node *node); +internal VoidPList void_ptr_node_to_list(VoidPNode *node); +internal B32List b32_node_to_list(B32Node *node); +internal CharList char_node_to_list(CharNode *node); +internal C8List c8_node_to_list(C8Node *node); +internal C16List c16_node_to_list(C16Node *node); +internal C32List c32_node_to_list(C32Node *node); +internal I8List i8_node_to_list(I8Node *node); +internal I16List i16_node_to_list(I16Node *node); +internal I32List i32_node_to_list(I32Node *node); +internal I64List i64_node_to_list(I64Node *node); +internal U8List u8_node_to_list(U8Node *node); +internal U16List u16_node_to_list(U16Node *node); +internal U32List u32_node_to_list(U32Node *node); +internal U64List u64_node_to_list(U64Node *node); +internal F32List f32_node_to_list(F32Node *node); +internal F64List f64_node_to_list(F64Node *node); +internal F128List f128_node_to_list(F128Node *node); +internal IptrList iptr_node_to_list(IptrNode *node); +internal UptrList uptr_node_to_list(UptrNode *node); + +Str8Node *wapp_str8_list_get(const Str8List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + Str8Node *output = NULL; + Str8Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_str8_list_push_front(Str8List *list, Str8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + Str8List node_list = str8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + Str8Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_str8_list_push_back(Str8List *list, Str8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + Str8List node_list = str8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + Str8Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_str8_list_insert(Str8List *list, Str8Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_str8_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_str8_list_push_back(list, node); + return; + } + + Str8Node *dst_node = wapp_str8_list_get(list, index); + if (!dst_node) { + return; + } + + Str8List node_list = str8_node_to_list(node); + + list->node_count += node_list.node_count; + + Str8Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +Str8Node *wapp_str8_list_pop_front(Str8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + Str8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_STR8_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (Str8List){0}; + goto RETURN_STR8_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_STR8_LIST_POP_FRONT: + return output; +} + +Str8Node *wapp_str8_list_pop_back(Str8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + Str8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_STR8_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (Str8List){0}; + goto RETURN_STR8_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_STR8_LIST_POP_BACK: + return output; +} + +Str8Node *wapp_str8_list_remove(Str8List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + Str8Node *output = NULL; + + if (index == 0) { + output = wapp_str8_list_pop_front(list); + goto RETURN_STR8_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_str8_list_pop_back(list); + goto RETURN_STR8_LIST_REMOVE; + } + + output = wapp_str8_list_get(list, index); + if (!output) { + goto RETURN_STR8_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_STR8_LIST_REMOVE: + return output; +} + +void wapp_str8_list_empty(Str8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_str8_list_pop_back(list); + } +} + +VoidPNode *wapp_void_ptr_list_get(const VoidPList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + VoidPNode *output = NULL; + VoidPNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_void_ptr_list_push_front(VoidPList *list, VoidPNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + VoidPList node_list = void_ptr_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + VoidPNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_void_ptr_list_push_back(VoidPList *list, VoidPNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + VoidPList node_list = void_ptr_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + VoidPNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_void_ptr_list_insert(VoidPList *list, VoidPNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_void_ptr_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_void_ptr_list_push_back(list, node); + return; + } + + VoidPNode *dst_node = wapp_void_ptr_list_get(list, index); + if (!dst_node) { + return; + } + + VoidPList node_list = void_ptr_node_to_list(node); + + list->node_count += node_list.node_count; + + VoidPNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +VoidPNode *wapp_void_ptr_list_pop_front(VoidPList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + VoidPNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_VOID_PTR_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (VoidPList){0}; + goto RETURN_VOID_PTR_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_VOID_PTR_LIST_POP_FRONT: + return output; +} + +VoidPNode *wapp_void_ptr_list_pop_back(VoidPList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + VoidPNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_VOID_PTR_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (VoidPList){0}; + goto RETURN_VOID_PTR_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_VOID_PTR_LIST_POP_BACK: + return output; +} + +VoidPNode *wapp_void_ptr_list_remove(VoidPList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + VoidPNode *output = NULL; + + if (index == 0) { + output = wapp_void_ptr_list_pop_front(list); + goto RETURN_VOID_PTR_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_void_ptr_list_pop_back(list); + goto RETURN_VOID_PTR_LIST_REMOVE; + } + + output = wapp_void_ptr_list_get(list, index); + if (!output) { + goto RETURN_VOID_PTR_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_VOID_PTR_LIST_REMOVE: + return output; +} + +void wapp_void_ptr_list_empty(VoidPList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_void_ptr_list_pop_back(list); + } +} + +B32Node *wapp_b32_list_get(const B32List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + B32Node *output = NULL; + B32Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_b32_list_push_front(B32List *list, B32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + B32List node_list = b32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + B32Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_b32_list_push_back(B32List *list, B32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + B32List node_list = b32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + B32Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_b32_list_insert(B32List *list, B32Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_b32_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_b32_list_push_back(list, node); + return; + } + + B32Node *dst_node = wapp_b32_list_get(list, index); + if (!dst_node) { + return; + } + + B32List node_list = b32_node_to_list(node); + + list->node_count += node_list.node_count; + + B32Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +B32Node *wapp_b32_list_pop_front(B32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + B32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_B32_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (B32List){0}; + goto RETURN_B32_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_B32_LIST_POP_FRONT: + return output; +} + +B32Node *wapp_b32_list_pop_back(B32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + B32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_B32_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (B32List){0}; + goto RETURN_B32_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_B32_LIST_POP_BACK: + return output; +} + +B32Node *wapp_b32_list_remove(B32List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + B32Node *output = NULL; + + if (index == 0) { + output = wapp_b32_list_pop_front(list); + goto RETURN_B32_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_b32_list_pop_back(list); + goto RETURN_B32_LIST_REMOVE; + } + + output = wapp_b32_list_get(list, index); + if (!output) { + goto RETURN_B32_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_B32_LIST_REMOVE: + return output; +} + +void wapp_b32_list_empty(B32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_b32_list_pop_back(list); + } +} + +CharNode *wapp_char_list_get(const CharList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + CharNode *output = NULL; + CharNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_char_list_push_front(CharList *list, CharNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CharList node_list = char_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CharNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_char_list_push_back(CharList *list, CharNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + CharList node_list = char_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + CharNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_char_list_insert(CharList *list, CharNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_char_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_char_list_push_back(list, node); + return; + } + + CharNode *dst_node = wapp_char_list_get(list, index); + if (!dst_node) { + return; + } + + CharList node_list = char_node_to_list(node); + + list->node_count += node_list.node_count; + + CharNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +CharNode *wapp_char_list_pop_front(CharList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CharNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CHAR_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (CharList){0}; + goto RETURN_CHAR_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_CHAR_LIST_POP_FRONT: + return output; +} + +CharNode *wapp_char_list_pop_back(CharList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CharNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_CHAR_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (CharList){0}; + goto RETURN_CHAR_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_CHAR_LIST_POP_BACK: + return output; +} + +CharNode *wapp_char_list_remove(CharList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + CharNode *output = NULL; + + if (index == 0) { + output = wapp_char_list_pop_front(list); + goto RETURN_CHAR_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_char_list_pop_back(list); + goto RETURN_CHAR_LIST_REMOVE; + } + + output = wapp_char_list_get(list, index); + if (!output) { + goto RETURN_CHAR_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_CHAR_LIST_REMOVE: + return output; +} + +void wapp_char_list_empty(CharList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_char_list_pop_back(list); + } +} + +C8Node *wapp_c8_list_get(const C8List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + C8Node *output = NULL; + C8Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_c8_list_push_front(C8List *list, C8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + C8List node_list = c8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + C8Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_c8_list_push_back(C8List *list, C8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + C8List node_list = c8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + C8Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_c8_list_insert(C8List *list, C8Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_c8_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_c8_list_push_back(list, node); + return; + } + + C8Node *dst_node = wapp_c8_list_get(list, index); + if (!dst_node) { + return; + } + + C8List node_list = c8_node_to_list(node); + + list->node_count += node_list.node_count; + + C8Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +C8Node *wapp_c8_list_pop_front(C8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_C8_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (C8List){0}; + goto RETURN_C8_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_C8_LIST_POP_FRONT: + return output; +} + +C8Node *wapp_c8_list_pop_back(C8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_C8_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (C8List){0}; + goto RETURN_C8_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_C8_LIST_POP_BACK: + return output; +} + +C8Node *wapp_c8_list_remove(C8List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C8Node *output = NULL; + + if (index == 0) { + output = wapp_c8_list_pop_front(list); + goto RETURN_C8_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_c8_list_pop_back(list); + goto RETURN_C8_LIST_REMOVE; + } + + output = wapp_c8_list_get(list, index); + if (!output) { + goto RETURN_C8_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_C8_LIST_REMOVE: + return output; +} + +void wapp_c8_list_empty(C8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_c8_list_pop_back(list); + } +} + +C16Node *wapp_c16_list_get(const C16List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + C16Node *output = NULL; + C16Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_c16_list_push_front(C16List *list, C16Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + C16List node_list = c16_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + C16Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_c16_list_push_back(C16List *list, C16Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + C16List node_list = c16_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + C16Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_c16_list_insert(C16List *list, C16Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_c16_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_c16_list_push_back(list, node); + return; + } + + C16Node *dst_node = wapp_c16_list_get(list, index); + if (!dst_node) { + return; + } + + C16List node_list = c16_node_to_list(node); + + list->node_count += node_list.node_count; + + C16Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +C16Node *wapp_c16_list_pop_front(C16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C16Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_C16_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (C16List){0}; + goto RETURN_C16_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_C16_LIST_POP_FRONT: + return output; +} + +C16Node *wapp_c16_list_pop_back(C16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C16Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_C16_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (C16List){0}; + goto RETURN_C16_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_C16_LIST_POP_BACK: + return output; +} + +C16Node *wapp_c16_list_remove(C16List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C16Node *output = NULL; + + if (index == 0) { + output = wapp_c16_list_pop_front(list); + goto RETURN_C16_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_c16_list_pop_back(list); + goto RETURN_C16_LIST_REMOVE; + } + + output = wapp_c16_list_get(list, index); + if (!output) { + goto RETURN_C16_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_C16_LIST_REMOVE: + return output; +} + +void wapp_c16_list_empty(C16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_c16_list_pop_back(list); + } +} + +C32Node *wapp_c32_list_get(const C32List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + C32Node *output = NULL; + C32Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_c32_list_push_front(C32List *list, C32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + C32List node_list = c32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + C32Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_c32_list_push_back(C32List *list, C32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + C32List node_list = c32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + C32Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_c32_list_insert(C32List *list, C32Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_c32_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_c32_list_push_back(list, node); + return; + } + + C32Node *dst_node = wapp_c32_list_get(list, index); + if (!dst_node) { + return; + } + + C32List node_list = c32_node_to_list(node); + + list->node_count += node_list.node_count; + + C32Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +C32Node *wapp_c32_list_pop_front(C32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_C32_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (C32List){0}; + goto RETURN_C32_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_C32_LIST_POP_FRONT: + return output; +} + +C32Node *wapp_c32_list_pop_back(C32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_C32_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (C32List){0}; + goto RETURN_C32_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_C32_LIST_POP_BACK: + return output; +} + +C32Node *wapp_c32_list_remove(C32List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + C32Node *output = NULL; + + if (index == 0) { + output = wapp_c32_list_pop_front(list); + goto RETURN_C32_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_c32_list_pop_back(list); + goto RETURN_C32_LIST_REMOVE; + } + + output = wapp_c32_list_get(list, index); + if (!output) { + goto RETURN_C32_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_C32_LIST_REMOVE: + return output; +} + +void wapp_c32_list_empty(C32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_c32_list_pop_back(list); + } +} + +I8Node *wapp_i8_list_get(const I8List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + I8Node *output = NULL; + I8Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_i8_list_push_front(I8List *list, I8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I8List node_list = i8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I8Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_i8_list_push_back(I8List *list, I8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I8List node_list = i8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I8Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_i8_list_insert(I8List *list, I8Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_i8_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_i8_list_push_back(list, node); + return; + } + + I8Node *dst_node = wapp_i8_list_get(list, index); + if (!dst_node) { + return; + } + + I8List node_list = i8_node_to_list(node); + + list->node_count += node_list.node_count; + + I8Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +I8Node *wapp_i8_list_pop_front(I8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I8_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (I8List){0}; + goto RETURN_I8_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_I8_LIST_POP_FRONT: + return output; +} + +I8Node *wapp_i8_list_pop_back(I8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I8_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (I8List){0}; + goto RETURN_I8_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_I8_LIST_POP_BACK: + return output; +} + +I8Node *wapp_i8_list_remove(I8List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I8Node *output = NULL; + + if (index == 0) { + output = wapp_i8_list_pop_front(list); + goto RETURN_I8_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_i8_list_pop_back(list); + goto RETURN_I8_LIST_REMOVE; + } + + output = wapp_i8_list_get(list, index); + if (!output) { + goto RETURN_I8_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_I8_LIST_REMOVE: + return output; +} + +void wapp_i8_list_empty(I8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_i8_list_pop_back(list); + } +} + +I16Node *wapp_i16_list_get(const I16List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + I16Node *output = NULL; + I16Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_i16_list_push_front(I16List *list, I16Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I16List node_list = i16_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I16Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_i16_list_push_back(I16List *list, I16Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I16List node_list = i16_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I16Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_i16_list_insert(I16List *list, I16Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_i16_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_i16_list_push_back(list, node); + return; + } + + I16Node *dst_node = wapp_i16_list_get(list, index); + if (!dst_node) { + return; + } + + I16List node_list = i16_node_to_list(node); + + list->node_count += node_list.node_count; + + I16Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +I16Node *wapp_i16_list_pop_front(I16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I16Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I16_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (I16List){0}; + goto RETURN_I16_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_I16_LIST_POP_FRONT: + return output; +} + +I16Node *wapp_i16_list_pop_back(I16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I16Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I16_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (I16List){0}; + goto RETURN_I16_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_I16_LIST_POP_BACK: + return output; +} + +I16Node *wapp_i16_list_remove(I16List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I16Node *output = NULL; + + if (index == 0) { + output = wapp_i16_list_pop_front(list); + goto RETURN_I16_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_i16_list_pop_back(list); + goto RETURN_I16_LIST_REMOVE; + } + + output = wapp_i16_list_get(list, index); + if (!output) { + goto RETURN_I16_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_I16_LIST_REMOVE: + return output; +} + +void wapp_i16_list_empty(I16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_i16_list_pop_back(list); + } +} + +I32Node *wapp_i32_list_get(const I32List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + I32Node *output = NULL; + I32Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_i32_list_push_front(I32List *list, I32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I32List node_list = i32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I32Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_i32_list_push_back(I32List *list, I32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I32List node_list = i32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I32Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_i32_list_insert(I32List *list, I32Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_i32_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_i32_list_push_back(list, node); + return; + } + + I32Node *dst_node = wapp_i32_list_get(list, index); + if (!dst_node) { + return; + } + + I32List node_list = i32_node_to_list(node); + + list->node_count += node_list.node_count; + + I32Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +I32Node *wapp_i32_list_pop_front(I32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I32_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (I32List){0}; + goto RETURN_I32_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_I32_LIST_POP_FRONT: + return output; +} + +I32Node *wapp_i32_list_pop_back(I32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I32_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (I32List){0}; + goto RETURN_I32_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_I32_LIST_POP_BACK: + return output; +} + +I32Node *wapp_i32_list_remove(I32List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I32Node *output = NULL; + + if (index == 0) { + output = wapp_i32_list_pop_front(list); + goto RETURN_I32_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_i32_list_pop_back(list); + goto RETURN_I32_LIST_REMOVE; + } + + output = wapp_i32_list_get(list, index); + if (!output) { + goto RETURN_I32_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_I32_LIST_REMOVE: + return output; +} + +void wapp_i32_list_empty(I32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_i32_list_pop_back(list); + } +} + +I64Node *wapp_i64_list_get(const I64List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + I64Node *output = NULL; + I64Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_i64_list_push_front(I64List *list, I64Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I64List node_list = i64_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I64Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_i64_list_push_back(I64List *list, I64Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + I64List node_list = i64_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + I64Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_i64_list_insert(I64List *list, I64Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_i64_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_i64_list_push_back(list, node); + return; + } + + I64Node *dst_node = wapp_i64_list_get(list, index); + if (!dst_node) { + return; + } + + I64List node_list = i64_node_to_list(node); + + list->node_count += node_list.node_count; + + I64Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +I64Node *wapp_i64_list_pop_front(I64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I64Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I64_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (I64List){0}; + goto RETURN_I64_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_I64_LIST_POP_FRONT: + return output; +} + +I64Node *wapp_i64_list_pop_back(I64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I64Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_I64_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (I64List){0}; + goto RETURN_I64_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_I64_LIST_POP_BACK: + return output; +} + +I64Node *wapp_i64_list_remove(I64List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + I64Node *output = NULL; + + if (index == 0) { + output = wapp_i64_list_pop_front(list); + goto RETURN_I64_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_i64_list_pop_back(list); + goto RETURN_I64_LIST_REMOVE; + } + + output = wapp_i64_list_get(list, index); + if (!output) { + goto RETURN_I64_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_I64_LIST_REMOVE: + return output; +} + +void wapp_i64_list_empty(I64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_i64_list_pop_back(list); + } +} + +U8Node *wapp_u8_list_get(const U8List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + U8Node *output = NULL; + U8Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_u8_list_push_front(U8List *list, U8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U8List node_list = u8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U8Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_u8_list_push_back(U8List *list, U8Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U8List node_list = u8_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U8Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_u8_list_insert(U8List *list, U8Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_u8_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_u8_list_push_back(list, node); + return; + } + + U8Node *dst_node = wapp_u8_list_get(list, index); + if (!dst_node) { + return; + } + + U8List node_list = u8_node_to_list(node); + + list->node_count += node_list.node_count; + + U8Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +U8Node *wapp_u8_list_pop_front(U8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U8_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (U8List){0}; + goto RETURN_U8_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_U8_LIST_POP_FRONT: + return output; +} + +U8Node *wapp_u8_list_pop_back(U8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U8Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U8_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (U8List){0}; + goto RETURN_U8_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_U8_LIST_POP_BACK: + return output; +} + +U8Node *wapp_u8_list_remove(U8List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U8Node *output = NULL; + + if (index == 0) { + output = wapp_u8_list_pop_front(list); + goto RETURN_U8_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_u8_list_pop_back(list); + goto RETURN_U8_LIST_REMOVE; + } + + output = wapp_u8_list_get(list, index); + if (!output) { + goto RETURN_U8_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_U8_LIST_REMOVE: + return output; +} + +void wapp_u8_list_empty(U8List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_u8_list_pop_back(list); + } +} + +U16Node *wapp_u16_list_get(const U16List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + U16Node *output = NULL; + U16Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_u16_list_push_front(U16List *list, U16Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U16List node_list = u16_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U16Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_u16_list_push_back(U16List *list, U16Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U16List node_list = u16_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U16Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_u16_list_insert(U16List *list, U16Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_u16_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_u16_list_push_back(list, node); + return; + } + + U16Node *dst_node = wapp_u16_list_get(list, index); + if (!dst_node) { + return; + } + + U16List node_list = u16_node_to_list(node); + + list->node_count += node_list.node_count; + + U16Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +U16Node *wapp_u16_list_pop_front(U16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U16Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U16_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (U16List){0}; + goto RETURN_U16_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_U16_LIST_POP_FRONT: + return output; +} + +U16Node *wapp_u16_list_pop_back(U16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U16Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U16_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (U16List){0}; + goto RETURN_U16_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_U16_LIST_POP_BACK: + return output; +} + +U16Node *wapp_u16_list_remove(U16List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U16Node *output = NULL; + + if (index == 0) { + output = wapp_u16_list_pop_front(list); + goto RETURN_U16_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_u16_list_pop_back(list); + goto RETURN_U16_LIST_REMOVE; + } + + output = wapp_u16_list_get(list, index); + if (!output) { + goto RETURN_U16_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_U16_LIST_REMOVE: + return output; +} + +void wapp_u16_list_empty(U16List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_u16_list_pop_back(list); + } +} + +U32Node *wapp_u32_list_get(const U32List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + U32Node *output = NULL; + U32Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_u32_list_push_front(U32List *list, U32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U32List node_list = u32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U32Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_u32_list_push_back(U32List *list, U32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U32List node_list = u32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U32Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_u32_list_insert(U32List *list, U32Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_u32_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_u32_list_push_back(list, node); + return; + } + + U32Node *dst_node = wapp_u32_list_get(list, index); + if (!dst_node) { + return; + } + + U32List node_list = u32_node_to_list(node); + + list->node_count += node_list.node_count; + + U32Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +U32Node *wapp_u32_list_pop_front(U32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U32_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (U32List){0}; + goto RETURN_U32_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_U32_LIST_POP_FRONT: + return output; +} + +U32Node *wapp_u32_list_pop_back(U32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U32_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (U32List){0}; + goto RETURN_U32_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_U32_LIST_POP_BACK: + return output; +} + +U32Node *wapp_u32_list_remove(U32List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U32Node *output = NULL; + + if (index == 0) { + output = wapp_u32_list_pop_front(list); + goto RETURN_U32_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_u32_list_pop_back(list); + goto RETURN_U32_LIST_REMOVE; + } + + output = wapp_u32_list_get(list, index); + if (!output) { + goto RETURN_U32_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_U32_LIST_REMOVE: + return output; +} + +void wapp_u32_list_empty(U32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_u32_list_pop_back(list); + } +} + +U64Node *wapp_u64_list_get(const U64List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + U64Node *output = NULL; + U64Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_u64_list_push_front(U64List *list, U64Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U64List node_list = u64_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U64Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_u64_list_push_back(U64List *list, U64Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + U64List node_list = u64_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + U64Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_u64_list_insert(U64List *list, U64Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_u64_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_u64_list_push_back(list, node); + return; + } + + U64Node *dst_node = wapp_u64_list_get(list, index); + if (!dst_node) { + return; + } + + U64List node_list = u64_node_to_list(node); + + list->node_count += node_list.node_count; + + U64Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +U64Node *wapp_u64_list_pop_front(U64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U64Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U64_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (U64List){0}; + goto RETURN_U64_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_U64_LIST_POP_FRONT: + return output; +} + +U64Node *wapp_u64_list_pop_back(U64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U64Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_U64_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (U64List){0}; + goto RETURN_U64_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_U64_LIST_POP_BACK: + return output; +} + +U64Node *wapp_u64_list_remove(U64List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + U64Node *output = NULL; + + if (index == 0) { + output = wapp_u64_list_pop_front(list); + goto RETURN_U64_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_u64_list_pop_back(list); + goto RETURN_U64_LIST_REMOVE; + } + + output = wapp_u64_list_get(list, index); + if (!output) { + goto RETURN_U64_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_U64_LIST_REMOVE: + return output; +} + +void wapp_u64_list_empty(U64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_u64_list_pop_back(list); + } +} + +F32Node *wapp_f32_list_get(const F32List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + F32Node *output = NULL; + F32Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_f32_list_push_front(F32List *list, F32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + F32List node_list = f32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + F32Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_f32_list_push_back(F32List *list, F32Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + F32List node_list = f32_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + F32Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_f32_list_insert(F32List *list, F32Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_f32_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_f32_list_push_back(list, node); + return; + } + + F32Node *dst_node = wapp_f32_list_get(list, index); + if (!dst_node) { + return; + } + + F32List node_list = f32_node_to_list(node); + + list->node_count += node_list.node_count; + + F32Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +F32Node *wapp_f32_list_pop_front(F32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_F32_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (F32List){0}; + goto RETURN_F32_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_F32_LIST_POP_FRONT: + return output; +} + +F32Node *wapp_f32_list_pop_back(F32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F32Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_F32_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (F32List){0}; + goto RETURN_F32_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_F32_LIST_POP_BACK: + return output; +} + +F32Node *wapp_f32_list_remove(F32List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F32Node *output = NULL; + + if (index == 0) { + output = wapp_f32_list_pop_front(list); + goto RETURN_F32_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_f32_list_pop_back(list); + goto RETURN_F32_LIST_REMOVE; + } + + output = wapp_f32_list_get(list, index); + if (!output) { + goto RETURN_F32_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_F32_LIST_REMOVE: + return output; +} + +void wapp_f32_list_empty(F32List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_f32_list_pop_back(list); + } +} + +F64Node *wapp_f64_list_get(const F64List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + F64Node *output = NULL; + F64Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_f64_list_push_front(F64List *list, F64Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + F64List node_list = f64_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + F64Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_f64_list_push_back(F64List *list, F64Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + F64List node_list = f64_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + F64Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_f64_list_insert(F64List *list, F64Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_f64_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_f64_list_push_back(list, node); + return; + } + + F64Node *dst_node = wapp_f64_list_get(list, index); + if (!dst_node) { + return; + } + + F64List node_list = f64_node_to_list(node); + + list->node_count += node_list.node_count; + + F64Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +F64Node *wapp_f64_list_pop_front(F64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F64Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_F64_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (F64List){0}; + goto RETURN_F64_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_F64_LIST_POP_FRONT: + return output; +} + +F64Node *wapp_f64_list_pop_back(F64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F64Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_F64_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (F64List){0}; + goto RETURN_F64_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_F64_LIST_POP_BACK: + return output; +} + +F64Node *wapp_f64_list_remove(F64List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F64Node *output = NULL; + + if (index == 0) { + output = wapp_f64_list_pop_front(list); + goto RETURN_F64_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_f64_list_pop_back(list); + goto RETURN_F64_LIST_REMOVE; + } + + output = wapp_f64_list_get(list, index); + if (!output) { + goto RETURN_F64_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_F64_LIST_REMOVE: + return output; +} + +void wapp_f64_list_empty(F64List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_f64_list_pop_back(list); + } +} + +F128Node *wapp_f128_list_get(const F128List *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + F128Node *output = NULL; + F128Node *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_f128_list_push_front(F128List *list, F128Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + F128List node_list = f128_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + F128Node *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_f128_list_push_back(F128List *list, F128Node *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + F128List node_list = f128_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + F128Node *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_f128_list_insert(F128List *list, F128Node *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_f128_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_f128_list_push_back(list, node); + return; + } + + F128Node *dst_node = wapp_f128_list_get(list, index); + if (!dst_node) { + return; + } + + F128List node_list = f128_node_to_list(node); + + list->node_count += node_list.node_count; + + F128Node *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +F128Node *wapp_f128_list_pop_front(F128List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F128Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_F128_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (F128List){0}; + goto RETURN_F128_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_F128_LIST_POP_FRONT: + return output; +} + +F128Node *wapp_f128_list_pop_back(F128List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F128Node *output = NULL; + + if (list->node_count == 0) { + goto RETURN_F128_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (F128List){0}; + goto RETURN_F128_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_F128_LIST_POP_BACK: + return output; +} + +F128Node *wapp_f128_list_remove(F128List *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + F128Node *output = NULL; + + if (index == 0) { + output = wapp_f128_list_pop_front(list); + goto RETURN_F128_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_f128_list_pop_back(list); + goto RETURN_F128_LIST_REMOVE; + } + + output = wapp_f128_list_get(list, index); + if (!output) { + goto RETURN_F128_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_F128_LIST_REMOVE: + return output; +} + +void wapp_f128_list_empty(F128List *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_f128_list_pop_back(list); + } +} + +IptrNode *wapp_iptr_list_get(const IptrList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + IptrNode *output = NULL; + IptrNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_iptr_list_push_front(IptrList *list, IptrNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + IptrList node_list = iptr_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + IptrNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_iptr_list_push_back(IptrList *list, IptrNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + IptrList node_list = iptr_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + IptrNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_iptr_list_insert(IptrList *list, IptrNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_iptr_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_iptr_list_push_back(list, node); + return; + } + + IptrNode *dst_node = wapp_iptr_list_get(list, index); + if (!dst_node) { + return; + } + + IptrList node_list = iptr_node_to_list(node); + + list->node_count += node_list.node_count; + + IptrNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +IptrNode *wapp_iptr_list_pop_front(IptrList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + IptrNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_IPTR_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (IptrList){0}; + goto RETURN_IPTR_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_IPTR_LIST_POP_FRONT: + return output; +} + +IptrNode *wapp_iptr_list_pop_back(IptrList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + IptrNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_IPTR_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (IptrList){0}; + goto RETURN_IPTR_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_IPTR_LIST_POP_BACK: + return output; +} + +IptrNode *wapp_iptr_list_remove(IptrList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + IptrNode *output = NULL; + + if (index == 0) { + output = wapp_iptr_list_pop_front(list); + goto RETURN_IPTR_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_iptr_list_pop_back(list); + goto RETURN_IPTR_LIST_REMOVE; + } + + output = wapp_iptr_list_get(list, index); + if (!output) { + goto RETURN_IPTR_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_IPTR_LIST_REMOVE: + return output; +} + +void wapp_iptr_list_empty(IptrList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_iptr_list_pop_back(list); + } +} + +UptrNode *wapp_uptr_list_get(const UptrList *list, u64 index) { + wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); + + UptrNode *output = NULL; + UptrNode *current = list->first; + for (u64 i = 1; i <= index; ++i) { + current = current->next; + } + + output = current; + + return output; +} + +void wapp_uptr_list_push_front(UptrList *list, UptrNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + UptrList node_list = uptr_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + UptrNode *first = list->first; + if (first) { + first->prev = node_list.last; + } + + list->first = node_list.first; + node_list.last->next = first; +} + +void wapp_uptr_list_push_back(UptrList *list, UptrNode *node) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + UptrList node_list = uptr_node_to_list(node); + + if (list->node_count == 0) { + *list = node_list; + return; + } + + list->node_count += node_list.node_count; + + UptrNode *last = list->last; + if (last) { + last->next = node_list.first; + } + + list->last = node_list.last; + node_list.first->prev = last; +} + +void wapp_uptr_list_insert(UptrList *list, UptrNode *node, u64 index) { + wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); + + if (index == 0) { + wapp_uptr_list_push_front(list, node); + return; + } else if (index == list->node_count) { + wapp_uptr_list_push_back(list, node); + return; + } + + UptrNode *dst_node = wapp_uptr_list_get(list, index); + if (!dst_node) { + return; + } + + UptrList node_list = uptr_node_to_list(node); + + list->node_count += node_list.node_count; + + UptrNode *prev = dst_node->prev; + + dst_node->prev = node_list.last; + prev->next = node_list.first; + + node_list.first->prev = prev; + node_list.last->next = dst_node; +} + +UptrNode *wapp_uptr_list_pop_front(UptrList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + UptrNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_UPTR_LIST_POP_FRONT; + } + + output = list->first; + + if (list->node_count == 1) { + *list = (UptrList){0}; + goto RETURN_UPTR_LIST_POP_FRONT; + } + + --(list->node_count); + list->first = output->next; + + output->prev = output->next = NULL; + +RETURN_UPTR_LIST_POP_FRONT: + return output; +} + +UptrNode *wapp_uptr_list_pop_back(UptrList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + UptrNode *output = NULL; + + if (list->node_count == 0) { + goto RETURN_UPTR_LIST_POP_BACK; + } + + output = list->last; + + if (list->node_count == 1) { + *list = (UptrList){0}; + goto RETURN_UPTR_LIST_POP_BACK; + } + + --(list->node_count); + list->last = output->prev; + + output->prev = output->next = NULL; + +RETURN_UPTR_LIST_POP_BACK: + return output; +} + +UptrNode *wapp_uptr_list_remove(UptrList *list, u64 index) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + UptrNode *output = NULL; + + if (index == 0) { + output = wapp_uptr_list_pop_front(list); + goto RETURN_UPTR_LIST_REMOVE; + } else if (index == list->node_count) { + output = wapp_uptr_list_pop_back(list); + goto RETURN_UPTR_LIST_REMOVE; + } + + output = wapp_uptr_list_get(list, index); + if (!output) { + goto RETURN_UPTR_LIST_REMOVE; + } + + output->prev->next = output->next; + output->next->prev = output->prev; + + --(list->node_count); + + output->prev = output->next = NULL; + +RETURN_UPTR_LIST_REMOVE: + return output; +} + +void wapp_uptr_list_empty(UptrList *list) { + wapp_debug_assert(list != NULL, "`list` should not be NULL"); + + u64 count = list->node_count; + for (u64 i = 0; i < count; ++i) { + wapp_uptr_list_pop_back(list); + } +} + +internal Str8List str8_node_to_list(Str8Node *node) { + Str8List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal VoidPList void_ptr_node_to_list(VoidPNode *node) { + VoidPList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal B32List b32_node_to_list(B32Node *node) { + B32List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal CharList char_node_to_list(CharNode *node) { + CharList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal C8List c8_node_to_list(C8Node *node) { + C8List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal C16List c16_node_to_list(C16Node *node) { + C16List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal C32List c32_node_to_list(C32Node *node) { + C32List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal I8List i8_node_to_list(I8Node *node) { + I8List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal I16List i16_node_to_list(I16Node *node) { + I16List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal I32List i32_node_to_list(I32Node *node) { + I32List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal I64List i64_node_to_list(I64Node *node) { + I64List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal U8List u8_node_to_list(U8Node *node) { + U8List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal U16List u16_node_to_list(U16Node *node) { + U16List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal U32List u32_node_to_list(U32Node *node) { + U32List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal U64List u64_node_to_list(U64Node *node) { + U64List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal F32List f32_node_to_list(F32Node *node) { + F32List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal F64List f64_node_to_list(F64Node *node) { + F64List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal F128List f128_node_to_list(F128Node *node) { + F128List output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal IptrList iptr_node_to_list(IptrNode *node) { + IptrList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + +internal UptrList uptr_node_to_list(UptrNode *node) { + UptrList output = {.first = node, .last = node, .node_count = 1}; + + while (output.first->prev != NULL) { + output.first = output.first->prev; + ++(output.node_count); + } + + while (output.last->next != NULL) { + output.last = output.last->next; + ++(output.node_count); + } + + return output; +} + diff --git a/wapp/primitives/dbl_list/dbl_list.h b/wapp/primitives/dbl_list/dbl_list.h new file mode 100644 index 0000000..80f3eae --- /dev/null +++ b/wapp/primitives/dbl_list/dbl_list.h @@ -0,0 +1,507 @@ +/** + * THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN + */ + +#ifndef DBL_LIST_H +#define DBL_LIST_H + +#include "../../common/aliases/aliases.h" +#include "../../common/aliases/aliases.h" +#include "../../common/platform/platform.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_CPP +#define wapp_str8_list_node(ITEM_PTR) Str8Node{ITEM_PTR, nullptr, nullptr} +#define wapp_void_ptr_list_node(ITEM_PTR) VoidPNode{ITEM_PTR, nullptr, nullptr} +#define wapp_b32_list_node(ITEM_PTR) B32Node{ITEM_PTR, nullptr, nullptr} +#define wapp_char_list_node(ITEM_PTR) CharNode{ITEM_PTR, nullptr, nullptr} +#define wapp_c8_list_node(ITEM_PTR) C8Node{ITEM_PTR, nullptr, nullptr} +#define wapp_c16_list_node(ITEM_PTR) C16Node{ITEM_PTR, nullptr, nullptr} +#define wapp_c32_list_node(ITEM_PTR) C32Node{ITEM_PTR, nullptr, nullptr} +#define wapp_i8_list_node(ITEM_PTR) I8Node{ITEM_PTR, nullptr, nullptr} +#define wapp_i16_list_node(ITEM_PTR) I16Node{ITEM_PTR, nullptr, nullptr} +#define wapp_i32_list_node(ITEM_PTR) I32Node{ITEM_PTR, nullptr, nullptr} +#define wapp_i64_list_node(ITEM_PTR) I64Node{ITEM_PTR, nullptr, nullptr} +#define wapp_u8_list_node(ITEM_PTR) U8Node{ITEM_PTR, nullptr, nullptr} +#define wapp_u16_list_node(ITEM_PTR) U16Node{ITEM_PTR, nullptr, nullptr} +#define wapp_u32_list_node(ITEM_PTR) U32Node{ITEM_PTR, nullptr, nullptr} +#define wapp_u64_list_node(ITEM_PTR) U64Node{ITEM_PTR, nullptr, nullptr} +#define wapp_f32_list_node(ITEM_PTR) F32Node{ITEM_PTR, nullptr, nullptr} +#define wapp_f64_list_node(ITEM_PTR) F64Node{ITEM_PTR, nullptr, nullptr} +#define wapp_f128_list_node(ITEM_PTR) F128Node{ITEM_PTR, nullptr, nullptr} +#define wapp_iptr_list_node(ITEM_PTR) IptrNode{ITEM_PTR, nullptr, nullptr} +#define wapp_uptr_list_node(ITEM_PTR) UptrNode{ITEM_PTR, nullptr, nullptr} +#else +#define wapp_str8_list_node(ITEM_PTR) ((Str8Node){.item = ITEM_PTR}) +#define wapp_void_ptr_list_node(ITEM_PTR) ((VoidPNode){.item = ITEM_PTR}) +#define wapp_b32_list_node(ITEM_PTR) ((B32Node){.item = ITEM_PTR}) +#define wapp_char_list_node(ITEM_PTR) ((CharNode){.item = ITEM_PTR}) +#define wapp_c8_list_node(ITEM_PTR) ((C8Node){.item = ITEM_PTR}) +#define wapp_c16_list_node(ITEM_PTR) ((C16Node){.item = ITEM_PTR}) +#define wapp_c32_list_node(ITEM_PTR) ((C32Node){.item = ITEM_PTR}) +#define wapp_i8_list_node(ITEM_PTR) ((I8Node){.item = ITEM_PTR}) +#define wapp_i16_list_node(ITEM_PTR) ((I16Node){.item = ITEM_PTR}) +#define wapp_i32_list_node(ITEM_PTR) ((I32Node){.item = ITEM_PTR}) +#define wapp_i64_list_node(ITEM_PTR) ((I64Node){.item = ITEM_PTR}) +#define wapp_u8_list_node(ITEM_PTR) ((U8Node){.item = ITEM_PTR}) +#define wapp_u16_list_node(ITEM_PTR) ((U16Node){.item = ITEM_PTR}) +#define wapp_u32_list_node(ITEM_PTR) ((U32Node){.item = ITEM_PTR}) +#define wapp_u64_list_node(ITEM_PTR) ((U64Node){.item = ITEM_PTR}) +#define wapp_f32_list_node(ITEM_PTR) ((F32Node){.item = ITEM_PTR}) +#define wapp_f64_list_node(ITEM_PTR) ((F64Node){.item = ITEM_PTR}) +#define wapp_f128_list_node(ITEM_PTR) ((F128Node){.item = ITEM_PTR}) +#define wapp_iptr_list_node(ITEM_PTR) ((IptrNode){.item = ITEM_PTR}) +#define wapp_uptr_list_node(ITEM_PTR) ((UptrNode){.item = ITEM_PTR}) +#endif // !WAPP_PLATFORM_CPP + +typedef struct str8 Str8; + +typedef struct Str8Node Str8Node; +struct Str8Node { + Str8 *item; + Str8Node *prev; + Str8Node *next; +}; + +typedef struct Str8List Str8List; +struct Str8List { + Str8Node *first; + Str8Node *last; + u64 node_count; +}; + +typedef struct VoidPNode VoidPNode; +struct VoidPNode { + void * *item; + VoidPNode *prev; + VoidPNode *next; +}; + +typedef struct VoidPList VoidPList; +struct VoidPList { + VoidPNode *first; + VoidPNode *last; + u64 node_count; +}; + +typedef struct B32Node B32Node; +struct B32Node { + b32 *item; + B32Node *prev; + B32Node *next; +}; + +typedef struct B32List B32List; +struct B32List { + B32Node *first; + B32Node *last; + u64 node_count; +}; + +typedef struct CharNode CharNode; +struct CharNode { + char *item; + CharNode *prev; + CharNode *next; +}; + +typedef struct CharList CharList; +struct CharList { + CharNode *first; + CharNode *last; + u64 node_count; +}; + +typedef struct C8Node C8Node; +struct C8Node { + c8 *item; + C8Node *prev; + C8Node *next; +}; + +typedef struct C8List C8List; +struct C8List { + C8Node *first; + C8Node *last; + u64 node_count; +}; + +typedef struct C16Node C16Node; +struct C16Node { + c16 *item; + C16Node *prev; + C16Node *next; +}; + +typedef struct C16List C16List; +struct C16List { + C16Node *first; + C16Node *last; + u64 node_count; +}; + +typedef struct C32Node C32Node; +struct C32Node { + c32 *item; + C32Node *prev; + C32Node *next; +}; + +typedef struct C32List C32List; +struct C32List { + C32Node *first; + C32Node *last; + u64 node_count; +}; + +typedef struct I8Node I8Node; +struct I8Node { + i8 *item; + I8Node *prev; + I8Node *next; +}; + +typedef struct I8List I8List; +struct I8List { + I8Node *first; + I8Node *last; + u64 node_count; +}; + +typedef struct I16Node I16Node; +struct I16Node { + i16 *item; + I16Node *prev; + I16Node *next; +}; + +typedef struct I16List I16List; +struct I16List { + I16Node *first; + I16Node *last; + u64 node_count; +}; + +typedef struct I32Node I32Node; +struct I32Node { + i32 *item; + I32Node *prev; + I32Node *next; +}; + +typedef struct I32List I32List; +struct I32List { + I32Node *first; + I32Node *last; + u64 node_count; +}; + +typedef struct I64Node I64Node; +struct I64Node { + i64 *item; + I64Node *prev; + I64Node *next; +}; + +typedef struct I64List I64List; +struct I64List { + I64Node *first; + I64Node *last; + u64 node_count; +}; + +typedef struct U8Node U8Node; +struct U8Node { + u8 *item; + U8Node *prev; + U8Node *next; +}; + +typedef struct U8List U8List; +struct U8List { + U8Node *first; + U8Node *last; + u64 node_count; +}; + +typedef struct U16Node U16Node; +struct U16Node { + u16 *item; + U16Node *prev; + U16Node *next; +}; + +typedef struct U16List U16List; +struct U16List { + U16Node *first; + U16Node *last; + u64 node_count; +}; + +typedef struct U32Node U32Node; +struct U32Node { + u32 *item; + U32Node *prev; + U32Node *next; +}; + +typedef struct U32List U32List; +struct U32List { + U32Node *first; + U32Node *last; + u64 node_count; +}; + +typedef struct U64Node U64Node; +struct U64Node { + u64 *item; + U64Node *prev; + U64Node *next; +}; + +typedef struct U64List U64List; +struct U64List { + U64Node *first; + U64Node *last; + u64 node_count; +}; + +typedef struct F32Node F32Node; +struct F32Node { + f32 *item; + F32Node *prev; + F32Node *next; +}; + +typedef struct F32List F32List; +struct F32List { + F32Node *first; + F32Node *last; + u64 node_count; +}; + +typedef struct F64Node F64Node; +struct F64Node { + f64 *item; + F64Node *prev; + F64Node *next; +}; + +typedef struct F64List F64List; +struct F64List { + F64Node *first; + F64Node *last; + u64 node_count; +}; + +typedef struct F128Node F128Node; +struct F128Node { + f128 *item; + F128Node *prev; + F128Node *next; +}; + +typedef struct F128List F128List; +struct F128List { + F128Node *first; + F128Node *last; + u64 node_count; +}; + +typedef struct IptrNode IptrNode; +struct IptrNode { + iptr *item; + IptrNode *prev; + IptrNode *next; +}; + +typedef struct IptrList IptrList; +struct IptrList { + IptrNode *first; + IptrNode *last; + u64 node_count; +}; + +typedef struct UptrNode UptrNode; +struct UptrNode { + uptr *item; + UptrNode *prev; + UptrNode *next; +}; + +typedef struct UptrList UptrList; +struct UptrList { + UptrNode *first; + UptrNode *last; + u64 node_count; +}; + +Str8Node *wapp_str8_list_get(const Str8List *list, u64 index); +void wapp_str8_list_push_front(Str8List *list, Str8Node *node); +void wapp_str8_list_push_back(Str8List *list, Str8Node *node); +void wapp_str8_list_insert(Str8List *list, Str8Node *node, u64 index); +Str8Node *wapp_str8_list_pop_front(Str8List *list); +Str8Node *wapp_str8_list_pop_back(Str8List *list); +Str8Node *wapp_str8_list_remove(Str8List *list, u64 index); +void wapp_str8_list_empty(Str8List *list); +VoidPNode *wapp_void_ptr_list_get(const VoidPList *list, u64 index); +void wapp_void_ptr_list_push_front(VoidPList *list, VoidPNode *node); +void wapp_void_ptr_list_push_back(VoidPList *list, VoidPNode *node); +void wapp_void_ptr_list_insert(VoidPList *list, VoidPNode *node, u64 index); +VoidPNode *wapp_void_ptr_list_pop_front(VoidPList *list); +VoidPNode *wapp_void_ptr_list_pop_back(VoidPList *list); +VoidPNode *wapp_void_ptr_list_remove(VoidPList *list, u64 index); +void wapp_void_ptr_list_empty(VoidPList *list); +B32Node *wapp_b32_list_get(const B32List *list, u64 index); +void wapp_b32_list_push_front(B32List *list, B32Node *node); +void wapp_b32_list_push_back(B32List *list, B32Node *node); +void wapp_b32_list_insert(B32List *list, B32Node *node, u64 index); +B32Node *wapp_b32_list_pop_front(B32List *list); +B32Node *wapp_b32_list_pop_back(B32List *list); +B32Node *wapp_b32_list_remove(B32List *list, u64 index); +void wapp_b32_list_empty(B32List *list); +CharNode *wapp_char_list_get(const CharList *list, u64 index); +void wapp_char_list_push_front(CharList *list, CharNode *node); +void wapp_char_list_push_back(CharList *list, CharNode *node); +void wapp_char_list_insert(CharList *list, CharNode *node, u64 index); +CharNode *wapp_char_list_pop_front(CharList *list); +CharNode *wapp_char_list_pop_back(CharList *list); +CharNode *wapp_char_list_remove(CharList *list, u64 index); +void wapp_char_list_empty(CharList *list); +C8Node *wapp_c8_list_get(const C8List *list, u64 index); +void wapp_c8_list_push_front(C8List *list, C8Node *node); +void wapp_c8_list_push_back(C8List *list, C8Node *node); +void wapp_c8_list_insert(C8List *list, C8Node *node, u64 index); +C8Node *wapp_c8_list_pop_front(C8List *list); +C8Node *wapp_c8_list_pop_back(C8List *list); +C8Node *wapp_c8_list_remove(C8List *list, u64 index); +void wapp_c8_list_empty(C8List *list); +C16Node *wapp_c16_list_get(const C16List *list, u64 index); +void wapp_c16_list_push_front(C16List *list, C16Node *node); +void wapp_c16_list_push_back(C16List *list, C16Node *node); +void wapp_c16_list_insert(C16List *list, C16Node *node, u64 index); +C16Node *wapp_c16_list_pop_front(C16List *list); +C16Node *wapp_c16_list_pop_back(C16List *list); +C16Node *wapp_c16_list_remove(C16List *list, u64 index); +void wapp_c16_list_empty(C16List *list); +C32Node *wapp_c32_list_get(const C32List *list, u64 index); +void wapp_c32_list_push_front(C32List *list, C32Node *node); +void wapp_c32_list_push_back(C32List *list, C32Node *node); +void wapp_c32_list_insert(C32List *list, C32Node *node, u64 index); +C32Node *wapp_c32_list_pop_front(C32List *list); +C32Node *wapp_c32_list_pop_back(C32List *list); +C32Node *wapp_c32_list_remove(C32List *list, u64 index); +void wapp_c32_list_empty(C32List *list); +I8Node *wapp_i8_list_get(const I8List *list, u64 index); +void wapp_i8_list_push_front(I8List *list, I8Node *node); +void wapp_i8_list_push_back(I8List *list, I8Node *node); +void wapp_i8_list_insert(I8List *list, I8Node *node, u64 index); +I8Node *wapp_i8_list_pop_front(I8List *list); +I8Node *wapp_i8_list_pop_back(I8List *list); +I8Node *wapp_i8_list_remove(I8List *list, u64 index); +void wapp_i8_list_empty(I8List *list); +I16Node *wapp_i16_list_get(const I16List *list, u64 index); +void wapp_i16_list_push_front(I16List *list, I16Node *node); +void wapp_i16_list_push_back(I16List *list, I16Node *node); +void wapp_i16_list_insert(I16List *list, I16Node *node, u64 index); +I16Node *wapp_i16_list_pop_front(I16List *list); +I16Node *wapp_i16_list_pop_back(I16List *list); +I16Node *wapp_i16_list_remove(I16List *list, u64 index); +void wapp_i16_list_empty(I16List *list); +I32Node *wapp_i32_list_get(const I32List *list, u64 index); +void wapp_i32_list_push_front(I32List *list, I32Node *node); +void wapp_i32_list_push_back(I32List *list, I32Node *node); +void wapp_i32_list_insert(I32List *list, I32Node *node, u64 index); +I32Node *wapp_i32_list_pop_front(I32List *list); +I32Node *wapp_i32_list_pop_back(I32List *list); +I32Node *wapp_i32_list_remove(I32List *list, u64 index); +void wapp_i32_list_empty(I32List *list); +I64Node *wapp_i64_list_get(const I64List *list, u64 index); +void wapp_i64_list_push_front(I64List *list, I64Node *node); +void wapp_i64_list_push_back(I64List *list, I64Node *node); +void wapp_i64_list_insert(I64List *list, I64Node *node, u64 index); +I64Node *wapp_i64_list_pop_front(I64List *list); +I64Node *wapp_i64_list_pop_back(I64List *list); +I64Node *wapp_i64_list_remove(I64List *list, u64 index); +void wapp_i64_list_empty(I64List *list); +U8Node *wapp_u8_list_get(const U8List *list, u64 index); +void wapp_u8_list_push_front(U8List *list, U8Node *node); +void wapp_u8_list_push_back(U8List *list, U8Node *node); +void wapp_u8_list_insert(U8List *list, U8Node *node, u64 index); +U8Node *wapp_u8_list_pop_front(U8List *list); +U8Node *wapp_u8_list_pop_back(U8List *list); +U8Node *wapp_u8_list_remove(U8List *list, u64 index); +void wapp_u8_list_empty(U8List *list); +U16Node *wapp_u16_list_get(const U16List *list, u64 index); +void wapp_u16_list_push_front(U16List *list, U16Node *node); +void wapp_u16_list_push_back(U16List *list, U16Node *node); +void wapp_u16_list_insert(U16List *list, U16Node *node, u64 index); +U16Node *wapp_u16_list_pop_front(U16List *list); +U16Node *wapp_u16_list_pop_back(U16List *list); +U16Node *wapp_u16_list_remove(U16List *list, u64 index); +void wapp_u16_list_empty(U16List *list); +U32Node *wapp_u32_list_get(const U32List *list, u64 index); +void wapp_u32_list_push_front(U32List *list, U32Node *node); +void wapp_u32_list_push_back(U32List *list, U32Node *node); +void wapp_u32_list_insert(U32List *list, U32Node *node, u64 index); +U32Node *wapp_u32_list_pop_front(U32List *list); +U32Node *wapp_u32_list_pop_back(U32List *list); +U32Node *wapp_u32_list_remove(U32List *list, u64 index); +void wapp_u32_list_empty(U32List *list); +U64Node *wapp_u64_list_get(const U64List *list, u64 index); +void wapp_u64_list_push_front(U64List *list, U64Node *node); +void wapp_u64_list_push_back(U64List *list, U64Node *node); +void wapp_u64_list_insert(U64List *list, U64Node *node, u64 index); +U64Node *wapp_u64_list_pop_front(U64List *list); +U64Node *wapp_u64_list_pop_back(U64List *list); +U64Node *wapp_u64_list_remove(U64List *list, u64 index); +void wapp_u64_list_empty(U64List *list); +F32Node *wapp_f32_list_get(const F32List *list, u64 index); +void wapp_f32_list_push_front(F32List *list, F32Node *node); +void wapp_f32_list_push_back(F32List *list, F32Node *node); +void wapp_f32_list_insert(F32List *list, F32Node *node, u64 index); +F32Node *wapp_f32_list_pop_front(F32List *list); +F32Node *wapp_f32_list_pop_back(F32List *list); +F32Node *wapp_f32_list_remove(F32List *list, u64 index); +void wapp_f32_list_empty(F32List *list); +F64Node *wapp_f64_list_get(const F64List *list, u64 index); +void wapp_f64_list_push_front(F64List *list, F64Node *node); +void wapp_f64_list_push_back(F64List *list, F64Node *node); +void wapp_f64_list_insert(F64List *list, F64Node *node, u64 index); +F64Node *wapp_f64_list_pop_front(F64List *list); +F64Node *wapp_f64_list_pop_back(F64List *list); +F64Node *wapp_f64_list_remove(F64List *list, u64 index); +void wapp_f64_list_empty(F64List *list); +F128Node *wapp_f128_list_get(const F128List *list, u64 index); +void wapp_f128_list_push_front(F128List *list, F128Node *node); +void wapp_f128_list_push_back(F128List *list, F128Node *node); +void wapp_f128_list_insert(F128List *list, F128Node *node, u64 index); +F128Node *wapp_f128_list_pop_front(F128List *list); +F128Node *wapp_f128_list_pop_back(F128List *list); +F128Node *wapp_f128_list_remove(F128List *list, u64 index); +void wapp_f128_list_empty(F128List *list); +IptrNode *wapp_iptr_list_get(const IptrList *list, u64 index); +void wapp_iptr_list_push_front(IptrList *list, IptrNode *node); +void wapp_iptr_list_push_back(IptrList *list, IptrNode *node); +void wapp_iptr_list_insert(IptrList *list, IptrNode *node, u64 index); +IptrNode *wapp_iptr_list_pop_front(IptrList *list); +IptrNode *wapp_iptr_list_pop_back(IptrList *list); +IptrNode *wapp_iptr_list_remove(IptrList *list, u64 index); +void wapp_iptr_list_empty(IptrList *list); +UptrNode *wapp_uptr_list_get(const UptrList *list, u64 index); +void wapp_uptr_list_push_front(UptrList *list, UptrNode *node); +void wapp_uptr_list_push_back(UptrList *list, UptrNode *node); +void wapp_uptr_list_insert(UptrList *list, UptrNode *node, u64 index); +UptrNode *wapp_uptr_list_pop_front(UptrList *list); +UptrNode *wapp_uptr_list_pop_back(UptrList *list); +UptrNode *wapp_uptr_list_remove(UptrList *list, u64 index); +void wapp_uptr_list_empty(UptrList *list); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !DBL_LIST_H diff --git a/wapp/primitives/mem_allocator/mem_allocator.c b/wapp/primitives/mem_allocator/mem_allocator.c new file mode 100644 index 0000000..c551576 --- /dev/null +++ b/wapp/primitives/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 *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"); + return allocator->alloc(size, allocator->obj); +} + +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"); + return allocator->alloc_aligned(size, alignment, allocator->obj); +} + +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"); + return allocator->realloc(ptr, old_size, new_size, allocator->obj); +} + +void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size, + u64 new_size, u64 alignment) { + 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); +} + +void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size) { + if (!allocator || !(allocator->free)) { + return; + } + + allocator->free(ptr, size, allocator->obj); +} diff --git a/wapp/primitives/mem_allocator/mem_allocator.h b/wapp/primitives/mem_allocator/mem_allocator.h new file mode 100644 index 0000000..389e158 --- /dev/null +++ b/wapp/primitives/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef void *(MemAllocFunc)(u64 size, 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 *(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 struct allocator Allocator; +struct allocator { + void *obj; + MemAllocFunc *alloc; + MemAllocAlignedFunc *alloc_aligned; + MemReallocFunc *realloc; + MemReallocAlignedFunc *realloc_aligned; + MemFreeFunc *free; +}; + +#ifdef WAPP_PLATFORM_CPP +#define wapp_mem_allocator_invalid(ALLOCATOR) ([&]() { \ + Allocator alloc{}; \ + return memcmp(ALLOCATOR, &alloc, sizeof(Allocator)) == 0; \ +}()) +#else +#define wapp_mem_allocator_invalid(ALLOCATOR) (memcmp(ALLOCATOR, &((Allocator){0}), sizeof(Allocator)) == 0) +#endif // !WAPP_PLATFORM_CPP + +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_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, + u64 new_size, u64 alignment); +void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !MEM_ALLOCATOR_H diff --git a/wapp/primitives/strings/str8/str8.c b/wapp/primitives/strings/str8/str8.c new file mode 100644 index 0000000..7a507db --- /dev/null +++ b/wapp/primitives/strings/str8/str8.c @@ -0,0 +1,446 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "str8.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include "../../mem_allocator/mem_allocator.h" +#include +#include +#include +#include +#include + +#define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(Str8) + sizeof(c8) * CAPACITY) + +Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity) { + wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); + + Str8 *str = wapp_mem_allocator_alloc(allocator, STR8_BUF_ALLOC_SIZE(capacity)); + if (!str) { + goto RETURN_STR8; + } + + str->buf = (u8 *)str + sizeof(Str8); + str->size = 0; + str->capacity = capacity; + +RETURN_STR8: + return str; +} + +Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity) { + Str8 *out = wapp_str8_alloc_buf(allocator, capacity); + if (out) { + memset(out->buf, 0, capacity); + out->size = capacity; + } + return out; +} + +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"); + + u64 length = strlen(str); + Str8 *output = wapp_str8_alloc_buf(allocator, length * 2); + if (!output) { + goto RETURN_ALLOC_CSTR; + } + + output->size = length; + memcpy(output->buf, str, length); + +RETURN_ALLOC_CSTR: + return output; +} + +Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str) { + wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL"); + + Str8 *output = wapp_str8_alloc_buf(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; +} + +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"); + + Str8 *output = NULL; + + if (start >= str->size || start >= end) { + goto RETURN_ALLOC_SUBSTR; + } + + if (end > str->size) { + end = str->size; + } + + output = wapp_str8_alloc_buf(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 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_mem_allocator_free(allocator, (void **)str, STR8_BUF_ALLOC_SIZE((*str)->capacity)); +} + +c8 wapp_str8_get(const Str8 *str, u64 index) { + if (index >= str->size) { + return '\0'; + } + + return str->buf[index]; +} + +void wapp_str8_set(Str8 *str, u64 index, c8 c) { + if (index >= str->size) { + return; + } + + str->buf[index] = c; +} + +void wapp_str8_push_back(Str8 *str, c8 c) { + if (!(str->size < str->capacity)) { + return; + } + + u64 index = (str->size)++; + wapp_str8_set(str, index, c); +} + +bool wapp_str8_equal(Str8RO *s1, Str8RO *s2) { + if (s1->size != s2->size) { + return false; + } + + return wapp_str8_equal_to_count(s1, s2, s1->size); +} + +bool wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count) { + if (!s1 || !s2) { + return false; + } + + return memcmp(s1->buf, s2->buf, count) == 0; +} + +Str8 wapp_str8_slice(Str8RO *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 (Str8RO){ + .capacity = end - start, + .size = end - start, + .buf = str->buf + start, + }; +} + +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"); + + Str8 *output = NULL; + u64 remaining = dst->capacity - dst->size; + if (src->size <= remaining) { + output = dst; + goto COPY_STRING_STR8_CONCAT; + } + + u64 capacity = dst->capacity + src->size; + + output = wapp_str8_alloc_buf(allocator, capacity); + if (!output) { + goto RETURN_STR8_CONCAT; + } + + wapp_str8_concat_capped(output, dst); + +COPY_STRING_STR8_CONCAT: + wapp_str8_concat_capped(output, src); + +RETURN_STR8_CONCAT: + return output; +} + +void wapp_str8_concat_capped(Str8 *dst, Str8RO *src) { + wapp_debug_assert(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 wapp_str8_copy_cstr_capped(Str8 *dst, const char *src) { + wapp_debug_assert(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 wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src) { + 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; + + memset(dst->buf, 0, dst->size); + memcpy(dst->buf, src->buf, to_copy); + dst->size = to_copy; +} + +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"); + + u64 to_copy = src->size < dst_capacity ? src->size : dst_capacity - 1; + + memset(dst, 0, dst_capacity); + memcpy(dst, src->buf, to_copy); +} + +void wapp_str8_format(Str8 *dst, const char *format, ...) { + wapp_debug_assert(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); +} + +i64 wapp_str8_find(Str8RO *str, Str8RO 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; + bool 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 wapp_str8_rfind(Str8RO *str, Str8RO 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; + bool 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; +} + +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"); + + Str8List *output = wapp_mem_allocator_alloc(allocator, sizeof(Str8List)); + + if (delimiter->size > str->size) { + Str8 *full = wapp_str8_alloc_str8(allocator, str); + Str8Node *node = wapp_mem_allocator_alloc(allocator, sizeof(Str8Node)); + if (node) { + node->item = full; + wapp_str8_list_push_back(output, node); + } + + goto RETURN_STR8_SPLIT; + } + + i64 start = 0; + i64 end = 0; + i64 splits = 0; + Str8 *rest = wapp_str8_alloc_str8(allocator, str); + Str8 *before_str; + + while ((end = wapp_str8_find(rest, *delimiter)) != -1) { + if (max_splits > 0 && splits >= max_splits) { + break; + } + + before_str = wapp_str8_alloc_substr(allocator, str, start, start + end); + Str8Node *node = wapp_mem_allocator_alloc(allocator, sizeof(Str8Node)); + if (node && before_str) { + node->item = before_str; + wapp_str8_list_push_back(output, node); + } + + wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8)); + rest = wapp_str8_alloc_substr(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 = wapp_str8_alloc_substr(allocator, str, start, str->size); + Str8Node *node = wapp_mem_allocator_alloc(allocator, sizeof(Str8Node)); + if (node && rest) { + node->item = rest; + wapp_str8_list_push_back(output, node); + } + +RETURN_STR8_SPLIT: + return output; +} + +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"); + + Str8List *output = wapp_mem_allocator_alloc(allocator, sizeof(Str8List)); + + if (delimiter->size > str->size) { + Str8 *full = wapp_str8_alloc_str8(allocator, str); + Str8Node *node = wapp_mem_allocator_alloc(allocator, sizeof(Str8Node)); + if (node && full) { + node->item = full; + wapp_str8_list_push_back(output, node); + } + + goto RETURN_STR8_SPLIT; + } + + i64 end = 0; + i64 splits = 0; + Str8 *rest = wapp_str8_alloc_str8(allocator, str); + Str8 *after_str; + + while ((end = wapp_str8_rfind(rest, *delimiter)) != -1) { + if (max_splits > 0 && splits >= max_splits) { + break; + } + + after_str = wapp_str8_alloc_substr(allocator, rest, end + delimiter->size, str->size); + Str8Node *node = wapp_mem_allocator_alloc(allocator, sizeof(Str8Node)); + if (node) { + node->item = after_str; + wapp_str8_list_push_front(output, node); + } + + wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8)); + rest = wapp_str8_alloc_substr(allocator, rest, 0, end); + + ++splits; + } + + rest = wapp_str8_alloc_substr(allocator, str, 0, rest->size); + Str8Node *node = wapp_mem_allocator_alloc(allocator, sizeof(Str8Node)); + if (node && rest) { + node->item = rest; + wapp_str8_list_push_front(output, node); + } + +RETURN_STR8_SPLIT: + return output; +} + +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"); + + u64 capacity = wapp_str8_list_total_size(list) + (delimiter->size * (list->node_count - 1)); + Str8 *output = wapp_str8_alloc_buf(allocator, capacity * 2); + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + Str8Node *node; + u64 node_index = 0; + bool running = node_index < list->node_count; + while (running) { + node = wapp_str8_list_get(list, node_index); + if (!node) { + break; + } + + wapp_str8_concat_capped(output, node->item); + + // NOTE (Abdelrahman): Comparison extracted to variable to silence + // MSVC Spectre mitigation warnings + bool not_last = node_index + 1 < list->node_count; + if (not_last) { + wapp_str8_concat_capped(output, delimiter); + } + + ++node_index; + running = node_index < list->node_count; + } + + return output; +} + +u64 wapp_str8_list_total_size(const Str8List *list) { + if (!list) { + return 0; + } + + // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of + // MSVC Spectre mitigation warnings + Str8Node* node; + u64 node_index = 0; + u64 output = 0; + bool running = node_index < list->node_count; + while (running) { + node = wapp_str8_list_get(list, node_index); + if (!node) { + break; + } + + output += node->item->size; + ++node_index; + running = node_index < list->node_count; + } + + return output; +} diff --git a/wapp/primitives/strings/str8/str8.h b/wapp/primitives/strings/str8/str8.h new file mode 100644 index 0000000..b74ffc8 --- /dev/null +++ b/wapp/primitives/strings/str8/str8.h @@ -0,0 +1,138 @@ +// 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 "../../../primitives/dbl_list/dbl_list.h" +#include "../../mem_allocator/mem_allocator.h" +#include +#include + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef struct str8 Str8; +struct str8 { + u64 capacity; + u64 size; + c8 *buf; +}; + +typedef const Str8 Str8RO; + +/** + * Utilities to be used with printf functions + */ +#define WAPP_STR8_SPEC "%.*s" +#define wapp_str8_varg(STRING) (int)((STRING).size), (STRING).buf + +/** + * Str8 stack buffers + */ + +#ifdef WAPP_PLATFORM_CPP +// Uses a lambda to achieve the same behaviour achieved by the C macro +#define wapp_str8_buf(CAPACITY) ([&](){ \ + persistent c8 buf[CAPACITY] = {}; \ + memset(buf, 0, CAPACITY); \ + return Str8{CAPACITY, 0, buf}; \ +}()) + +// Uses a lambda to achieve the same behaviour achieved by the C macro +#define wapp_str8_lit(STRING) ([&]() { \ + persistent c8 buf[sizeof(STRING) * 2] = {}; \ + memcpy(buf, STRING, sizeof(STRING)); \ + 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_initialiser_list(STRING) {sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING} +#else +#define wapp_str8_buf(CAPACITY) ((Str8){.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 wapp_str8_lit(STRING) ((Str8){.capacity = (sizeof(STRING) - 1) * 2, \ + .size = sizeof(STRING) - 1, \ + .buf = memcpy(&((c8 [sizeof(STRING) * 2]){0}), STRING, sizeof(STRING))}) +#define wapp_str8_lit_ro(STRING) ((Str8RO){.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 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 +#define wapp_str8_lit_ro_initialiser_list(STRING) {.capacity = sizeof(STRING) - 1, \ + .size = sizeof(STRING) - 1, \ + .buf = (c8 *)STRING} +#endif // !WAPP_PLATFORM_CPP + +/** + * Str8 allocated buffers + */ +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_cstr(const Allocator *allocator, const char *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_concat(const Allocator *allocator, Str8 *dst, Str8RO *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 wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str); + +/** + * Str8 utilities + */ +c8 wapp_str8_get(Str8RO *str, u64 index); +void wapp_str8_set(Str8 *str, u64 index, c8 c); +void wapp_str8_push_back(Str8 *str, c8 c); +bool wapp_str8_equal(Str8RO *s1, Str8RO *s2); +bool wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count); +Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end); +void wapp_str8_concat_capped(Str8 *dst, Str8RO *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_to_cstr(char *dst, Str8RO *src, u64 dst_capacity); +void wapp_str8_format(Str8 *dst, const char *format, ...); + +/** + * Str8 find functions + */ +i64 wapp_str8_find(Str8RO *str, Str8RO substr); +i64 wapp_str8_rfind(Str8RO *str, Str8RO substr); + +/** + * Str8 split and join + */ +#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) +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); +Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter); + +/** + * Str8 list utilities + */ +#ifdef WAPP_PLATFORM_CPP +#define wapp_str8_node_from_cstr(STRING) wapp_str8_list_node([&]() { \ + persistent Str8 str = wapp_str8_lit(STRING); \ + return &str; \ +}()) +#define wapp_str8_node_from_str8(STRING) wapp_str8_list_node([&]() { \ + persistent Str8 str = STRING; \ + return &str; \ +}()) +#else +#define wapp_str8_node_from_cstr(STRING) wapp_str8_list_node(&wapp_str8_lit(STRING)) +#define wapp_str8_node_from_str8(STRING) wapp_str8_list_node(&(STRING)) +#endif // !WAPP_PLATFORM_CPP +u64 wapp_str8_list_total_size(const Str8List *list); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !STR8_H diff --git a/wapp/primitives/wapp_primitives.c b/wapp/primitives/wapp_primitives.c new file mode 100644 index 0000000..1e3e4a3 --- /dev/null +++ b/wapp/primitives/wapp_primitives.c @@ -0,0 +1,12 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_PRIMITIVES_C +#define WAPP_PRIMITIVES_C + +#include "wapp_primitives.h" +#include "array/array.c" +#include "dbl_list/dbl_list.c" +#include "mem_allocator/mem_allocator.c" +#include "strings/str8/str8.c" + +#endif // !WAPP_PRIMITIVES_C diff --git a/wapp/primitives/wapp_primitives.h b/wapp/primitives/wapp_primitives.h new file mode 100644 index 0000000..7c72ee8 --- /dev/null +++ b/wapp/primitives/wapp_primitives.h @@ -0,0 +1,12 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_PRIMITIVES_H +#define WAPP_PRIMITIVES_H + +#include "dbl_list/dbl_list.h" +#include "array/array.h" +#include "mem_allocator/mem_allocator.h" +#include "strings/str8/str8.h" +#include "../common/wapp_common.h" + +#endif // !WAPP_PRIMITIVES_H diff --git a/wapp/prng/wapp_prng.c b/wapp/prng/wapp_prng.c new file mode 100644 index 0000000..e5081be --- /dev/null +++ b/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/wapp/prng/wapp_prng.h b/wapp/prng/wapp_prng.h new file mode 100644 index 0000000..e64dfac --- /dev/null +++ b/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/wapp/prng/xorshift/xorshift.c b/wapp/prng/xorshift/xorshift.c new file mode 100644 index 0000000..a6e3417 --- /dev/null +++ b/wapp/prng/xorshift/xorshift.c @@ -0,0 +1,136 @@ +// 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 +#include + +typedef struct split_mix_64_state SplitMix64State; +struct split_mix_64_state { + u64 seed; +}; + +internal u64 rol64(u64 x, u64 bits); +internal u64 split_mix_64(SplitMix64State *state); +internal void seed_os_generator(void); +internal u64 generate_random_number(void); + +XOR256State wapp_prng_xorshift_init_state(void) { + persistent bool seeded = false; + if (!seeded) { + seeded = true; + seed_os_generator(); + } + + SplitMix64State sm64 = {.seed = generate_random_number()}; + + return (XOR256State){ + .x = split_mix_64(&sm64), + .y = split_mix_64(&sm64), + .z = split_mix_64(&sm64), + .w = split_mix_64(&sm64), + }; +} + +u64 wapp_prng_xorshift_256(XOR256State *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 wapp_prng_xorshift_256ss(XOR256State *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 wapp_prng_xorshift_256p(XOR256State *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; +} + +internal u64 rol64(u64 x, u64 bits) { + return (x << bits) | (x >> (64 - bits)); +} + +internal 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(WAPP_PLATFORM_C) && WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C11_VERSION +#ifdef WAPP_PLATFORM_POSIX +internal void seed_os_generator(void) { + struct timespec ts = {0}; + int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + wapp_runtime_assert(result == 0, "Invalid seed value"); + + srand48(ts.tv_nsec); +} + +internal u64 generate_random_number(void) { + return lrand48(); +} +#else +internal void seed_os_generator(void) { + struct timespec ts = {0}; + int result = timespec_get(&ts, TIME_UTC); + wapp_runtime_assert(result != 0, "Invalid seed value"); + + srand(ts.tv_nsec); +} + +internal u64 generate_random_number(void) { + i32 n1 = rand(); + i32 n2 = rand(); + + return (((u64)n1) << 32 | (u64)n2); +} +#endif // !WAPP_PLATFORM_POSIX +#else +internal void seed_os_generator(void) { + time_t result = time(NULL); + wapp_runtime_assert(result != (time_t)(-1), "Invalid seed value"); + + srand(result); +} + +internal u64 generate_random_number(void) { + i32 n1 = rand(); + i32 n2 = rand(); + + return (((u64)n1) << 32 | (u64)n2); +} +#endif // !WAPP_PLATFORM_C diff --git a/wapp/prng/xorshift/xorshift.h b/wapp/prng/xorshift/xorshift.h new file mode 100644 index 0000000..20d1aea --- /dev/null +++ b/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 WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +typedef struct xor_256_state XOR256State; +struct xor_256_state { + u64 x; + u64 y; + u64 z; + u64 w; +}; + +XOR256State wapp_prng_xorshift_init_state(void); +u64 wapp_prng_xorshift_256(XOR256State *state); +u64 wapp_prng_xorshift_256ss(XOR256State *state); +u64 wapp_prng_xorshift_256p(XOR256State *state); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !XORSHIFT_H diff --git a/wapp/testing/tester/tester.c b/wapp/testing/tester/tester.c new file mode 100644 index 0000000..48b38f7 --- /dev/null +++ b/wapp/testing/tester/tester.c @@ -0,0 +1,55 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "tester.h" +#include "../../common/aliases/aliases.h" +#include "../../core/os/shell/termcolour/termcolour.h" +#include "../../primitives/strings/str8/str8.h" +#include +#include +#include + +internal void handle_test_result(TestFuncResult result); + +void run_tests(TestFunc *func1, ...) { + printf("\n"); + + handle_test_result(func1()); + + va_list args; + va_start(args, func1); + + TestFunc *func = va_arg(args, TestFunc *); + + while (func) { + TestFuncResult result = func(); + handle_test_result(result); + + func = va_arg(args, TestFunc *); + } + + va_end(args); + + printf("\n"); +} + +internal void handle_test_result(TestFuncResult result) { + TerminalColour colour; + Str8 result_text = wapp_str8_buf(64); + + if (result.passed) { + colour = WAPP_TERM_COLOUR_FG_BR_GREEN; + wapp_str8_copy_cstr_capped(&result_text, "PASSED"); + } else { + colour = WAPP_TERM_COLOUR_FG_BR_RED; + wapp_str8_copy_cstr_capped(&result_text, "FAILED"); + } + + printf("["); + wapp_shell_termcolour_print_text(&result_text, colour); + wapp_shell_termcolour_clear_colour(); + printf("] " WAPP_STR8_SPEC "\n", wapp_str8_varg(result.name)); + + if (!result.passed) { + exit(EXIT_FAILURE); + } +} diff --git a/wapp/testing/tester/tester.h b/wapp/testing/tester/tester.h new file mode 100644 index 0000000..c8dace5 --- /dev/null +++ b/wapp/testing/tester/tester.h @@ -0,0 +1,41 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef TESTER_H +#define TESTER_H + +#include "../../common/misc/misc_utils.h" +#include "../../common/platform/platform.h" +#include "../../primitives/strings/str8/str8.h" +#include + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#ifdef WAPP_PLATFORM_CPP +#define wapp_tester_result(PASSED) (TestFuncResult{wapp_str8_lit_ro(__func__), PASSED}) +#else +#define wapp_tester_result(PASSED) ((TestFuncResult){.name = wapp_str8_lit_ro(__func__), .passed = PASSED}) +#endif // !WAPP_PLATFORM_CPP + +#define wapp_tester_run_tests(...) run_tests(__VA_ARGS__, NULL) + +typedef struct test_func_result TestFuncResult; +struct test_func_result { + Str8RO name; + bool passed; + +#ifdef WAPP_PLATFORM_WINDOWS + wapp_misc_utils_padding_size(sizeof(Str8RO) + sizeof(bool)); +#endif // WAPP_PLATFORM_WINDOWS +}; + +typedef TestFuncResult(TestFunc)(void); + +void run_tests(TestFunc *func1, ...); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !TESTER_H diff --git a/wapp/testing/wapp_testing.c b/wapp/testing/wapp_testing.c new file mode 100644 index 0000000..2bab834 --- /dev/null +++ b/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 "../core/wapp_core.c" + +#endif // !WAPP_TESTING_C diff --git a/wapp/testing/wapp_testing.h b/wapp/testing/wapp_testing.h new file mode 100644 index 0000000..a9643ce --- /dev/null +++ b/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 "../core/wapp_core.h" + +#endif // !WAPP_TESTING_H diff --git a/wapp/uuid/uuid.c b/wapp/uuid/uuid.c new file mode 100644 index 0000000..30c234c --- /dev/null +++ b/wapp/uuid/uuid.c @@ -0,0 +1,59 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "uuid.h" +#include "../common/aliases/aliases.h" +#include "../common/assert/assert.h" +#include "../primitives/strings/str8/str8.h" +#include "../prng/xorshift/xorshift.h" +#include +#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; +}; + +internal UUID4 generate_uuid4(void); +internal void uuid4_to_uuid(const UUID4* uuid4, UUID *uuid); + +UUID *wapp_uuid_init_uuid4(UUID *uuid) { + wapp_debug_assert(uuid != NULL, "`uuid` should not be NULL"); + + UUID4 uuid4 = generate_uuid4(); + uuid4_to_uuid(&uuid4, uuid); + + return uuid; +} + +internal UUID4 generate_uuid4(void) { + persistent XOR256State state = {0}; + persistent bool initialised = false; + + if (!initialised) { + initialised = true; + state = wapp_prng_xorshift_init_state(); + } + + UUID4 uuid = (UUID4){ + .high = wapp_prng_xorshift_256(&state), + .low = wapp_prng_xorshift_256(&state), + }; + + uuid.high = (uuid.high & 0xffffffffffff0fff) | 0x0000000000004000; + uuid.low = (uuid.low & 0x3fffffffffffffff) | 0x8000000000000000; + + return uuid; +} + +internal void uuid4_to_uuid(const UUID4* uuid4, UUID *uuid) { + u64 grp1 = uuid4->high >> 32; + u64 grp2 = (uuid4->high << 32) >> 48; + u64 grp3 = (uuid4->high << 48) >> 48; + u64 grp4 = uuid4->low >> 48; + u64 grp5 = (uuid4->low << 16) >> 16; + + wapp_str8_format(&(uuid->uuid), UUID_STR_FORMAT, grp1, grp2, grp3, grp4, grp5); +} diff --git a/wapp/uuid/uuid.h b/wapp/uuid/uuid.h new file mode 100644 index 0000000..290a462 --- /dev/null +++ b/wapp/uuid/uuid.h @@ -0,0 +1,37 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef UUID_H +#define UUID_H + +#include "../common/aliases/aliases.h" +#include "../common/platform/platform.h" +#include "../primitives/strings/str8/str8.h" + +#ifdef WAPP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#define UUID_BUF_LENGTH 48 +#define WAPP_UUID_SPEC WAPP_STR8_SPEC +#define wapp_uuid_varg(UUID) wapp_str8_varg((UUID).uuid) + +typedef struct uuid UUID; +struct uuid { + Str8 uuid; +}; + +#define wapp_uuid_gen_uuid4() *(wapp_uuid_init_uuid4(&wapp_uuid_create())) + +/* Low level UUID API */ + +#define wapp_uuid_create() ((UUID){.uuid = wapp_str8_buf(UUID_BUF_LENGTH)}) + +// Just returns the same pointer that was passed in with the UUID initialised. +// Fails when passed a NULL pointer. +UUID *wapp_uuid_init_uuid4(UUID *uuid); + +#ifdef WAPP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WAPP_PLATFORM_CPP + +#endif // !UUID_H diff --git a/wapp/uuid/wapp_uuid.c b/wapp/uuid/wapp_uuid.c new file mode 100644 index 0000000..426132b --- /dev/null +++ b/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 "../primitives/wapp_primitives.c" +#include "../prng/wapp_prng.c" + +#endif // !WAPP_UUID_C diff --git a/wapp/uuid/wapp_uuid.h b/wapp/uuid/wapp_uuid.h new file mode 100644 index 0000000..83f29df --- /dev/null +++ b/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 "../primitives/wapp_primitives.h" +#include "../prng/wapp_prng.h" + +#endif // !WAPP_UUID_H diff --git a/wapp/wapp.c b/wapp/wapp.c new file mode 100644 index 0000000..67f2482 --- /dev/null +++ b/wapp/wapp.c @@ -0,0 +1,13 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_C +#define WAPP_C + +#include "wapp.h" +#include "primitives/wapp_primitives.c" +#include "core/wapp_core.c" +#include "prng/wapp_prng.c" +#include "uuid/uuid.c" +#include "testing/wapp_testing.c" + +#endif // !WAPP_C diff --git a/wapp/wapp.h b/wapp/wapp.h new file mode 100644 index 0000000..e2c83f1 --- /dev/null +++ b/wapp/wapp.h @@ -0,0 +1,13 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#ifndef WAPP_H +#define WAPP_H + +#include "common/wapp_common.h" +#include "primitives/wapp_primitives.h" +#include "core/wapp_core.h" +#include "prng/wapp_prng.h" +#include "uuid/wapp_uuid.h" +#include "testing/wapp_testing.h" + +#endif // !WAPP_H