108 Commits

Author SHA1 Message Date
Abdelrahman Said
1108ed686e Switch to using snprintf instead of sprintf 2024-10-07 08:01:33 +01:00
36e88ba84d Remove old strings implementation 2024-10-06 22:41:43 +01:00
0617ca2316 Update compile script 2024-10-06 22:06:57 +01:00
40d301fd95 Reformat 2024-10-06 21:31:04 +01:00
7d8df816a5 Move cpath to os 2024-10-06 20:04:38 +01:00
17f0f0eaf3 Fix cpath tests on Windows 2024-10-06 19:54:34 +01:00
ce656a6275 Fix Spectre warnings for MSVC 2024-10-06 19:54:13 +01:00
8d8fcf9dc5 Improve early exit code in test_cpath 2024-10-06 19:33:13 +01:00
77e634ec2d Fix comment 2024-10-06 19:30:19 +01:00
22ece7215a Move path utils to os, fix bugs with it and write tests 2024-10-06 19:28:34 +01:00
4af4b39d6f Remove unnecessary clang-format comments 2024-10-06 12:59:21 +01:00
a48002996e Reorganise src directory 2024-10-06 12:54:04 +01:00
e9451f10f8 Reformat and increase minimum arena capacity to 4 pages 2024-10-06 12:42:12 +01:00
1de3608b1f Pass MemInitType to platform functions 2024-10-05 22:30:11 +01:00
3a25571105 Reformat 2024-10-05 23:18:23 +01:00
139b4ca589 Restore missing mem_utils code 2024-10-05 23:17:23 +01:00
e431cf729e Reformat 2024-10-05 23:15:03 +01:00
1d1c3ca928 Split the platform specific mem_utils implementations 2024-10-05 23:05:32 +01:00
f2f155744a Declare external functions for termcolour and commander in the headers 2024-10-05 23:04:35 +01:00
d3a86ec6cb Add extern alias 2024-10-05 23:03:19 +01:00
e053aa44ab Remove unnecessary termcolour header files 2024-10-05 22:28:24 +01:00
a546a09565 Split commander windows and posix implementations 2024-10-05 22:25:21 +01:00
12f182f0cf Define macros for C linkage 2024-10-05 22:06:13 +01:00
ffb99a3644 Fix MSVC errors and warnings 2024-10-05 20:07:48 +01:00
1ddc5610f9 Remove aligned_alloc from libc allocator since it's not implemented on Windows 2024-10-05 19:11:13 +01:00
d8c7b3162f Split termcolour implementations by platform and simplify the API 2024-10-05 18:46:14 +01:00
9e1e4688e4 Reformat 2024-10-05 18:45:32 +01:00
cd38672581 Add test for Arena's reallocation functionality 2024-09-14 17:28:07 +01:00
7fea236618 Implement reallocation functionality for Arena allocator 2024-09-14 17:27:33 +01:00
16a1b8fa35 Reformat 2024-09-14 14:49:18 +01:00
a0dfe8acd0 Start implementing realloc functions for Arena allocator 2024-09-14 13:39:59 +01:00
95c47ec940 Update libc allocator realloc function 2024-09-14 13:39:32 +01:00
46f32f2ba9 Update signature of realloc functions to expect old and new sizes 2024-09-14 13:38:55 +01:00
8f794dee15 Reformat 2024-09-07 20:54:49 +01:00
034b105ea1 Reformat 2024-09-07 20:53:20 +01:00
c90874ad10 Reformat 2024-09-07 20:49:13 +01:00
8468bb8e28 Reorganise allocators 2024-09-07 20:27:49 +01:00
d30eee0cf8 Add tests for Allocator implementations 2024-09-07 15:43:47 +01:00
59e56a75d3 Reimplement Allocator API for Arena 2024-09-07 15:43:25 +01:00
5d6ce1d2c3 Restore libc Allocator implementation 2024-09-07 15:43:00 +01:00
ce537b7494 Restore Allocator implementation 2024-09-07 15:42:36 +01:00
b8f6e5f187 Fix bug in memory allocation function 2024-08-24 19:07:00 +01:00
775f0864a8 Rename arena default allocation function 2024-08-23 22:29:56 +01:00
8b6fb23bac Use size utils in arena tests 2024-08-23 21:50:22 +01:00
1fb340561f Add size utils 2024-08-23 21:48:38 +01:00
8ed372d938 Ensure stderr is piped to stdout to capture errors in output 2024-06-17 00:18:27 +01:00
8a91a0ec6b Add tests for the shell commander 2024-06-17 00:15:10 +01:00
802b70f5ee Add option to discard command output 2024-06-17 00:14:34 +01:00
92c2439b56 Ensure cleanup on command failure 2024-06-16 23:29:19 +01:00
781a46713b Add shell commander 2024-06-16 23:19:34 +01:00
7c4725edef Add shell_utils 2024-06-16 23:18:52 +01:00
4fc99f76a5 Move termcolour to shell 2024-06-16 23:17:54 +01:00
25ab75f74f Move memory utilities to common 2024-06-16 15:30:53 +01:00
f6dd7e7aa8 Reorganise files 2024-06-16 12:29:43 +01:00
8f5bee45c6 Reformat compile script 2024-06-12 23:20:49 +01:00
25964d9a3c Run tests before building library 2024-06-09 22:46:17 +01:00
d9cf98da73 Rename print_test_result and exit on any failing function 2024-06-09 22:45:27 +01:00
8c153b5321 Build tests on Windows 2024-06-09 22:31:14 +01:00
3c4112d080 Remove building test.c from the Posix compilation script 2024-06-09 22:30:46 +01:00
aa28dd481b Platform abstraction for terminal colour 2024-06-09 22:30:21 +01:00
42187beee5 Fix auto formatting 2024-06-09 22:29:30 +01:00
8cc17f1490 Reformat and update types 2024-06-09 22:28:07 +01:00
b4c1301600 Update .gitignore 2024-06-09 22:25:46 +01:00
2c556e12f1 Initial implementation of Windows build script 2024-06-09 18:27:34 +01:00
6c82898225 Update dstr to remove MSVC warnings 2024-06-09 18:25:37 +01:00
a85508e0a4 Add padding to StringUpdate struct 2024-06-09 18:25:00 +01:00
cd78913e83 Add padding to arena and test_func_result structs 2024-06-09 17:40:41 +01:00
a0acada9b4 Fix Windows warning about assigning in conditional expression 2024-06-09 17:40:01 +01:00
8eaa4afed1 Add WINDOWS_LEAN_AND_MEAN to mem_utils.c 2024-06-09 17:35:22 +01:00
1ce07e9e4e Add WINDOWS_LEAN_AND_MEAN 2024-06-09 17:34:54 +01:00
162b255e1b Add utility for calculating padding size 2024-06-09 17:34:16 +01:00
99a9cd10f5 Update .gitignore 2024-06-09 16:20:15 +01:00
7e1c25b649 Use out of source build 2024-06-09 16:19:44 +01:00
9008e10651 Fix bug in dirup function 2024-06-09 16:19:26 +01:00
d27fc14b31 Fix termcolour include in tester.c 2024-06-09 15:26:20 +01:00
dbdab01a2c Merge branch 'temp' into 'main' 2024-06-09 01:50:51 +01:00
cf12144230 Add utility macros for arena initialisation 2024-06-09 01:46:23 +01:00
ccc86342cd Add address parameter to wapp_mem_util_alloc 2024-06-09 01:45:29 +01:00
Abdelrahman Said
8d89695fcc Test reserving a massive arena 2024-06-03 08:05:14 +01:00
Abdelrahman Said
6499dd7be9 Rename testing macros 2024-06-03 07:58:24 +01:00
75bbb82058 Add helper macro for running test functions 2024-06-02 23:55:41 +01:00
7fb13f2439 Update compile script to run tests 2024-06-02 23:35:34 +01:00
0b63bc746d Add tests 2024-06-02 23:35:26 +01:00
6ee3c762df Add terminal colour constants 2024-06-02 23:35:04 +01:00
59f1c3eb58 Add testing utilities 2024-06-02 23:34:53 +01:00
55d0c25c90 Reformat 2024-06-02 23:34:38 +01:00
cfc98e0137 Update .gitignore 2024-06-02 21:26:32 +01:00
Abdelrahman Said
32877cdeaa Fix platform detection on Apple platforms 2024-06-02 20:54:20 +01:00
Abdelrahman Said
7e2d7b28b7 Update .gitignore 2024-06-02 20:54:07 +01:00
23886f40e8 Switch to using wapp_mem_util_alloc instead of calloc 2024-06-02 20:42:10 +01:00
57de75c1f8 Set allocation flags per platform 2024-06-02 20:41:30 +01:00
9807334ac9 Complete memory allocation and deallocation function definitions 2024-06-02 20:09:56 +01:00
18448dd7c1 Define memory allocation and deallocation functions 2024-06-02 20:09:08 +01:00
62fdef8601 Add platform detection definitions 2024-06-02 20:08:28 +01:00
61c29ee564 Remove growing_arena and use base_arena 2024-06-02 01:17:03 +01:00
36bc8ab54a Ignore test files 2024-06-02 01:16:46 +01:00
a8e5913254 Add release build and compile test 2024-06-02 01:16:24 +01:00
b59aedad89 Add BasicString and StringView 2024-04-29 23:22:59 +01:00
3f5e3558b9 Add BasicString 2024-04-29 23:06:22 +01:00
bb2db0d30d Return StringUpdate from the dstr update functions 2024-04-29 22:55:40 +01:00
e75846a507 Update dstr to use Arena 2024-04-29 22:48:10 +01:00
05e56d67ea Reorganise the code 2024-04-29 21:42:33 +01:00
7164156c35 Simplify Arena 2024-04-28 22:59:37 +01:00
e67e1df9a5 Rename arena free functions 2024-04-28 22:04:23 +01:00
e206b4f4a6 Remove Allocator functions from Arena 2024-04-24 23:40:10 +01:00
05bfa73509 Revert "Simplify Arena allocator"
This reverts commit d4313fb8e4.
2024-04-24 23:18:19 +01:00
d4313fb8e4 Simplify Arena allocator 2024-04-24 23:10:55 +01:00
92db9206cc Remove complicated memory abstractions 2024-04-24 22:51:42 +01:00
56 changed files with 1949 additions and 1072 deletions

6
.gitignore vendored
View File

@@ -1,4 +1,10 @@
.cache
.vscode
test
test.*
*.dSYM
*.pdb
*.obj
compile_commands.json
libwapp-build
libwapp.so

58
build.ps1 Normal file
View File

@@ -0,0 +1,58 @@
Param(
[switch]$Release
)
$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 + '"')}
$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"
} Else {
$GeneralFlags += " /Zi /Od /fsanitize=address"
$BuildType = "debug"
}
$BuildDir = "./libwapp-build/windows-$BuildType"
$ObjDir = "$BuildDir/objects"
$OutDir = "$BuildDir/output"
$TestsDir = "$BuildDir/tests"
$OutBasename = "libwapp"
$Objects = "/Fo:$ObjDir/"
$Outputs = "/Fd:$OutDir/$OutBasename /Fe:$OutDir/$OutBasename"
$TestOutBasename = "wapptest"
$TestOutputs = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestOutBasename"
If (Test-Path $BuildDir) {
Remove-Item $BuildDir -Recurse -Force
}
mkdir -p $ObjDir > $null
mkdir -p $OutDir > $null
mkdir -p $TestsDir > $null
# Build and run tests
Invoke-Expression "$Compiler $GeneralFlags $IncludeDirs $TestIncludeDirs $SrcFiles $TestSrcFiles $TestOutputs" -ErrorAction Stop
Invoke-Expression "$TestsDir/$TestOutBasename.exe"
$Status = $LASTEXITCODE
Remove-Item $TestsDir -Recurse -Force
If ($Status -ne 0) {
Write-Error "Tests failed"
Exit 1
}
# Build library
Invoke-Expression "$Compiler $GeneralFlags $LibraryFlags $IncludeDirs $SrcFiles $Objects $Outputs"

73
compile
View File

@@ -1,18 +1,61 @@
#!/bin/bash
CC=clang
INCLUDE="\
-Ialiases \
-Icpath/include \
-Idstr/include \
$(find mem/include -type d | xargs -I{} echo -n "-I{} ") \
"
SRC="\
cpath/src/*.c \
dstr/src/*.c \
mem/src/*/*.c \
"
CFLAGS="-O3 -shared -fPIC -Wall -Werror -pedantic"
OUT="libwapp.so"
BUILD_TYPE="debug"
(set -x ; $CC $CFLAGS $INCLUDE $SRC -o $OUT)
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)

View File

@@ -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

View File

@@ -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 (u64 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);
}

View File

@@ -1,31 +0,0 @@
#ifndef DSTR_H
#define DSTR_H
#include "aliases.h"
#include "mem_allocator.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef struct dstr String;
String *wapp_dstr_with_capacity(u64 capacity, const Allocator *allocator);
String *wapp_dstr_from_string(const char *str, const Allocator *allocator);
void wapp_dstr_update(String **dst, const char *src);
void wapp_dstr_free(String **str);
void wapp_dstr_concat(String **dst, const char *src);
void wapp_dstr_append(String **dst, char c);
void wapp_dstr_resize(String **str);
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

View File

@@ -1,223 +0,0 @@
#include "dstr.h"
#include "aliases.h"
#include "mem_allocator.h"
#include "mem_libc.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
struct dstr {
Allocator allocator;
u64 capacity;
u64 size;
char buf[];
};
String *wapp_dstr_with_capacity(u64 capacity, const Allocator *allocator) {
Allocator alloc;
if (allocator) {
alloc = *allocator;
} else {
alloc = wapp_mem_libc_allocator();
}
String *out =
(String *)wapp_mem_allocator_alloc(&alloc, sizeof(String) + capacity + 1);
if (!out) {
return NULL;
}
out->allocator = alloc;
out->capacity = capacity;
out->size = 0;
return out;
}
String *wapp_dstr_from_string(const char *str, const Allocator *allocator) {
if (!str) {
return NULL;
}
u64 length = strlen(str);
u64 capacity = length * CAPACITY_SCALAR;
String *out = wapp_dstr_with_capacity(capacity, allocator);
if (!out) {
return NULL;
}
out->size = length;
strncpy(out->buf, str, length + 1);
return out;
}
void wapp_dstr_update(String **dst, const char *src) {
if (!dst || !(*dst)) {
return;
}
u64 length = strlen(src);
String *str = *dst;
if (length < str->capacity) {
memset(str->buf, 0, str->capacity);
str->size = length;
strncpy(str->buf, src, length + 1);
} else {
u64 capacity = length * CAPACITY_SCALAR;
String *tmp = (String *)wapp_mem_allocator_realloc(
&(str->allocator), *dst, sizeof(String) + capacity + 1);
if (!tmp) {
return;
}
tmp->capacity = capacity;
tmp->size = length;
strncpy(tmp->buf, src, length + 1);
*dst = tmp;
}
}
void wapp_dstr_free(String **str) {
if (!str || !(*str)) {
return;
}
String *str_ptr = *str;
wapp_mem_allocator_free(&(str_ptr->allocator), (void **)str);
}
void wapp_dstr_concat(String **dst, const char *src) {
if (!dst || !(*dst)) {
return;
}
u64 src_length = strlen(src);
if (src_length == 0) {
return;
}
u64 new_length = (*dst)->size + src_length;
char str[new_length + 1];
memset(str, 0, new_length + 1);
strncpy(str, (*dst)->buf, (*dst)->size);
strncat(str, src, new_length + 1 - (*dst)->size);
wapp_dstr_update(dst, str);
}
void wapp_dstr_append(String **dst, char c) {
if (!dst || !(*dst)) {
return;
}
u64 new_length = (*dst)->size + 1;
char str[new_length + 1];
memset(str, 0, new_length + 1);
strncpy(str, (*dst)->buf, (*dst)->size);
str[(*dst)->size] = c;
wapp_dstr_update(dst, str);
}
void wapp_dstr_resize(String **str) {
if (!str || !(*str)) {
return;
}
String *str_ptr = *str;
u64 capacity = (*str)->size;
String *tmp = (String *)wapp_mem_allocator_realloc(
&(str_ptr->allocator), *str, sizeof(String) + capacity + 1);
if (!tmp) {
return;
}
tmp->capacity = capacity;
*str = tmp;
}
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;
}

View File

@@ -1,40 +0,0 @@
#ifndef MEM_ALLOCATOR_H
#define MEM_ALLOCATOR_H
#include "aliases.h"
#ifdef __cplusplus
extern "C" {
#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 size, void *alloc_obj);
typedef void *(MemReallocAlignedFunc)(void *ptr, u64 size, u64 alignment,
void *alloc_obj);
typedef void(MemFreeFunc)(void **ptr, void *alloc_obj);
typedef struct allocator Allocator;
struct allocator {
void *obj;
MemAllocFunc *alloc;
MemAllocAlignedFunc *alloc_aligned;
MemReallocFunc *realloc;
MemReallocAlignedFunc *realloc_aligned;
MemFreeFunc *free;
};
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 size);
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr,
u64 size, u64 alignment);
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !MEM_ALLOCATOR_H

View File

@@ -1,28 +0,0 @@
#ifndef MEM_ARENA_H
#define MEM_ARENA_H
#include "aliases.h"
#include "mem_allocator.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef struct growing_arena Arena;
Allocator wapp_mem_arena_allocator(const Arena *arena);
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity);
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 size);
void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 size,
u64 alignment);
void wapp_mem_arena_clear(Arena *arena);
void wapp_mem_arena_free(Arena **arena);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !MEM_ARENA_H

View File

@@ -1,32 +0,0 @@
#ifndef MEM_CTX_H
#define MEM_CTX_H
#include "mem_allocator.h"
#include "mem_arena.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef enum {
CTX_DEST_BUFFER_MAIN,
CTX_DEST_BUFFER_TEMP,
COUNT_CTX_DEST_BUFFER,
} CTXDestBuffer;
Allocator wapp_mem_ctx_allocator(CTXDestBuffer buffer);
void wapp_mem_ctx_init(u64 main_buf_capacity, u64 temp_buf_capacity);
void *wapp_mem_ctx_alloc(CTXDestBuffer buffer, u64 size);
void *wapp_mem_ctx_alloc_aligned(CTXDestBuffer buffer, u64 size, u64 alignment);
void *wapp_mem_ctx_realloc(CTXDestBuffer buffer, void *ptr, u64 size);
void *wapp_mem_ctx_realloc_aligned(CTXDestBuffer buffer, void *ptr, u64 size,
u64 alignment);
void wapp_mem_ctx_clear(CTXDestBuffer buffer);
void wapp_mem_ctx_free(void);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !MEM_CTX_H

View File

@@ -1,16 +0,0 @@
#ifndef MEM_UTILS_H
#define MEM_UTILS_H
#include "aliases.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // !MEM_UTILS_H

View File

@@ -1,406 +0,0 @@
#include "mem_arena.h"
#include "aliases.h"
#include "mem_allocator.h"
#include "mem_utils.h"
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#ifndef DEFAULT_ALIGNMENT
// Why 2 * sizeof(void *) instead of sizeof(void *)
// https://handmade.network/forums/t/6860-alignment_arena_allocator
#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
#endif /* ifndef DEFAULT_ALIGNMENT */
#define HDR_MAGIC_BYTE_COUNT 8
#define HDR_MAGIC \
{ 0x57, 0x41, 0x41, 0x52, 0x4e, 0x48, 0x44, 0x52 }
#define MAX_HDR_SEARCH_LENGTH 256
#define ARENA_MINIMUM_CAPACITY 1024
typedef struct arena_alloc_hdr ArenaAllocHDR;
struct arena_alloc_hdr {
u8 magic[HDR_MAGIC_BYTE_COUNT];
u64 alloc_size;
u64 alignment;
u8 *alloc_start;
};
typedef struct base_arena BaseArena;
struct base_arena {
u8 *buf;
u8 *offset;
u64 capacity;
BaseArena *prev;
BaseArena *next;
};
struct growing_arena {
BaseArena *active_arena;
u64 count;
u64 initial_capacity;
};
internal BaseArena *find_arena_from_pointer(const Arena *arena, void *ptr);
internal bool base_arena_init(BaseArena *arena, u64 capacity);
internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
u64 alignment);
internal void base_arena_clear(BaseArena *arena);
internal void base_arena_free(BaseArena *arena);
internal ArenaAllocHDR *find_alloc_header(BaseArena *arena, void *alloc_ptr);
internal void *mem_arena_alloc(u64 size, void *alloc_obj);
internal void *mem_arena_alloc_aligned(u64 size, u64 alignment,
void *alloc_obj);
internal void *mem_arena_realloc(void *ptr, u64 size, void *alloc_obj);
internal void *mem_arena_realloc_aligned(void *ptr, u64 size, u64 alignment,
void *alloc_obj);
// PUBLIC API
Allocator wapp_mem_arena_allocator(const Arena *arena) {
return (Allocator){
.obj = (void *)arena,
.alloc = mem_arena_alloc,
.alloc_aligned = mem_arena_alloc_aligned,
.realloc = mem_arena_realloc,
.realloc_aligned = mem_arena_realloc_aligned,
.free = NULL,
};
}
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) {
if (!arena || *arena || base_capacity == 0) {
return false;
}
*arena = (Arena *)calloc(1, sizeof(Arena));
Arena *arena_ptr = *arena;
if (!arena_ptr) {
return false;
}
arena_ptr->active_arena = (BaseArena *)calloc(1, sizeof(BaseArena));
if (!(arena_ptr->active_arena)) {
wapp_mem_arena_free(arena);
return false;
}
if (!base_arena_init(arena_ptr->active_arena, base_capacity)) {
wapp_mem_arena_free(arena);
return false;
}
arena_ptr->count = 1;
arena_ptr->initial_capacity = base_capacity;
return true;
}
void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT);
}
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
if (!arena || !(arena->active_arena)) {
return NULL;
}
void *output = base_arena_alloc_aligned(arena->active_arena, size, alignment);
if (!output) {
if (arena->active_arena->next) {
arena->active_arena = arena->active_arena->next;
} else {
arena->active_arena->next = (BaseArena *)calloc(1, sizeof(BaseArena));
if (!(arena->active_arena->next)) {
return NULL;
}
if (!base_arena_init(arena->active_arena->next,
arena->initial_capacity)) {
free(arena->active_arena->next);
return NULL;
}
arena->active_arena->next->prev = arena->active_arena;
arena->active_arena = arena->active_arena->next;
++(arena->count);
}
output = base_arena_alloc_aligned(arena->active_arena, size, alignment);
if (!output) {
return NULL;
}
}
memset(output, 0, size);
return output;
}
void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 size) {
return wapp_mem_arena_realloc_aligned(arena, ptr, size, DEFAULT_ALIGNMENT);
}
void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 size,
u64 alignment) {
if (!arena) {
return NULL;
}
BaseArena *base_arena = find_arena_from_pointer(arena, ptr);
if (!base_arena) {
return NULL;
}
ArenaAllocHDR *header = find_alloc_header(base_arena, ptr);
if (!header) {
return NULL;
}
if (header->alloc_start + header->alloc_size == base_arena->offset) {
// Avoid allocating new pointer and copying memory if pointer is at the end
// of the arena
i64 diff = size - header->alloc_size;
u8 *new_offset = base_arena->offset + diff;
u8 *clear_start = diff < 0 ? new_offset : base_arena->offset;
memset(clear_start, 0, llabs(diff));
header->alloc_size = size;
base_arena->offset = new_offset;
return header->alloc_start;
}
void *new_alloc = wapp_mem_arena_alloc_aligned(arena, size, alignment);
if (!new_alloc) {
return NULL;
}
u64 to_copy = size < header->alloc_size ? size : header->alloc_size;
memcpy(new_alloc, ptr, to_copy);
return new_alloc;
}
void wapp_mem_arena_clear(Arena *arena) {
if (!arena) {
return;
}
BaseArena *last_active = NULL;
while (arena->active_arena) {
base_arena_clear(arena->active_arena);
last_active = arena->active_arena;
arena->active_arena = arena->active_arena->prev;
}
arena->active_arena = last_active;
}
void wapp_mem_arena_free(Arena **arena) {
if (!arena) {
return;
}
Arena *arena_ptr = *arena;
if (!arena_ptr) {
return;
}
BaseArena *current;
BaseArena *next;
BaseArena *prev;
current = arena_ptr->active_arena->next;
while (current) {
next = current->next;
base_arena_free(current);
free(current);
current = next;
}
current = arena_ptr->active_arena->prev;
while (current) {
prev = current->prev;
base_arena_free(current);
free(current);
current = prev;
}
base_arena_free(arena_ptr->active_arena);
free(arena_ptr->active_arena);
arena_ptr->active_arena = NULL;
arena_ptr->count = 0;
arena_ptr->initial_capacity = 0;
free(*arena);
*arena = NULL;
}
// INTERNAL FUNCTIONS
internal BaseArena *find_arena_from_pointer(const Arena *arena, void *ptr) {
if (!arena || !ptr) {
return NULL;
}
// Ensure pointer is not out of bounds
u8 *alloc = (u8 *)ptr;
BaseArena *active = arena->active_arena;
if (alloc > active->buf + arena->initial_capacity) {
return NULL;
}
for (u64 i = 0; i < arena->count; ++i) {
if (alloc >= active->buf && alloc < active->buf + arena->initial_capacity) {
return (BaseArena *)active;
}
active = active->prev;
}
return NULL;
}
internal bool base_arena_init(BaseArena *arena, u64 capacity) {
if (!arena || arena->buf || capacity == 0) {
return false;
}
u64 arena_capacity =
capacity >= ARENA_MINIMUM_CAPACITY ? capacity : ARENA_MINIMUM_CAPACITY;
arena->buf = (u8 *)calloc(arena_capacity, sizeof(u8));
if (!(arena->buf)) {
return false;
}
arena->capacity = arena_capacity;
arena->offset = arena->buf;
arena->prev = arena->next = NULL;
return true;
}
internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
u64 alignment) {
if (!arena) {
return NULL;
}
u8 *start_offset = arena->offset;
u8 *alloc_start = arena->offset + sizeof(ArenaAllocHDR);
u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment);
if (output + size >= arena->buf + arena->capacity) {
return NULL;
}
ArenaAllocHDR *header = (ArenaAllocHDR *)start_offset;
*header = (ArenaAllocHDR){
.magic = HDR_MAGIC,
.alloc_size = size,
.alignment = alignment,
.alloc_start = output,
};
arena->offset = output + size;
return (void *)output;
}
internal void base_arena_clear(BaseArena *arena) {
if (!arena) {
return;
}
memset(arena->buf, 0, arena->offset - arena->buf);
arena->offset = arena->buf;
}
internal void base_arena_free(BaseArena *arena) {
if (!arena) {
return;
}
if (arena->buf) {
free(arena->buf);
}
arena->buf = arena->offset = NULL;
arena->capacity = 0;
arena->prev = arena->next = NULL;
}
internal ArenaAllocHDR *find_alloc_header(BaseArena *arena, void *alloc_ptr) {
persistent const u8 magic[HDR_MAGIC_BYTE_COUNT] = HDR_MAGIC;
u8 *current = (u8 *)alloc_ptr;
u8 *max_search_end = current - MAX_HDR_SEARCH_LENGTH;
u8 *arena_buf_start = arena->buf;
u8 *search_end =
max_search_end > arena_buf_start ? max_search_end : arena_buf_start;
bool match;
for (; current >= search_end; --current) {
match = true;
for (u64 i = 0; i < HDR_MAGIC_BYTE_COUNT; ++i) {
if (current[i] != magic[i]) {
match = false;
break;
}
}
if (match) {
return (ArenaAllocHDR *)current;
}
}
return NULL;
}
internal void *mem_arena_alloc(u64 size, void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_alloc(arena, size);
}
internal 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 void *mem_arena_realloc(void *ptr, u64 size, void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_realloc(arena, ptr, size);
}
internal void *mem_arena_realloc_aligned(void *ptr, u64 size, u64 alignment,
void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_realloc_aligned(arena, ptr, size, alignment);
}

View File

@@ -1,106 +0,0 @@
#include "mem_ctx.h"
#include "aliases.h"
#include "mem_arena.h"
#include <assert.h>
#include <stdlib.h>
typedef struct mem_ctx MemCTX;
struct mem_ctx {
Arena *main;
Arena *temp;
bool main_initialised;
bool temp_initialised;
};
internal MemCTX g_context = {0};
internal Arena *get_arena(CTXDestBuffer buffer);
Allocator wapp_mem_ctx_allocator(CTXDestBuffer buffer) {
Arena *arena = get_arena(buffer);
return wapp_mem_arena_allocator(arena);
}
void wapp_mem_ctx_init(u64 main_buf_capacity, u64 temp_buf_capacity) {
g_context.main_initialised =
wapp_mem_arena_init(&g_context.main, main_buf_capacity);
g_context.temp_initialised =
wapp_mem_arena_init(&g_context.temp, temp_buf_capacity);
}
void *wapp_mem_ctx_alloc(CTXDestBuffer buffer, u64 size) {
Arena *arena = get_arena(buffer);
if (!arena) {
return NULL;
}
return wapp_mem_arena_alloc(arena, size);
}
void *wapp_mem_ctx_alloc_aligned(CTXDestBuffer buffer, u64 size,
u64 alignment) {
Arena *arena = get_arena(buffer);
if (!arena) {
return NULL;
}
return wapp_mem_arena_alloc_aligned(arena, size, alignment);
}
void *wapp_mem_ctx_realloc(CTXDestBuffer buffer, void *ptr, u64 size) {
Arena *arena = get_arena(buffer);
if (!arena) {
return NULL;
}
return wapp_mem_arena_realloc(arena, ptr, size);
}
void *wapp_mem_ctx_realloc_aligned(CTXDestBuffer buffer, void *ptr, u64 size,
u64 alignment) {
Arena *arena = get_arena(buffer);
if (!arena) {
return NULL;
}
return wapp_mem_arena_realloc_aligned(arena, ptr, size, alignment);
}
void wapp_mem_ctx_clear(CTXDestBuffer buffer) {
Arena *arena = get_arena(buffer);
if (!arena) {
return;
}
wapp_mem_arena_clear(arena);
}
void wapp_mem_ctx_free(void) {
wapp_mem_arena_free(&(g_context.main));
g_context.main_initialised = false;
wapp_mem_arena_free(&(g_context.temp));
g_context.temp_initialised = false;
}
internal Arena *get_arena(CTXDestBuffer buffer) {
Arena *output = NULL;
switch (buffer) {
case CTX_DEST_BUFFER_MAIN:
if (g_context.main_initialised) {
output = g_context.main;
}
break;
case CTX_DEST_BUFFER_TEMP:
if (g_context.temp_initialised) {
output = g_context.temp;
}
break;
default:
assert(false && "Not all context destination buffers are handled");
break;
}
return output;
}

View File

@@ -1,48 +0,0 @@
#include "mem_libc.h"
#include "aliases.h"
#include "mem_allocator.h"
#include <stdlib.h>
#include <string.h>
internal void *mem_libc_alloc(u64 size, void *alloc_obj);
internal void *mem_libc_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
internal void *mem_libc_realloc(void *ptr, u64 size, void *alloc_obj);
internal void mem_libc_free(void **ptr, void *alloc_obj);
Allocator wapp_mem_libc_allocator(void) {
return (Allocator){
.obj = NULL,
.alloc = mem_libc_alloc,
.alloc_aligned = mem_libc_alloc_aligned,
.realloc = mem_libc_realloc,
.realloc_aligned = NULL,
.free = mem_libc_free,
};
}
internal void *mem_libc_alloc(u64 size, void *alloc_obj) {
return calloc(1, size);
}
internal void *mem_libc_alloc_aligned(u64 size, u64 alignment,
void *alloc_obj) {
void *output = aligned_alloc(alignment, size);
if (output) {
memset(output, 0, size);
}
return output;
}
internal void *mem_libc_realloc(void *ptr, u64 size, void *alloc_obj) {
return realloc(ptr, size);
}
internal void mem_libc_free(void **ptr, void *alloc_obj) {
if (!ptr || !(*ptr)) {
return;
}
free(*ptr);
*ptr = NULL;
}

View File

@@ -3,28 +3,31 @@
#include <stdint.h>
#define u8 uint8_t
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define i8 int8_t
#define i8 int8_t
#define i16 int16_t
#define i32 int32_t
#define i64 int64_t
#define f32 float
#define f64 double
#define f32 float
#define f64 double
#define f128 long double
#define uptr uintptr_t
#define iptr intptr_t
#define internal static
#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

View File

@@ -0,0 +1,13 @@
#ifndef MISC_UTILS_H
#define MISC_UTILS_H
#include "aliases.h"
#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

View File

@@ -0,0 +1,61 @@
#ifndef PLATFORM_H
#define PLATFORM_H
#if defined(__ANDROID__)
#define WAPP_PLATFORM_ANDROID
#define WAPP_PLATFORM_POSIX
#elif defined(__FreeBSD__)
#define WAPP_PLATFORM_FREE_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__NetBSD__)
#define WAPP_PLATFORM_NET_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__OpenBSD__)
#define WAPP_PLATFORM_OPEN_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__DragonFly__)
#define WAPP_PLATFORM_DRAGON_FLY
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__bsdi__)
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__linux__) || defined(linux) || defined(__linux) || defined(__gnu_linux__)
#define WAPP_PLATFORM_LINUX
#define WAPP_PLATFORM_POSIX
#elif defined(__GNU__) || defined(__gnu_hurd__)
#define WAPP_PLATFORM_GNU
#define WAPP_PLATFORM_POSIX
#elif defined(__APPLE__) || defined(__MACH__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#define WAPP_PLATFORM_IOS
#define WAPP_PLATFORM_APPLE
#define WAPP_PLATFORM_POSIX
#elif TARGET_OS_MAC
#define WAPP_PLATFORM_MACOS
#define WAPP_PLATFORM_APPLE
#define WAPP_PLATFORM_POSIX
#else
#error "Unrecognised Apple platform"
#endif
#elif defined(_WIN64)
#define WAPP_PLATFORM_WINDOWS64
#define WAPP_PLATFORM_WINDOWS
#elif defined(_WIN32)
#define WAPP_PLATFORM_WINDOWS32
#define WAPP_PLATFORM_WINDOWS
#elif defined(__CYGWIN__)
#define WAPP_PLATFORM_CYGWIN
#define WAPP_PLATFORM_WINDOWS
#elif defined(__unix__) || defined(__unix)
#define WAPP_PLATFORM_UNIX
#define WAPP_PLATFORM_POSIX
#else
#error "Unrecognised platform"
#endif
#endif // !PLATFORM_H

View File

@@ -1,6 +1,12 @@
#include "mem_allocator.h"
#include <stdlib.h>
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator API definitions
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) {
if (!allocator || !(allocator->alloc)) {
return NULL;
@@ -9,8 +15,7 @@ void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) {
return allocator->alloc(size, allocator->obj);
}
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size,
u64 alignment) {
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment) {
if (!allocator || !(allocator->alloc_aligned)) {
return NULL;
}
@@ -18,22 +23,21 @@ void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size,
return allocator->alloc_aligned(size, alignment, allocator->obj);
}
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr,
u64 size) {
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, size, allocator->obj);
return allocator->realloc(ptr, old_size, new_size, allocator->obj);
}
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr,
u64 size, u64 alignment) {
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, size, alignment, allocator->obj);
return allocator->realloc_aligned(ptr, old_size, new_size, alignment, allocator->obj);
}
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr) {

View File

@@ -0,0 +1,55 @@
#ifndef MEM_ALLOCATOR_H
#define MEM_ALLOCATOR_H
#include "aliases.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator function pointer types
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
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, void *alloc_obj);
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator type
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
typedef struct allocator Allocator;
struct allocator {
void *obj;
MemAllocFunc *alloc;
MemAllocAlignedFunc *alloc_aligned;
MemReallocFunc *realloc;
MemReallocAlignedFunc *realloc_aligned;
MemFreeFunc *free;
};
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator API declarations
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
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);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_ALLOCATOR_H

View File

@@ -0,0 +1,145 @@
#include "mem_arena.h"
#include "aliases.h"
#include "misc_utils.h"
#include "mem_utils.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#ifndef DEFAULT_ALIGNMENT
// Why 2 * sizeof(void *) instead of sizeof(void *)
// https://handmade.network/forums/t/6860-alignment_arena_allocator
#define DEFAULT_ALIGNMENT (2 * sizeof(void *))
#endif /* ifndef DEFAULT_ALIGNMENT */
#define ARENA_MINIMUM_CAPACITY KB(16) // Allocate minimum of 4 pages
struct arena {
u8 *buf;
u8 *offset;
u64 capacity;
bool committed;
#ifdef WAPP_PLATFORM_WINDOWS
wapp_misc_utils_padding_size(sizeof(u8 *) * 2 + sizeof(u64) + sizeof(bool));
#endif // ifdef WAPP_PLATFORM_WINDOWS
};
bool wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, bool zero_buffer) {
if (!arena || *arena || base_capacity == 0) {
return false;
}
*arena = (Arena *)calloc(1, sizeof(Arena));
Arena *arena_ptr = *arena;
if (!arena_ptr) {
return false;
}
u64 arena_capacity = base_capacity >= ARENA_MINIMUM_CAPACITY ? base_capacity : ARENA_MINIMUM_CAPACITY;
arena_ptr->buf = (u8 *)wapp_mem_util_alloc(NULL, arena_capacity, WAPP_MEM_ACCESS_READ_WRITE, flags,
zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED);
if (!(arena_ptr->buf)) {
wapp_mem_arena_destroy(arena);
return false;
}
arena_ptr->capacity = arena_capacity;
arena_ptr->offset = arena_ptr->buf;
arena_ptr->committed = (flags & WAPP_MEM_ALLOC_COMMIT) == WAPP_MEM_ALLOC_COMMIT;
return true;
}
void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT);
}
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
if (!arena) {
return NULL;
}
u8 *alloc_start = arena->offset;
u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment);
if (output + size >= arena->buf + arena->capacity) {
return NULL;
}
arena->offset = output + size;
#ifdef WAPP_PLATFORM_WINDOWS
if (!(arena->committed)) {
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);
}
#else
memset(output, 0, size);
#endif // ifdef WAPP_PLATFORM_WINDOWS
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;
}
memset(arena->buf, 0, arena->offset - arena->buf);
arena->offset = arena->buf;
}
void wapp_mem_arena_destroy(Arena **arena) {
if (!arena) {
return;
}
Arena *arena_ptr = *arena;
if (arena_ptr->buf) {
wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity);
}
arena_ptr->buf = arena_ptr->offset = NULL;
arena_ptr->capacity = 0;
free(*arena);
*arena = NULL;
}

View File

@@ -0,0 +1,40 @@
#ifndef MEM_ARENA_H
#define MEM_ARENA_H
#include "aliases.h"
#include "mem_utils.h"
#include <stdbool.h>
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
typedef struct arena Arena;
#define wapp_mem_arena_init(arena_dptr, base_capacity) \
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, false))
#define wapp_mem_arena_init_commit(arena_dptr, base_capacity) \
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
#define wapp_mem_arena_init_zero(arena_dptr, base_capacity) \
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
#define wapp_mem_arena_init_commit_and_zero(arena_dptr, base_capacity) \
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
/**
* Arena initialisation function. `wapp_mem_arena_init_custom` provides the most
* control over how the Arena is initialised. Wrapper macros are provided for
* easier use.
*/
bool wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, bool zero_buffer);
void *wapp_mem_arena_alloc(Arena *arena, u64 size);
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment);
void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 old_size, u64 new_size);
void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment);
void wapp_mem_arena_clear(Arena *arena);
void wapp_mem_arena_destroy(Arena **arena);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_ARENA_H

View File

@@ -0,0 +1,71 @@
#include "mem_arena_allocator.h"
#include "mem_arena.h"
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Arena Allocator wrappers declarations
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
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);
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Arena Allocator API definitions
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
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};
}
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Arena Allocator wrappers definitions
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
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);
}

View File

@@ -0,0 +1,41 @@
#ifndef MEM_ARENA_ALLOCATOR_H
#define MEM_ARENA_ALLOCATOR_H
#include "aliases.h"
#include "mem_utils.h"
#include "mem_allocator.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

View File

@@ -0,0 +1,62 @@
#include "mem_libc_allocator.h"
#include "aliases.h"
#include "mem_allocator.h"
#include <stdlib.h>
#include <string.h>
internal inline void *mem_libc_alloc(u64 size, void *alloc_obj);
// TODO (Abdelrahman): aligned_alloc isn't implemented on Windows. Revisit later
#if 0
internal inline void *mem_libc_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
#endif
internal inline void *mem_libc_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
internal inline void mem_libc_free(void **ptr, void *alloc_obj);
Allocator wapp_mem_libc_allocator(void) {
return (Allocator){
.obj = NULL,
.alloc = mem_libc_alloc,
.alloc_aligned = NULL,
.realloc = mem_libc_realloc,
.realloc_aligned = NULL,
.free = mem_libc_free,
};
}
internal inline void *mem_libc_alloc(u64 size, void *alloc_obj) {
(void)alloc_obj; // Silence unused warnings
return calloc(1, size);
}
#if 0
internal inline void *mem_libc_alloc_aligned(u64 size, u64 alignment,
void *alloc_obj) {
(void)alloc_obj; // Silence unused warnings
void *output = aligned_alloc(alignment, size);
if (output) {
memset(output, 0, size);
}
return output;
}
#endif
internal inline void *mem_libc_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) {
// Silence unused warnings
(void)alloc_obj;
(void)new_size;
return realloc(ptr, old_size);
}
internal inline void mem_libc_free(void **ptr, void *alloc_obj) {
(void)alloc_obj; // Silence unused warnings
if (!ptr || !(*ptr)) {
return;
}
free(*ptr);
*ptr = NULL;
}

View File

@@ -2,14 +2,15 @@
#define MEM_LIBC_H
#include "mem_allocator.h"
#ifdef __cplusplus
extern "C" {
BEGIN_C_LINKAGE
#endif // __cplusplus
Allocator wapp_mem_libc_allocator(void);
#ifdef __cplusplus
}
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_LIBC_H

92
src/os/cpath/cpath.c Normal file
View File

@@ -0,0 +1,92 @@
#include "cpath.h"
#include "aliases.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
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 copy_count = 0;
u64 sep_count = 0;
u64 full_length;
u64 length;
length = full_length = strlen(path);
if (length > 1 && path[length - 1] == PATH_SEP) {
--length;
}
for (i64 i = length - 1; i >= 0; --i) {
if (path[i] == PATH_SEP) {
++sep_count;
copy_count = i + 1;
if (sep_count == levels) {
break;
}
}
}
char tmp[256];
snprintf(tmp, 2, "%c", PATH_SEP);
// NOTE (Abdelrahman): Conditions stored in variables to silence MSVC warning C5045
bool insufficient_levels = sep_count < levels;
bool path_to_copy_is_separator = strncmp(path, tmp, copy_count) != 0;
if (insufficient_levels && path_to_copy_is_separator) {
copy_count = 0;
}
if (dst == path) {
memset(&dst[copy_count], 0, full_length - copy_count);
} else {
u64 dst_length = strlen(dst);
memset(dst, 0, dst_length);
strncpy(dst, path, copy_count);
}
u64 final_length = strlen(dst);
if (final_length > 1) {
dst[final_length - 1] = '\0';
} else if (final_length == 0) {
dst[0] = '.';
}
}
void join_root_and_leaf(const char *root, const char *leaf, char *dst) {
u64 root_length = strlen(root);
u64 leaf_length = strlen(leaf);
memcpy(dst, root, root_length);
if (leaf_length == 0) {
return;
}
u64 copy_start = root_length;
if (root_length > 0 && root[root_length - 1] != PATH_SEP && leaf[0] != PATH_SEP) {
dst[root_length] = PATH_SEP;
++copy_start;
}
memcpy(&(dst[copy_start]), leaf, leaf_length);
}

32
src/os/cpath/cpath.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef CPATH_H
#define CPATH_H
#include "aliases.h"
#include "platform.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 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
END_C_LINKAGE
#endif // __cplusplus
#endif // !CPATH_H

View File

@@ -1,8 +1,19 @@
#include "mem_utils.h"
#include "mem_utils_ops.h"
#include "aliases.h"
#include "platform.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if defined(WAPP_PLATFORM_WINDOWS)
#include "mem_utils_win.h"
#elif defined(WAPP_PLATFORM_POSIX)
#include "mem_utils_posix.h"
#else
#error "Unrecognised platform"
#endif
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
@@ -26,3 +37,17 @@ void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
return (void *)p;
}
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/os/mem/mem_utils.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef MEM_UTILS_H
#define MEM_UTILS_H
#include "aliases.h"
#include "platform.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
#include "mem_utils_ops.h"
#if defined(WAPP_PLATFORM_WINDOWS)
#include "mem_utils_win.h"
#elif defined(WAPP_PLATFORM_POSIX)
#include "mem_utils_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_UTILS_H

View File

@@ -0,0 +1,26 @@
#ifndef MEM_UTILS_OPS_H
#define MEM_UTILS_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_UTILS_OPS_H

View File

@@ -0,0 +1,33 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "mem_utils_ops.h"
#include "mem_utils_posix.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) {
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

View File

@@ -0,0 +1,33 @@
#ifndef MEM_UTILS_POSIX_H
#define MEM_UTILS_POSIX_H
#include "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_UTILS_POSIX_H

View File

@@ -0,0 +1,35 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "mem_utils_ops.h"
#include "mem_utils_win.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

View File

@@ -0,0 +1,27 @@
#ifndef MEM_UTILS_WIN_H
#define MEM_UTILS_WIN_H
#include "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_UTILS_WIN_H

View File

@@ -0,0 +1,118 @@
#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);
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...) {
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 = va_arg(args, const char *);
while (arg) {
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;
arg = va_arg(args, const char *);
}
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);
}
CMDResult output;
CMDError err = get_command_output(fp, out_handling, out_buf, buf_size);
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,
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, (i32)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 if (out_handling == SHELL_OUTPUT_PRINT) {
printf("%s", out);
}
}
return SHELL_ERR_NO_ERROR;
}

View File

@@ -0,0 +1,26 @@
#ifndef COMMANDER_H
#define COMMANDER_H
#include "aliases.h"
#include "commander_output.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})
#define wapp_shell_commander_execute(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, ...) \
run_command(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, __VA_ARGS__, "2>&1", NULL)
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...);
external CMDError get_output_status(FILE *fp, i32 *status_out);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !COMMANDER_H

View File

@@ -0,0 +1,42 @@
#ifndef COMMANDER_OUTPUT_H
#define COMMANDER_OUTPUT_H
#include "aliases.h"
#include "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_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 {
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

View File

@@ -0,0 +1,23 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "commander_output.h"
#include "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

View File

@@ -0,0 +1,22 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "commander_output.h"
#include "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

View File

@@ -0,0 +1,33 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "terminal_colours.h"
#include <stdio.h>
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",
[WAPP_TERM_COLOUR_CLEAR] = "\033[0m",
};
void print_coloured_text(const char *text, TerminalColour colour) {
printf("%s%s", colours[colour], text);
}
#endif // !WAPP_PLATFORM_POSIX

View File

@@ -0,0 +1,14 @@
#include "termcolour.h"
#include "terminal_colours.h"
void wapp_shell_termcolour_print_text(const char *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) {
print_coloured_text("", WAPP_TERM_COLOUR_CLEAR);
}

View File

@@ -0,0 +1,20 @@
#ifndef TERM_COLOUR_H
#define TERM_COLOUR_H
#include "aliases.h"
#include "terminal_colours.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
void wapp_shell_termcolour_print_text(const char *text, TerminalColour colour);
void wapp_shell_termcolour_clear_colour(void);
external void print_coloured_text(const char *text, TerminalColour colour);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !TERM_COLOUR_H

View 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

View File

@@ -0,0 +1,70 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "misc_utils.h"
#include "terminal_colours.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(const char *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("%s", 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

View File

@@ -0,0 +1,15 @@
#ifndef SHELL_UTILS_H
#define SHELL_UTILS_H
#include "platform.h"
#include <stdio.h>
#ifdef WAPP_PLATFORM_WINDOWS
#define wapp_shell_utils_popen _popen
#define wapp_shell_utils_pclose _pclose
#else
#define wapp_shell_utils_popen popen
#define wapp_shell_utils_pclose pclose
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
#endif // !SHELL_UTILS_H

52
src/tester/tester.c Normal file
View File

@@ -0,0 +1,52 @@
#include "tester.h"
#include "aliases.h"
#include "termcolour.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;
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(result_text, colour);
wapp_shell_termcolour_clear_colour();
printf("] %s\n", result.name);
if (!result.passed) {
exit(EXIT_FAILURE);
}
}

33
src/tester/tester.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef TESTER_H
#define TESTER_H
#include "misc_utils.h"
#include "platform.h"
#include <stdbool.h>
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
#define wapp_tester_result(PASSED) ((TestFuncResult){.name = __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;
bool passed;
#ifdef WAPP_PLATFORM_WINDOWS
wapp_misc_utils_padding_size(sizeof(const char *) + sizeof(bool));
#endif // WAPP_PLATFORM_WINDOWS
};
typedef TestFuncResult(TestFunc)(void);
void run_tests(TestFunc *func1, ...);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !TESTER_H

View File

@@ -0,0 +1,37 @@
#include "test_allocator.h"
#include "libc/mem_libc_allocator.h"
#include "mem_allocator.h"
#include "mem_arena_allocator.h"
#include "tester.h"
#include <stdbool.h>
#include <stdlib.h>
TestFuncResult test_libc_allocator(void) {
Allocator allocator = wapp_mem_libc_allocator();
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);
if (ptr != NULL) {
wapp_mem_allocator_free(&allocator, &ptr);
result = result && (ptr == NULL);
}
return wapp_tester_result(result);
}
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);
}

View File

@@ -0,0 +1,17 @@
#ifndef TEST_ALLOCATOR_H
#define TEST_ALLOCATOR_H
#include "tester.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
TestFuncResult test_libc_allocator(void);
TestFuncResult test_arena_allocator(void);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !TEST_ALLOCATOR_H

115
tests/arena/test_arena.c Normal file
View File

@@ -0,0 +1,115 @@
#include "test_arena.h"
#include "aliases.h"
#include "mem_arena.h"
#include "misc_utils.h"
#include "tester.h"
#include <stdbool.h>
#include <stdlib.h>
#define ARENA_CAPACITY KB(16)
internal Arena *arena = NULL;
internal i32 count = 20;
internal i32 *array = NULL;
TestFuncResult test_arena_init(void) {
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 = GB(512);
bool result = wapp_mem_arena_init(&large_arena, capacity);
if (result) {
wapp_mem_arena_destroy(&large_arena);
}
return wapp_tester_result(result);
}
TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void) {
array = wapp_mem_arena_alloc(arena, count * sizeof(i32));
bool result = array != NULL;
for (i32 i = 0; i < count; ++i) {
array[i] = i * 10;
}
return wapp_tester_result(result);
}
TestFuncResult test_arena_alloc_fails_when_over_capacity(void) {
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;
for (i32 i = 0; i < count; ++i) {
if (array[i] != 0) {
result = false;
break;
}
}
return wapp_tester_result(result);
}
TestFuncResult test_arena_destroy(void) {
wapp_mem_arena_destroy(&arena);
bool result = arena == NULL;
return wapp_tester_result(result);
}

23
tests/arena/test_arena.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef TEST_ARENA_H
#define TEST_ARENA_H
#include "tester.h"
#ifdef __cplusplus
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

183
tests/cpath/test_cpath.c Normal file
View File

@@ -0,0 +1,183 @@
#include "test_cpath.h"
#include "cpath.h"
#include "tester.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) {
char expected[MAIN_BUF_SIZE] = {0};
char out[MAIN_BUF_SIZE] = {0};
char tmp[TMP_BUF_SIZE] = {0};
snprintf(expected, MAIN_BUF_SIZE, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
snprintf(tmp, 2, "%c", PATH_SEP);
wapp_cpath_join_path(out, tmp, "home", "abdelrahman", "Documents");
bool result = strcmp(out, expected) == 0;
if (!result) {
goto TEST_JOIN_PATH_EXIT;
}
memset(out, 0, strlen(out));
snprintf(expected, MAIN_BUF_SIZE, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
wapp_cpath_join_path(out, "home", "abdelrahman", "Documents");
result = result && strcmp(out, expected) == 0;
if (!result) {
goto TEST_JOIN_PATH_EXIT;
}
memset(out, 0, strlen(out));
memset(tmp, 0, strlen(tmp));
snprintf(expected, MAIN_BUF_SIZE, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
snprintf(tmp, TMP_BUF_SIZE, "%chome", PATH_SEP);
wapp_cpath_join_path(out, tmp, "abdelrahman", "Documents");
result = result && strcmp(out, expected) == 0;
if (!result) {
goto TEST_JOIN_PATH_EXIT;
}
memset(out, 0, strlen(out));
memset(tmp, 0, strlen(tmp));
snprintf(expected, MAIN_BUF_SIZE, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
snprintf(tmp, TMP_BUF_SIZE, "home%c", PATH_SEP);
wapp_cpath_join_path(out, tmp, "abdelrahman", "Documents");
result = result && strcmp(out, expected) == 0;
if (!result) {
goto TEST_JOIN_PATH_EXIT;
}
memset(out, 0, strlen(out));
memset(tmp, 0, strlen(tmp));
snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP);
snprintf(tmp, TMP_BUF_SIZE, "%chome", PATH_SEP);
wapp_cpath_join_path(out, tmp, "");
result = result && strcmp(out, expected) == 0;
if (!result) {
goto TEST_JOIN_PATH_EXIT;
}
memset(out, 0, strlen(out));
snprintf(expected, 1, "");
wapp_cpath_join_path(out, "", "");
result = result && strcmp(out, expected) == 0;
if (!result) {
goto TEST_JOIN_PATH_EXIT;
}
memset(out, 0, strlen(out));
snprintf(expected, MAIN_BUF_SIZE, "home");
wapp_cpath_join_path(out, "", "home");
result = result && strcmp(out, expected) == 0;
TEST_JOIN_PATH_EXIT:
return wapp_tester_result(result);
}
TestFuncResult test_cpath_dirname(void) {
char dst[MAIN_BUF_SIZE] = {0};
char expected[MAIN_BUF_SIZE] = {0};
char tmp[TMP_BUF_SIZE] = {0};
snprintf(tmp, 2, "%c", PATH_SEP);
wapp_cpath_dirname(dst, tmp);
bool result = strcmp(dst, tmp) == 0;
if (!result) {
goto TEST_DIRNAME_EXIT;
}
memset(dst, 0, strlen(dst));
wapp_cpath_dirname(dst, "home");
result = strcmp(dst, ".") == 0;
if (!result) {
goto TEST_DIRNAME_EXIT;
}
memset(dst, 0, strlen(dst));
wapp_cpath_dirname(dst, "");
result = strcmp(dst, ".") == 0;
if (!result) {
goto TEST_DIRNAME_EXIT;
}
memset(dst, 0, strlen(dst));
snprintf(tmp, TMP_BUF_SIZE, "%chome%ctest", PATH_SEP, PATH_SEP);
snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP);
wapp_cpath_dirname(dst, tmp);
result = strcmp(dst, expected) == 0;
if (!result) {
goto TEST_DIRNAME_EXIT;
}
memset(dst, 0, strlen(dst));
memset(tmp, 0, strlen(tmp));
memset(expected, 0, strlen(expected));
snprintf(tmp, TMP_BUF_SIZE, "%chome%ctest%c", PATH_SEP, PATH_SEP, PATH_SEP);
snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP);
wapp_cpath_dirname(dst, tmp);
result = strcmp(dst, expected) == 0;
TEST_DIRNAME_EXIT:
return wapp_tester_result(result);
}
TestFuncResult test_cpath_dirup(void) {
char dst[MAIN_BUF_SIZE] = {0};
char expected[MAIN_BUF_SIZE] = {0};
char tmp[TMP_BUF_SIZE] = {0};
snprintf(tmp, 2, "%c", PATH_SEP);
wapp_cpath_dirup(dst, 3, tmp);
bool result = strcmp(dst, tmp) == 0;
if (!result) {
goto TEST_DIRUP_EXIT;
}
memset(dst, 0, strlen(dst));
memset(tmp, 0, strlen(tmp));
snprintf(tmp, TMP_BUF_SIZE, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
snprintf(expected, MAIN_BUF_SIZE, "%c", PATH_SEP);
wapp_cpath_dirup(dst, 3, tmp);
result = strcmp(dst, expected) == 0;
if (!result) {
goto TEST_DIRUP_EXIT;
}
memset(dst, 0, strlen(dst));
memset(tmp, 0, strlen(tmp));
snprintf(tmp, TMP_BUF_SIZE, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
wapp_cpath_dirup(dst, 3, tmp);
result = strcmp(dst, ".") == 0;
if (!result) {
goto TEST_DIRUP_EXIT;
}
memset(dst, 0, strlen(dst));
memset(tmp, 0, strlen(tmp));
memset(expected, 0, strlen(expected));
snprintf(tmp, TMP_BUF_SIZE, "%chome%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP, PATH_SEP);
snprintf(expected, MAIN_BUF_SIZE, "%chome", PATH_SEP);
wapp_cpath_dirup(dst, 2, tmp);
result = strcmp(dst, expected) == 0;
if (!result) {
goto TEST_DIRUP_EXIT;
}
memset(dst, 0, strlen(dst));
memset(tmp, 0, strlen(tmp));
snprintf(tmp, TMP_BUF_SIZE, "home%cabdelrahman%cDocuments", PATH_SEP, PATH_SEP);
wapp_cpath_dirup(dst, 2, tmp);
result = strcmp(dst, "home") == 0;
TEST_DIRUP_EXIT:
return wapp_tester_result(result);
}

18
tests/cpath/test_cpath.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef TEST_CPATH_H
#define TEST_CPATH_H
#include "tester.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

View File

@@ -0,0 +1,49 @@
#include "test_shell_commander.h"
#include "commander.h"
#include "tester.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
TestFuncResult test_commander_cmd_success(void) {
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, 0, "echo", "hello world");
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) {
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, 0, "grep");
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) {
char buf[64] = {0};
char expected_output[64] = {0};
const char *msg = "hello world";
u64 length = strlen(msg);
snprintf(expected_output, length + 2, "%s\n", msg);
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, buf, 64, "echo", msg);
bool succeeded = result.exited && result.exit_code == EXIT_SUCCESS &&
result.error == SHELL_ERR_NO_ERROR &&
strncmp(buf, expected_output, length) == 0;
return wapp_tester_result(succeeded);
}
TestFuncResult test_commander_cmd_out_buf_failure(void) {
char buf[4] = {0};
const char *msg = "hello world";
u64 length = strlen(msg);
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, buf, 4, "echo", msg);
bool failed = !result.exited && result.exit_code != EXIT_SUCCESS &&
result.error == SHELL_ERR_OUT_BUF_FULL && strncmp(buf, msg, length) != 0;
return wapp_tester_result(failed);
}

View File

@@ -0,0 +1,19 @@
#ifndef TEST_SHELL_COMMANDER_H
#define TEST_SHELL_COMMANDER_H
#include "tester.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

18
tests/wapptest.c Normal file
View File

@@ -0,0 +1,18 @@
#include "test_allocator.h"
#include "test_arena.h"
#include "test_cpath.h"
#include "test_shell_commander.h"
#include "tester.h"
#include <stdlib.h>
int main(void) {
wapp_tester_run_tests(test_libc_allocator, test_arena_allocator, test_arena_init,
test_arena_init_succeeds_when_reserving_very_large_size, test_cpath_join_path,
test_cpath_dirname, test_cpath_dirup, test_arena_alloc_succeeds_when_within_capacity,
test_arena_alloc_fails_when_over_capacity, test_arena_realloc_bigger_size,
test_arena_realloc_smaller_size, test_arena_clear, test_arena_destroy,
test_commander_cmd_success, test_commander_cmd_failure,
test_commander_cmd_out_buf_success, test_commander_cmd_out_buf_failure);
return EXIT_SUCCESS;
}