Compare commits
16 Commits
growing_ar
...
7fb13f2439
Author | SHA1 | Date | |
---|---|---|---|
7fb13f2439 | |||
0b63bc746d | |||
6ee3c762df | |||
59f1c3eb58 | |||
55d0c25c90 | |||
cfc98e0137 | |||
|
32877cdeaa | ||
|
7e2d7b28b7 | ||
23886f40e8 | |||
57de75c1f8 | |||
9807334ac9 | |||
18448dd7c1 | |||
62fdef8601 | |||
61c29ee564 | |||
36bc8ab54a | |||
a8e5913254 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
.cache
|
||||
.vscode
|
||||
test
|
||||
test.*
|
||||
*.dSYM
|
||||
compile_commands.json
|
||||
libwapp.so
|
||||
|
63
compile
63
compile
@@ -1,13 +1,66 @@
|
||||
#!/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{} ") \
|
||||
$(find src -type d | xargs -I{} echo -n "-I{} ") \
|
||||
"
|
||||
TEST_INCLUDE="\
|
||||
$(find tests -type d | xargs -I{} echo -n "-I{} ") \
|
||||
"
|
||||
SRC="\
|
||||
$(find src -type f -name *.c | xargs -I{} echo -n "{} ") \
|
||||
$(find src -type f -name "*.c" | xargs -I{} echo -n "{} ") \
|
||||
"
|
||||
TEST_SRC="\
|
||||
$(find tests -type f -name "*.c" | xargs -I{} echo -n "{} ") \
|
||||
"
|
||||
CFLAGS="-O3 -shared -fPIC -Wall -Werror -pedantic"
|
||||
OUT="libwapp.so"
|
||||
|
||||
(set -x ; $CC $CFLAGS $INCLUDE $SRC -o $OUT)
|
||||
if [[ $BUILD_TYPE == "release" ]]; then
|
||||
CFLAGS+="-O3"
|
||||
else
|
||||
CFLAGS+="-g -fsanitize=address -fsanitize=undefined"
|
||||
fi
|
||||
|
||||
OUT="libwapp.so"
|
||||
TEST_OUT="./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)
|
||||
|
||||
# Compile test.c if it exists
|
||||
if [[ -f ./test.c ]]; then
|
||||
(set -x ; $CC $CFLAGS $INCLUDE $SRC ./test.c -o test)
|
||||
fi
|
||||
|
@@ -13,30 +13,16 @@
|
||||
|
||||
#define ARENA_MINIMUM_CAPACITY 1024
|
||||
|
||||
typedef struct base_arena BaseArena;
|
||||
struct base_arena {
|
||||
struct arena {
|
||||
u8 *buf;
|
||||
u8 *offset;
|
||||
u64 capacity;
|
||||
BaseArena *prev;
|
||||
BaseArena *next;
|
||||
};
|
||||
|
||||
struct growing_arena {
|
||||
BaseArena *active_arena;
|
||||
u64 count;
|
||||
u64 initial_capacity;
|
||||
};
|
||||
|
||||
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_destroy(BaseArena *arena);
|
||||
|
||||
// PUBLIC API
|
||||
|
||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) {
|
||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
|
||||
bool zero_buffer) {
|
||||
if (!arena || *arena || base_capacity == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -47,19 +33,21 @@ bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
arena_ptr->active_arena = (BaseArena *)calloc(1, sizeof(BaseArena));
|
||||
if (!(arena_ptr->active_arena)) {
|
||||
u64 arena_capacity = base_capacity >= ARENA_MINIMUM_CAPACITY
|
||||
? base_capacity
|
||||
: ARENA_MINIMUM_CAPACITY;
|
||||
|
||||
arena_ptr->buf = (u8 *)wapp_mem_util_alloc(
|
||||
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;
|
||||
}
|
||||
|
||||
if (!base_arena_init(arena_ptr->active_arena, base_capacity)) {
|
||||
wapp_mem_arena_destroy(arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
arena_ptr->count = 1;
|
||||
arena_ptr->initial_capacity = base_capacity;
|
||||
arena_ptr->capacity = arena_capacity;
|
||||
arena_ptr->offset = arena_ptr->buf;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -69,130 +57,6 @@ void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
|
||||
}
|
||||
|
||||
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_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_destroy(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_destroy(current);
|
||||
free(current);
|
||||
|
||||
current = next;
|
||||
}
|
||||
|
||||
current = arena_ptr->active_arena->prev;
|
||||
while (current) {
|
||||
prev = current->prev;
|
||||
|
||||
base_arena_destroy(current);
|
||||
free(current);
|
||||
|
||||
current = prev;
|
||||
}
|
||||
|
||||
base_arena_destroy(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 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;
|
||||
}
|
||||
@@ -206,10 +70,12 @@ internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
|
||||
|
||||
arena->offset = output + size;
|
||||
|
||||
memset(output, 0, size);
|
||||
|
||||
return (void *)output;
|
||||
}
|
||||
|
||||
internal void base_arena_clear(BaseArena *arena) {
|
||||
void wapp_mem_arena_clear(Arena *arena) {
|
||||
if (!arena) {
|
||||
return;
|
||||
}
|
||||
@@ -218,16 +84,19 @@ internal void base_arena_clear(BaseArena *arena) {
|
||||
arena->offset = arena->buf;
|
||||
}
|
||||
|
||||
internal void base_arena_destroy(BaseArena *arena) {
|
||||
void wapp_mem_arena_destroy(Arena **arena) {
|
||||
if (!arena) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arena->buf) {
|
||||
free(arena->buf);
|
||||
Arena *arena_ptr = *arena;
|
||||
if (arena_ptr->buf) {
|
||||
wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity);
|
||||
}
|
||||
|
||||
arena->buf = arena->offset = NULL;
|
||||
arena->capacity = 0;
|
||||
arena->prev = arena->next = NULL;
|
||||
arena_ptr->buf = arena_ptr->offset = NULL;
|
||||
arena_ptr->capacity = 0;
|
||||
|
||||
free(*arena);
|
||||
*arena = NULL;
|
||||
}
|
||||
|
@@ -2,15 +2,17 @@
|
||||
#define MEM_ARENA_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "mem_utils.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct growing_arena Arena;
|
||||
typedef struct arena Arena;
|
||||
|
||||
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity);
|
||||
bool wapp_mem_arena_init(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_clear(Arena *arena);
|
||||
|
@@ -1,8 +1,43 @@
|
||||
#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)
|
||||
#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(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(u64 size, MemAccess access,
|
||||
MemAllocFlags flags);
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
|
||||
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
||||
|
||||
@@ -26,3 +61,54 @@ void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
||||
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
void *wapp_mem_util_alloc(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(size, access, flags);
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
void *output = alloc_posix(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(u64 size, MemAccess access,
|
||||
MemAllocFlags flags) {
|
||||
return VirtualAlloc2(NULL, NULL, (SIZE_T)size, flags, access_types[access]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WAPP_PLATFORM_POSIX)
|
||||
internal inline void *alloc_posix(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(NULL, size, access_types[access], alloc_flags, -1, 0);
|
||||
}
|
||||
#endif
|
||||
|
@@ -2,12 +2,56 @@
|
||||
#define MEM_UTILS_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
#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(u64 size, MemAccess access, MemAllocFlags flags,
|
||||
MemInitType type);
|
||||
void wapp_mem_util_free(void *ptr, u64 size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
63
src/platform/platform.h
Normal file
63
src/platform/platform.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
// clang-format off
|
||||
#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
|
||||
// clang-format on
|
||||
|
||||
#endif // !PLATFORM_H
|
48
src/termcolour/termcolour.h
Normal file
48
src/termcolour/termcolour.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef TERM_COLOUR_H
|
||||
#define TERM_COLOUR_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
// clang-format off
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
#define TERM_COLOUR_CLEAR ""
|
||||
#define TERM_COLOUR_BOLD ""
|
||||
#define TERM_COLOUR_FG_BLACK ""
|
||||
#define TERM_COLOUR_FG_RED ""
|
||||
#define TERM_COLOUR_FG_GREEN ""
|
||||
#define TERM_COLOUR_FG_YELLOW ""
|
||||
#define TERM_COLOUR_FG_BLUE ""
|
||||
#define TERM_COLOUR_FG_MAGENTA ""
|
||||
#define TERM_COLOUR_FG_CYAN ""
|
||||
#define TERM_COLOUR_FG_WHITE ""
|
||||
#define TERM_COLOUR_FG_BR_BLACK ""
|
||||
#define TERM_COLOUR_FG_BR_RED ""
|
||||
#define TERM_COLOUR_FG_BR_GREEN ""
|
||||
#define TERM_COLOUR_FG_BR_YELLOW ""
|
||||
#define TERM_COLOUR_FG_BR_BLUE ""
|
||||
#define TERM_COLOUR_FG_BR_MAGENTA ""
|
||||
#define TERM_COLOUR_FG_BR_CYAN ""
|
||||
#define TERM_COLOUR_FG_BR_WHITE ""
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
#define TERM_COLOUR_CLEAR "\033[0m"
|
||||
#define TERM_COLOUR_BOLD "\033[1m"
|
||||
#define TERM_COLOUR_FG_BLACK "\033[30m"
|
||||
#define TERM_COLOUR_FG_RED "\033[31m"
|
||||
#define TERM_COLOUR_FG_GREEN "\033[32m"
|
||||
#define TERM_COLOUR_FG_YELLOW "\033[33m"
|
||||
#define TERM_COLOUR_FG_BLUE "\033[34m"
|
||||
#define TERM_COLOUR_FG_MAGENTA "\033[35m"
|
||||
#define TERM_COLOUR_FG_CYAN "\033[36m"
|
||||
#define TERM_COLOUR_FG_WHITE "\033[37m"
|
||||
#define TERM_COLOUR_FG_BR_BLACK "\033[90m"
|
||||
#define TERM_COLOUR_FG_BR_RED "\033[91m"
|
||||
#define TERM_COLOUR_FG_BR_GREEN "\033[92m"
|
||||
#define TERM_COLOUR_FG_BR_YELLOW "\033[93m"
|
||||
#define TERM_COLOUR_FG_BR_BLUE "\033[94m"
|
||||
#define TERM_COLOUR_FG_BR_MAGENTA "\033[95m"
|
||||
#define TERM_COLOUR_FG_BR_CYAN "\033[96m"
|
||||
#define TERM_COLOUR_FG_BR_WHITE "\033[97m"
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#endif // !TERM_COLOUR_H
|
48
src/tester/tester.c
Normal file
48
src/tester/tester.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "tester.h"
|
||||
#include "aliases.h"
|
||||
#include "termcolour/termcolour.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
internal void print_test_result(TestFuncResult result);
|
||||
|
||||
void run_tests(TestFunc *func1, ...) {
|
||||
printf("\n");
|
||||
|
||||
print_test_result(func1());
|
||||
|
||||
va_list args;
|
||||
va_start(args, func1);
|
||||
|
||||
TestFunc *func = NULL;
|
||||
|
||||
while ((func = va_arg(args, TestFunc *))) {
|
||||
TestFuncResult result = func();
|
||||
print_test_result(result);
|
||||
|
||||
if (!result.success) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
internal void print_test_result(TestFuncResult result) {
|
||||
const char *colour;
|
||||
const char *result_text;
|
||||
|
||||
if (result.success) {
|
||||
colour = TERM_COLOUR_FG_BR_GREEN;
|
||||
result_text = "PASSED";
|
||||
} else {
|
||||
colour = TERM_COLOUR_FG_BR_RED;
|
||||
result_text = "FAILED";
|
||||
}
|
||||
|
||||
printf("[%s%s%s%s] %s\n", colour, TERM_COLOUR_BOLD, result_text,
|
||||
TERM_COLOUR_CLEAR, result.name);
|
||||
}
|
26
src/tester/tester.h
Normal file
26
src/tester/tester.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef TESTER_H
|
||||
#define TESTER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define TEST_RESULT(BOOL) ((TestFuncResult){.name = __func__, .success = BOOL})
|
||||
|
||||
typedef struct test_func_result TestFuncResult;
|
||||
struct test_func_result {
|
||||
const char *name;
|
||||
bool success;
|
||||
};
|
||||
|
||||
typedef TestFuncResult(TestFunc)(void);
|
||||
|
||||
void run_tests(TestFunc *func1, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TESTER_H
|
59
tests/arena/test_arena.c
Normal file
59
tests/arena/test_arena.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "test_arena.h"
|
||||
#include "aliases.h"
|
||||
#include "mem_arena.h"
|
||||
#include "mem_utils.h"
|
||||
#include "tester.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARENA_CAPACITY 1024
|
||||
|
||||
internal Arena *arena = NULL;
|
||||
internal u64 count = 20;
|
||||
internal i32 *array = NULL;
|
||||
|
||||
TestFuncResult test_arena_init(void) {
|
||||
bool result = wapp_mem_arena_init(&arena, ARENA_CAPACITY,
|
||||
WAPP_MEM_ALLOC_RESERVE, false);
|
||||
|
||||
return TEST_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 (u64 i = 0; i < count; ++i) {
|
||||
array[i] = i * 10;
|
||||
}
|
||||
|
||||
return TEST_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 TEST_RESULT(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_clear(void) {
|
||||
wapp_mem_arena_clear(arena);
|
||||
bool result = true;
|
||||
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
if (array[i] != 0) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TEST_RESULT(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_destroy(void) {
|
||||
wapp_mem_arena_destroy(&arena);
|
||||
bool result = arena == NULL;
|
||||
|
||||
return TEST_RESULT(result);
|
||||
}
|
20
tests/arena/test_arena.h
Normal file
20
tests/arena/test_arena.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef TEST_ARENA_H
|
||||
#define TEST_ARENA_H
|
||||
|
||||
#include "tester.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
TestFuncResult test_arena_init(void);
|
||||
TestFuncResult test_arena_alloc_succeeds_when_within_capacity(void);
|
||||
TestFuncResult test_arena_alloc_fails_when_over_capacity(void);
|
||||
TestFuncResult test_arena_clear(void);
|
||||
TestFuncResult test_arena_destroy(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !TEST_ARENA_H
|
11
tests/wapptest.c
Normal file
11
tests/wapptest.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "test_arena.h"
|
||||
#include "tester.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
run_tests(test_arena_init, test_arena_alloc_succeeds_when_within_capacity,
|
||||
test_arena_alloc_fails_when_over_capacity, test_arena_clear,
|
||||
test_arena_destroy);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user