Compare commits
131 Commits
92c2439b56
...
generic
Author | SHA1 | Date | |
---|---|---|---|
|
31373eba03 | ||
|
778a4da092 | ||
|
6fb078a868 | ||
0942643b4e | |||
|
0e5942af34 | ||
|
c83c652b37 | ||
|
74428f1caf | ||
|
d661312cfa | ||
70e075d2f6 | |||
96db885344 | |||
fb512e4a15 | |||
9361f0fe37 | |||
e7d2553400 | |||
509724cc31 | |||
|
82c23eed5e | ||
|
9403193f09 | ||
|
fa1d9eec0d | ||
|
4c14588d92 | ||
|
9e66bd60bd | ||
|
ce4957d0a0 | ||
b9ea290322 | |||
1479c13417 | |||
4520f2269d | |||
6119cf5c5f | |||
358f61e556 | |||
7ac6100a5a | |||
19efb08a3a | |||
491c742189 | |||
4f5dd3900f | |||
dbedcb3100 | |||
d9314fb41e | |||
fe2bb65b06 | |||
ed4ec54c7a | |||
ba5e902a1d | |||
01f066d20c | |||
80bd68f313 | |||
cda7e413e2 | |||
54da75f89f | |||
7df64a3168 | |||
f9f8f092b5 | |||
f89a4bf343 | |||
0d795cc0d9 | |||
28ac9ed8c8 | |||
99f7dcd794 | |||
c5ca39939d | |||
a308359942 | |||
a3d9bcf1a1 | |||
|
a534d44db5 | ||
11949e69be | |||
2c9e4c91a0 | |||
76b078fbc0 | |||
0569fca193 | |||
6078e54087 | |||
180425707b | |||
62dcfdaa93 | |||
19134d0e15 | |||
ca2b1cbf23 | |||
f60442bfcf | |||
a4a1e82c40 | |||
d50b41acac | |||
71b6242f16 | |||
241edfc7e4 | |||
d635e03cd8 | |||
68fe421ab0 | |||
622a4391a0 | |||
ff4d3c9e99 | |||
023c74d8d9 | |||
86fe867011 | |||
98829b8400 | |||
a7e98211f9 | |||
4642361969 | |||
093d0daf6f | |||
f8e0804dd2 | |||
fdb0650634 | |||
d1d6a8e64b | |||
bbf38499ca | |||
7657ad1b58 | |||
70399cb797 | |||
76c3b02e45 | |||
abf9b09495 | |||
6d09059911 | |||
894ae028b7 | |||
84a4ec223c | |||
8f10ac2916 | |||
bfb4e87a1e | |||
685682e1c8 | |||
40d301fd95 | |||
7d8df816a5 | |||
17f0f0eaf3 | |||
ce656a6275 | |||
8d8fcf9dc5 | |||
77e634ec2d | |||
22ece7215a | |||
4af4b39d6f | |||
a48002996e | |||
e9451f10f8 | |||
1de3608b1f | |||
3a25571105 | |||
139b4ca589 | |||
e431cf729e | |||
1d1c3ca928 | |||
f2f155744a | |||
d3a86ec6cb | |||
e053aa44ab | |||
a546a09565 | |||
12f182f0cf | |||
ffb99a3644 | |||
1ddc5610f9 | |||
d8c7b3162f | |||
9e1e4688e4 | |||
cd38672581 | |||
7fea236618 | |||
16a1b8fa35 | |||
a0dfe8acd0 | |||
95c47ec940 | |||
46f32f2ba9 | |||
8f794dee15 | |||
034b105ea1 | |||
c90874ad10 | |||
8468bb8e28 | |||
d30eee0cf8 | |||
59e56a75d3 | |||
5d6ce1d2c3 | |||
ce537b7494 | |||
b8f6e5f187 | |||
775f0864a8 | |||
8b6fb23bac | |||
1fb340561f | |||
8ed372d938 | |||
8a91a0ec6b | |||
802b70f5ee |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,8 +3,11 @@
|
||||
test
|
||||
test.*
|
||||
*.dSYM
|
||||
.DS_Store
|
||||
*.pdb
|
||||
*.obj
|
||||
compile_commands.json
|
||||
libwapp-build
|
||||
libwapp.so
|
||||
*.vs
|
||||
__pycache__
|
||||
|
63
Makefile
Normal file
63
Makefile
Normal file
@@ -0,0 +1,63 @@
|
||||
CC = clang
|
||||
BUILD_TYPE = debug
|
||||
CFLAGS = -Wall -Wextra -Werror -pedantic
|
||||
LIBFLAGS = -fPIC -shared
|
||||
KERNEL = $(shell uname -s)
|
||||
MACHINE = $(shell uname -m)
|
||||
PLATFORM = $(KERNEL)_$(MACHINE)
|
||||
TEST_INCLUDE = -Isrc $(shell find tests -type d | xargs -I{} echo -n "-I{} ")
|
||||
TEST_SRC = src/wapp.c $(shell find tests -type f -name "*.c" | xargs -I{} echo -n "{} ")
|
||||
BUILD_DIR = libwapp-build/$(PLATFORM)-$(BUILD_TYPE)
|
||||
LIB_OUT = $(BUILD_DIR)/libwapp.so
|
||||
TEST_OUT = $(BUILD_DIR)/wapptest
|
||||
|
||||
ifeq ($(BUILD_TYPE),debug)
|
||||
CFLAGS += -g -fsanitize=address,undefined
|
||||
else ifeq ($(BUILD_TYPE),release)
|
||||
CFLAGS += -O3
|
||||
else
|
||||
$(error Invalid BUILD type '$(BUILD_TYPE)'. Use 'debug' or 'release')
|
||||
endif
|
||||
|
||||
ifeq ($(CC),gcc)
|
||||
# Used to disable the "ASan runtime does not come first in initial library list" error when compiling with gcc
|
||||
export ASAN_OPTIONS=verify_asan_link_order=0
|
||||
endif
|
||||
|
||||
.PHONY: all clean builddir build-test run-test build-lib full prng testing uuid core containers
|
||||
|
||||
all: clean builddir run-test full
|
||||
|
||||
clean:
|
||||
@rm -rf $(BUILD_DIR)
|
||||
|
||||
builddir:
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
|
||||
build-test:
|
||||
$(CC) $(CFLAGS) $(TEST_INCLUDE) $(TEST_SRC) -o $(TEST_OUT)
|
||||
|
||||
run-test: build-test
|
||||
@$(TEST_OUT)
|
||||
@rm $(TEST_OUT)
|
||||
|
||||
build-lib:
|
||||
$(CC) $(CFLAGS) $(LIBFLAGS) $(LIB_SRC) -o $(LIB_OUT)
|
||||
|
||||
full: LIB_SRC = src/wapp.c
|
||||
full: build-lib
|
||||
|
||||
prng: LIB_SRC = src/prng/wapp_prng.c
|
||||
prng: build-lib
|
||||
|
||||
testing: LIB_SRC = src/testing/wapp_testing.c
|
||||
testing: build-lib
|
||||
|
||||
uuid: LIB_SRC = src/uuid/wapp_uuid.c
|
||||
uuid: build-lib
|
||||
|
||||
core: LIB_SRC = src/core/wapp_core.c
|
||||
core: build-lib
|
||||
|
||||
containers: LIB_SRC = src/core/wapp_containers.c
|
||||
containers: build-lib
|
19
build
19
build
@@ -1,3 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
bear -- ./compile $@
|
||||
BUILD_TYPE="debug"
|
||||
ARGS=""
|
||||
|
||||
while [[ $# > 0 ]];do
|
||||
case $1 in
|
||||
--release)
|
||||
BUILD_TYPE="release"
|
||||
shift
|
||||
;;
|
||||
*|-*|--*)
|
||||
rest=("$@")
|
||||
ARGS+=" ${rest[0]}"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
bear -- make BUILD_TYPE=$BUILD_TYPE $ARGS
|
||||
|
31
build.ps1
31
build.ps1
@@ -1,5 +1,5 @@
|
||||
Param(
|
||||
[switch]$Release
|
||||
[switch]$Release
|
||||
)
|
||||
|
||||
$Compiler = "cl.exe"
|
||||
@@ -7,21 +7,25 @@ $Compiler = "cl.exe"
|
||||
$GeneralFlags = "/Wall /WX /wd4996"
|
||||
$LibraryFlags = "/LD"
|
||||
|
||||
$IncludeDirs = Get-ChildItem -Path src -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
|
||||
$SrcFiles = Get-ChildItem -Path src -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
|
||||
$Kernel = (Get-ChildItem Env:OS).Value
|
||||
$Machine = (Get-ChildItem Env:PROCESSOR_ARCHITECTURE).Value
|
||||
$Platform = "${Kernel}_${Machine}"
|
||||
|
||||
$IncludeDirs = "/I src"
|
||||
$SrcFiles = "src/wapp.c"
|
||||
|
||||
$TestIncludeDirs = Get-ChildItem -Path tests -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
|
||||
$TestSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
|
||||
|
||||
If ($Release -eq $True) {
|
||||
$GeneralFlags += " /O2 /Og"
|
||||
$BuildType = "release"
|
||||
$GeneralFlags += " /O2 /Og"
|
||||
$BuildType = "release"
|
||||
} Else {
|
||||
$GeneralFlags += " /Zi /Od /fsanitize=address"
|
||||
$BuildType = "debug"
|
||||
$GeneralFlags += " /Zi /Od /fsanitize=address"
|
||||
$BuildType = "debug"
|
||||
}
|
||||
|
||||
$BuildDir = "./libwapp-build/windows-$BuildType"
|
||||
$BuildDir = "./libwapp-build/${Platform}-${BuildType}"
|
||||
$ObjDir = "$BuildDir/objects"
|
||||
$OutDir = "$BuildDir/output"
|
||||
$TestsDir = "$BuildDir/tests"
|
||||
@@ -34,13 +38,16 @@ $TestOutBasename = "wapptest"
|
||||
$TestOutputs = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestOutBasename"
|
||||
|
||||
If (Test-Path $BuildDir) {
|
||||
Remove-Item $BuildDir -Recurse -Force
|
||||
Remove-Item $BuildDir -Recurse -Force
|
||||
}
|
||||
|
||||
mkdir -p $ObjDir > $null
|
||||
mkdir -p $OutDir > $null
|
||||
mkdir -p $TestsDir > $null
|
||||
|
||||
# Run code generation
|
||||
Invoke-Expression "python3 -m codegen"
|
||||
|
||||
# Build and run tests
|
||||
Invoke-Expression "$Compiler $GeneralFlags $IncludeDirs $TestIncludeDirs $SrcFiles $TestSrcFiles $TestOutputs" -ErrorAction Stop
|
||||
|
||||
@@ -50,9 +57,9 @@ $Status = $LASTEXITCODE
|
||||
Remove-Item $TestsDir -Recurse -Force
|
||||
|
||||
If ($Status -ne 0) {
|
||||
Write-Error "Tests failed"
|
||||
Exit 1
|
||||
Write-Error "Tests failed"
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# Build library
|
||||
Invoke-Expression "$Compiler $GeneralFlags $LibraryFlags $IncludeDirs $SrcFiles $Objects $Outputs"
|
||||
Invoke-Expression "$Compiler $GeneralFlags $LibraryFlags $SrcFiles $Objects $Outputs"
|
||||
|
61
compile
61
compile
@@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
BUILD_TYPE="debug"
|
||||
|
||||
while [[ $# > 0 ]];do
|
||||
case $1 in
|
||||
--release)
|
||||
BUILD_TYPE="release"
|
||||
shift
|
||||
;;
|
||||
*|-*|--*)
|
||||
echo "Unknown option $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
CC=clang
|
||||
CFLAGS="-Wall -Werror -pedantic "
|
||||
LIBFLAGS="-fPIC -shared"
|
||||
|
||||
INCLUDE="$(find src -type d | xargs -I{} echo -n "-I{} ")"
|
||||
SRC="$(find src -type f -name "*.c" | xargs -I{} echo -n "{} ")"
|
||||
|
||||
TEST_INCLUDE="$(find tests -type d | xargs -I{} echo -n "-I{} ")"
|
||||
TEST_SRC="$(find tests -type f -name "*.c" | xargs -I{} echo -n "{} ")"
|
||||
|
||||
BUILD_DIR="libwapp-build/posix-$BUILD_TYPE"
|
||||
if [[ -d $BUILD_DIR ]]; then
|
||||
rm -rf $BUILD_DIR
|
||||
fi
|
||||
mkdir -p $BUILD_DIR
|
||||
|
||||
if [[ $BUILD_TYPE == "release" ]]; then
|
||||
CFLAGS+="-O3"
|
||||
else
|
||||
CFLAGS+="-g -fsanitize=address -fsanitize=undefined"
|
||||
fi
|
||||
|
||||
OUT="$BUILD_DIR/libwapp.so"
|
||||
TEST_OUT="$BUILD_DIR/wapptest"
|
||||
|
||||
# Compile tests
|
||||
if [[ $(echo $TEST_SRC | xargs) != "" ]]; then
|
||||
(set -x ; $CC $CFLAGS $INCLUDE $TEST_INCLUDE $SRC $TEST_SRC -o $TEST_OUT)
|
||||
fi
|
||||
|
||||
# Run tests and exit on failure
|
||||
if [[ -f $TEST_OUT ]]; then
|
||||
$TEST_OUT
|
||||
STATUS="$?"
|
||||
|
||||
rm $TEST_OUT
|
||||
|
||||
if [[ $STATUS != "0" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Compile library
|
||||
(set -x ; $CC $CFLAGS $LIBFLAGS $INCLUDE $SRC -o $OUT)
|
@@ -3,6 +3,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define c8 uint8_t
|
||||
#define c16 uint16_t
|
||||
#define c32 uint32_t
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
@@ -20,11 +24,14 @@
|
||||
#define uptr uintptr_t
|
||||
#define iptr intptr_t
|
||||
|
||||
#define external extern
|
||||
#define internal static
|
||||
#define persistent static
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define class_mem static
|
||||
#define BEGIN_C_LINKAGE extern "C" {
|
||||
#define END_C_LINKAGE }
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !ALIASES_H
|
||||
|
@@ -1,115 +0,0 @@
|
||||
#include "mem_utils.h"
|
||||
#include "aliases.h"
|
||||
#include "platform.h"
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <memoryapi.h>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
internal inline void *alloc_windows(void *addr, u64 size, MemAccess access,
|
||||
MemAllocFlags flags);
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
#include <sys/mman.h>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
internal inline void *alloc_posix(void *addr, u64 size, MemAccess access,
|
||||
MemAllocFlags flags);
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
|
||||
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(is_power_of_two(alignment));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access,
|
||||
MemAllocFlags flags, MemInitType type) {
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
// Ensure memory is committed if it's meant to be initialised
|
||||
if (type == WAPP_MEM_INIT_INITIALISED) {
|
||||
flags |= WAPP_MEM_ALLOC_COMMIT;
|
||||
}
|
||||
|
||||
void *output = alloc_windows(addr, size, access, flags);
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
void *output = alloc_posix(addr, size, access, flags);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
if (type == WAPP_MEM_INIT_INITIALISED) {
|
||||
memset(output, 0, size);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void wapp_mem_util_free(void *ptr, u64 size) {
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
VirtualFree(ptr, size, MEM_RELEASE);
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
munmap(ptr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
internal inline void *alloc_windows(void *addr, u64 size, MemAccess access,
|
||||
MemAllocFlags flags) {
|
||||
return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WAPP_PLATFORM_POSIX)
|
||||
internal inline void *alloc_posix(void *addr, u64 size, MemAccess access,
|
||||
MemAllocFlags flags) {
|
||||
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);
|
||||
}
|
||||
#endif
|
@@ -1,61 +0,0 @@
|
||||
#ifndef MEM_UTILS_H
|
||||
#define MEM_UTILS_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <memoryapi.h>
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
#include <sys/mman.h>
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
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_alloc_flags {
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
WAPP_MEM_ALLOC_RESERVE = MEM_RESERVE,
|
||||
WAPP_MEM_ALLOC_COMMIT = MEM_COMMIT,
|
||||
#elif 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;
|
||||
|
||||
typedef enum mem_init_type {
|
||||
WAPP_MEM_INIT_UNINITIALISED,
|
||||
WAPP_MEM_INIT_INITIALISED,
|
||||
} MemInitType;
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
|
||||
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access,
|
||||
MemAllocFlags flags, MemInitType type);
|
||||
void wapp_mem_util_free(void *ptr, u64 size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_UTILS_H
|
@@ -1,9 +1,13 @@
|
||||
#ifndef MISC_UTILS_H
|
||||
#define MISC_UTILS_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "../aliases/aliases.h"
|
||||
|
||||
#define wapp_misc_utils_padding_size(SIZE) \
|
||||
u8 reserved_padding[sizeof(void *) - ((SIZE) % sizeof(void *))]
|
||||
#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 *))]
|
||||
|
||||
#endif // !MISC_UTILS_H
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
// clang-format off
|
||||
#if defined(__ANDROID__)
|
||||
#define WAPP_PLATFORM_ANDROID
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
@@ -58,6 +57,5 @@
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#endif // !PLATFORM_H
|
||||
|
@@ -1,132 +0,0 @@
|
||||
#include "commander.h"
|
||||
#include "aliases.h"
|
||||
#include "shell_utils.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CMD_BUF_LEN 8192
|
||||
#define OUT_BUF_LEN 4096
|
||||
|
||||
internal inline CMDError build_command_from_args(char *cmd, u64 buf_len,
|
||||
va_list args);
|
||||
internal inline CMDResult execute_command(const char *cmd,
|
||||
CMDOutHandling out_handling,
|
||||
char *out_buf, u64 buf_size);
|
||||
internal inline CMDError get_command_output(FILE *fp,
|
||||
CMDOutHandling out_handling,
|
||||
char *out_buf, u64 buf_size);
|
||||
internal inline CMDError get_output_status(FILE *fp, i32 *status_out);
|
||||
|
||||
// clang-format off
|
||||
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...) { // clang-format on
|
||||
va_list args;
|
||||
va_start(args, buf_size);
|
||||
|
||||
char cmd[CMD_BUF_LEN] = {0};
|
||||
CMDError err = build_command_from_args(cmd, CMD_BUF_LEN, args);
|
||||
if (err > SHELL_ERR_NO_ERROR) {
|
||||
va_end(args);
|
||||
return CMD_NO_EXIT(err);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return execute_command(cmd, out_handling, out_buf, buf_size);
|
||||
}
|
||||
|
||||
internal inline CMDError build_command_from_args(char *cmd, u64 buf_len,
|
||||
va_list args) {
|
||||
u64 size = 0;
|
||||
u64 arg_len = 0;
|
||||
|
||||
const char *arg;
|
||||
while ((arg = va_arg(args, const char *))) {
|
||||
arg_len = strlen(arg);
|
||||
if (arg_len >= buf_len - size) {
|
||||
return SHELL_ERR_CMD_BUF_FULL;
|
||||
}
|
||||
|
||||
strcat(cmd, arg);
|
||||
cmd[size + arg_len] = ' ';
|
||||
|
||||
size += arg_len + 1;
|
||||
}
|
||||
|
||||
return SHELL_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
internal inline CMDResult execute_command(const char *cmd,
|
||||
CMDOutHandling out_handling,
|
||||
char *out_buf, u64 buf_size) {
|
||||
FILE *fp = wapp_shell_utils_popen(cmd, "r");
|
||||
if (!fp) {
|
||||
return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL);
|
||||
}
|
||||
|
||||
CMDError err = get_command_output(fp, out_handling, out_buf, buf_size);
|
||||
if (err > SHELL_ERR_NO_ERROR) {
|
||||
// Ensure process is closed on failure
|
||||
wapp_shell_utils_pclose(fp);
|
||||
return CMD_NO_EXIT(err);
|
||||
}
|
||||
|
||||
i32 st = EXIT_SUCCESS;
|
||||
err = get_output_status(fp, &st);
|
||||
if (err > SHELL_ERR_NO_ERROR) {
|
||||
return CMD_NO_EXIT(err);
|
||||
}
|
||||
|
||||
return (CMDResult){
|
||||
.exited = true,
|
||||
.exit_code = st,
|
||||
.error = SHELL_ERR_NO_ERROR,
|
||||
};
|
||||
}
|
||||
|
||||
internal inline CMDError get_command_output(FILE *fp,
|
||||
CMDOutHandling out_handling,
|
||||
char *out_buf, u64 buf_size) {
|
||||
char out[OUT_BUF_LEN] = {0};
|
||||
u64 max_out_length = OUT_BUF_LEN - 1;
|
||||
|
||||
u64 buf_filled = 0;
|
||||
while (fgets(out, max_out_length, fp)) {
|
||||
if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) {
|
||||
buf_filled += strlen(out);
|
||||
if (buf_filled >= buf_size) {
|
||||
return SHELL_ERR_OUT_BUF_FULL;
|
||||
}
|
||||
|
||||
strcat(out_buf, out);
|
||||
} else {
|
||||
printf("%s", out);
|
||||
}
|
||||
}
|
||||
|
||||
return SHELL_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
internal inline CMDError get_output_status(FILE *fp, i32 *status_out) {
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
if (!feof(fp)) {
|
||||
// Ensure process is closed on failure
|
||||
wapp_shell_utils_pclose(fp);
|
||||
return SHELL_ERR_PROC_EXIT_FAIL;
|
||||
}
|
||||
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||
|
||||
*status_out = wapp_shell_utils_pclose(fp);
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
if (!WIFEXITED(*status_out)) {
|
||||
return SHELL_ERR_PROC_EXIT_FAIL;
|
||||
}
|
||||
|
||||
*status_out = WEXITSTATUS(*status_out);
|
||||
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||
|
||||
return SHELL_ERR_NO_ERROR;
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
#ifndef COMMANDER_H
|
||||
#define COMMANDER_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define CMD_NO_EXIT(ERR) \
|
||||
((CMDResult){.exited = false, .exit_code = EXIT_FAILURE})
|
||||
#define wapp_shell_commander_execute(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, ...) \
|
||||
run_command(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, __VA_ARGS__, NULL)
|
||||
|
||||
typedef enum {
|
||||
SHELL_OUTPUT_PRINT,
|
||||
SHELL_OUTPUT_CAPTURE,
|
||||
} CMDOutHandling;
|
||||
|
||||
typedef enum {
|
||||
SHELL_ERR_NO_ERROR,
|
||||
SHELL_ERR_CMD_BUF_FULL,
|
||||
SHELL_ERR_PROC_START_FAIL,
|
||||
SHELL_ERR_OUT_BUF_FULL,
|
||||
SHELL_ERR_PROC_EXIT_FAIL,
|
||||
} CMDError;
|
||||
|
||||
typedef struct commander_result CMDResult;
|
||||
struct commander_result {
|
||||
bool exited;
|
||||
int exit_code;
|
||||
CMDError error;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...);
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !COMMANDER_H
|
@@ -1,101 +0,0 @@
|
||||
#include "termcolour.h"
|
||||
#include "aliases.h"
|
||||
#include "platform.h"
|
||||
#include <stdio.h>
|
||||
|
||||
internal void print_coloured_text(const TerminalColourist *colourist,
|
||||
const char *text);
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
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,
|
||||
};
|
||||
#else
|
||||
internal const char *colours[COUNT_TERM_COLOUR] = {
|
||||
[WAPP_TERM_COLOUR_FG_BLACK] = "\033[30m",
|
||||
[WAPP_TERM_COLOUR_FG_RED] = "\033[31m",
|
||||
[WAPP_TERM_COLOUR_FG_GREEN] = "\033[32m",
|
||||
[WAPP_TERM_COLOUR_FG_BLUE] = "\033[34m",
|
||||
[WAPP_TERM_COLOUR_FG_CYAN] = "\033[36m",
|
||||
[WAPP_TERM_COLOUR_FG_MAGENTA] = "\033[35m",
|
||||
[WAPP_TERM_COLOUR_FG_YELLOW] = "\033[33m",
|
||||
[WAPP_TERM_COLOUR_FG_WHITE] = "\033[37m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_BLACK] = "\033[90m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_RED] = "\033[91m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_GREEN] = "\033[92m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_BLUE] = "\033[94m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_CYAN] = "\033[96m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] = "\033[95m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_YELLOW] = "\033[93m",
|
||||
[WAPP_TERM_COLOUR_FG_BR_WHITE] = "\033[97m",
|
||||
};
|
||||
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||
|
||||
TerminalColourist wapp_shell_termcolour_get_colourist(void) {
|
||||
TerminalColourist colourist;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
// create handle
|
||||
colourist.handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// get console colour information
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
GetConsoleScreenBufferInfo(colourist.handle, &csbi);
|
||||
colourist.default_colour = csbi.wAttributes;
|
||||
#else
|
||||
colourist.default_colour = "\033[0m";
|
||||
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
colourist.current_colour = colourist.default_colour;
|
||||
|
||||
return colourist;
|
||||
}
|
||||
|
||||
void wapp_shell_termcolour_print_text(TerminalColourist *colourist,
|
||||
const char *text, TerminalColour colour) {
|
||||
if (colour < WAPP_TERM_COLOUR_FG_BLACK ||
|
||||
colour > WAPP_TERM_COLOUR_FG_BR_WHITE) {
|
||||
return;
|
||||
}
|
||||
|
||||
colourist->current_colour = colours[colour];
|
||||
print_coloured_text(colourist, text);
|
||||
}
|
||||
|
||||
void wapp_shell_termcolour_clear_colour(TerminalColourist *colourist) {
|
||||
colourist->current_colour = colourist->default_colour;
|
||||
print_coloured_text(colourist, "");
|
||||
}
|
||||
|
||||
internal void print_coloured_text(const TerminalColourist *colourist,
|
||||
const char *text) {
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
SetConsoleTextAttribute(colourist->handle, colourist->current_colour);
|
||||
printf("%s", text);
|
||||
#else
|
||||
printf("%s%s", colourist->current_colour, text);
|
||||
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
#ifndef TERM_COLOUR_H
|
||||
#define TERM_COLOUR_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "misc_utils.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
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,
|
||||
|
||||
COUNT_TERM_COLOUR,
|
||||
} TerminalColour;
|
||||
|
||||
typedef struct terminal_colourist TerminalColourist;
|
||||
|
||||
// clang-format off
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <WinCon.h>
|
||||
|
||||
struct terminal_colourist {
|
||||
HANDLE handle;
|
||||
WORD default_colour;
|
||||
WORD current_colour;
|
||||
wapp_misc_utils_padding_size(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
|
||||
};
|
||||
#else
|
||||
struct terminal_colourist {
|
||||
const char *default_colour;
|
||||
const char *current_colour;
|
||||
};
|
||||
#endif // WAPP_PLATFORM_WINDOWS
|
||||
// clang-format on
|
||||
|
||||
TerminalColourist wapp_shell_termcolour_get_colourist(void);
|
||||
void wapp_shell_termcolour_print_text(TerminalColourist *colourist,
|
||||
const char *text, TerminalColour colour);
|
||||
void wapp_shell_termcolour_clear_colour(TerminalColourist *colourist);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TERM_COLOUR_H
|
8
src/common/wapp_common.h
Normal file
8
src/common/wapp_common.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef WAPP_COMMON_H
|
||||
#define WAPP_COMMON_H
|
||||
|
||||
#include "aliases/aliases.h"
|
||||
#include "misc/misc_utils.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#endif // !WAPP_COMMON_H
|
209
src/containers/dbl_list/dbl_list.c
Normal file
209
src/containers/dbl_list/dbl_list.c
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "./dbl_list.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include <stddef.h>
|
||||
|
||||
internal DBL_LIST(void) node_to_list(DBL_NODE(void) *node);
|
||||
|
||||
DBL_NODE(void) *_dbl_list_get(const DBL_LIST(void) *list, u64 index) {
|
||||
if (index >= list->node_count) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBL_NODE(void) *output = NULL;
|
||||
DBL_NODE(void) *current = list->first;
|
||||
for (u64 i = 1; i <= index; ++i) {
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
output = current;
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
void _dbl_list_push_front(DBL_LIST(void) *list, DBL_NODE(void) *node) {
|
||||
if (!list || !node || !(node->item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBL_LIST(void) node_list = node_to_list(node);
|
||||
|
||||
if (list->node_count == 0) {
|
||||
*list = node_list;
|
||||
return;
|
||||
}
|
||||
|
||||
list->node_count += node_list.node_count;
|
||||
|
||||
DBL_NODE(void) *first = list->first;
|
||||
if (first) {
|
||||
first->prev = node_list.last;
|
||||
}
|
||||
|
||||
list->first = node_list.first;
|
||||
node_list.last->next = first;
|
||||
|
||||
}
|
||||
|
||||
void _dbl_list_push_back(DBL_LIST(void) *list, DBL_NODE(void) *node) {
|
||||
if (!list || !node || !(node->item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBL_LIST(void) node_list = node_to_list(node);
|
||||
|
||||
if (list->node_count == 0) {
|
||||
*list = node_list;
|
||||
return;
|
||||
}
|
||||
|
||||
list->node_count += node_list.node_count;
|
||||
|
||||
DBL_NODE(void) *last = list->last;
|
||||
if (last) {
|
||||
last->next = node_list.first;
|
||||
}
|
||||
|
||||
list->last = node_list.last;
|
||||
node_list.first->prev = last;
|
||||
|
||||
}
|
||||
|
||||
void _dbl_list_insert(DBL_LIST(void) *list, DBL_NODE(void) *node, u64 index) {
|
||||
if (!list || !node || !(node->item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
_dbl_list_push_front(list, node);
|
||||
return;
|
||||
} else if (index == list->node_count) {
|
||||
_dbl_list_push_back(list, node);
|
||||
return;
|
||||
}
|
||||
|
||||
DBL_NODE(void) *dst_node = _dbl_list_get(list, index);
|
||||
if (!dst_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBL_LIST(void) node_list = node_to_list(node);
|
||||
|
||||
list->node_count += node_list.node_count;
|
||||
|
||||
DBL_NODE(void) *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;
|
||||
|
||||
}
|
||||
|
||||
DBL_NODE(void) *_dbl_list_pop_front(DBL_LIST(void) *list) {
|
||||
DBL_NODE(void) *output = NULL;
|
||||
|
||||
if (!list || list->node_count == 0) {
|
||||
goto RETURN_STR8_LIST_POP_FRONT;
|
||||
}
|
||||
|
||||
output = list->first;
|
||||
|
||||
if (list->node_count == 1) {
|
||||
*list = (DBL_LIST(void)){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;
|
||||
|
||||
}
|
||||
|
||||
DBL_NODE(void) *_dbl_list_pop_back(DBL_LIST(void) *list) {
|
||||
DBL_NODE(void) *output = NULL;
|
||||
|
||||
if (!list || list->node_count == 0) {
|
||||
goto RETURN_STR8_LIST_POP_BACK;
|
||||
}
|
||||
|
||||
output = list->last;
|
||||
|
||||
if (list->node_count == 1) {
|
||||
*list = (DBL_LIST(void)){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;
|
||||
|
||||
}
|
||||
|
||||
DBL_NODE(void) *_dbl_list_remove(DBL_LIST(void) *list, u64 index) {
|
||||
DBL_NODE(void) *output = NULL;
|
||||
if (!list) {
|
||||
goto RETURN_STR8_LIST_REMOVE;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
output = _dbl_list_pop_front(list);
|
||||
goto RETURN_STR8_LIST_REMOVE;
|
||||
} else if (index == list->node_count) {
|
||||
output = _dbl_list_pop_back(list);
|
||||
goto RETURN_STR8_LIST_REMOVE;
|
||||
}
|
||||
|
||||
output = _dbl_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 _dbl_list_empty(DBL_LIST(void) *list) {
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
u64 count = list->node_count;
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
_dbl_list_pop_back(list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal DBL_LIST(void) node_to_list(DBL_NODE(void) *node) {
|
||||
DBL_LIST(void) 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;
|
||||
}
|
75
src/containers/dbl_list/dbl_list.h
Normal file
75
src/containers/dbl_list/dbl_list.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef DBL_LIST_H
|
||||
#define DBL_LIST_H
|
||||
|
||||
#include "../../common/aliases/aliases.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#define DBL_NODE(T) T##Node
|
||||
#define DBL_LIST(T) T##List
|
||||
|
||||
#define CAST_NODE(NODE) ((DBL_NODE(void))(NODE))
|
||||
#define CAST_LIST(LIST) ((DBL_LIST(void))(LIST))
|
||||
|
||||
#define CAST_NODE_PTR(NODE_PTR) ((DBL_NODE(void)*)(NODE_PTR))
|
||||
#define CAST_LIST_PTR(LIST_PTR) ((DBL_LIST(void)*)(LIST_PTR))
|
||||
|
||||
#define DBL_LIST_DECL(T) typedef struct DBL_NODE(T) DBL_NODE(T); \
|
||||
struct DBL_NODE(T) { \
|
||||
T *item; \
|
||||
DBL_NODE(T) *prev; \
|
||||
DBL_NODE(T) *next; \
|
||||
}; \
|
||||
\
|
||||
typedef struct DBL_LIST(T) DBL_LIST(T); \
|
||||
struct DBL_LIST(T) { \
|
||||
DBL_NODE(T) *first; \
|
||||
DBL_NODE(T) *last; \
|
||||
u64 node_count; \
|
||||
}
|
||||
|
||||
DBL_LIST_DECL(void);
|
||||
|
||||
#define wapp_dbl_list_node_from_item(T, ITEM_PTR) \
|
||||
((DBL_NODE(T)){ .item = ITEM_PTR })
|
||||
|
||||
#define wapp_dbl_list_get(T, LIST_PTR, INDEX) \
|
||||
(DBL_NODE(T)*)_dbl_list_get(CAST_LIST_PTR(LIST_PTR), INDEX)
|
||||
|
||||
#define wapp_dbl_list_push_front(LIST_PTR, NODE_PTR) \
|
||||
_dbl_list_push_front(CAST_LIST_PTR(LIST_PTR), CAST_NODE_PTR(NODE_PTR))
|
||||
|
||||
#define wapp_dbl_list_push_back(LIST_PTR, NODE_PTR) \
|
||||
_dbl_list_push_back(CAST_LIST_PTR(LIST_PTR), CAST_NODE_PTR(NODE_PTR))
|
||||
|
||||
#define wapp_dbl_list_insert(LIST_PTR, NODE_PTR, INDEX) \
|
||||
_dbl_list_insert(CAST_LIST_PTR(LIST_PTR), CAST_NODE_PTR(NODE_PTR), INDEX)
|
||||
|
||||
#define wapp_dbl_list_pop_front(T, LIST_PTR) \
|
||||
(DBL_NODE(T)*)_dbl_list_pop_front(CAST_LIST_PTR(LIST_PTR))
|
||||
|
||||
#define wapp_dbl_list_pop_back(T, LIST_PTR) \
|
||||
(DBL_NODE(T)*)_dbl_list_pop_back(CAST_LIST_PTR(LIST_PTR))
|
||||
|
||||
#define wapp_dbl_list_remove(T, LIST_PTR, INDEX) \
|
||||
(DBL_NODE(T)*)_dbl_list_remove(CAST_LIST_PTR(LIST_PTR), INDEX)
|
||||
|
||||
#define wapp_dbl_list_empty(LIST_PTR) \
|
||||
_dbl_list_empty(CAST_LIST_PTR(LIST_PTR))
|
||||
|
||||
DBL_NODE(void) *_dbl_list_get(const DBL_LIST(void) *list, u64 index);
|
||||
void _dbl_list_push_front(DBL_LIST(void) *list, DBL_NODE(void) *node);
|
||||
void _dbl_list_push_back(DBL_LIST(void) *list, DBL_NODE(void) *node);
|
||||
void _dbl_list_insert(DBL_LIST(void) *list, DBL_NODE(void) *node, u64 index);
|
||||
DBL_NODE(void) *_dbl_list_pop_front(DBL_LIST(void) *list);
|
||||
DBL_NODE(void) *_dbl_list_pop_back(DBL_LIST(void) *list);
|
||||
DBL_NODE(void) *_dbl_list_remove(DBL_LIST(void) *list, u64 index);
|
||||
void _dbl_list_empty(DBL_LIST(void) *list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#endif // !DBL_LIST_H
|
6
src/containers/wapp_containers.c
Normal file
6
src/containers/wapp_containers.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef WAPP_CONTAINERS_C
|
||||
#define WAPP_CONTAINERS_C
|
||||
|
||||
#include "dbl_list/dbl_list.c"
|
||||
|
||||
#endif // !WAPP_CONTAINERS_C
|
7
src/containers/wapp_containers.h
Normal file
7
src/containers/wapp_containers.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef WAPP_CONTAINERS_H
|
||||
#define WAPP_CONTAINERS_H
|
||||
|
||||
#include "dbl_list/dbl_list.h"
|
||||
#include "../common/wapp_common.h"
|
||||
|
||||
#endif // !WAPP_CONTAINERS_H
|
@@ -1,87 +0,0 @@
|
||||
#include "cpath.h"
|
||||
#include "aliases.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__unix__) || defined(__APPLE__) || defined(__ANDROID__)
|
||||
internal char path_sep = '/';
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
internal char path_sep = '\\';
|
||||
#endif
|
||||
|
||||
void join_root_and_leaf(const char *root, const char *leaf, char *dst);
|
||||
|
||||
void join_path(char *dst, u64 count, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, count);
|
||||
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
join_root_and_leaf(dst, va_arg(args, const char *), dst);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dirup(char *dst, u64 levels, const char *path) {
|
||||
if (levels < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
u64 end_index = 0;
|
||||
u64 sep_count = 0;
|
||||
|
||||
u64 full_length;
|
||||
u64 length;
|
||||
length = full_length = strlen(path);
|
||||
|
||||
if (path[length - 1] == path_sep) {
|
||||
--length;
|
||||
}
|
||||
|
||||
for (i64 i = length - 1; i >= 0; --i) {
|
||||
if (path[i] == path_sep) {
|
||||
++sep_count;
|
||||
end_index = i;
|
||||
|
||||
if (sep_count == levels) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sep_count < levels) {
|
||||
end_index = 0;
|
||||
}
|
||||
|
||||
if (dst == path) {
|
||||
memset(&dst[end_index], 0, full_length - end_index);
|
||||
} else {
|
||||
u64 dst_length = strlen(dst);
|
||||
memset(dst, 0, dst_length);
|
||||
strncpy(dst, path, end_index);
|
||||
}
|
||||
}
|
||||
|
||||
void join_root_and_leaf(const char *root, const char *leaf, char *dst) {
|
||||
u64 root_length = strlen(root);
|
||||
u64 root_end = root_length - 1;
|
||||
|
||||
u64 leaf_length = strlen(leaf);
|
||||
u64 leaf_start = 0;
|
||||
|
||||
if (root[root_end] == path_sep) {
|
||||
--root_end;
|
||||
}
|
||||
|
||||
if (leaf[leaf_start] == path_sep) {
|
||||
++leaf_start;
|
||||
}
|
||||
|
||||
memcpy(dst, root, ++root_end);
|
||||
|
||||
dst[root_end] = path_sep;
|
||||
|
||||
memcpy(&(dst[++root_end]), &(leaf[leaf_start]), leaf_length - leaf_start);
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
#ifndef PATH_UTILS_H
|
||||
#define PATH_UTILS_H
|
||||
|
||||
#include "aliases.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define NUMPARTS(...) \
|
||||
(sizeof((const char *[]){"", __VA_ARGS__}) / sizeof(const char *) - 1)
|
||||
|
||||
#define wapp_cpath_join_path(DST, ...) \
|
||||
join_path(DST, NUMPARTS(__VA_ARGS__), __VA_ARGS__)
|
||||
#define wapp_cpath_dirname(DST, PATH) dirup(DST, 1, PATH)
|
||||
#define wapp_cpath_dirup(DST, COUNT, PATH) dirup(DST, COUNT, PATH)
|
||||
|
||||
void join_path(char *dst, u64 count, ...);
|
||||
void dirup(char *dst, u64 levels, const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !PATH_UTILS_H
|
44
src/core/mem/allocator/mem_allocator.c
Normal file
44
src/core/mem/allocator/mem_allocator.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "mem_allocator.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) {
|
||||
if (!allocator || !(allocator->alloc)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return allocator->alloc(size, allocator->obj);
|
||||
}
|
||||
|
||||
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment) {
|
||||
if (!allocator || !(allocator->alloc_aligned)) {
|
||||
return 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) {
|
||||
if (!allocator || !(allocator->realloc)) {
|
||||
return 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) {
|
||||
if (!allocator || !(allocator->realloc_aligned)) {
|
||||
return 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);
|
||||
}
|
42
src/core/mem/allocator/mem_allocator.h
Normal file
42
src/core/mem/allocator/mem_allocator.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef MEM_ALLOCATOR_H
|
||||
#define MEM_ALLOCATOR_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#define wapp_mem_allocator_invalid(ALLOCATOR) (memcmp(ALLOCATOR, &((Allocator){0}), sizeof(Allocator)) == 0)
|
||||
|
||||
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_ALLOCATOR_H
|
@@ -1,7 +1,7 @@
|
||||
#include "mem_arena.h"
|
||||
#include "aliases.h"
|
||||
#include "mem_utils.h"
|
||||
#include "misc_utils.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/misc/misc_utils.h"
|
||||
#include "../../os/mem/mem_os.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -12,7 +12,7 @@
|
||||
#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
|
||||
#endif /* ifndef DEFAULT_ALIGNMENT */
|
||||
|
||||
#define ARENA_MINIMUM_CAPACITY 1024
|
||||
#define ARENA_MINIMUM_CAPACITY KB(16) // Allocate minimum of 4 pages
|
||||
|
||||
struct arena {
|
||||
u8 *buf;
|
||||
@@ -25,10 +25,7 @@ struct arena {
|
||||
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
// PUBLIC API
|
||||
|
||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
|
||||
bool zero_buffer) {
|
||||
bool wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, bool zero_buffer) {
|
||||
if (!arena || *arena || base_capacity == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -39,23 +36,19 @@ bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 arena_capacity = base_capacity >= ARENA_MINIMUM_CAPACITY
|
||||
? base_capacity
|
||||
: ARENA_MINIMUM_CAPACITY;
|
||||
u64 arena_capacity = 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);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
@@ -80,18 +73,51 @@ void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
if (!(arena->committed)) {
|
||||
output = (u8 *)wapp_mem_util_alloc(
|
||||
alloc_start, (uptr)(arena->offset) - (uptr)(alloc_start),
|
||||
WAPP_MEM_ACCESS_READ_WRITE, WAPP_MEM_ALLOC_COMMIT,
|
||||
WAPP_MEM_INIT_INITIALISED);
|
||||
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);
|
||||
}
|
||||
#else
|
||||
memset(output, 0, size);
|
||||
#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) {
|
||||
if (!arena) {
|
||||
return;
|
||||
|
@@ -1,37 +1,40 @@
|
||||
#ifndef MEM_ARENA_H
|
||||
#define MEM_ARENA_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "mem_utils.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../os/mem/mem_os.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct arena Arena;
|
||||
|
||||
#define wapp_mem_arena_init_default(arena_dptr, base_capacity) \
|
||||
(wapp_mem_arena_init(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, \
|
||||
false))
|
||||
#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(arena_dptr, base_capacity, \
|
||||
WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
|
||||
(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(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
|
||||
(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(arena_dptr, base_capacity, \
|
||||
WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
|
||||
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
|
||||
|
||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
|
||||
bool zero_buffer);
|
||||
/**
|
||||
* 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 __cplusplus
|
||||
}
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_ARENA_H
|
||||
|
57
src/core/mem/arena/mem_arena_allocator.c
Normal file
57
src/core/mem/arena/mem_arena_allocator.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#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);
|
||||
}
|
41
src/core/mem/arena/mem_arena_allocator.h
Normal file
41
src/core/mem/arena/mem_arena_allocator.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef MEM_ARENA_ALLOCATOR_H
|
||||
#define MEM_ARENA_ALLOCATOR_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../allocator/mem_allocator.h"
|
||||
#include "../../os/mem/mem_os.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_ARENA_ALLOCATOR_H
|
28
src/core/mem/utils/mem_utils.c
Normal file
28
src/core/mem/utils/mem_utils.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "mem_utils.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(is_power_of_two(alignment));
|
||||
|
||||
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;
|
||||
}
|
16
src/core/mem/utils/mem_utils.h
Normal file
16
src/core/mem/utils/mem_utils.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef MEM_UTILS_H
|
||||
#define MEM_UTILS_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_UTILS_H
|
134
src/core/os/cpath/cpath.c
Normal file
134
src/core/os/cpath/cpath.c
Normal file
@@ -0,0 +1,134 @@
|
||||
#include "cpath.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/misc/misc_utils.h"
|
||||
#include "../../mem/allocator/mem_allocator.h"
|
||||
#include "../../mem/arena/mem_arena_allocator.h"
|
||||
#include "../../strings/str8/str8.h"
|
||||
#include "../../strings/str8/str8_list.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
u32 wapp_cpath_join_path(Str8 *dst, const DBL_LIST(Str8) *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 DBL_NODE(Str8) *first_node = wapp_dbl_list_get(Str8, 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 DBL_NODE(Str8) *node = first_node;
|
||||
u64 node_index = 1;
|
||||
bool running = true;
|
||||
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;
|
||||
}
|
||||
|
||||
DBL_LIST(Str8) *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_dbl_list_pop_back(Str8, 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;
|
||||
}
|
38
src/core/os/cpath/cpath.h
Normal file
38
src/core/os/cpath/cpath.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef CPATH_H
|
||||
#define CPATH_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include "../../mem/allocator/mem_allocator.h"
|
||||
#include "../../strings/str8/str8.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#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 DBL_LIST(Str8) *parts);
|
||||
Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !CPATH_H
|
29
src/core/os/mem/mem_os.c
Normal file
29
src/core/os/mem/mem_os.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "mem_os.h"
|
||||
#include "mem_os_ops.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
32
src/core/os/mem/mem_os.h
Normal file
32
src/core/os/mem/mem_os.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef MEM_OS_H
|
||||
#define MEM_OS_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "mem_os_ops.h"
|
||||
|
||||
#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_align_forward(void *ptr, u64 alignment);
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_OS_H
|
26
src/core/os/mem/mem_os_ops.h
Normal file
26
src/core/os/mem/mem_os_ops.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef MEM_OS_OPS_H
|
||||
#define MEM_OS_OPS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_OS_OPS_H
|
34
src/core/os/mem/posix/mem_os_posix.c
Normal file
34
src/core/os/mem/posix/mem_os_posix.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#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 <sys/mman.h>
|
||||
|
||||
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
|
33
src/core/os/mem/posix/mem_os_posix.h
Normal file
33
src/core/os/mem/posix/mem_os_posix.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef MEM_OS_POSIX_H
|
||||
#define MEM_OS_POSIX_H
|
||||
|
||||
#include "../../../../common/platform/platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#endif // !MEM_OS_POSIX_H
|
35
src/core/os/mem/win/mem_os_win.c
Normal file
35
src/core/os/mem/win/mem_os_win.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#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 <Windows.h>
|
||||
#include <memoryapi.h>
|
||||
|
||||
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
|
27
src/core/os/mem/win/mem_os_win.h
Normal file
27
src/core/os/mem/win/mem_os_win.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef MEM_OS_WIN_H
|
||||
#define MEM_OS_WIN_H
|
||||
|
||||
#include "../../../../common/platform/platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <memoryapi.h>
|
||||
|
||||
typedef enum mem_alloc_flags {
|
||||
WAPP_MEM_ALLOC_RESERVE = MEM_RESERVE,
|
||||
WAPP_MEM_ALLOC_COMMIT = MEM_COMMIT,
|
||||
} MemAllocFlags;
|
||||
|
||||
#endif // !WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#endif // !MEM_OS_WIN_H
|
99
src/core/os/shell/commander/commander.c
Normal file
99
src/core/os/shell/commander/commander.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "commander.h"
|
||||
#include "commander_output.h"
|
||||
#include "../utils/shell_utils.h"
|
||||
#include "../../../mem/allocator/mem_allocator.h"
|
||||
#include "../../../mem/arena/mem_arena_allocator.h"
|
||||
#include "../../../strings/str8/str8.h"
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../../common/misc/misc_utils.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 DBL_LIST(Str8) *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;
|
||||
}
|
25
src/core/os/shell/commander/commander.h
Normal file
25
src/core/os/shell/commander/commander.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef COMMANDER_H
|
||||
#define COMMANDER_H
|
||||
|
||||
#include "commander_output.h"
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../strings/str8/str8.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#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 DBL_LIST(Str8) *cmd);
|
||||
|
||||
external CMDError get_output_status(FILE *fp, i32 *status_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !COMMANDER_H
|
43
src/core/os/shell/commander/commander_output.h
Normal file
43
src/core/os/shell/commander/commander_output.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef COMMANDER_OUTPUT_H
|
||||
#define COMMANDER_OUTPUT_H
|
||||
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../../common/platform/platform.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
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 "misc_utils.h"
|
||||
wapp_misc_utils_padding_size(sizeof(bool) + sizeof(i32) + sizeof(CMDError));
|
||||
#endif // !WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !COMMANDER_OUTPUT_H
|
23
src/core/os/shell/commander/posix/commander_posix.c
Normal file
23
src/core/os/shell/commander/posix/commander_posix.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "../../../../../common/aliases/aliases.h"
|
||||
#include "../../../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include "../commander_output.h"
|
||||
#include "../../utils/shell_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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
|
22
src/core/os/shell/commander/win/commander_win.c
Normal file
22
src/core/os/shell/commander/win/commander_win.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "../../../../../common/aliases/aliases.h"
|
||||
#include "../../../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#include "../commander_output.h"
|
||||
#include "../../utils/shell_utils.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
34
src/core/os/shell/termcolour/posix/termcolour_posix.c
Normal file
34
src/core/os/shell/termcolour/posix/termcolour_posix.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "../../../../../common/aliases/aliases.h"
|
||||
#include "../../../../../common/platform/platform.h"
|
||||
#include "../../../../strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include "../terminal_colours.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
16
src/core/os/shell/termcolour/termcolour.c
Normal file
16
src/core/os/shell/termcolour/termcolour.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "termcolour.h"
|
||||
#include "terminal_colours.h"
|
||||
#include "../../../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);
|
||||
}
|
21
src/core/os/shell/termcolour/termcolour.h
Normal file
21
src/core/os/shell/termcolour/termcolour.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef TERM_COLOUR_H
|
||||
#define TERM_COLOUR_H
|
||||
|
||||
#include "terminal_colours.h"
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../strings/str8/str8.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TERM_COLOUR_H
|
34
src/core/os/shell/termcolour/terminal_colours.h
Normal file
34
src/core/os/shell/termcolour/terminal_colours.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef TERMINAL_COLOURS_H
|
||||
#define TERMINAL_COLOURS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TERMINAL_COLOURS_H
|
71
src/core/os/shell/termcolour/win/termcolour_win.c
Normal file
71
src/core/os/shell/termcolour/win/termcolour_win.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "../../../../../common/aliases/aliases.h"
|
||||
#include "../../../../../common/platform/platform.h"
|
||||
#include "../../../../strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#include "../terminal_colours.h"
|
||||
#include "../../../../../common/misc/misc_utils.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
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
|
@@ -1,16 +1,15 @@
|
||||
#ifndef SHELL_UTILS_H
|
||||
#define SHELL_UTILS_H
|
||||
|
||||
#include "platform.h"
|
||||
#include "../../../../common/platform/platform.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// clang-format off
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
#define wapp_shell_utils_popen _popen
|
||||
#define wapp_shell_utils_popen _popen
|
||||
#define wapp_shell_utils_pclose _pclose
|
||||
#else
|
||||
#define wapp_shell_utils_popen popen
|
||||
#define wapp_shell_utils_popen popen
|
||||
#define wapp_shell_utils_pclose pclose
|
||||
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||
// clang-format on
|
||||
|
||||
#endif // !SHELL_UTILS_H
|
@@ -1,34 +0,0 @@
|
||||
#ifndef BASIC_STRING_H
|
||||
#define BASIC_STRING_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct bstr BasicString;
|
||||
struct bstr {
|
||||
u64 size;
|
||||
const char *buf;
|
||||
};
|
||||
|
||||
typedef struct strvw StringView;
|
||||
struct strvw {
|
||||
const u64 size;
|
||||
const char *buf;
|
||||
};
|
||||
|
||||
#define new_string(STR) \
|
||||
{ .size = strlen(STR), .buf = STR }
|
||||
#define wapp_bstr_new(STR) ((BasicString)new_string(STR))
|
||||
#define wapp_strvw_new(STR) ((StringView)new_string(STR))
|
||||
#define wapp_string_print(STR) (printf("%.*s\n", (i32)STR.size, STR.buf))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !BASIC_STRING_H
|
@@ -1,191 +0,0 @@
|
||||
#include "dstr.h"
|
||||
#include "aliases.h"
|
||||
#include "mem_arena.h"
|
||||
#include "platform.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Use this scalar to allocate extra memory in order to avoid having to
|
||||
// constantly reallocate
|
||||
#define CAPACITY_SCALAR 8
|
||||
#define MINIMUM_DSTR_CAPACITY 1024
|
||||
|
||||
struct dstr {
|
||||
u64 capacity;
|
||||
u64 size;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
char *buf;
|
||||
#else
|
||||
char buf[];
|
||||
#endif // WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena) {
|
||||
if (!arena) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
String *out =
|
||||
(String *)wapp_mem_arena_alloc(arena, sizeof(String) + capacity + 1);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->capacity = capacity;
|
||||
out->size = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
String *wapp_dstr_from_string(const char *str, Arena *arena) {
|
||||
if (!str || !arena) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 length = strlen(str);
|
||||
u64 capacity = length * CAPACITY_SCALAR;
|
||||
capacity =
|
||||
capacity >= MINIMUM_DSTR_CAPACITY ? capacity : MINIMUM_DSTR_CAPACITY;
|
||||
|
||||
String *out = wapp_dstr_with_capacity(capacity, arena);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->size = length;
|
||||
strncpy(out->buf, str, length + 1);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
StringUpdate wapp_dstr_update(String **dst, const char *src, Arena *arena) {
|
||||
if (!dst || !(*dst)) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
u64 length = strlen(src);
|
||||
|
||||
String *str = *dst;
|
||||
|
||||
if (length >= str->capacity) {
|
||||
if (!arena) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
String *new_str = wapp_dstr_from_string(src, arena);
|
||||
if (!new_str) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
return (StringUpdate){.updated = true, .str = new_str};
|
||||
}
|
||||
|
||||
memset(str->buf, 0, str->capacity);
|
||||
|
||||
str->size = length;
|
||||
|
||||
strncpy(str->buf, src, length + 1);
|
||||
|
||||
return (StringUpdate){.updated = true, .str = *dst};
|
||||
}
|
||||
|
||||
StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena) {
|
||||
if (!dst || !(*dst)) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
u64 src_length = strlen(src);
|
||||
if (src_length == 0) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
u64 new_length = (*dst)->size + src_length;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
char *str =
|
||||
wapp_mem_util_alloc(NULL, new_length + 1, WAPP_MEM_ACCESS_READ_WRITE,
|
||||
WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT,
|
||||
WAPP_MEM_INIT_INITIALISED);
|
||||
|
||||
if (!str) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
#else
|
||||
char str[new_length + 1];
|
||||
memset(str, 0, new_length + 1);
|
||||
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||
|
||||
strncpy(str, (*dst)->buf, (*dst)->size);
|
||||
strncat(str, src, new_length + 1 - (*dst)->size);
|
||||
|
||||
return wapp_dstr_update(dst, str, arena);
|
||||
}
|
||||
|
||||
void wapp_dstr_clear(String *str) {
|
||||
if (!str || str->size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(str->buf, 0, str->capacity);
|
||||
str->size = 0;
|
||||
}
|
||||
|
||||
void wapp_dstr_print(const String *str) {
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%.*s\n", (i32)str->size, str->buf);
|
||||
}
|
||||
|
||||
i64 wapp_dstr_find(const String *str, const char *substr) {
|
||||
if (!str || !substr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 substr_length = strlen(substr);
|
||||
if (substr_length == 0 || substr_length > str->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *s1;
|
||||
for (u64 i = 0; i < str->size; ++i) {
|
||||
if (i + substr_length > str->size) {
|
||||
break;
|
||||
}
|
||||
|
||||
s1 = &(str->buf[i]);
|
||||
|
||||
if (strncmp(s1, substr, substr_length) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 wapp_dstr_length(const String *str) {
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return str->size;
|
||||
}
|
||||
|
||||
u64 wapp_dstr_capacity(const String *str) {
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return str->capacity;
|
||||
}
|
||||
|
||||
const char *wapp_dstr_to_cstr(const String *str) {
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return str->buf;
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
#ifndef DSTR_H
|
||||
#define DSTR_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "mem_arena.h"
|
||||
#include "misc_utils.h"
|
||||
#include "platform.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct dstr String;
|
||||
|
||||
typedef struct string_update StringUpdate;
|
||||
struct string_update {
|
||||
String *str;
|
||||
bool updated;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
wapp_misc_utils_padding_size(sizeof(bool) + sizeof(String *));
|
||||
#endif // WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena);
|
||||
String *wapp_dstr_from_string(const char *str, Arena *arena);
|
||||
StringUpdate wapp_dstr_update(String **dst, const char *src, Arena *arena);
|
||||
StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena);
|
||||
void wapp_dstr_clear(String *str);
|
||||
void wapp_dstr_print(const String *str);
|
||||
i64 wapp_dstr_find(const String *str, const char *substr);
|
||||
u64 wapp_dstr_length(const String *str);
|
||||
u64 wapp_dstr_capacity(const String *str);
|
||||
const char *wapp_dstr_to_cstr(const String *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !DSTR_H
|
437
src/core/strings/str8/str8.c
Normal file
437
src/core/strings/str8/str8.c
Normal file
@@ -0,0 +1,437 @@
|
||||
#include "str8.h"
|
||||
#include "str8_list.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../containers/dbl_list/dbl_list.h"
|
||||
#include "../../mem/allocator/mem_allocator.h"
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(Str8) + sizeof(c8) * CAPACITY)
|
||||
|
||||
Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity) {
|
||||
Str8 *str = NULL;
|
||||
|
||||
if (!allocator) {
|
||||
goto RETURN_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_cstr(const Allocator *allocator, const char *str) {
|
||||
Str8 *output = NULL;
|
||||
|
||||
if (!allocator || !str) {
|
||||
goto RETURN_ALLOC_CSTR;
|
||||
}
|
||||
|
||||
u64 length = strlen(str);
|
||||
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) {
|
||||
Str8 *output = NULL;
|
||||
|
||||
if (!allocator || !str) {
|
||||
goto RETURN_ALLOC_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) {
|
||||
Str8 *output = NULL;
|
||||
if (!allocator || !str) {
|
||||
goto RETURN_ALLOC_SUBSTR;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!allocator || !str || !(*str)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!allocator || !dst || !src) {
|
||||
return 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) {
|
||||
if (!dst || !src) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!dst || !src) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!dst || !src) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!dst || !src) {
|
||||
return;
|
||||
}
|
||||
|
||||
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, ...) {
|
||||
if (!dst || !format) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 = true;
|
||||
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 = true;
|
||||
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;
|
||||
}
|
||||
|
||||
DBL_LIST(Str8) *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) {
|
||||
if (!allocator || !str || !delimiter) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBL_LIST(Str8) *output = wapp_mem_allocator_alloc(allocator, sizeof(DBL_LIST(Str8)));
|
||||
|
||||
if (delimiter->size > str->size) {
|
||||
Str8 *full = wapp_str8_alloc_str8(allocator, str);
|
||||
DBL_NODE(Str8) *node = wapp_mem_allocator_alloc(allocator, sizeof(DBL_NODE(Str8)));
|
||||
if (node) {
|
||||
node->item = full;
|
||||
wapp_dbl_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);
|
||||
DBL_NODE(Str8) *node = wapp_mem_allocator_alloc(allocator, sizeof(DBL_NODE(Str8)));
|
||||
if (node) {
|
||||
node->item = before_str;
|
||||
wapp_dbl_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);
|
||||
DBL_NODE(Str8) *node = wapp_mem_allocator_alloc(allocator, sizeof(DBL_NODE(Str8)));
|
||||
if (node) {
|
||||
node->item = rest;
|
||||
wapp_dbl_list_push_back(output, node);
|
||||
}
|
||||
|
||||
RETURN_STR8_SPLIT:
|
||||
return output;
|
||||
}
|
||||
|
||||
DBL_LIST(Str8) *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) {
|
||||
if (!allocator || !str || !delimiter) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBL_LIST(Str8) *output = wapp_mem_allocator_alloc(allocator, sizeof(DBL_LIST(Str8)));
|
||||
|
||||
if (delimiter->size > str->size) {
|
||||
Str8 *full = wapp_str8_alloc_str8(allocator, str);
|
||||
DBL_NODE(Str8) *node = wapp_mem_allocator_alloc(allocator, sizeof(DBL_NODE(Str8)));
|
||||
if (node) {
|
||||
node->item = full;
|
||||
wapp_dbl_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);
|
||||
DBL_NODE(Str8) *node = wapp_mem_allocator_alloc(allocator, sizeof(DBL_NODE(Str8)));
|
||||
if (node) {
|
||||
node->item = after_str;
|
||||
wapp_dbl_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);
|
||||
DBL_NODE(Str8) *node = wapp_mem_allocator_alloc(allocator, sizeof(DBL_NODE(Str8)));
|
||||
if (node) {
|
||||
node->item = rest;
|
||||
wapp_dbl_list_push_front(output, node);
|
||||
}
|
||||
|
||||
RETURN_STR8_SPLIT:
|
||||
return output;
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_join(const Allocator *allocator, const DBL_LIST(Str8) *list, Str8RO *delimiter) {
|
||||
if (!allocator || !list || !delimiter) {
|
||||
return 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
|
||||
DBL_NODE(Str8) *node;
|
||||
u64 node_index = 0;
|
||||
bool running = true;
|
||||
while (running) {
|
||||
node = wapp_dbl_list_get(Str8, list, node_index);
|
||||
wapp_str8_concat_capped(output, node->item);
|
||||
if (node_index + 1 < list->node_count) {
|
||||
wapp_str8_concat_capped(output, delimiter);
|
||||
}
|
||||
|
||||
++node_index;
|
||||
running = node_index < list->node_count;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
102
src/core/strings/str8/str8.h
Normal file
102
src/core/strings/str8/str8.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#ifndef STR8_H
|
||||
#define STR8_H
|
||||
|
||||
#include "./str8_list.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../containers/dbl_list/dbl_list.h"
|
||||
#include "../../mem/allocator/mem_allocator.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
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
|
||||
*/
|
||||
#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}
|
||||
|
||||
/**
|
||||
* Str8 allocated buffers
|
||||
*/
|
||||
Str8 *wapp_str8_alloc_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)
|
||||
DBL_LIST(Str8) *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits);
|
||||
DBL_LIST(Str8) *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits);
|
||||
Str8 *wapp_str8_join(const Allocator *allocator, const DBL_LIST(Str8) *list, Str8RO *delimiter);
|
||||
|
||||
/**
|
||||
* Str8 list utilities
|
||||
*/
|
||||
#define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node_from_item(Str8, &wapp_str8_lit(STRING))
|
||||
#define wapp_str8_node_from_str8(STRING) wapp_dbl_list_node_from_item(Str8, &(STRING))
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#endif // !STR8_H
|
18
src/core/strings/str8/str8_list.c
Normal file
18
src/core/strings/str8/str8_list.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "./str8_list.h"
|
||||
#include "./str8.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../containers/dbl_list/dbl_list.h"
|
||||
|
||||
u64 wapp_str8_list_total_size(const DBL_LIST(Str8) *list) {
|
||||
if (!list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 output = 0;
|
||||
for (u64 i = 0; i < list->node_count; ++i) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list, i);
|
||||
output += node->item->size;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
25
src/core/strings/str8/str8_list.h
Normal file
25
src/core/strings/str8/str8_list.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN
|
||||
*/
|
||||
|
||||
#ifndef STR8_LIST_H
|
||||
#define STR8_LIST_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../containers/dbl_list/dbl_list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
typedef struct str8 Str8;
|
||||
|
||||
DBL_LIST_DECL(Str8);
|
||||
|
||||
u64 wapp_str8_list_total_size(const DBL_LIST(Str8) *list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // !__cplusplus
|
||||
|
||||
#endif // !STR8_LIST_H
|
22
src/core/wapp_core.c
Normal file
22
src/core/wapp_core.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef WAPP_CORE_C
|
||||
#define WAPP_CORE_C
|
||||
|
||||
#include "wapp_core.h"
|
||||
#include "strings/str8/str8.c"
|
||||
#include "strings/str8/str8_list.c"
|
||||
#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/allocator/mem_allocator.c"
|
||||
#include "mem/arena/mem_arena.c"
|
||||
#include "mem/arena/mem_arena_allocator.c"
|
||||
|
||||
#endif // !WAPP_CORE_C
|
22
src/core/wapp_core.h
Normal file
22
src/core/wapp_core.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef WAPP_CORE_H
|
||||
#define WAPP_CORE_H
|
||||
|
||||
#include "strings/str8/str8.h"
|
||||
#include "strings/str8/str8_list.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/allocator/mem_allocator.h"
|
||||
#include "mem/arena/mem_arena_allocator.h"
|
||||
#include "mem/arena/mem_arena.h"
|
||||
#include "../common/wapp_common.h"
|
||||
|
||||
#endif // !WAPP_CORE_H
|
6
src/prng/wapp_prng.c
Normal file
6
src/prng/wapp_prng.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef WAPP_PRNG_C
|
||||
#define WAPP_PRNG_C
|
||||
|
||||
#include "xorshift/xorshift.c"
|
||||
|
||||
#endif // !WAPP_PRNG_C
|
7
src/prng/wapp_prng.h
Normal file
7
src/prng/wapp_prng.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef WAPP_PRNG_H
|
||||
#define WAPP_PRNG_H
|
||||
|
||||
#include "xorshift/xorshift.h"
|
||||
#include "../common/wapp_common.h"
|
||||
|
||||
#endif // !WAPP_PRNG_H
|
89
src/prng/xorshift/xorshift.c
Normal file
89
src/prng/xorshift/xorshift.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "xorshift.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
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);
|
||||
|
||||
XOR256State wapp_prng_xorshift_init_state(void) {
|
||||
persistent bool seeded = false;
|
||||
if (!seeded) {
|
||||
seeded = true;
|
||||
|
||||
struct timespec ts = {0};
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
|
||||
srand48(ts.tv_nsec);
|
||||
}
|
||||
|
||||
SplitMix64State sm64 = {.seed = lrand48()};
|
||||
|
||||
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);
|
||||
}
|
27
src/prng/xorshift/xorshift.h
Normal file
27
src/prng/xorshift/xorshift.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef XORSHIFT_H
|
||||
#define XORSHIFT_H
|
||||
|
||||
#include "../../common/aliases/aliases.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
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 __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !XORSHIFT_H
|
@@ -1,57 +0,0 @@
|
||||
#include "tester.h"
|
||||
#include "aliases.h"
|
||||
#include "platform.h"
|
||||
#include "termcolour.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
internal void handle_test_result(TerminalColourist *colourist,
|
||||
TestFuncResult result);
|
||||
|
||||
void run_tests(TestFunc *func1, ...) {
|
||||
TerminalColourist colourist = wapp_shell_termcolour_get_colourist();
|
||||
|
||||
printf("\n");
|
||||
|
||||
handle_test_result(&colourist, func1());
|
||||
|
||||
va_list args;
|
||||
va_start(args, func1);
|
||||
|
||||
TestFunc *func = va_arg(args, TestFunc *);
|
||||
|
||||
while (func) {
|
||||
TestFuncResult result = func();
|
||||
handle_test_result(&colourist, result);
|
||||
|
||||
func = va_arg(args, TestFunc *);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
internal void handle_test_result(TerminalColourist *colourist,
|
||||
TestFuncResult result) {
|
||||
TerminalColour colour;
|
||||
const char *result_text;
|
||||
|
||||
if (result.passed) {
|
||||
colour = WAPP_TERM_COLOUR_FG_BR_GREEN;
|
||||
result_text = "PASSED";
|
||||
} else {
|
||||
colour = WAPP_TERM_COLOUR_FG_BR_RED;
|
||||
result_text = "FAILED";
|
||||
}
|
||||
|
||||
printf("[");
|
||||
wapp_shell_termcolour_print_text(colourist, result_text, colour);
|
||||
wapp_shell_termcolour_clear_colour(colourist);
|
||||
printf("] %s\n", result.name);
|
||||
|
||||
if (!result.passed) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
53
src/testing/tester/tester.c
Normal file
53
src/testing/tester/tester.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "tester.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../core/os/shell/termcolour/termcolour.h"
|
||||
#include "../../core/strings/str8/str8.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@@ -1,25 +1,25 @@
|
||||
#ifndef TESTER_H
|
||||
#define TESTER_H
|
||||
|
||||
#include "misc_utils.h"
|
||||
#include "platform.h"
|
||||
#include "../../common/misc/misc_utils.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
#include "../../core/strings/str8/str8.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#define wapp_tester_result(PASSED) \
|
||||
((TestFuncResult){.name = __func__, .passed = PASSED})
|
||||
#define wapp_tester_result(PASSED) ((TestFuncResult){.name = wapp_str8_lit_ro(__func__), .passed = PASSED})
|
||||
#define wapp_tester_run_tests(...) run_tests(__VA_ARGS__, NULL)
|
||||
|
||||
typedef struct test_func_result TestFuncResult;
|
||||
struct test_func_result {
|
||||
const char *name;
|
||||
Str8RO name;
|
||||
bool passed;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
wapp_misc_utils_padding_size(sizeof(const char *) + sizeof(bool));
|
||||
wapp_misc_utils_padding_size(sizeof(Str8RO) + sizeof(bool));
|
||||
#endif // WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ typedef TestFuncResult(TestFunc)(void);
|
||||
void run_tests(TestFunc *func1, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TESTER_H
|
8
src/testing/wapp_testing.c
Normal file
8
src/testing/wapp_testing.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#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
|
8
src/testing/wapp_testing.h
Normal file
8
src/testing/wapp_testing.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#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
|
59
src/uuid/uuid.c
Normal file
59
src/uuid/uuid.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "uuid.h"
|
||||
#include "../common/aliases/aliases.h"
|
||||
#include "../core/strings/str8/str8.h"
|
||||
#include "../prng/xorshift/xorshift.h"
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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) {
|
||||
if (!uuid) {
|
||||
goto RETURN_INIT_UUID4;
|
||||
}
|
||||
|
||||
UUID4 uuid4 = generate_uuid4();
|
||||
uuid4_to_uuid(&uuid4, uuid);
|
||||
|
||||
RETURN_INIT_UUID4:
|
||||
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);
|
||||
}
|
34
src/uuid/uuid.h
Normal file
34
src/uuid/uuid.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef UUID_H
|
||||
#define UUID_H
|
||||
|
||||
#include "../common/aliases/aliases.h"
|
||||
#include "../core/strings/str8/str8.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#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.
|
||||
// If the pointer is NULL, it skips initialisation.
|
||||
UUID *wapp_uuid_init_uuid4(UUID *uuid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !UUID_H
|
8
src/uuid/wapp_uuid.c
Normal file
8
src/uuid/wapp_uuid.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef WAPP_UUID_C
|
||||
#define WAPP_UUID_C
|
||||
|
||||
#include "uuid.c"
|
||||
#include "../core/wapp_core.c"
|
||||
#include "../prng/wapp_prng.c"
|
||||
|
||||
#endif // !WAPP_UUID_C
|
9
src/uuid/wapp_uuid.h
Normal file
9
src/uuid/wapp_uuid.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef WAPP_UUID_H
|
||||
#define WAPP_UUID_H
|
||||
|
||||
#include "uuid.h"
|
||||
#include "../common/wapp_common.h"
|
||||
#include "../core/wapp_core.h"
|
||||
#include "../prng/wapp_prng.h"
|
||||
|
||||
#endif // !WAPP_UUID_H
|
11
src/wapp.c
Normal file
11
src/wapp.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef WAPP_C
|
||||
#define WAPP_C
|
||||
|
||||
#include "wapp.h"
|
||||
#include "containers/wapp_containers.c"
|
||||
#include "core/wapp_core.c"
|
||||
#include "prng/wapp_prng.c"
|
||||
#include "uuid/uuid.c"
|
||||
#include "testing/wapp_testing.c"
|
||||
|
||||
#endif // !WAPP_C
|
11
src/wapp.h
Normal file
11
src/wapp.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef WAPP_H
|
||||
#define WAPP_H
|
||||
|
||||
#include "common/wapp_common.h"
|
||||
#include "containers/wapp_containers.h"
|
||||
#include "core/wapp_core.h"
|
||||
#include "prng/wapp_prng.h"
|
||||
#include "uuid/wapp_uuid.h"
|
||||
#include "testing/wapp_testing.h"
|
||||
|
||||
#endif // !WAPP_H
|
18
tests/allocator/test_allocator.c
Normal file
18
tests/allocator/test_allocator.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "test_allocator.h"
|
||||
#include "wapp.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
TestFuncResult test_arena_allocator(void) {
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(4096);
|
||||
bool result = allocator.obj != NULL && allocator.alloc != NULL &&
|
||||
allocator.alloc_aligned != NULL &&
|
||||
allocator.realloc != NULL && allocator.realloc_aligned != NULL &&
|
||||
allocator.free == NULL;
|
||||
void *ptr = wapp_mem_allocator_alloc(&allocator, 20);
|
||||
result = result && (ptr != NULL);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
16
tests/allocator/test_allocator.h
Normal file
16
tests/allocator/test_allocator.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef TEST_ALLOCATOR_H
|
||||
#define TEST_ALLOCATOR_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_arena_allocator(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_ALLOCATOR_H
|
@@ -1,27 +1,24 @@
|
||||
#include "test_arena.h"
|
||||
#include "aliases.h"
|
||||
#include "mem_arena.h"
|
||||
#include "tester.h"
|
||||
#include "wapp.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARENA_CAPACITY 1024
|
||||
#define ARENA_CAPACITY KB(16)
|
||||
|
||||
internal Arena *arena = NULL;
|
||||
internal i32 count = 20;
|
||||
internal i32 *array = NULL;
|
||||
internal i32 count = 20;
|
||||
internal i32 *array = NULL;
|
||||
|
||||
TestFuncResult test_arena_init(void) {
|
||||
bool result = wapp_mem_arena_init_default(&arena, ARENA_CAPACITY);
|
||||
bool result = wapp_mem_arena_init(&arena, ARENA_CAPACITY);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void) {
|
||||
Arena *large_arena = NULL;
|
||||
u64 capacity = 512ull * 1024ull * 1024ull * 1024ull;
|
||||
bool result = wapp_mem_arena_init(&large_arena, capacity,
|
||||
WAPP_MEM_ALLOC_RESERVE, false);
|
||||
u64 capacity = GB(512);
|
||||
bool result = wapp_mem_arena_init(&large_arena, capacity);
|
||||
if (result) {
|
||||
wapp_mem_arena_destroy(&large_arena);
|
||||
}
|
||||
@@ -30,7 +27,7 @@ TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void) {
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void) {
|
||||
array = wapp_mem_arena_alloc(arena, count * sizeof(i32));
|
||||
array = wapp_mem_arena_alloc(arena, count * sizeof(i32));
|
||||
bool result = array != NULL;
|
||||
|
||||
for (i32 i = 0; i < count; ++i) {
|
||||
@@ -41,12 +38,58 @@ TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void) {
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_alloc_fails_when_over_capacity(void) {
|
||||
u8 *bytes = wapp_mem_arena_alloc(arena, ARENA_CAPACITY * 2);
|
||||
u8 *bytes = wapp_mem_arena_alloc(arena, ARENA_CAPACITY * 2);
|
||||
bool result = bytes == NULL;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_realloc_bigger_size(void) {
|
||||
u64 old_count = 10;
|
||||
u64 new_count = 20;
|
||||
i32 *bytes = wapp_mem_arena_alloc(arena, old_count * sizeof(i32));
|
||||
|
||||
for (u64 i = 0; i < old_count; ++i) {
|
||||
bytes[i] = (i32)i;
|
||||
}
|
||||
|
||||
i32 *new_bytes = wapp_mem_arena_realloc(arena, bytes, old_count * sizeof(i32), new_count * sizeof(i32));
|
||||
if (!new_bytes) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < new_count; ++i) {
|
||||
if (i < old_count && new_bytes[i] != bytes[i]) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
}
|
||||
|
||||
return wapp_tester_result(true);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_realloc_smaller_size(void) {
|
||||
u64 old_count = 10;
|
||||
u64 new_count = 5;
|
||||
i32 *bytes = wapp_mem_arena_alloc(arena, old_count * sizeof(i32));
|
||||
|
||||
for (u64 i = 0; i < old_count; ++i) {
|
||||
bytes[i] = (i32)i;
|
||||
}
|
||||
|
||||
i32 *new_bytes = wapp_mem_arena_realloc(arena, bytes, old_count * sizeof(i32), new_count * sizeof(i32));
|
||||
if (!new_bytes) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < new_count; ++i) {
|
||||
if (i < new_count && new_bytes[i] != bytes[i]) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
}
|
||||
|
||||
return wapp_tester_result(true);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_clear(void) {
|
||||
wapp_mem_arena_clear(arena);
|
||||
bool result = true;
|
||||
|
@@ -1,21 +1,23 @@
|
||||
#ifndef TEST_ARENA_H
|
||||
#define TEST_ARENA_H
|
||||
|
||||
#include "tester.h"
|
||||
#include "wapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_arena_init(void);
|
||||
TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void);
|
||||
TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void);
|
||||
TestFuncResult test_arena_alloc_fails_when_over_capacity(void);
|
||||
TestFuncResult test_arena_realloc_bigger_size(void);
|
||||
TestFuncResult test_arena_realloc_smaller_size(void);
|
||||
TestFuncResult test_arena_clear(void);
|
||||
TestFuncResult test_arena_destroy(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_ARENA_H
|
||||
|
182
tests/cpath/test_cpath.c
Normal file
182
tests/cpath/test_cpath.c
Normal file
@@ -0,0 +1,182 @@
|
||||
#include "test_cpath.h"
|
||||
#include "wapp.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAIN_BUF_SIZE 4096
|
||||
#define TMP_BUF_SIZE 1024
|
||||
|
||||
TestFuncResult test_cpath_join_path(void) {
|
||||
bool result;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 out = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
wapp_str8_format(&expected, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
wapp_str8_format(&tmp, "%c", PATH_SEP);
|
||||
|
||||
DBL_LIST(Str8) parts = {0};
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_str8(tmp));
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_cstr("home"));
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_cstr("abdelrahman"));
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_cstr("Documents"));
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_front(Str8, &parts);
|
||||
|
||||
wapp_str8_format(&expected, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_str8_concat_capped(&tmp, &wapp_str8_lit_ro("home"));
|
||||
wapp_dbl_list_pop_front(Str8, &parts);
|
||||
wapp_dbl_list_push_front(&parts, &wapp_str8_node_from_str8(tmp));
|
||||
|
||||
wapp_str8_format(&expected, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_str8_format(&tmp, "home%c", PATH_SEP);
|
||||
wapp_dbl_list_pop_front(Str8, &parts);
|
||||
wapp_dbl_list_push_front(&parts, &wapp_str8_node_from_cstr("home"));
|
||||
|
||||
wapp_str8_format(&expected, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_empty(&parts);
|
||||
|
||||
wapp_str8_format(&tmp, "%chome", PATH_SEP);
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_str8(tmp));
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_cstr(""));
|
||||
|
||||
wapp_str8_format(&expected, "%chome", PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_front(Str8, &parts);
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_cstr(""));
|
||||
|
||||
wapp_str8_format(&expected, "%s", "");
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_back(Str8, &parts);
|
||||
wapp_dbl_list_push_back(&parts, &wapp_str8_node_from_cstr("home"));
|
||||
|
||||
wapp_str8_copy_cstr_capped(&expected, "home");
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_cpath_dirname(void) {
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&arena)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
bool result;
|
||||
Str8 *output = NULL;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
// CASE 1
|
||||
wapp_str8_format(&tmp, "%c", PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 2
|
||||
wapp_str8_format(&expected, "%s", ".");
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &wapp_str8_lit("home"));
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 3
|
||||
output = wapp_cpath_dirname(&arena, &wapp_str8_lit(""));
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 4
|
||||
wapp_str8_format(&tmp, "%chome%ctest", PATH_SEP, PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 5
|
||||
wapp_str8_format(&tmp, "%chome%ctest%c", PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_cpath_dirup(void) {
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&arena)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
bool result;
|
||||
Str8 *output = NULL;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
// CASE 1
|
||||
wapp_str8_format(&tmp, "%c", PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 2
|
||||
wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 3
|
||||
wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
|
||||
wapp_str8_copy_cstr_capped(&expected, ".");
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 4
|
||||
wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 2);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 5
|
||||
wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
|
||||
wapp_str8_copy_cstr_capped(&expected, "home");
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 2);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
18
tests/cpath/test_cpath.h
Normal file
18
tests/cpath/test_cpath.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef TEST_CPATH_H
|
||||
#define TEST_CPATH_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_cpath_join_path(void);
|
||||
TestFuncResult test_cpath_dirname(void);
|
||||
TestFuncResult test_cpath_dirup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_CPATH_H
|
63
tests/shell_commander/test_shell_commander.c
Normal file
63
tests/shell_commander/test_shell_commander.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "test_shell_commander.h"
|
||||
#include "wapp.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
TestFuncResult test_commander_cmd_success(void) {
|
||||
DBL_LIST(Str8) cmd = {0};
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr("echo"));
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr("hello world"));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd);
|
||||
bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_NO_ERROR;
|
||||
|
||||
return wapp_tester_result(succeeded);
|
||||
}
|
||||
|
||||
TestFuncResult test_commander_cmd_failure(void) {
|
||||
DBL_LIST(Str8) cmd = {0};
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr("grep"));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd);
|
||||
bool failed = result.exited && result.exit_code != EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_NO_ERROR;
|
||||
|
||||
return wapp_tester_result(failed);
|
||||
}
|
||||
|
||||
TestFuncResult test_commander_cmd_out_buf_success(void) {
|
||||
Str8 buf = wapp_str8_buf(64);
|
||||
Str8 expected = wapp_str8_buf(64);
|
||||
char msg[] = "hello world";
|
||||
wapp_str8_copy_cstr_capped(&expected, msg);
|
||||
|
||||
DBL_LIST(Str8) cmd = {0};
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr("echo"));
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr(msg));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd);
|
||||
bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_NO_ERROR && wapp_str8_equal_to_count(&buf, &expected, strlen(msg));
|
||||
|
||||
return wapp_tester_result(succeeded);
|
||||
}
|
||||
|
||||
TestFuncResult test_commander_cmd_out_buf_failure(void) {
|
||||
Str8 buf = wapp_str8_buf(4);
|
||||
Str8 expected = wapp_str8_buf(64);
|
||||
char msg[] = "hello world";
|
||||
wapp_str8_copy_cstr_capped(&expected, msg);
|
||||
|
||||
DBL_LIST(Str8) cmd = {0};
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr("echo"));
|
||||
wapp_dbl_list_push_back(&cmd, &wapp_str8_node_from_cstr(msg));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd);
|
||||
bool failed = !result.exited && result.exit_code != EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_OUT_BUF_FULL && !wapp_str8_equal(&buf, &expected);
|
||||
|
||||
return wapp_tester_result(failed);
|
||||
}
|
19
tests/shell_commander/test_shell_commander.h
Normal file
19
tests/shell_commander/test_shell_commander.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef TEST_SHELL_COMMANDER_H
|
||||
#define TEST_SHELL_COMMANDER_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_commander_cmd_success(void);
|
||||
TestFuncResult test_commander_cmd_failure(void);
|
||||
TestFuncResult test_commander_cmd_out_buf_success(void);
|
||||
TestFuncResult test_commander_cmd_out_buf_failure(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_SHELL_COMMANDER_H
|
614
tests/str8/test_str8.c
Normal file
614
tests/str8/test_str8.c
Normal file
@@ -0,0 +1,614 @@
|
||||
#include "test_str8.h"
|
||||
#include "wapp.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ARRLEN(ARR) (sizeof(ARR) / sizeof(ARR[0]))
|
||||
|
||||
TestFuncResult test_str8_lit(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("Hello world");
|
||||
result = s1.capacity == 22 && s1.capacity != s1.size;
|
||||
|
||||
Str8 s2 = wapp_str8_lit("Different strokes for different folks");
|
||||
result = result && s2.capacity == 74 && s2.capacity != s2.size;
|
||||
|
||||
Str8 s3 = wapp_str8_lit("Discretion is the better part of valour");
|
||||
result = result && s3.capacity == 78 && s3.capacity != s3.size;
|
||||
|
||||
Str8 s4 = wapp_str8_lit("Distance lends enchantment to the view");
|
||||
result = result && s4.capacity == 76 && s4.capacity != s4.size;
|
||||
|
||||
Str8 s5 = wapp_str8_lit("Do as I say, not as I do");
|
||||
result = result && s5.capacity == 48 && s5.capacity != s5.size;
|
||||
|
||||
Str8 s6 = wapp_str8_lit("Do as you would be done by");
|
||||
result = result && s6.capacity == 52 && s6.capacity != s6.size;
|
||||
|
||||
Str8 s7 = wapp_str8_lit("Do unto others as you would have them do to you");
|
||||
result = result && s7.capacity == 94 && s7.capacity != s7.size;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_lit_ro(void) {
|
||||
bool result;
|
||||
|
||||
Str8RO s1 = wapp_str8_lit_ro("Hello world");
|
||||
result = s1.capacity == 11 && s1.capacity == s1.size;
|
||||
|
||||
Str8RO s2 = wapp_str8_lit_ro("Different strokes for different folks");
|
||||
result = result && s2.capacity == 37 && s2.capacity == s2.size;
|
||||
|
||||
Str8RO s3 = wapp_str8_lit_ro("Discretion is the better part of valour");
|
||||
result = result && s3.capacity == 39 && s3.capacity == s3.size;
|
||||
|
||||
Str8RO s4 = wapp_str8_lit_ro("Distance lends enchantment to the view");
|
||||
result = result && s4.capacity == 38 && s4.capacity == s4.size;
|
||||
|
||||
Str8RO s5 = wapp_str8_lit_ro("Do as I say, not as I do");
|
||||
result = result && s5.capacity == 24 && s5.capacity == s5.size;
|
||||
|
||||
Str8RO s6 = wapp_str8_lit_ro("Do as you would be done by");
|
||||
result = result && s6.capacity == 26 && s6.capacity == s6.size;
|
||||
|
||||
Str8RO s7 = wapp_str8_lit_ro("Do unto others as you would have them do to you");
|
||||
result = result && s7.capacity == 47 && s7.capacity == s7.size;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_buf(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_buf(1024);
|
||||
result = s1.capacity == 1024 && s1.size == 0;
|
||||
|
||||
Str8 s2 = wapp_str8_buf(2048);
|
||||
result = result && s2.capacity == 2048 && s2.size == 0;
|
||||
|
||||
Str8 s3 = wapp_str8_buf(4096);
|
||||
result = result && s3.capacity == 4096 && s3.size == 0;
|
||||
|
||||
Str8 s4 = wapp_str8_buf(8192);
|
||||
result = result && s4.capacity == 8192 && s4.size == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_alloc_buf(void) {
|
||||
bool result;
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(KB(100));
|
||||
if (wapp_mem_allocator_invalid(&allocator)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
u64 capacity = 4096;
|
||||
|
||||
Str8 *s = wapp_str8_alloc_buf(&allocator, capacity);
|
||||
if (!s) {
|
||||
result = false;
|
||||
goto TEST_ALLOC_BUF_CLEANUP;
|
||||
}
|
||||
|
||||
result = s->capacity == capacity;
|
||||
|
||||
const char *cstr = "My name is Abdelrahman";
|
||||
wapp_str8_copy_cstr_capped(s, cstr);
|
||||
|
||||
result = result && s->capacity == capacity && s->size == strlen(cstr) && memcmp(s->buf, cstr, s->size) == 0;
|
||||
|
||||
TEST_ALLOC_BUF_CLEANUP:
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_alloc_cstr(void) {
|
||||
bool result;
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(KB(100));
|
||||
if (wapp_mem_allocator_invalid(&allocator)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
char *str = "Abdelrahman";
|
||||
u64 length = strlen(str);
|
||||
Str8 *s = wapp_str8_alloc_cstr(&allocator, str);
|
||||
if (!s) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
result = s->size == length && memcmp(s->buf, str, length) == 0;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_alloc_str8(void) {
|
||||
bool result;
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(KB(100));
|
||||
if (wapp_mem_allocator_invalid(&allocator)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
Str8 str = wapp_str8_lit("Abdelrahman");
|
||||
Str8 *s = wapp_str8_alloc_str8(&allocator, &str);
|
||||
if (!s) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
result = wapp_str8_equal(s, &str);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_alloc_substr(void) {
|
||||
bool result;
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(KB(100));
|
||||
if (wapp_mem_allocator_invalid(&allocator)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
Str8 str = wapp_str8_lit("Abdelrahman");
|
||||
Str8 *s = wapp_str8_alloc_substr(&allocator, &str, 3, 8);
|
||||
if (!s) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
result = s->size == 5 && memcmp(s->buf, "elrah", s->size) == 0;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_get_index_within_bounds(void) {
|
||||
bool result;
|
||||
|
||||
Str8RO s1 = wapp_str8_lit_ro("Hello world");
|
||||
result = wapp_str8_get(&s1, 4) == 'o';
|
||||
|
||||
Str8RO s2 = wapp_str8_lit_ro("Different strokes for different folks");
|
||||
result = result && wapp_str8_get(&s2, 0) == 'D';
|
||||
|
||||
Str8RO s3 = wapp_str8_lit_ro("Discretion is the better part of valour");
|
||||
result = result && wapp_str8_get(&s3, 13) == ' ';
|
||||
|
||||
Str8RO s4 = wapp_str8_lit_ro("Distance lends enchantment to the view");
|
||||
result = result && wapp_str8_get(&s4, 20) == 'n';
|
||||
|
||||
Str8RO s5 = wapp_str8_lit_ro("Do as I say, not as I do");
|
||||
result = result && wapp_str8_get(&s5, 11) == ',';
|
||||
|
||||
Str8RO s6 = wapp_str8_lit_ro("Do as you would be done by");
|
||||
result = result && wapp_str8_get(&s6, 25) == 'y';
|
||||
|
||||
Str8RO s7 = wapp_str8_lit_ro("Do unto others as you would have them do to you");
|
||||
result = result && wapp_str8_get(&s7, 16) == 's';
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_get_index_out_of_bounds(void) {
|
||||
Str8 s1 = wapp_str8_lit("Hello world");
|
||||
bool result = wapp_str8_get(&s1, 20) == '\0';
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_set(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("Hello world");
|
||||
wapp_str8_set(&s1, 4, 'f');
|
||||
result = wapp_str8_get(&s1, 4) == 'f';
|
||||
|
||||
Str8 s2 = wapp_str8_lit("Different strokes for different folks");
|
||||
wapp_str8_set(&s2, 0, 'A');
|
||||
result = result && wapp_str8_get(&s2, 0) == 'A';
|
||||
|
||||
Str8 s3 = wapp_str8_lit("Discretion is the better part of valour");
|
||||
wapp_str8_set(&s3, 13, 'u');
|
||||
result = result && wapp_str8_get(&s3, 13) == 'u';
|
||||
|
||||
Str8 s4 = wapp_str8_lit("Distance lends enchantment to the view");
|
||||
wapp_str8_set(&s4, 20, 'R');
|
||||
result = result && wapp_str8_get(&s4, 20) == 'R';
|
||||
|
||||
Str8 s5 = wapp_str8_lit("Do as I say, not as I do");
|
||||
wapp_str8_set(&s5, 11, '.');
|
||||
result = result && wapp_str8_get(&s5, 11) == '.';
|
||||
|
||||
Str8 s6 = wapp_str8_lit("Do as you would be done by");
|
||||
wapp_str8_set(&s6, 25, 'w');
|
||||
result = result && wapp_str8_get(&s6, 25) == 'w';
|
||||
|
||||
Str8 s7 = wapp_str8_lit("Do unto others as you would have them do to you");
|
||||
wapp_str8_set(&s7, 16, 'i');
|
||||
result = result && wapp_str8_get(&s7, 16) == 'i';
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_push_back(void) {
|
||||
bool result;
|
||||
|
||||
Str8 expected = wapp_str8_lit("Abdelrahman");
|
||||
Str8 buf = wapp_str8_buf(64);
|
||||
wapp_str8_push_back(&buf, 'A');
|
||||
wapp_str8_push_back(&buf, 'b');
|
||||
wapp_str8_push_back(&buf, 'd');
|
||||
wapp_str8_push_back(&buf, 'e');
|
||||
wapp_str8_push_back(&buf, 'l');
|
||||
wapp_str8_push_back(&buf, 'r');
|
||||
wapp_str8_push_back(&buf, 'a');
|
||||
wapp_str8_push_back(&buf, 'h');
|
||||
wapp_str8_push_back(&buf, 'm');
|
||||
wapp_str8_push_back(&buf, 'a');
|
||||
wapp_str8_push_back(&buf, 'n');
|
||||
|
||||
result = wapp_str8_equal(&buf, &expected);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_equal(void) {
|
||||
bool result;
|
||||
|
||||
Str8RO s1 = wapp_str8_lit_ro("hello");
|
||||
Str8RO s2 = wapp_str8_lit_ro("hell");
|
||||
Str8RO s3 = wapp_str8_lit_ro("hello");
|
||||
Str8RO s4 = wapp_str8_lit_ro("goodbye");
|
||||
|
||||
result = wapp_str8_equal(&s1, &s2) == false;
|
||||
result = result && wapp_str8_equal(&s1, &s3) == true;
|
||||
result = result && wapp_str8_equal(&s1, &s4) == false;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_slice(void) {
|
||||
bool result;
|
||||
Str8 s = wapp_str8_lit("Different strokes for different folks");
|
||||
|
||||
Str8RO sub1 = wapp_str8_slice(&s, 3, 9);
|
||||
result = sub1.size == 6 && sub1.capacity == 6;
|
||||
|
||||
Str8RO sub2 = wapp_str8_slice(&s, 18, 21);
|
||||
result = result && sub2.size == 3 && sub2.capacity == 3;
|
||||
|
||||
Str8RO sub3 = wapp_str8_slice(&s, 5, 1);
|
||||
result = result && sub3.size == 0 && sub3.capacity == 0;
|
||||
|
||||
Str8RO sub4 = wapp_str8_slice(&s, 70, 80);
|
||||
result = result && sub4.size == 0 && sub4.capacity == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_alloc_concat(void) {
|
||||
bool result;
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(100));
|
||||
|
||||
Str8 str = wapp_str8_lit("Hello world");
|
||||
Str8 suffix1 = wapp_str8_lit(" from me.");
|
||||
Str8 suffix2 = wapp_str8_lit(" This is my code.");
|
||||
Str8 concat1 = wapp_str8_lit("Hello world from me.");
|
||||
Str8 concat2 = wapp_str8_lit("Hello world from me. This is my code.");
|
||||
|
||||
Str8 *output;
|
||||
|
||||
output = wapp_str8_alloc_concat(&arena, &str, &suffix1);
|
||||
result = output->size == concat1.size && wapp_str8_equal(output, &concat1);
|
||||
|
||||
output = wapp_str8_alloc_concat(&arena, output, &suffix2);
|
||||
result = result && output->size == concat2.size && wapp_str8_equal(output, &concat2);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_concat_capped(void) {
|
||||
bool result;
|
||||
|
||||
Str8 str = wapp_str8_lit("Hello world");
|
||||
Str8 suffix1 = wapp_str8_lit(" from me.");
|
||||
Str8 suffix2 = wapp_str8_lit(" This is my code.");
|
||||
Str8 concat1 = wapp_str8_lit("Hello world from me.");
|
||||
Str8 concat2 = wapp_str8_lit("Hello world from me. T");
|
||||
|
||||
wapp_str8_concat_capped(&str, &suffix1);
|
||||
result = str.size == concat1.size && wapp_str8_equal(&str, &concat1);
|
||||
|
||||
wapp_str8_concat_capped(&str, &suffix2);
|
||||
result = result && str.size == concat2.size && wapp_str8_equal(&str, &concat2);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_copy_cstr_capped(void) {
|
||||
bool result;
|
||||
|
||||
Str8 buf = wapp_str8_buf(32);
|
||||
const char *src1 = "Hello world";
|
||||
const char *src2 = "Hello world from the Wizard Apprentice standard library";
|
||||
Str8RO src1_cp = wapp_str8_lit_ro("Hello world");
|
||||
Str8RO src2_cp = wapp_str8_lit_ro("Hello world from the Wizard Appr");
|
||||
|
||||
wapp_str8_copy_cstr_capped(&buf, src1);
|
||||
result = buf.size == src1_cp.size && wapp_str8_equal(&buf, &src1_cp);
|
||||
|
||||
wapp_str8_copy_cstr_capped(&buf, src2);
|
||||
result = result && buf.size == src2_cp.size && buf.size == buf.capacity && wapp_str8_equal(&buf, &src2_cp);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_copy_str8_capped(void) {
|
||||
bool result;
|
||||
|
||||
Str8 buf = wapp_str8_buf(32);
|
||||
Str8RO src1 = wapp_str8_lit_ro("Hello world");
|
||||
Str8RO src2 = wapp_str8_lit_ro("Hello world from the Wizard Apprentice standard library");
|
||||
Str8RO src2_cp = wapp_str8_lit_ro("Hello world from the Wizard Appr");
|
||||
|
||||
wapp_str8_copy_str8_capped(&buf, &src1);
|
||||
result = buf.size == src1.size && wapp_str8_equal(&buf, &src1);
|
||||
|
||||
wapp_str8_copy_str8_capped(&buf, &src2);
|
||||
result = result && buf.size < src2.size && buf.size == buf.capacity && wapp_str8_equal(&buf, &src2_cp);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_format(void) {
|
||||
bool result;
|
||||
|
||||
Str8 buf = wapp_str8_buf(128);
|
||||
Str8 expected = wapp_str8_lit("My name is Abdelrahman and I am 35 years old");
|
||||
|
||||
wapp_str8_format(&buf, "My name is %s and I am %u years old", "Abdelrahman", 35);
|
||||
|
||||
result = wapp_str8_equal(&buf, &expected);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_find(void) {
|
||||
bool result;
|
||||
Str8RO s = wapp_str8_lit("Do as I say, not as I do");
|
||||
|
||||
result = wapp_str8_find(&s, wapp_str8_lit_ro("d")) != -1;
|
||||
result = result && (wapp_str8_find(&s, wapp_str8_lit_ro("not")) != -1);
|
||||
result = result && (wapp_str8_find(&s, wapp_str8_lit_ro("as I say")) != -1);
|
||||
|
||||
result = result && (wapp_str8_find(&s, wapp_str8_lit_ro("f")) == -1);
|
||||
result = result && (wapp_str8_find(&s, wapp_str8_lit_ro("hello")) == -1);
|
||||
result = result && (wapp_str8_find(&s, wapp_str8_lit_ro("not sa I")) == -1);
|
||||
result = result && (wapp_str8_find(&s, wapp_str8_lit_ro("Do unto others as you would have them do to you")) == -1);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_rfind(void) {
|
||||
bool result;
|
||||
Str8RO s = wapp_str8_lit("Do as I say, not as I do");
|
||||
|
||||
result = wapp_str8_rfind(&s, wapp_str8_lit_ro("d")) != -1;
|
||||
result = result && (wapp_str8_rfind(&s, wapp_str8_lit_ro("not")) != -1);
|
||||
result = result && (wapp_str8_rfind(&s, wapp_str8_lit_ro("as I say")) != -1);
|
||||
|
||||
result = result && (wapp_str8_rfind(&s, wapp_str8_lit_ro("f")) == -1);
|
||||
result = result && (wapp_str8_rfind(&s, wapp_str8_lit_ro("hello")) == -1);
|
||||
result = result && (wapp_str8_rfind(&s, wapp_str8_lit_ro("not sa I")) == -1);
|
||||
result = result && (wapp_str8_rfind(&s, wapp_str8_lit_ro("Do unto others as you would have them do to you")) == -1);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_split(void) {
|
||||
bool result;
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(100));
|
||||
|
||||
Str8 str = wapp_str8_lit("hello world from me");
|
||||
Str8 delim1 = wapp_str8_lit(" ");
|
||||
Str8 delim2 = wapp_str8_lit("from");
|
||||
DBL_LIST(Str8) *list1 = wapp_str8_split(&arena, &str, &delim1);
|
||||
DBL_LIST(Str8) *list2 = wapp_str8_split(&arena, &str, &delim2);
|
||||
|
||||
Str8RO splits1[] = {
|
||||
wapp_str8_slice(&str, 0, 5),
|
||||
wapp_str8_slice(&str, 6, 11),
|
||||
wapp_str8_slice(&str, 12, 16),
|
||||
wapp_str8_slice(&str, 17, 19),
|
||||
};
|
||||
Str8RO splits2[] = {
|
||||
wapp_str8_slice(&str, 0, 12),
|
||||
wapp_str8_slice(&str, 16, 19),
|
||||
};
|
||||
|
||||
u64 index1 = 0;
|
||||
u64 count1 = ARRLEN(splits1);
|
||||
bool running1 = true;
|
||||
|
||||
u64 index2 = 0;
|
||||
u64 count2 = ARRLEN(splits2);
|
||||
bool running2 = true;
|
||||
|
||||
result = list1->node_count == count1 && wapp_str8_list_total_size(list1) == str.size - 3;
|
||||
result = result && list2->node_count == count2 && wapp_str8_list_total_size(list2) == str.size - 4;
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
while (running1) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list1, index1);
|
||||
result = result && wapp_str8_equal(node->item, &(splits1[index1]));
|
||||
|
||||
++index1;
|
||||
running1 = index1 < count1;
|
||||
}
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
while (running2) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list2, index2);
|
||||
result = result && wapp_str8_equal(node->item, &(splits2[index2]));
|
||||
|
||||
++index2;
|
||||
running2 = index2 < count2;
|
||||
}
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_split_with_max(void) {
|
||||
bool result;
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(100));
|
||||
|
||||
Str8 str = wapp_str8_lit("hello world from me");
|
||||
Str8 delim = wapp_str8_lit(" ");
|
||||
DBL_LIST(Str8) *list = wapp_str8_split_with_max(&arena, &str, &delim, 2);
|
||||
|
||||
Str8RO splits[] = {
|
||||
wapp_str8_slice(&str, 0, 5),
|
||||
wapp_str8_slice(&str, 6, 11),
|
||||
wapp_str8_slice(&str, 12, 19),
|
||||
};
|
||||
|
||||
u64 index = 0;
|
||||
u64 count = ARRLEN(splits);
|
||||
bool running = true;
|
||||
|
||||
result = list->node_count == count && wapp_str8_list_total_size(list) == str.size - 2;
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
while (running) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list, index);
|
||||
result = result && wapp_str8_equal(node->item, &(splits[index]));
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_rsplit(void) {
|
||||
bool result;
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(100));
|
||||
|
||||
Str8 str = wapp_str8_lit("hello world from me");
|
||||
Str8 delim1 = wapp_str8_lit(" ");
|
||||
Str8 delim2 = wapp_str8_lit("from");
|
||||
DBL_LIST(Str8) *list1 = wapp_str8_rsplit(&arena, &str, &delim1);
|
||||
DBL_LIST(Str8) *list2 = wapp_str8_rsplit(&arena, &str, &delim2);
|
||||
|
||||
Str8RO splits1[] = {
|
||||
wapp_str8_slice(&str, 0, 5),
|
||||
wapp_str8_slice(&str, 6, 11),
|
||||
wapp_str8_slice(&str, 12, 16),
|
||||
wapp_str8_slice(&str, 17, 19),
|
||||
};
|
||||
Str8RO splits2[] = {
|
||||
wapp_str8_slice(&str, 0, 12),
|
||||
wapp_str8_slice(&str, 16, 19),
|
||||
};
|
||||
|
||||
u64 index1 = 0;
|
||||
u64 count1 = ARRLEN(splits1);
|
||||
bool running1 = true;
|
||||
|
||||
u64 index2 = 0;
|
||||
u64 count2 = ARRLEN(splits2);
|
||||
bool running2 = true;
|
||||
|
||||
result = list1->node_count == count1 && wapp_str8_list_total_size(list1) == str.size - 3;
|
||||
result = result && list2->node_count == count2 && wapp_str8_list_total_size(list2) == str.size - 4;
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
while (running1) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list1, index1);
|
||||
result = result && wapp_str8_equal(node->item, &(splits1[index1]));
|
||||
|
||||
++index1;
|
||||
running1 = index1 < count1;
|
||||
}
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
while (running2) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list2, index2);
|
||||
result = result && wapp_str8_equal(node->item, &(splits2[index2]));
|
||||
|
||||
++index2;
|
||||
running2 = index2 < count2;
|
||||
}
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_rsplit_with_max(void) {
|
||||
bool result;
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(100));
|
||||
|
||||
Str8 str = wapp_str8_lit("hello world from me");
|
||||
Str8 delim = wapp_str8_lit(" ");
|
||||
DBL_LIST(Str8) *list = wapp_str8_rsplit_with_max(&arena, &str, &delim, 2);
|
||||
|
||||
Str8RO splits[] = {
|
||||
wapp_str8_slice(&str, 0, 11),
|
||||
wapp_str8_slice(&str, 12, 16),
|
||||
wapp_str8_slice(&str, 17, 19),
|
||||
};
|
||||
|
||||
u64 index = 0;
|
||||
u64 count = ARRLEN(splits);
|
||||
bool running = true;
|
||||
|
||||
result = list->node_count == count && wapp_str8_list_total_size(list) == str.size - 2;
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
while (running) {
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, list, index);
|
||||
result = result && wapp_str8_equal(node->item, &(splits[index]));
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_join(void) {
|
||||
bool result;
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(100));
|
||||
|
||||
Str8 str = wapp_str8_lit("hello world from me");
|
||||
Str8 delim1 = wapp_str8_lit(" ");
|
||||
Str8 delim2 = wapp_str8_lit("from");
|
||||
DBL_LIST(Str8) *list1 = wapp_str8_rsplit(&arena, &str, &delim1);
|
||||
DBL_LIST(Str8) *list2 = wapp_str8_rsplit(&arena, &str, &delim2);
|
||||
Str8 *join1 = wapp_str8_join(&arena, list1, &delim1);
|
||||
Str8 *join2 = wapp_str8_join(&arena, list2, &delim2);
|
||||
|
||||
result = join1->size == str.size && wapp_str8_equal(join1, &str);
|
||||
result = result && join2->size == str.size && wapp_str8_equal(join2, &str);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
40
tests/str8/test_str8.h
Normal file
40
tests/str8/test_str8.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef TEST_STR8_H
|
||||
#define TEST_STR8_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_str8_lit(void);
|
||||
TestFuncResult test_str8_lit_ro(void);
|
||||
TestFuncResult test_str8_buf(void);
|
||||
TestFuncResult test_str8_alloc_buf(void);
|
||||
TestFuncResult test_str8_alloc_cstr(void);
|
||||
TestFuncResult test_str8_alloc_str8(void);
|
||||
TestFuncResult test_str8_alloc_substr(void);
|
||||
TestFuncResult test_str8_alloc_concat(void);
|
||||
TestFuncResult test_str8_get_index_within_bounds(void);
|
||||
TestFuncResult test_str8_get_index_out_of_bounds(void);
|
||||
TestFuncResult test_str8_set(void);
|
||||
TestFuncResult test_str8_push_back(void);
|
||||
TestFuncResult test_str8_equal(void);
|
||||
TestFuncResult test_str8_slice(void);
|
||||
TestFuncResult test_str8_concat_capped(void);
|
||||
TestFuncResult test_str8_copy_cstr_capped(void);
|
||||
TestFuncResult test_str8_copy_str8_capped(void);
|
||||
TestFuncResult test_str8_format(void);
|
||||
TestFuncResult test_str8_find(void);
|
||||
TestFuncResult test_str8_rfind(void);
|
||||
TestFuncResult test_str8_split(void);
|
||||
TestFuncResult test_str8_split_with_max(void);
|
||||
TestFuncResult test_str8_rsplit(void);
|
||||
TestFuncResult test_str8_rsplit_with_max(void);
|
||||
TestFuncResult test_str8_join(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_STR8_H
|
263
tests/str8/test_str8_list.c
Normal file
263
tests/str8/test_str8_list.c
Normal file
@@ -0,0 +1,263 @@
|
||||
#include "test_str8_list.h"
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_str8_list_get(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
Str8 s4 = wapp_str8_lit("4");
|
||||
Str8 s5 = wapp_str8_lit("5");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
DBL_NODE(Str8) n4 = { .item = &s4 };
|
||||
DBL_NODE(Str8) n5 = { .item = &s5 };
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n1);
|
||||
wapp_dbl_list_push_back(&list, &n2);
|
||||
wapp_dbl_list_push_back(&list, &n3);
|
||||
wapp_dbl_list_push_back(&list, &n4);
|
||||
wapp_dbl_list_push_back(&list, &n5);
|
||||
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_get(Str8, &list, 0);
|
||||
result = node->item == &s1 && wapp_str8_equal(node->item, &s1);
|
||||
|
||||
node = wapp_dbl_list_get(Str8, &list, 1);
|
||||
result = result && node->item == &s2 && wapp_str8_equal(node->item, &s2);
|
||||
|
||||
node = wapp_dbl_list_get(Str8, &list, 2);
|
||||
result = result && node->item == &s3 && wapp_str8_equal(node->item, &s3);
|
||||
|
||||
node = wapp_dbl_list_get(Str8, &list, 3);
|
||||
result = result && node->item == &s4 && wapp_str8_equal(node->item, &s4);
|
||||
|
||||
node = wapp_dbl_list_get(Str8, &list, 4);
|
||||
result = result && node->item == &s5 && wapp_str8_equal(node->item, &s5);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_push_front(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
|
||||
wapp_dbl_list_push_front(&list, &n1);
|
||||
result = list.first == list.last && list.first == &n1 && list.first->item == &s1 && wapp_str8_list_total_size(&list) == 1 && list.node_count == 1;
|
||||
|
||||
wapp_dbl_list_push_front(&list, &n2);
|
||||
result = result && list.first == &n2 && list.first->item == &s2 && wapp_str8_list_total_size(&list) == 2 && list.node_count == 2;
|
||||
|
||||
wapp_dbl_list_push_front(&list, &n3);
|
||||
result = result && list.first == &n3 && list.first->item == &s3 && wapp_str8_list_total_size(&list) == 3 && list.node_count == 3;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_push_back(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n1);
|
||||
result = list.first == list.last && list.last == &n1 && list.last->item == &s1 && wapp_str8_list_total_size(&list) == 1 && list.node_count == 1;
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n2);
|
||||
result = result && list.last == &n2 && list.last->item == &s2 && wapp_str8_list_total_size(&list) == 2 && list.node_count == 2;
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n3);
|
||||
result = result && list.last == &n3 && list.last->item == &s3 && wapp_str8_list_total_size(&list) == 3 && list.node_count == 3;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_insert(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
Str8 s4 = wapp_str8_lit("4");
|
||||
Str8 s5 = wapp_str8_lit("5");
|
||||
Str8 s6 = wapp_str8_lit("6");
|
||||
Str8 s7 = wapp_str8_lit("7");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
DBL_NODE(Str8) n4 = { .item = &s4 };
|
||||
DBL_NODE(Str8) n5 = { .item = &s5 };
|
||||
DBL_NODE(Str8) n6 = { .item = &s6 };
|
||||
DBL_NODE(Str8) n7 = { .item = &s7 };
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n1);
|
||||
wapp_dbl_list_push_back(&list, &n2);
|
||||
wapp_dbl_list_push_back(&list, &n3);
|
||||
wapp_dbl_list_push_back(&list, &n4);
|
||||
wapp_dbl_list_push_back(&list, &n5);
|
||||
|
||||
DBL_NODE(Str8) *node;
|
||||
wapp_dbl_list_insert(&list, &n6, 2);
|
||||
node = wapp_dbl_list_get(Str8, &list, 2);
|
||||
result = node != NULL && node->item == &s6 && wapp_str8_list_total_size(&list) == 6 && list.node_count == 6;
|
||||
wapp_dbl_list_insert(&list, &n7, 5);
|
||||
node = wapp_dbl_list_get(Str8, &list, 5);
|
||||
result = result && node != NULL && node->item == &s7 && wapp_str8_list_total_size(&list) == 7 && list.node_count == 7;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_pop_front(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
Str8 s4 = wapp_str8_lit("4");
|
||||
Str8 s5 = wapp_str8_lit("5");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
DBL_NODE(Str8) n4 = { .item = &s4 };
|
||||
DBL_NODE(Str8) n5 = { .item = &s5 };
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n1);
|
||||
wapp_dbl_list_push_back(&list, &n2);
|
||||
wapp_dbl_list_push_back(&list, &n3);
|
||||
wapp_dbl_list_push_back(&list, &n4);
|
||||
wapp_dbl_list_push_back(&list, &n5);
|
||||
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_pop_front(Str8, &list);
|
||||
result = node == &n1 && node->item == &s1 && wapp_str8_equal(node->item, &s1) && wapp_str8_list_total_size(&list) == 4 && list.node_count == 4;
|
||||
|
||||
node = wapp_dbl_list_pop_front(Str8, &list);
|
||||
result = result && node == &n2 && node->item == &s2 && wapp_str8_equal(node->item, &s2) && wapp_str8_list_total_size(&list) == 3 && list.node_count == 3;
|
||||
|
||||
node = wapp_dbl_list_pop_front(Str8, &list);
|
||||
result = result && node == &n3 && node->item == &s3 && wapp_str8_equal(node->item, &s3) && wapp_str8_list_total_size(&list) == 2 && list.node_count == 2;
|
||||
|
||||
node = wapp_dbl_list_pop_front(Str8, &list);
|
||||
result = result && node == &n4 && node->item == &s4 && wapp_str8_equal(node->item, &s4) && wapp_str8_list_total_size(&list) == 1 && list.node_count == 1;
|
||||
|
||||
node = wapp_dbl_list_pop_front(Str8, &list);
|
||||
result = result && node == &n5 && node->item == &s5 && wapp_str8_equal(node->item, &s5) && wapp_str8_list_total_size(&list) == 0 && list.node_count == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_pop_back(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
Str8 s4 = wapp_str8_lit("4");
|
||||
Str8 s5 = wapp_str8_lit("5");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
DBL_NODE(Str8) n4 = { .item = &s4 };
|
||||
DBL_NODE(Str8) n5 = { .item = &s5 };
|
||||
|
||||
wapp_dbl_list_push_front(&list, &n1);
|
||||
wapp_dbl_list_push_front(&list, &n2);
|
||||
wapp_dbl_list_push_front(&list, &n3);
|
||||
wapp_dbl_list_push_front(&list, &n4);
|
||||
wapp_dbl_list_push_front(&list, &n5);
|
||||
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_pop_back(Str8, &list);
|
||||
result = node == &n1 && node->item == &s1 && wapp_str8_equal(node->item, &s1) && wapp_str8_list_total_size(&list) == 4 && list.node_count == 4;
|
||||
|
||||
node = wapp_dbl_list_pop_back(Str8, &list);
|
||||
result = result && node == &n2 && node->item == &s2 && wapp_str8_equal(node->item, &s2) && wapp_str8_list_total_size(&list) == 3 && list.node_count == 3;
|
||||
|
||||
node = wapp_dbl_list_pop_back(Str8, &list);
|
||||
result = result && node == &n3 && node->item == &s3 && wapp_str8_equal(node->item, &s3) && wapp_str8_list_total_size(&list) == 2 && list.node_count == 2;
|
||||
|
||||
node = wapp_dbl_list_pop_back(Str8, &list);
|
||||
result = result && node == &n4 && node->item == &s4 && wapp_str8_equal(node->item, &s4) && wapp_str8_list_total_size(&list) == 1 && list.node_count == 1;
|
||||
|
||||
node = wapp_dbl_list_pop_back(Str8, &list);
|
||||
result = result && node == &n5 && node->item == &s5 && wapp_str8_equal(node->item, &s5) && wapp_str8_list_total_size(&list) == 0 && list.node_count == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_remove(void) {
|
||||
bool result;
|
||||
|
||||
Str8 s1 = wapp_str8_lit("1");
|
||||
Str8 s2 = wapp_str8_lit("2");
|
||||
Str8 s3 = wapp_str8_lit("3");
|
||||
Str8 s4 = wapp_str8_lit("4");
|
||||
Str8 s5 = wapp_str8_lit("5");
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
DBL_NODE(Str8) n1 = { .item = &s1 };
|
||||
DBL_NODE(Str8) n2 = { .item = &s2 };
|
||||
DBL_NODE(Str8) n3 = { .item = &s3 };
|
||||
DBL_NODE(Str8) n4 = { .item = &s4 };
|
||||
DBL_NODE(Str8) n5 = { .item = &s5 };
|
||||
|
||||
wapp_dbl_list_push_back(&list, &n1);
|
||||
wapp_dbl_list_push_back(&list, &n2);
|
||||
wapp_dbl_list_push_back(&list, &n3);
|
||||
wapp_dbl_list_push_back(&list, &n4);
|
||||
wapp_dbl_list_push_back(&list, &n5);
|
||||
|
||||
DBL_NODE(Str8) *node = wapp_dbl_list_remove(Str8, &list, 0);
|
||||
result = node == &n1 && node->item == &s1 && wapp_str8_equal(node->item, &s1) && wapp_str8_list_total_size(&list) == 4 && list.node_count == 4;
|
||||
|
||||
node = wapp_dbl_list_remove(Str8, &list, 0);
|
||||
result = result && node == &n2 && node->item == &s2 && wapp_str8_equal(node->item, &s2) && wapp_str8_list_total_size(&list) == 3 && list.node_count == 3;
|
||||
|
||||
node = wapp_dbl_list_remove(Str8, &list, 0);
|
||||
result = result && node == &n3 && node->item == &s3 && wapp_str8_equal(node->item, &s3) && wapp_str8_list_total_size(&list) == 2 && list.node_count == 2;
|
||||
|
||||
node = wapp_dbl_list_remove(Str8, &list, 0);
|
||||
result = result && node == &n4 && node->item == &s4 && wapp_str8_equal(node->item, &s4) && wapp_str8_list_total_size(&list) == 1 && list.node_count == 1;
|
||||
|
||||
node = wapp_dbl_list_remove(Str8, &list, 0);
|
||||
result = result && node == &n5 && node->item == &s5 && wapp_str8_equal(node->item, &s5) && wapp_str8_list_total_size(&list) == 0 && list.node_count == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_str8_list_empty(void) {
|
||||
bool result;
|
||||
|
||||
DBL_LIST(Str8) list = {0};
|
||||
wapp_dbl_list_push_back(&list, &wapp_str8_node_from_cstr("Hello"));
|
||||
wapp_dbl_list_push_back(&list, &wapp_str8_node_from_cstr("from"));
|
||||
wapp_dbl_list_push_back(&list, &wapp_str8_node_from_cstr("wizapp"));
|
||||
wapp_dbl_list_push_back(&list, &wapp_str8_node_from_cstr("stdlib"));
|
||||
|
||||
wapp_dbl_list_empty(&list);
|
||||
|
||||
result = list.first == NULL && list.last == NULL && list.node_count == 0 && wapp_str8_list_total_size(&list) == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
23
tests/str8/test_str8_list.h
Normal file
23
tests/str8/test_str8_list.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef TEST_STR8_LIST_H
|
||||
#define TEST_STR8_LIST_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_str8_list_get(void);
|
||||
TestFuncResult test_str8_list_push_front(void);
|
||||
TestFuncResult test_str8_list_push_back(void);
|
||||
TestFuncResult test_str8_list_insert(void);
|
||||
TestFuncResult test_str8_list_pop_front(void);
|
||||
TestFuncResult test_str8_list_pop_back(void);
|
||||
TestFuncResult test_str8_list_remove(void);
|
||||
TestFuncResult test_str8_list_empty(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
END_C_LINKAGE
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_STR8_LIST_H
|
@@ -1,13 +1,61 @@
|
||||
#include "test_str8.h"
|
||||
#include "test_str8_list.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_arena.h"
|
||||
#include "tester.h"
|
||||
#include "test_cpath.h"
|
||||
#include "test_shell_commander.h"
|
||||
#include "wapp.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
wapp_tester_run_tests(test_arena_init,
|
||||
wapp_tester_run_tests(test_arena_allocator,
|
||||
test_arena_init,
|
||||
test_arena_init_succeeds_when_reserving_very_large_size,
|
||||
test_arena_alloc_succeeds_when_within_capacity,
|
||||
test_arena_alloc_fails_when_over_capacity,
|
||||
test_arena_clear, test_arena_destroy);
|
||||
test_arena_realloc_bigger_size,
|
||||
test_arena_realloc_smaller_size,
|
||||
test_arena_clear,
|
||||
test_arena_destroy,
|
||||
test_str8_lit,
|
||||
test_str8_lit_ro,
|
||||
test_str8_buf,
|
||||
test_str8_alloc_buf,
|
||||
test_str8_alloc_cstr,
|
||||
test_str8_alloc_str8,
|
||||
test_str8_alloc_substr,
|
||||
test_str8_alloc_concat,
|
||||
test_str8_get_index_within_bounds,
|
||||
test_str8_get_index_out_of_bounds,
|
||||
test_str8_set,
|
||||
test_str8_equal,
|
||||
test_str8_slice,
|
||||
test_str8_concat_capped,
|
||||
test_str8_copy_cstr_capped,
|
||||
test_str8_copy_str8_capped,
|
||||
test_str8_format,
|
||||
test_str8_find,
|
||||
test_str8_rfind,
|
||||
test_str8_split,
|
||||
test_str8_split_with_max,
|
||||
test_str8_rsplit,
|
||||
test_str8_rsplit_with_max,
|
||||
test_str8_join,
|
||||
test_str8_list_get,
|
||||
test_str8_list_push_front,
|
||||
test_str8_list_push_back,
|
||||
test_str8_list_insert,
|
||||
test_str8_list_pop_front,
|
||||
test_str8_list_pop_back,
|
||||
test_str8_list_remove,
|
||||
test_str8_list_empty,
|
||||
test_cpath_join_path,
|
||||
test_cpath_dirname,
|
||||
test_cpath_dirup,
|
||||
test_commander_cmd_success,
|
||||
test_commander_cmd_failure,
|
||||
test_commander_cmd_out_buf_success,
|
||||
test_commander_cmd_out_buf_failure);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
Reference in New Issue
Block a user