Compare commits
285 Commits
growing_ar
...
d79e7615a1
| Author | SHA1 | Date | |
|---|---|---|---|
| d79e7615a1 | |||
| 80d79fca53 | |||
| e90901406e | |||
| 80308172ec | |||
| 4805b183e8 | |||
| d36812e632 | |||
| 4b95a681d4 | |||
| c0d901d7e9 | |||
| 31727dd6e7 | |||
| af56a5be3f | |||
| e16abc2459 | |||
| 05b7cfbbea | |||
| a5928b03c9 | |||
| a9c6b8ba72 | |||
| c6560ab7f5 | |||
| 04858b76c0 | |||
| e3c1283017 | |||
| b55a3ff5d8 | |||
| 50b6a0b0f7 | |||
| 6b7421c25d | |||
| ec0ab2170c | |||
| efadbf5fc2 | |||
| 056dbbf3d7 | |||
| b11ee05df4 | |||
| de9ce5791a | |||
| 331f7e5e4e | |||
| ae7a8d4bab | |||
| 9c5b95c229 | |||
|
|
432e4a48d5 | ||
| 1bdc1ad955 | |||
| 0a00721c10 | |||
| 725955cb2e | |||
| 0354c7b485 | |||
| 9f32891bbc | |||
| b3ebff3635 | |||
| 14bd6ce5fd | |||
| 09e96f8112 | |||
|
|
9cbd0b29ef | ||
| 26fd329caa | |||
| 1e224702a3 | |||
| 74cca183e0 | |||
| e26bf613a5 | |||
|
|
81e3ab2c67 | ||
|
|
8ec0757b34 | ||
|
|
eb98de7c2b | ||
| d3fccd61b5 | |||
| 011083ab83 | |||
| b8c548ee4b | |||
| 75be2316e0 | |||
|
|
d452225d02 | ||
| 74164717d0 | |||
| 6c8434a530 | |||
| cac66b9dbb | |||
| 175f627f93 | |||
| be30189d15 | |||
| 3689c17d09 | |||
| 8e952d9bc8 | |||
| def7576101 | |||
| 3fed536a74 | |||
| aae39fe656 | |||
| 4e3945d1d0 | |||
| 98a802e3eb | |||
| 0d4aa7a9c2 | |||
| a229f9be8c | |||
| 2156d2ff3a | |||
| 12f083edb0 | |||
| f444911452 | |||
| 163283f77f | |||
| 6064ed346c | |||
| 77f3c40ebd | |||
| d3f1686d58 | |||
| a359331df7 | |||
| 14115f7e7e | |||
| 12bd3eb489 | |||
| 266d43e262 | |||
| a568b30163 | |||
| b1773746d8 | |||
| a479a43f4c | |||
| b476ceaeef | |||
| 4d69b97149 | |||
| 181c4b8614 | |||
| 0d541f6ee8 | |||
| 9e34b37d8d | |||
| b884d0e6a6 | |||
| 494bbeb398 | |||
| 7605eb4e57 | |||
| 037b0fe698 | |||
| b13274cd81 | |||
| 4f9f632362 | |||
| 6b039aeac0 | |||
| 2ab3bfc2e1 | |||
| bf99bef291 | |||
| 50e23d8a13 | |||
| 3a49dba366 | |||
| 1cfc52b35e | |||
| 25395553d7 | |||
| 9a651665ba | |||
| 8dbdfa2094 | |||
| add2ba541d | |||
| 63ed2633ea | |||
|
|
3c32b247c0 | ||
|
|
aa04fab6ea | ||
|
|
2017f6de79 | ||
|
|
63acdd1336 | ||
|
|
cfa8094260 | ||
|
|
31373eba03 | ||
|
|
778a4da092 | ||
|
|
6fb078a868 | ||
| 0942643b4e | |||
|
|
0e5942af34 | ||
|
|
c83c652b37 | ||
|
|
74428f1caf | ||
|
|
d661312cfa | ||
| 70e075d2f6 | |||
| 96db885344 | |||
| fb512e4a15 | |||
| 9361f0fe37 | |||
| e7d2553400 | |||
| 509724cc31 | |||
|
|
82c23eed5e | ||
|
|
9403193f09 | ||
|
|
fa1d9eec0d | ||
|
|
4c14588d92 | ||
|
|
9e66bd60bd | ||
|
|
ce4957d0a0 | ||
| b9ea290322 | |||
| 1479c13417 | |||
| 4520f2269d | |||
| 6119cf5c5f | |||
| 358f61e556 | |||
| 7ac6100a5a | |||
| 19efb08a3a | |||
| 491c742189 | |||
| 4f5dd3900f | |||
| dbedcb3100 | |||
| d9314fb41e | |||
| fe2bb65b06 | |||
| ed4ec54c7a | |||
| ba5e902a1d | |||
| 01f066d20c | |||
| 80bd68f313 | |||
| cda7e413e2 | |||
| 54da75f89f | |||
| 7df64a3168 | |||
| f9f8f092b5 | |||
| f89a4bf343 | |||
| 0d795cc0d9 | |||
| 28ac9ed8c8 | |||
| 99f7dcd794 | |||
| c5ca39939d | |||
| a308359942 | |||
| a3d9bcf1a1 | |||
|
|
a534d44db5 | ||
| 11949e69be | |||
| 2c9e4c91a0 | |||
| 76b078fbc0 | |||
| 0569fca193 | |||
| 6078e54087 | |||
| 180425707b | |||
| 62dcfdaa93 | |||
| 19134d0e15 | |||
| ca2b1cbf23 | |||
| f60442bfcf | |||
| a4a1e82c40 | |||
| d50b41acac | |||
| 71b6242f16 | |||
| 241edfc7e4 | |||
| d635e03cd8 | |||
| 68fe421ab0 | |||
| 622a4391a0 | |||
| ff4d3c9e99 | |||
| 023c74d8d9 | |||
| 86fe867011 | |||
| 98829b8400 | |||
| a7e98211f9 | |||
| 4642361969 | |||
| 093d0daf6f | |||
| f8e0804dd2 | |||
| fdb0650634 | |||
| d1d6a8e64b | |||
| bbf38499ca | |||
| 7657ad1b58 | |||
| 70399cb797 | |||
| 76c3b02e45 | |||
| abf9b09495 | |||
| 6d09059911 | |||
| 894ae028b7 | |||
| 84a4ec223c | |||
| 8f10ac2916 | |||
| bfb4e87a1e | |||
| 685682e1c8 | |||
| 40d301fd95 | |||
| 7d8df816a5 | |||
| 17f0f0eaf3 | |||
| ce656a6275 | |||
| 8d8fcf9dc5 | |||
| 77e634ec2d | |||
| 22ece7215a | |||
| 4af4b39d6f | |||
| a48002996e | |||
| e9451f10f8 | |||
| 1de3608b1f | |||
| 3a25571105 | |||
| 139b4ca589 | |||
| e431cf729e | |||
| 1d1c3ca928 | |||
| f2f155744a | |||
| d3a86ec6cb | |||
| e053aa44ab | |||
| a546a09565 | |||
| 12f182f0cf | |||
| ffb99a3644 | |||
| 1ddc5610f9 | |||
| d8c7b3162f | |||
| 9e1e4688e4 | |||
| cd38672581 | |||
| 7fea236618 | |||
| 16a1b8fa35 | |||
| a0dfe8acd0 | |||
| 95c47ec940 | |||
| 46f32f2ba9 | |||
| 8f794dee15 | |||
| 034b105ea1 | |||
| c90874ad10 | |||
| 8468bb8e28 | |||
| d30eee0cf8 | |||
| 59e56a75d3 | |||
| 5d6ce1d2c3 | |||
| ce537b7494 | |||
| b8f6e5f187 | |||
| 775f0864a8 | |||
| 8b6fb23bac | |||
| 1fb340561f | |||
| 8ed372d938 | |||
| 8a91a0ec6b | |||
| 802b70f5ee | |||
| 92c2439b56 | |||
| 781a46713b | |||
| 7c4725edef | |||
| 4fc99f76a5 | |||
| 25ab75f74f | |||
| f6dd7e7aa8 | |||
| 8f5bee45c6 | |||
| 25964d9a3c | |||
| d9cf98da73 | |||
| 8c153b5321 | |||
| 3c4112d080 | |||
| aa28dd481b | |||
| 42187beee5 | |||
| 8cc17f1490 | |||
| b4c1301600 | |||
| 2c556e12f1 | |||
| 6c82898225 | |||
| a85508e0a4 | |||
| cd78913e83 | |||
| a0acada9b4 | |||
| 8eaa4afed1 | |||
| 1ce07e9e4e | |||
| 162b255e1b | |||
| 99a9cd10f5 | |||
| 7e1c25b649 | |||
| 9008e10651 | |||
| d27fc14b31 | |||
| dbdab01a2c | |||
| cf12144230 | |||
| ccc86342cd | |||
|
|
8d89695fcc | ||
|
|
6499dd7be9 | ||
| 75bbb82058 | |||
| 7fb13f2439 | |||
| 0b63bc746d | |||
| 6ee3c762df | |||
| 59f1c3eb58 | |||
| 55d0c25c90 | |||
| cfc98e0137 | |||
|
|
32877cdeaa | ||
|
|
7e2d7b28b7 | ||
| 23886f40e8 | |||
| 57de75c1f8 | |||
| 9807334ac9 | |||
| 18448dd7c1 | |||
| 62fdef8601 | |||
| 61c29ee564 | |||
| 36bc8ab54a | |||
| a8e5913254 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -1,4 +1,14 @@
|
||||
.cache
|
||||
.vscode
|
||||
.venv
|
||||
test
|
||||
test.*
|
||||
*.dSYM
|
||||
.DS_Store
|
||||
*.pdb
|
||||
*.obj
|
||||
compile_commands.json
|
||||
libwapp.so
|
||||
libwapp-build
|
||||
dist
|
||||
*.vs
|
||||
__pycache__
|
||||
|
||||
180
Makefile
Normal file
180
Makefile
Normal file
@@ -0,0 +1,180 @@
|
||||
.PHONY: help full base os prng testing uuid all clean builddir build-test run-test install build-lib ccodegen
|
||||
|
||||
# External variables
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
AR = ar
|
||||
BUILD_TYPE = Debug
|
||||
BUILD_DIR = libwapp-build/$(PLATFORM)-$(BUILD_TYPE)
|
||||
INSTALL_PREFIX = dist
|
||||
RUNTIME_ASSERT = true
|
||||
|
||||
# Internal variables
|
||||
override CFLAGS = -Wall -Wextra -Werror -pedantic -Isrc
|
||||
override LIBFLAGS = -fPIC
|
||||
override CSTD := -std=gnu11
|
||||
override CXXSTD := -std=gnu++11
|
||||
override KERNEL := $(shell uname -s)
|
||||
override MACHINE := $(shell uname -m)
|
||||
override PLATFORM := $(KERNEL)_$(MACHINE)
|
||||
override TEST_INCLUDE := -Isrc $(shell find tests -type d | xargs -I{} echo -n "-I{} ")
|
||||
override TEST_SRC := $(shell find tests -type f -name "*.c" | xargs -I{} echo -n "{} ")
|
||||
override TEST_C_SRC := src/wapp.c $(TEST_SRC)
|
||||
override TEST_CXX_SRC := $(shell find tests -type f -name "*.cc" | xargs -I{} echo -n "{} ")
|
||||
override LIB_NAME := wapp
|
||||
override OBJ_OUT := $(BUILD_DIR)/$(LIB_NAME).o
|
||||
override LIB_OUT := $(BUILD_DIR)/lib$(LIB_NAME).a
|
||||
override TEST_C_OUT := $(BUILD_DIR)/wapptest
|
||||
override TEST_CXX_OUT := $(BUILD_DIR)/wapptestcc
|
||||
override ABS_INSTALL_PREFIX := $(shell mkdir -p $(INSTALL_PREFIX) && realpath $(INSTALL_PREFIX))
|
||||
override INCLUDE_INSTALL := $(ABS_INSTALL_PREFIX)/include/$(LIB_NAME)
|
||||
override LIB_INSTALL := $(ABS_INSTALL_PREFIX)/lib
|
||||
override HEADER_INSTALL_CMD := scripts/header_install.sh
|
||||
|
||||
ifeq ($(origin BUILD_FLAGS), undefined)
|
||||
ifeq ($(BUILD_TYPE),Debug)
|
||||
BUILD_FLAGS += -g -fsanitize=address,undefined -DWAPP_DEBUG_ASSERT
|
||||
else ifeq ($(BUILD_TYPE),RelWithDebInfo)
|
||||
BUILD_FLAGS += -g -O2 -fsanitize=address,undefined -DWAPP_DEBUG_ASSERT
|
||||
else ifeq ($(BUILD_TYPE),Release)
|
||||
BUILD_FLAGS += -O3
|
||||
else
|
||||
$(error Invalid BUILD type '$(BUILD_TYPE)'. Use 'Debug', 'RelWithDebInfo' or 'Release')
|
||||
endif
|
||||
endif
|
||||
|
||||
# Disable runtime asserts
|
||||
ifeq ($(RUNTIME_ASSERT), false)
|
||||
override BUILD_FLAGS += WAPP_NO_RUNTIME_ASSERT
|
||||
endif
|
||||
|
||||
ifeq ($(CC),gcc)
|
||||
# Used to disable the "ASan runtime does not come first in initial library list" error when compiling with gcc
|
||||
export ASAN_OPTIONS=verify_asan_link_order=0
|
||||
endif
|
||||
|
||||
# Escape sequences
|
||||
BOLD = \033[1m
|
||||
BLACK = \033[30m
|
||||
BG_BLACK = \033[40m
|
||||
RED = \033[31m
|
||||
BG_RED = \033[41m
|
||||
GREEN = \033[32m
|
||||
BG_GREEN = \033[42m
|
||||
YELLOW = \033[33m
|
||||
BG_YELLOW = \033[43m
|
||||
BLUE = \033[34m
|
||||
BG_BLUE = \033[44m
|
||||
MAGENTA = \033[35m
|
||||
BG_MAGENTA = \033[45m
|
||||
CYAN = \033[36m
|
||||
BG_CYAN = \033[46m
|
||||
WHITE = \033[37m
|
||||
BG_WHITE = \033[47m
|
||||
GRAY = \033[90m
|
||||
BG_GRAY = \033[100m
|
||||
BRIGHT_RED = \033[91m
|
||||
BG_BRIGHT_RED = \033[101m
|
||||
BRIGHT_GREEN = \033[92m
|
||||
BG_BRIGHT_GREEN = \033[102m
|
||||
BRIGHT_YELLOW = \033[93m
|
||||
BG_BRIGHT_YELLOW = \033[103m
|
||||
BRIGHT_BLUE = \033[94m
|
||||
BG_BRIGHT_BLUE = \033[104m
|
||||
BRIGHT_MAGENTA = \033[95m
|
||||
BG_BRIGHT_MAGENTA = \033[105m
|
||||
BRIGHT_CYAN = \033[96m
|
||||
BG_BRIGHT_CYAN = \033[106m
|
||||
BRIGHT_WHITE = \033[97m
|
||||
BG_BRIGHT_WHITE = \033[107m
|
||||
RESET = \033[0m
|
||||
|
||||
ECHO_E = echo -e
|
||||
ifeq ($(KERNEL), Darwin)
|
||||
ECHO_E = echo
|
||||
endif
|
||||
|
||||
all: clean builddir run-c-test full run-cc-test
|
||||
|
||||
help:
|
||||
@$(ECHO_E) "$(BOLD)$(BLUE)Available build variables:$(RESET)"
|
||||
@$(ECHO_E) " $(GREEN)CC$(RESET) C compiler to use $(YELLOW)(Default: clang)$(RESET)."
|
||||
@$(ECHO_E) " $(GREEN)CXX$(RESET) C++ compiler to use $(YELLOW)(Default: clang++)$(RESET)."
|
||||
@$(ECHO_E) " $(GREEN)AR$(RESET) Archiving utility to use for building static libraries $(YELLOW)(Default: ar)$(RESET)."
|
||||
@$(ECHO_E) " $(GREEN)BUILD_TYPE$(RESET) Build type $(MAGENTA)[Debug | RelWithDebInfo | Release] $(YELLOW)(Default: Debug)$(RESET)."
|
||||
@$(ECHO_E) " $(GREEN)BUILD_DIR$(RESET) Directory where build files will be written."
|
||||
@$(ECHO_E) " $(GREEN)INSTALL_PREFIX$(RESET) Prefix where library and include files will be installed."
|
||||
@$(ECHO_E) " $(GREEN)RUNTIME_ASSERT$(RESET) Whether runtime asserts are enabled $(MAGENTA)[true | false] $(YELLOW)(Default: true)$(RESET)."
|
||||
@$(ECHO_E) " $(GREEN)$(RESET) $(BOLD)$(BG_RED)DISCLAIMER:$(RESET) Using this flag is not recommended as it disables safety checks"
|
||||
@$(ECHO_E) " $(GREEN)$(RESET) potentially leading to Undefined Behaviour."
|
||||
@$(ECHO_E)
|
||||
@$(ECHO_E) "$(BOLD)$(BLUE)Available targets:$(RESET)"
|
||||
@$(ECHO_E) " $(GREEN)make$(RESET) Build, install and test the full wapp library."
|
||||
@$(ECHO_E) " $(GREEN)make full$(RESET) Build and install the full wapp library."
|
||||
@$(ECHO_E) " $(GREEN)make base$(RESET) Build and install only the $(CYAN)base$(RESET) component of the wapp library with all its dependencies."
|
||||
@$(ECHO_E) " $(GREEN)make os$(RESET) Build and install only the $(CYAN)os$(RESET) component of the wapp library with all its dependencies."
|
||||
@$(ECHO_E) " $(GREEN)make prng$(RESET) Build and install only the $(CYAN)prng$(RESET) component of the wapp library with all its dependencies."
|
||||
@$(ECHO_E) " $(GREEN)make uuid$(RESET) Build and install only the $(CYAN)uuid$(RESET) component of the wapp library with all its dependencies."
|
||||
@$(ECHO_E) " $(GREEN)make testing$(RESET) Build and install only the $(CYAN)testing$(RESET) component of the wapp library with all its dependencies."
|
||||
@$(ECHO_E) " $(GREEN)make clean$(RESET) Clean the build directory."
|
||||
@$(ECHO_E) " $(GREEN)make help$(RESET) Print this help message and exit."
|
||||
|
||||
full: LIB_SRC = src/wapp.c
|
||||
full: INCLUDES = common os base prng testing uuid
|
||||
full: install
|
||||
|
||||
base: LIB_SRC = src/base/wapp_base.c
|
||||
base: INCLUDES = common base
|
||||
base: install
|
||||
|
||||
os: LIB_SRC = src/os/wapp_os.c
|
||||
os: INCLUDES = common os base
|
||||
os: install
|
||||
|
||||
prng: LIB_SRC = src/prng/wapp_prng.c
|
||||
prng: INCLUDES = common prng
|
||||
prng: install
|
||||
|
||||
testing: LIB_SRC = src/testing/wapp_testing.c
|
||||
testing: INCLUDES = common os testing
|
||||
testing: install
|
||||
|
||||
uuid: LIB_SRC = src/uuid/wapp_uuid.c
|
||||
uuid: INCLUDES = common base prng
|
||||
uuid: install
|
||||
|
||||
clean:
|
||||
@rm -rf "$(BUILD_DIR)"
|
||||
|
||||
builddir:
|
||||
@mkdir -p "$(BUILD_DIR)"
|
||||
|
||||
build-c-test:
|
||||
$(CC) $(CSTD) $(CFLAGS) $(BUILD_FLAGS) $(TEST_INCLUDE) $(TEST_C_SRC) -o "$(TEST_C_OUT)"
|
||||
|
||||
run-c-test: build-c-test
|
||||
@echo -e "\n\033[34;1mRUNNING C TESTS\033[0m"
|
||||
@"$(TEST_C_OUT)"
|
||||
@rm "$(TEST_C_OUT)"
|
||||
|
||||
build-cc-test:
|
||||
$(CXX) $(CXXSTD) $(CFLAGS) $(BUILD_FLAGS) $(TEST_INCLUDE) $(TEST_CXX_SRC) "$(LIB_OUT)" -o "$(TEST_CXX_OUT)"
|
||||
|
||||
run-cc-test: build-cc-test
|
||||
@echo -e "\n\033[34;1mRUNNING C++ TESTS\033[0m"
|
||||
@export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:"$(BUILD_DIR)" && "$(TEST_CXX_OUT)"
|
||||
@rm "$(TEST_CXX_OUT)"
|
||||
|
||||
install: build-lib
|
||||
@mkdir -p "$(LIB_INSTALL)"
|
||||
@cp -v "$(LIB_OUT)" "$(LIB_INSTALL)"
|
||||
@mkdir -p "$(INCLUDE_INSTALL)"
|
||||
@bash $(HEADER_INSTALL_CMD) $(LIB_SRC) "$(INCLUDE_INSTALL)" $(INCLUDES)
|
||||
|
||||
build-lib: builddir
|
||||
$(CC) -c $(CSTD) $(CFLAGS) $(BUILD_FLAGS) $(LIBFLAGS) $(LIB_SRC) -o "$(OBJ_OUT)"
|
||||
$(AR) r "$(LIB_OUT)" "$(OBJ_OUT)"
|
||||
@rm "$(OBJ_OUT)"
|
||||
|
||||
ccodegen:
|
||||
$(CC) $(CSTD) $(CFLAGS) $(BUILD_FLAGS) $(LIBFLAGS) -Isrc/os src/os/wapp_os.c ccodegen/*.c -o ccgen
|
||||
@@ -1,3 +1,3 @@
|
||||
# Wizard Apprentice Standard Library
|
||||
|
||||
A collection of useful C/C++ utilities for my projects
|
||||
A base layer for C/C++ projects
|
||||
|
||||
57
build
57
build
@@ -1,3 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
bear -- ./compile $@
|
||||
# Colors
|
||||
RED="\033[0;31m"
|
||||
BOLD="\033[1m"
|
||||
NC="\033[0m" # No Color
|
||||
|
||||
BUILD_TYPE="Debug"
|
||||
ACCEPTED_BUILD_TYPES=("Debug" "RelWithDebInfo" "Release")
|
||||
KERNEL="$(uname -s)"
|
||||
ARGS=""
|
||||
|
||||
join_array_elements() {
|
||||
local IFS=","
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
contains() {
|
||||
local item="$1"; shift
|
||||
local e
|
||||
for e; do
|
||||
[[ "$e" == "$item" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
print_usage() {
|
||||
echo -e "Usage: build [-b build_type] ..."
|
||||
echo -e " Options:"
|
||||
echo -e " -b, --build-type Choose from $(join_array_elements ${ACCEPTED_BUILD_TYPES[*]}) (Default: Debug)."
|
||||
echo -e " -h, --help Print this message and exit"
|
||||
}
|
||||
|
||||
while [[ $# > 0 ]];do
|
||||
case $1 in
|
||||
-b|--build-type)
|
||||
BUILD_TYPE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
*|-*|--*)
|
||||
rest=("$@")
|
||||
ARGS+=" ${rest[0]}"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! contains ${BUILD_TYPE} "${ACCEPTED_BUILD_TYPES[@]}"; then
|
||||
echo -e "${RED}${BOLD}Unknown build type: ${BUILD_TYPE}${NC}\n"
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bear -- make BUILD_TYPE=$BUILD_TYPE $ARGS
|
||||
|
||||
77
build.ps1
Normal file
77
build.ps1
Normal file
@@ -0,0 +1,77 @@
|
||||
Param(
|
||||
[switch]$Release
|
||||
)
|
||||
|
||||
$Compiler = "cl.exe"
|
||||
$Linker = "lib.exe"
|
||||
|
||||
$GeneralFlags = "/Wall /WX /wd4996 /wd4464 /wd5105 /EHs"
|
||||
$CStd = "/std:c11"
|
||||
$CppStd = "/std:c++14"
|
||||
$LibraryFlags = "/c"
|
||||
|
||||
$Kernel = (Get-ChildItem Env:OS).Value
|
||||
$Machine = (Get-ChildItem Env:PROCESSOR_ARCHITECTURE).Value
|
||||
$Platform = "${Kernel}_${Machine}"
|
||||
|
||||
$IncludeDirs = "/I src"
|
||||
$SrcFiles = "src/wapp.c"
|
||||
|
||||
$TestIncludeDirs = Get-ChildItem -Path tests -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
|
||||
$TestCSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
|
||||
$TestCppSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.cc -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
|
||||
|
||||
If ($Release -eq $True) {
|
||||
$GeneralFlags += " /O2 /Og"
|
||||
$BuildType = "Release"
|
||||
} Else {
|
||||
$GeneralFlags += " /Zi /Od /fsanitize=address"
|
||||
$BuildType = "Debug"
|
||||
}
|
||||
|
||||
$BuildDir = "./libwapp-build/${Platform}-${BuildType}"
|
||||
$ObjDir = "$BuildDir/objects"
|
||||
$OutDir = "$BuildDir/output"
|
||||
$TestsDir = "$BuildDir/tests"
|
||||
|
||||
$LibOutput = "$OutDir/libwapp.lib"
|
||||
$Objects = "/Fo:$ObjDir/"
|
||||
$LibOutputFlags = "/OUT:$LibOutput"
|
||||
|
||||
$TestCOutputBasename = "wapptest"
|
||||
$TestCOutputFlags = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestCOutputBasename"
|
||||
|
||||
$TestCppOutputBasename = "wapptestcc"
|
||||
$TestCppOutputFlags = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestCppOutputBasename"
|
||||
|
||||
If (Test-Path $BuildDir) {
|
||||
Remove-Item $BuildDir -Recurse -Force
|
||||
}
|
||||
|
||||
mkdir -p $ObjDir > $null
|
||||
mkdir -p $OutDir > $null
|
||||
mkdir -p $TestsDir > $null
|
||||
|
||||
# Run code generation
|
||||
Invoke-Expression "python -m codegen"
|
||||
|
||||
# Build and run C tests
|
||||
Invoke-Expression "$Compiler $GeneralFlags $CStd $IncludeDirs $TestIncludeDirs $SrcFiles $TestCSrcFiles $TestCOutputFlags" -ErrorAction Stop
|
||||
Invoke-Expression "$TestsDir/$TestCOutputBasename.exe"
|
||||
|
||||
$Status = $LASTEXITCODE
|
||||
If ($Status -ne 0) {
|
||||
Remove-Item $TestsDir -Recurse -Force
|
||||
Write-Error "Tests failed"
|
||||
Exit 1
|
||||
}
|
||||
|
||||
# Build library
|
||||
Invoke-Expression "$Compiler $GeneralFlags $CStd $LibraryFlags $SrcFiles $Objects"
|
||||
Invoke-Expression "$Linker $ObjDir/*.obj $LibOutputFlags"
|
||||
|
||||
# Build and run C++ tests
|
||||
Invoke-Expression "$Compiler $GeneralFlags $CppStd $IncludeDirs $TestIncludeDirs $LibOutput $TestCppSrcFiles $TestCppOutputFlags" -ErrorAction Stop
|
||||
Invoke-Expression "$TestsDir/$TestCppOutputBasename.exe"
|
||||
|
||||
Remove-Item $TestsDir -Recurse -Force
|
||||
522
ccodegen/datatypes.c
Normal file
522
ccodegen/datatypes.c
Normal file
@@ -0,0 +1,522 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "dbl_list.h"
|
||||
#include "type_enums.h"
|
||||
#include "wapp_core.h"
|
||||
|
||||
#define ERR_MSG "Not enough capacity in dst buffer"
|
||||
#define CFILE_DISCLAIMER "/**\n" \
|
||||
" * THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN.\n" \
|
||||
" */\n\n"
|
||||
|
||||
void cobject_to_string(Str8 *dst, const CObject *object) {
|
||||
wapp_debug_assert(dst != NULL && object != NULL, "`allocator`, `dst` and `object` should not be NULL");
|
||||
|
||||
switch (object->kind) {
|
||||
case COBJECT_CTYPE:
|
||||
ctype_to_string(dst, object->object.c_type);
|
||||
break;
|
||||
case COBJECT_CQUALIFIER:
|
||||
cqualifier_to_string(dst, object->object.c_qualifier);
|
||||
break;
|
||||
case COBJECT_CPOINTERTYPE:
|
||||
cpointertype_to_string(dst, object->object.c_pointertype);
|
||||
break;
|
||||
case COBJECT_CPOINTER:
|
||||
cpointer_to_string(dst, &(object->object.c_pointer));
|
||||
break;
|
||||
case COBJECT_CENUMVAL:
|
||||
cenumval_to_string(dst, &(object->object.c_enumval));
|
||||
break;
|
||||
case COBJECT_CENUM:
|
||||
cenum_to_string(dst, &(object->object.c_enum));
|
||||
break;
|
||||
case COBJECT_CMACRO:
|
||||
cmacro_to_string(dst, &(object->object.c_macro));
|
||||
break;
|
||||
case COBJECT_CSTRUCT:
|
||||
cstruct_to_string(dst, &(object->object.c_struct));
|
||||
break;
|
||||
case COBJECT_CUSERTYPE:
|
||||
cusertype_to_string(dst, &(object->object.c_usertype));
|
||||
break;
|
||||
case COBJECT_CDATATYPE:
|
||||
cdatatype_to_string(dst, &(object->object.c_datatype));
|
||||
break;
|
||||
case COBJECT_CARG:
|
||||
carg_to_string(dst, &(object->object.c_arg));
|
||||
break;
|
||||
case COBJECT_CFUNC:
|
||||
cfunc_to_string(dst, &(object->object.c_func));
|
||||
break;
|
||||
case COBJECT_CINCULDE:
|
||||
cinclude_to_string(dst, &(object->object.c_include));
|
||||
break;
|
||||
case COBJECT_CHEADER:
|
||||
cheader_to_string(dst, &(object->object.c_header));
|
||||
break;
|
||||
case COBJECT_CSOURCE:
|
||||
csource_to_string(dst, &(object->object.c_source));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ctype_to_string(Str8 *dst, CType ctype) {
|
||||
wapp_runtime_assert(ctypes[ctype].size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, &ctypes[ctype]);
|
||||
}
|
||||
|
||||
void cqualifier_to_string(Str8 *dst, CQualifier cqualifier) {
|
||||
wapp_runtime_assert(cqualifiers[cqualifier].size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, &cqualifiers[cqualifier]);
|
||||
}
|
||||
|
||||
void cpointertype_to_string(Str8 *dst, CPointerType cpointertype) {
|
||||
wapp_runtime_assert(cpointertypes[cpointertype].size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, &cpointertypes[cpointertype]);
|
||||
}
|
||||
|
||||
void cpointer_to_string(Str8 *dst, const CPointer *cpointer) {
|
||||
wapp_debug_assert(dst != NULL && cpointer != NULL, "`dst` and `cpointer` should not be NULL");
|
||||
|
||||
u64 total_size = cpointertypes[cpointer->type].size + cqualifiers[cpointer->qualifier].size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC,
|
||||
wapp_str8_varg(cpointertypes[cpointer->type]),
|
||||
wapp_str8_varg(cqualifiers[cpointer->qualifier]));
|
||||
}
|
||||
|
||||
void cenumval_to_string(Str8 *dst, const CEnumVal *cenumval) {
|
||||
wapp_debug_assert(dst != NULL && cenumval != NULL, "`dst` and `cenumval` should not be NULL");
|
||||
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_TINY);
|
||||
u64 tmp_size = 0;
|
||||
if (cenumval->value != NULL) {
|
||||
wapp_str8_format(&tmp, " = %d", *(cenumval->value));
|
||||
tmp_size = tmp.size;
|
||||
}
|
||||
|
||||
u64 total_size = cenumval->name.size + tmp_size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC,
|
||||
wapp_str8_varg(cenumval->name),
|
||||
wapp_str8_varg(tmp));
|
||||
}
|
||||
|
||||
void cenum_to_string(Str8 *dst, const CEnum *cenum) {
|
||||
wapp_debug_assert(dst != NULL && cenum != NULL, "`dst` and `cenum` should not be NULL");
|
||||
|
||||
Str8 header = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 values = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
Str8 footer = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
|
||||
if (cenum->add_typedef) {
|
||||
wapp_str8_copy_cstr_capped(&header, "typedef enum {\n");
|
||||
wapp_str8_format(&footer, "} " WAPP_STR8_SPEC ";\n", wapp_str8_varg(cenum->name));
|
||||
} else {
|
||||
wapp_str8_format(&header, "enum " WAPP_STR8_SPEC " {\n", wapp_str8_varg(cenum->name));
|
||||
wapp_str8_copy_cstr_capped(&footer, "};\n");
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < cenum->values.node_count; ++i) {
|
||||
cenumval_to_string(&tmp, wapp_cenumval_list_get(&(cenum->values), i)->item);
|
||||
// Add 4 for extra characters
|
||||
wapp_runtime_assert(tmp.size + 4 <= values.capacity - values.size, ERR_MSG);
|
||||
wapp_str8_concat_capped(&values, &wapp_str8_lit_ro(" "));
|
||||
wapp_str8_concat_capped(&values, &tmp);
|
||||
wapp_str8_concat_capped(&values, &wapp_str8_lit_ro(",\n"));
|
||||
}
|
||||
|
||||
u64 total_size = header.size + values.size + footer.size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC,
|
||||
wapp_str8_varg(header),
|
||||
wapp_str8_varg(values),
|
||||
wapp_str8_varg(footer));
|
||||
}
|
||||
|
||||
void cmacro_to_string(Str8 *dst, const CMacro *cmacro) {
|
||||
wapp_debug_assert(dst != NULL && cmacro != NULL, "`dst` and `cmacro` should not be NULL");
|
||||
|
||||
Str8 def = wapp_str8_lit("#define ");
|
||||
u64 total_size = def.size + cmacro->name.size + cmacro->value.size + 1; // Add 1 for newline
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC " " WAPP_STR8_SPEC "\n",
|
||||
wapp_str8_varg(def),
|
||||
wapp_str8_varg(cmacro->name),
|
||||
wapp_str8_varg(cmacro->value));
|
||||
}
|
||||
|
||||
void cstruct_to_string(Str8 *dst, const CStruct *cstruct) {
|
||||
wapp_debug_assert(dst != NULL && cstruct != NULL, "`dst` and `cstruct` should not be NULL");
|
||||
|
||||
Str8 declaration = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 definition = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
|
||||
declare_cstruct(&declaration, cstruct);
|
||||
define_cstruct(&definition, cstruct);
|
||||
|
||||
u64 total_size = declaration.size + definition.size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst, WAPP_STR8_SPEC WAPP_STR8_SPEC,
|
||||
wapp_str8_varg(declaration), wapp_str8_varg(definition));
|
||||
}
|
||||
|
||||
void declare_cstruct(Str8 *dst, const CStruct *cstruct) {
|
||||
wapp_debug_assert(dst != NULL && cstruct != NULL, "`dst` and `cstruct` should not be NULL");
|
||||
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
wapp_str8_format(&tmp,
|
||||
"typedef struct " WAPP_STR8_SPEC " " WAPP_STR8_SPEC ";\n",
|
||||
wapp_str8_varg(cstruct->name),
|
||||
wapp_str8_varg(cstruct->typedef_name.size > 0 ? cstruct->typedef_name : cstruct->name));
|
||||
|
||||
wapp_runtime_assert(tmp.size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, &tmp);
|
||||
}
|
||||
|
||||
void define_cstruct(Str8 *dst, const CStruct *cstruct) {
|
||||
wapp_debug_assert(dst != NULL && cstruct != NULL, "`dst` and `cstruct` should not be NULL");
|
||||
|
||||
Str8 definition = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 args = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
Str8 footer = wapp_str8_lit_ro("};\n");
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MEDIUM);
|
||||
|
||||
wapp_str8_format(&definition, "struct " WAPP_STR8_SPEC " {\n", wapp_str8_varg(cstruct->name));
|
||||
|
||||
for (u64 i = 0; i < cstruct->args.node_count; ++i) {
|
||||
carg_to_string(&tmp, wapp_carg_list_get(&(cstruct->args), i)->item);
|
||||
// Add 4 for extra characters
|
||||
wapp_runtime_assert(tmp.size + 4 <= args.capacity - args.size, ERR_MSG);
|
||||
wapp_str8_concat_capped(&args, &wapp_str8_lit_ro(" "));
|
||||
wapp_str8_concat_capped(&args, &tmp);
|
||||
wapp_str8_concat_capped(&args, &wapp_str8_lit_ro(";\n"));
|
||||
}
|
||||
|
||||
u64 total_size = definition.size + args.size + footer.size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC,
|
||||
wapp_str8_varg(definition),
|
||||
wapp_str8_varg(args),
|
||||
wapp_str8_varg(footer));
|
||||
}
|
||||
|
||||
void cusertype_to_string(Str8 *dst, const CUserType *cusertype) {
|
||||
wapp_debug_assert(dst != NULL && cusertype != NULL, "`dst` and `cusertype` should not be NULL");
|
||||
|
||||
switch (cusertype->kind) {
|
||||
case CUSERTYPE_CENUM:
|
||||
cenum_to_string(dst, &(cusertype->type.c_enum));
|
||||
break;
|
||||
case CUSERTYPE_CSTRUCT:
|
||||
cstruct_to_string(dst, &(cusertype->type.c_struct));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cdatatype_to_string(Str8 *dst, const CDataType *cdatatype) {
|
||||
wapp_debug_assert(dst != NULL && cdatatype != NULL, "`dst` and `cdatatype` should not be NULL");
|
||||
|
||||
switch (cdatatype->kind) {
|
||||
case CDATATYPE_CTYPE:
|
||||
ctype_to_string(dst, cdatatype->type.c_type);
|
||||
break;
|
||||
case CDATATYPE_CUSERTYPE:
|
||||
cusertype_to_string(dst, &(cdatatype->type.c_usertype));
|
||||
break;
|
||||
case CDATATYPE_STR:
|
||||
wapp_runtime_assert(cdatatype->type.str.size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, &(cdatatype->type.str));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void carg_to_string(Str8 *dst, const CArg *carg) {
|
||||
wapp_debug_assert(dst != NULL && carg != NULL, "`dst` and `carg` should not be NULL");
|
||||
|
||||
Str8 qualifier = wapp_str8_buf(CCGEN_BUF_MEDIUM);
|
||||
Str8 type = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 pointer = wapp_str8_buf(CCGEN_BUF_MEDIUM);
|
||||
Str8 array = wapp_str8_buf(CCGEN_BUF_MEDIUM);
|
||||
|
||||
cqualifier_to_string(&qualifier, carg->qualifier);
|
||||
cdatatype_to_string(&type, &(carg->type));
|
||||
wapp_str8_concat_capped(&type, &wapp_str8_lit_ro(" "));
|
||||
cpointer_to_string(&pointer, &(carg->pointer));
|
||||
if (carg->is_array) { wapp_str8_copy_cstr_capped(&array, "[]"); }
|
||||
|
||||
u64 total_size = qualifier.size + type.size + pointer.size + array.size + carg->name.size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst, WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC,
|
||||
wapp_str8_varg(qualifier), wapp_str8_varg(type), wapp_str8_varg(pointer),
|
||||
wapp_str8_varg(carg->name), wapp_str8_varg(array));
|
||||
}
|
||||
|
||||
void cfunc_to_string(Str8 *dst, const CFunc *cfunc) {
|
||||
wapp_debug_assert(dst != NULL && cfunc != NULL, "`dst` and `cfunc` should not be NULL");
|
||||
|
||||
Str8 qualifiers = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 args = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
Str8 ret_type = wapp_str8_buf(CCGEN_BUF_SMALL);
|
||||
Str8 pointer = wapp_str8_buf(CCGEN_BUF_SMALL);
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MEDIUM);
|
||||
CQualifier *qf = NULL;
|
||||
CArg *arg = NULL;
|
||||
|
||||
for (u64 i = 0; i < cfunc->qualifiers.node_count; ++i) {
|
||||
qf = wapp_cqualifier_list_get(&(cfunc->qualifiers), i)->item;
|
||||
if (*qf == CQUALIFIER_NONE) { continue; }
|
||||
|
||||
cqualifier_to_string(&tmp, *qf);
|
||||
|
||||
wapp_runtime_assert(tmp.size + 1 <= qualifiers.capacity - qualifiers.size, ERR_MSG);
|
||||
if (qualifiers.size > 0) { wapp_str8_concat_capped(&qualifiers, &wapp_str8_lit_ro(" ")); }
|
||||
|
||||
wapp_str8_concat_capped(&qualifiers, &tmp);
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < cfunc->args.node_count; ++i) {
|
||||
arg = wapp_carg_list_get(&(cfunc->args), i)->item;
|
||||
carg_to_string(&tmp, arg);
|
||||
|
||||
wapp_runtime_assert(tmp.size + 2 <= args.capacity - args.size, ERR_MSG);
|
||||
wapp_str8_concat_capped(&args, &tmp);
|
||||
if (i + 1 < cfunc->args.node_count) { wapp_str8_concat_capped(&args, &wapp_str8_lit_ro(", ")); }
|
||||
}
|
||||
|
||||
cdatatype_to_string(&ret_type, &(cfunc->ret_type));
|
||||
cpointer_to_string(&pointer, &(cfunc->pointer));
|
||||
|
||||
u64 total_size = cfunc->name.size + qualifiers.size + args.size + ret_type.size + pointer.size + 4;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC " " WAPP_STR8_SPEC WAPP_STR8_SPEC "(" WAPP_STR8_SPEC ")",
|
||||
wapp_str8_varg(qualifiers),
|
||||
wapp_str8_varg(ret_type),
|
||||
wapp_str8_varg(pointer),
|
||||
wapp_str8_varg(cfunc->name),
|
||||
wapp_str8_varg(args));
|
||||
}
|
||||
|
||||
void declare_cfunc(Str8 *dst, const CFunc *cfunc) {
|
||||
wapp_debug_assert(dst != NULL && cfunc != NULL, "`dst` and `cfunc` should not be NULL");
|
||||
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
cfunc_to_string(&tmp, cfunc);
|
||||
|
||||
wapp_runtime_assert(tmp.size + 2 <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst, WAPP_STR8_SPEC ";\n", wapp_str8_varg(tmp));
|
||||
}
|
||||
|
||||
void define_cfunc(Str8 *dst, const CFunc *cfunc) {
|
||||
wapp_debug_assert(dst != NULL && cfunc != NULL, "`dst` and `cfunc` should not be NULL");
|
||||
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
cfunc_to_string(&tmp, cfunc);
|
||||
|
||||
wapp_runtime_assert(tmp.size + cfunc->body.size + 8 <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst, WAPP_STR8_SPEC " {\n" WAPP_STR8_SPEC "\n}\n\n",
|
||||
wapp_str8_varg(tmp), wapp_str8_varg(cfunc->body));
|
||||
}
|
||||
|
||||
void cinclude_to_string(Str8 *dst, const CInclude *cinclude) {
|
||||
wapp_debug_assert(dst != NULL && cinclude != NULL, "`dst` and `cinclude` should not be NULL");
|
||||
|
||||
Str8 header_str = wapp_str8_buf(CCGEN_BUF_LARGE);
|
||||
if (!cheaderinclude_to_string(&header_str, &(cinclude->header))) { return; }
|
||||
|
||||
Str8 inc = wapp_str8_lit("#include ");
|
||||
Str8 open_symbol = wapp_str8_buf(CCGEN_BUF_MIN);
|
||||
Str8 close_symbol = wapp_str8_buf(CCGEN_BUF_MIN);
|
||||
|
||||
if (cinclude->is_local) {
|
||||
wapp_str8_concat_capped(&open_symbol, &wapp_str8_lit_ro("\""));
|
||||
wapp_str8_concat_capped(&close_symbol, &wapp_str8_lit_ro("\""));
|
||||
if (cinclude->same_dir) { wapp_str8_concat_capped(&open_symbol, &wapp_str8_lit_ro("./")); }
|
||||
} else {
|
||||
wapp_str8_concat_capped(&open_symbol, &wapp_str8_lit_ro("<"));
|
||||
wapp_str8_concat_capped(&close_symbol, &wapp_str8_lit_ro(">"));
|
||||
}
|
||||
|
||||
u64 total_size = header_str.size + inc.size + open_symbol.size + close_symbol.size;
|
||||
wapp_runtime_assert(total_size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst,
|
||||
WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC WAPP_STR8_SPEC "\n",
|
||||
wapp_str8_varg(inc),
|
||||
wapp_str8_varg(open_symbol),
|
||||
wapp_str8_varg(header_str),
|
||||
wapp_str8_varg(close_symbol));
|
||||
}
|
||||
|
||||
void cheader_to_string(Str8 *dst, const CHeader *cheader) {
|
||||
wapp_debug_assert(dst != NULL && cheader != NULL, "`dst` and `cheader` should not be NULL");
|
||||
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(64));
|
||||
Str8 *output = wapp_str8_alloc_buf(&arena, KB(32));
|
||||
wapp_runtime_assert(output != NULL, "Failed to allocate buffer");
|
||||
|
||||
Str8 header_guard_name = wapp_str8_buf(CCGEN_BUF_SMALL);
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
|
||||
// ADD HEADER GUARD AND START C LINKAGE
|
||||
wapp_str8_to_upper(&header_guard_name, &(cheader->name));
|
||||
wapp_str8_concat_capped(&header_guard_name, &wapp_str8_lit_ro("_H"));
|
||||
wapp_str8_format(&tmp, "#ifndef " WAPP_STR8_SPEC "\n#define " WAPP_STR8_SPEC "\n\n"
|
||||
"#ifdef WAPP_PLATFORM_CPP\nBEGIN_C_LINKAGE\n#endif // !WAPP_PLATFORM_CPP\n\n",
|
||||
wapp_str8_varg(header_guard_name), wapp_str8_varg(header_guard_name));
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
|
||||
for (u64 i = 0; i < cheader->includes.node_count; ++i) {
|
||||
cinclude_to_string(&tmp, wapp_cinclude_list_get(&(cheader->includes), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
if (cheader->includes.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
for (u64 i = 0; i < cheader->macros.node_count; ++i) {
|
||||
cmacro_to_string(&tmp, wapp_cmacro_list_get(&(cheader->macros), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
if (cheader->macros.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
if (cheader->cpp_macros.node_count > 0) {
|
||||
wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("#ifdef WAPP_PLATFORM_CPP\n"));
|
||||
|
||||
for (u64 i = 0; i < cheader->cpp_macros.node_count; ++i) {
|
||||
cmacro_to_string(&tmp, wapp_cmacro_list_get(&(cheader->cpp_macros), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
|
||||
wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("#else\n"));
|
||||
|
||||
for (u64 i = 0; i < cheader->c_macros.node_count; ++i) {
|
||||
cmacro_to_string(&tmp, wapp_cmacro_list_get(&(cheader->c_macros), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
|
||||
wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("#endif // !WAPP_PLATFORM_CPP\n\n"));
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < cheader->decl_types.node_count; ++i) {
|
||||
declare_cstruct(&tmp, wapp_cstruct_list_get(&(cheader->decl_types), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
if (cheader->decl_types.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
for (u64 i = 0; i < cheader->types.node_count; ++i) {
|
||||
cusertype_to_string(&tmp, wapp_cusertype_list_get(&(cheader->types), i)->item);
|
||||
wapp_str8_concat_capped(&tmp, &wapp_str8_lit_ro("\n"));
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < cheader->funcs.node_count; ++i) {
|
||||
declare_cfunc(&tmp, wapp_cfunc_list_get(&(cheader->funcs), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
|
||||
// END C LINKAGE AND CLOSE HEADER GUARD
|
||||
wapp_str8_format(&tmp, "\n#ifdef WAPP_PLATFORM_CPP\nEND_C_LINKAGE\n#endif // !WAPP_PLATFORM_CPP\n\n"
|
||||
"#endif // !" WAPP_STR8_SPEC "\n", wapp_str8_varg(header_guard_name));
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
|
||||
wapp_runtime_assert(output->size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, output);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
}
|
||||
|
||||
void csource_to_string(Str8 *dst, const CSource *csource) {
|
||||
wapp_debug_assert(dst != NULL && csource != NULL, "`dst` and `csource` should not be NULL");
|
||||
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(64));
|
||||
Str8 *output = wapp_str8_alloc_buf(&arena, KB(32));
|
||||
Str8 *internal_funcs_def = wapp_str8_alloc_buf(&arena, KB(16));
|
||||
wapp_runtime_assert(output != NULL && internal_funcs_def != NULL, "Failed to allocate buffer");
|
||||
|
||||
Str8 tmp = wapp_str8_buf(CCGEN_BUF_MAX);
|
||||
|
||||
for (u64 i = 0; i < csource->includes.node_count; ++i) {
|
||||
cinclude_to_string(&tmp, wapp_cinclude_list_get(&(csource->includes), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
if (csource->includes.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
for (u64 i = 0; i < csource->macros.node_count; ++i) {
|
||||
cmacro_to_string(&tmp, wapp_cmacro_list_get(&(csource->macros), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
if (csource->macros.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
for (u64 i = 0; i < csource->decl_types.node_count; ++i) {
|
||||
declare_cstruct(&tmp, wapp_cstruct_list_get(&(csource->decl_types), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
if (csource->decl_types.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
for (u64 i = 0; i < csource->types.node_count; ++i) {
|
||||
cusertype_to_string(&tmp, wapp_cusertype_list_get(&(csource->types), i)->item);
|
||||
wapp_str8_concat_capped(&tmp, &wapp_str8_lit_ro("\n"));
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
|
||||
Str8RO _wapp_intern = wapp_str8_lit_ro("wapp_intern ");
|
||||
for (u64 i = 0; i < csource->internal_funcs.node_count; ++i) {
|
||||
declare_cfunc(&tmp, wapp_cfunc_list_get(&(csource->internal_funcs), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &_internal);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
|
||||
define_cfunc(&tmp, wapp_cfunc_list_get(&(csource->internal_funcs), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, internal_funcs_def, &_internal);
|
||||
wapp_str8_alloc_concat(&arena, internal_funcs_def, &tmp);
|
||||
}
|
||||
if (csource->internal_funcs.node_count > 0) { wapp_str8_alloc_concat(&arena, output, &wapp_str8_lit_ro("\n")); }
|
||||
|
||||
for (u64 i = 0; i < csource->funcs.node_count; ++i) {
|
||||
define_cfunc(&tmp, wapp_cfunc_list_get(&(csource->funcs), i)->item);
|
||||
wapp_str8_alloc_concat(&arena, output, &tmp);
|
||||
}
|
||||
|
||||
wapp_runtime_assert(output->size + internal_funcs_def->size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_copy_str8_capped(dst, output);
|
||||
wapp_str8_concat_capped(dst, internal_funcs_def);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
}
|
||||
|
||||
b8 cheaderinclude_to_string(Str8 *dst, const CHeaderInclude *cheaderinclude) {
|
||||
wapp_debug_assert(dst != NULL && cheaderinclude != NULL, "`dst` and `cheaderinclude` should not be NULL");
|
||||
|
||||
switch (cheaderinclude->kind) {
|
||||
case C_HEADER_INCLUDE_STR:
|
||||
wapp_runtime_assert(cheaderinclude->header.name.size <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(dst, WAPP_STR8_SPEC, wapp_str8_varg(cheaderinclude->header.name));
|
||||
return true;
|
||||
case C_HEADER_INCLUDE_HEADER:
|
||||
// Take extension into account
|
||||
wapp_runtime_assert(cheaderinclude->header.header.name.size + 2 <= dst->capacity, ERR_MSG);
|
||||
wapp_str8_format(
|
||||
dst,
|
||||
WAPP_STR8_SPEC ".%s",
|
||||
wapp_str8_varg(cheaderinclude->header.header.name),
|
||||
cheaderinclude->header.header.extension == CFILE_EXT_H ? "h" : "c"
|
||||
);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
280
ccodegen/datatypes.h
Normal file
280
ccodegen/datatypes.h
Normal file
@@ -0,0 +1,280 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef DATATYPES_H
|
||||
#define DATATYPES_H
|
||||
|
||||
#include "wapp_core.h"
|
||||
#include "dbl_list.h"
|
||||
#include "type_enums.h"
|
||||
|
||||
#ifndef CCGEN_BUF_MIN
|
||||
#define CCGEN_BUF_MIN 16
|
||||
#endif // !CCGEN_BUF_MIN
|
||||
|
||||
#ifndef CCGEN_BUF_TINY
|
||||
#define CCGEN_BUF_TINY 32
|
||||
#endif // !CCGEN_BUF_TINY
|
||||
|
||||
#ifndef CCGEN_BUF_SMALL
|
||||
#define CCGEN_BUF_SMALL 512
|
||||
#endif // !CCGEN_BUF_SMALL
|
||||
|
||||
#ifndef CCGEN_BUF_MEDIUM
|
||||
#define CCGEN_BUF_MEDIUM 1024
|
||||
#endif // !CCGEN_BUF_MEDIUM
|
||||
|
||||
#ifndef CCGEN_BUF_LARGE
|
||||
#define CCGEN_BUF_LARGE 4096
|
||||
#endif // !CCGEN_BUF_LARGE
|
||||
|
||||
#ifndef CCGEN_BUF_MAX
|
||||
#define CCGEN_BUF_MAX 8192
|
||||
#endif // !CCGEN_BUF_MAX
|
||||
|
||||
#define CENUM(NAME, VALUES, TYPEDEF) ((CEnum){ .name = (NAME), .values = (VALUES), .add_typedef = (TYPEDEF) })
|
||||
#define CSTRUCT(NAME, ARGS, TYPEDEF_NAME_PTR) ((CStruct){ .name = (NAME), .args = (ARGS), .typedef_name = (TYPEDEF_NAME_PTR) })
|
||||
|
||||
#define CUSERTYPE_ENUM(ENUM) ((CUserType){ .kind = CUSERTYPE_CENUM, .type.c_enum = ENUM })
|
||||
#define CUSERTYPE_STRUCT(STRUCT) ((CUserType){ .kind = CUSERTYPE_CSTRUCT, .type.c_struct = STRUCT })
|
||||
|
||||
#define CDATATYPE_CTYPE(VALUE) ((CDataType){ .kind = CDATATYPE_CTYPE, .type.c_type = (VALUE) })
|
||||
#define CDATATYPE_USERTYPE(USERTYPE) ((CDataType){ .kind = CDATATYPE_CUSERTYPE, .type.c_usertype = (USERTYPE) })
|
||||
#define CDATATYPE_STR(STR) ((CDataType){ .kind = CDATATYPE_STR, .type.str = (STR) })
|
||||
|
||||
#define CHEADERINCLUDE_STR(NAME) ((CHeaderInclude){ .kind = C_HEADER_INCLUDE_STR, .header.name = (NAME) })
|
||||
#define CHEADERINCLUDE_CHEADER(CHEADER) ((CHeaderInclude){ .kind = C_HEADER_INCLUDE_HEADER, .header.header = (CHEADER) })
|
||||
|
||||
#define COBJECT_TYPE(VALUE) \
|
||||
((CObject){ .kind = COBJECT_CTYPE, .object.c_type = (VALUE) })
|
||||
#define COBJECT_QUALIFIER(VALUE) \
|
||||
((CObject){ .kind = COBJECT_CQUALIFIER, .object.c_qualifier = (VALUE) })
|
||||
#define COBJECT_POINTERTYPE(VALUE) \
|
||||
((CObject){ .kind = COBJECT_CPOINTERTYPE, .object.c_pointertype = (VALUE) })
|
||||
#define COBJECT_POINTER(CPOINTER) \
|
||||
((CObject){ .kind = COBJECT_CPOINTER, .object.c_pointer = (CPOINTER) })
|
||||
#define COBJECT_ENUMVAL(CENUMVAL) \
|
||||
((CObject){ .kind = COBJECT_CENUMVAL, .object.c_enumval = (CENUMVAL) })
|
||||
#define COBJECT_ENUM(ENUM) \
|
||||
((CObject){ .kind = COBJECT_CENUM, .object.c_enum = (ENUM) })
|
||||
#define COBJECT_MACRO(CMACRO) \
|
||||
((CObject){ .kind = COBJECT_CMACRO, .object.c_macro = (CMACRO) })
|
||||
#define COBJECT_STRUCT(STRUCT) \
|
||||
((CObject){ .kind = COBJECT_CSTRUCT, .object.c_struct = STRUCT })
|
||||
#define COBJECT_USERTYPE(USERTYPE) \
|
||||
((CObject){ .kind = COBJECT_CUSERTYPE, .object.c_usertype = (USERTYPE) })
|
||||
#define COBJECT_DATATYPE(DATATYPE) \
|
||||
((CObject){ .kind = COBJECT_CDATATYPE, .object.c_datatype = (DATATYPE) })
|
||||
#define COBJECT_ARG(CARG) \
|
||||
((CObject){ .kind = COBJECT_CARG, .object.c_arg = (CARG) })
|
||||
#define COBJECT_FUNC(CFUNC) \
|
||||
((CObject){ .kind = COBJECT_CFUNC, .object.c_func = (CFUNC) })
|
||||
#define COBJECT_INCULDE(CINCLUDE) \
|
||||
((CObject){ .kind = COBJECT_CINCULDE, .object.c_include = (CINCLUDE) })
|
||||
#define COBJECT_HEADER(CHEADER) \
|
||||
((CObject){ .kind = COBJECT_CHEADER, .object.c_header = (CHEADER) })
|
||||
#define COBJECT_SOURCE(CSOURCE) \
|
||||
((CObject){ .kind = COBJECT_CSOURCE, .object.c_source = (CSOURCE) })
|
||||
|
||||
typedef enum {
|
||||
CUSERTYPE_CENUM,
|
||||
CUSERTYPE_CSTRUCT,
|
||||
|
||||
COUNT_CUSERTYPEKIND,
|
||||
} CUserTypeKind;
|
||||
|
||||
typedef enum {
|
||||
CDATATYPE_CTYPE,
|
||||
CDATATYPE_CUSERTYPE,
|
||||
CDATATYPE_STR,
|
||||
|
||||
COUNT_CDATATYPEKIND,
|
||||
} CDataTypeKind;
|
||||
|
||||
typedef enum {
|
||||
CFILE_EXT_H,
|
||||
CFILE_EXT_C,
|
||||
|
||||
COUNT_CFILE_EXT,
|
||||
} CFileExtension;
|
||||
|
||||
typedef enum {
|
||||
C_HEADER_INCLUDE_STR,
|
||||
C_HEADER_INCLUDE_HEADER,
|
||||
|
||||
COUNT_CHEADERINCLUDEKIND,
|
||||
} CHeaderIncludeKind;
|
||||
|
||||
typedef enum {
|
||||
COBJECT_CTYPE,
|
||||
COBJECT_CQUALIFIER,
|
||||
COBJECT_CPOINTERTYPE,
|
||||
COBJECT_CPOINTER,
|
||||
COBJECT_CENUMVAL,
|
||||
COBJECT_CENUM,
|
||||
COBJECT_CMACRO,
|
||||
COBJECT_CSTRUCT,
|
||||
COBJECT_CUSERTYPE,
|
||||
COBJECT_CDATATYPE,
|
||||
COBJECT_CARG,
|
||||
COBJECT_CFUNC,
|
||||
COBJECT_CINCULDE,
|
||||
COBJECT_CHEADER,
|
||||
COBJECT_CSOURCE,
|
||||
|
||||
COUNT_COBJECTKIND,
|
||||
} CObjectKind;
|
||||
|
||||
typedef struct cpointer CPointer;
|
||||
typedef struct cenumval CEnumVal;
|
||||
typedef struct cenum CEnum;
|
||||
typedef struct cmacro CMacro;
|
||||
typedef struct cstruct CStruct;
|
||||
typedef struct cusertype CUserType;
|
||||
typedef struct cdatatype CDataType;
|
||||
typedef struct carg CArg;
|
||||
typedef struct cfunc CFunc;
|
||||
typedef struct cheader_include CHeaderInclude;
|
||||
typedef struct cinclude CInclude;
|
||||
typedef struct cheader CHeader;
|
||||
typedef struct csource CSource;
|
||||
typedef struct cobject CObject;
|
||||
|
||||
struct cpointer {
|
||||
CPointerType type;
|
||||
CQualifier qualifier;
|
||||
};
|
||||
|
||||
struct cenumval {
|
||||
Str8 name;
|
||||
i32 *value;
|
||||
};
|
||||
|
||||
struct cenum {
|
||||
Str8 name;
|
||||
CEnumValList values;
|
||||
b8 add_typedef;
|
||||
};
|
||||
|
||||
struct cmacro {
|
||||
Str8 name;
|
||||
Str8 value;
|
||||
};
|
||||
|
||||
struct cstruct {
|
||||
Str8 name;
|
||||
CArgList args;
|
||||
Str8 typedef_name;
|
||||
};
|
||||
|
||||
struct cusertype {
|
||||
CUserTypeKind kind;
|
||||
union {
|
||||
CEnum c_enum;
|
||||
CStruct c_struct;
|
||||
} type;
|
||||
};
|
||||
|
||||
struct cdatatype {
|
||||
CDataTypeKind kind;
|
||||
union {
|
||||
CType c_type;
|
||||
CUserType c_usertype;
|
||||
Str8 str;
|
||||
} type;
|
||||
};
|
||||
|
||||
struct carg {
|
||||
Str8 name;
|
||||
CDataType type;
|
||||
CPointer pointer;
|
||||
CQualifier qualifier;
|
||||
b8 is_array;
|
||||
};
|
||||
|
||||
struct cfunc {
|
||||
Str8 name;
|
||||
CDataType ret_type;
|
||||
CArgList args;
|
||||
Str8 body;
|
||||
CPointer pointer;
|
||||
CQualifierList qualifiers;
|
||||
};
|
||||
|
||||
#define CFILE_ARGS \
|
||||
Str8 name; \
|
||||
CFileExtension extension; \
|
||||
CIncludeList includes; \
|
||||
CUserTypeList types; \
|
||||
CFuncList funcs; \
|
||||
CStructList decl_types; \
|
||||
CMacroList macros; \
|
||||
CMacroList c_macros; \
|
||||
CMacroList cpp_macros \
|
||||
|
||||
struct cheader {
|
||||
CFILE_ARGS;
|
||||
};
|
||||
|
||||
struct csource {
|
||||
CFILE_ARGS;
|
||||
CFuncList internal_funcs;
|
||||
};
|
||||
|
||||
struct cheader_include {
|
||||
CHeaderIncludeKind kind;
|
||||
union {
|
||||
Str8 name;
|
||||
CHeader header;
|
||||
} header;
|
||||
};
|
||||
|
||||
struct cinclude {
|
||||
CHeaderInclude header;
|
||||
b8 is_local;
|
||||
b8 same_dir;
|
||||
};
|
||||
|
||||
struct cobject {
|
||||
CObjectKind kind;
|
||||
union {
|
||||
CType c_type;
|
||||
CQualifier c_qualifier;
|
||||
CPointerType c_pointertype;
|
||||
CPointer c_pointer;
|
||||
CEnumVal c_enumval;
|
||||
CEnum c_enum;
|
||||
CMacro c_macro;
|
||||
CStruct c_struct;
|
||||
CUserType c_usertype;
|
||||
CDataType c_datatype;
|
||||
CArg c_arg;
|
||||
CFunc c_func;
|
||||
CInclude c_include;
|
||||
CHeader c_header;
|
||||
CSource c_source;
|
||||
} object;
|
||||
};
|
||||
|
||||
void cobject_to_string(Str8 *dst, const CObject *object);
|
||||
void ctype_to_string(Str8 *dst, CType ctype);
|
||||
void cqualifier_to_string(Str8 *dst, CQualifier cqualifier);
|
||||
void cpointertype_to_string(Str8 *dst, CPointerType cpointertype);
|
||||
void cpointer_to_string(Str8 *dst, const CPointer *cpointer);
|
||||
void cenumval_to_string(Str8 *dst, const CEnumVal *cenumval);
|
||||
void cenum_to_string(Str8 *dst, const CEnum *cenum);
|
||||
void cmacro_to_string(Str8 *dst, const CMacro *cmacro);
|
||||
void cstruct_to_string(Str8 *dst, const CStruct *cstruct);
|
||||
void declare_cstruct(Str8 *dst, const CStruct *cstruct);
|
||||
void define_cstruct(Str8 *dst, const CStruct *cstruct);
|
||||
void cusertype_to_string(Str8 *dst, const CUserType *cusertype);
|
||||
void cdatatype_to_string(Str8 *dst, const CDataType *cdatatype);
|
||||
void carg_to_string(Str8 *dst, const CArg *carg);
|
||||
void cfunc_to_string(Str8 *dst, const CFunc *cfunc);
|
||||
void declare_cfunc(Str8 *dst, const CFunc *cfunc);
|
||||
void define_cfunc(Str8 *dst, const CFunc *cfunc);
|
||||
void cinclude_to_string(Str8 *dst, const CInclude *cinclude);
|
||||
void cheader_to_string(Str8 *dst, const CHeader *cheader);
|
||||
void csource_to_string(Str8 *dst, const CSource *csource);
|
||||
b8 cheaderinclude_to_string(Str8 *dst, const CHeaderInclude *cheaderinclude);
|
||||
|
||||
#endif // !DATATYPES_H
|
||||
1526
ccodegen/dbl_list.c
Normal file
1526
ccodegen/dbl_list.c
Normal file
File diff suppressed because it is too large
Load Diff
222
ccodegen/dbl_list.h
Normal file
222
ccodegen/dbl_list.h
Normal file
@@ -0,0 +1,222 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef CCGEN_DBL_LIST_H
|
||||
#define CCGEN_DBL_LIST_H
|
||||
|
||||
#include "wapp_core.h"
|
||||
#include "type_enums.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
#define wapp_cenumval_list_node(ITEM_PTR) CEnumValNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_carg_list_node(ITEM_PTR) CArgNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_cqualifier_list_node(ITEM_PTR) CQualifierNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_cinclude_list_node(ITEM_PTR) CIncludeNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_cusertype_list_node(ITEM_PTR) CUserTypeNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_cfunc_list_node(ITEM_PTR) CFuncNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_cstruct_list_node(ITEM_PTR) CStructNode{ITEM_PTR, nullptr, nullptr}
|
||||
#define wapp_cmacro_list_node(ITEM_PTR) CMacroNode{ITEM_PTR, nullptr, nullptr}
|
||||
#else
|
||||
#define wapp_cenumval_list_node(ITEM_PTR) ((CEnumValNode){.item = ITEM_PTR})
|
||||
#define wapp_carg_list_node(ITEM_PTR) ((CArgNode){.item = ITEM_PTR})
|
||||
#define wapp_cqualifier_list_node(ITEM_PTR) ((CQualifierNode){.item = ITEM_PTR})
|
||||
#define wapp_cinclude_list_node(ITEM_PTR) ((CIncludeNode){.item = ITEM_PTR})
|
||||
#define wapp_cusertype_list_node(ITEM_PTR) ((CUserTypeNode){.item = ITEM_PTR})
|
||||
#define wapp_cfunc_list_node(ITEM_PTR) ((CFuncNode){.item = ITEM_PTR})
|
||||
#define wapp_cstruct_list_node(ITEM_PTR) ((CStructNode){.item = ITEM_PTR})
|
||||
#define wapp_cmacro_list_node(ITEM_PTR) ((CMacroNode){.item = ITEM_PTR})
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef struct cenumval CEnumVal;
|
||||
typedef struct carg CArg;
|
||||
typedef struct cinclude CInclude;
|
||||
typedef struct cusertype CUserType;
|
||||
typedef struct cfunc CFunc;
|
||||
typedef struct cstruct CStruct;
|
||||
typedef struct cmacro CMacro;
|
||||
|
||||
typedef struct CEnumValNode CEnumValNode;
|
||||
struct CEnumValNode {
|
||||
CEnumVal *item;
|
||||
CEnumValNode *prev;
|
||||
CEnumValNode *next;
|
||||
};
|
||||
|
||||
typedef struct CEnumValList CEnumValList;
|
||||
struct CEnumValList {
|
||||
CEnumValNode *first;
|
||||
CEnumValNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CArgNode CArgNode;
|
||||
struct CArgNode {
|
||||
CArg *item;
|
||||
CArgNode *prev;
|
||||
CArgNode *next;
|
||||
};
|
||||
|
||||
typedef struct CArgList CArgList;
|
||||
struct CArgList {
|
||||
CArgNode *first;
|
||||
CArgNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CQualifierNode CQualifierNode;
|
||||
struct CQualifierNode {
|
||||
CQualifier *item;
|
||||
CQualifierNode *prev;
|
||||
CQualifierNode *next;
|
||||
};
|
||||
|
||||
typedef struct CQualifierList CQualifierList;
|
||||
struct CQualifierList {
|
||||
CQualifierNode *first;
|
||||
CQualifierNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CIncludeNode CIncludeNode;
|
||||
struct CIncludeNode {
|
||||
CInclude *item;
|
||||
CIncludeNode *prev;
|
||||
CIncludeNode *next;
|
||||
};
|
||||
|
||||
typedef struct CIncludeList CIncludeList;
|
||||
struct CIncludeList {
|
||||
CIncludeNode *first;
|
||||
CIncludeNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CUserTypeNode CUserTypeNode;
|
||||
struct CUserTypeNode {
|
||||
CUserType *item;
|
||||
CUserTypeNode *prev;
|
||||
CUserTypeNode *next;
|
||||
};
|
||||
|
||||
typedef struct CUserTypeList CUserTypeList;
|
||||
struct CUserTypeList {
|
||||
CUserTypeNode *first;
|
||||
CUserTypeNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CFuncNode CFuncNode;
|
||||
struct CFuncNode {
|
||||
CFunc *item;
|
||||
CFuncNode *prev;
|
||||
CFuncNode *next;
|
||||
};
|
||||
|
||||
typedef struct CFuncList CFuncList;
|
||||
struct CFuncList {
|
||||
CFuncNode *first;
|
||||
CFuncNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CStructNode CStructNode;
|
||||
struct CStructNode {
|
||||
CStruct *item;
|
||||
CStructNode *prev;
|
||||
CStructNode *next;
|
||||
};
|
||||
|
||||
typedef struct CStructList CStructList;
|
||||
struct CStructList {
|
||||
CStructNode *first;
|
||||
CStructNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
typedef struct CMacroNode CMacroNode;
|
||||
struct CMacroNode {
|
||||
CMacro *item;
|
||||
CMacroNode *prev;
|
||||
CMacroNode *next;
|
||||
};
|
||||
|
||||
typedef struct CMacroList CMacroList;
|
||||
struct CMacroList {
|
||||
CMacroNode *first;
|
||||
CMacroNode *last;
|
||||
u64 node_count;
|
||||
};
|
||||
|
||||
CEnumValNode *wapp_cenumval_list_get(const CEnumValList *list, u64 index);
|
||||
void wapp_cenumval_list_push_front(CEnumValList *list, CEnumValNode *node);
|
||||
void wapp_cenumval_list_push_back(CEnumValList *list, CEnumValNode *node);
|
||||
void wapp_cenumval_list_insert(CEnumValList *list, CEnumValNode *node, u64 index);
|
||||
CEnumValNode *wapp_cenumval_list_pop_front(CEnumValList *list);
|
||||
CEnumValNode *wapp_cenumval_list_pop_back(CEnumValList *list);
|
||||
CEnumValNode *wapp_cenumval_list_remove(CEnumValList *list, u64 index);
|
||||
void wapp_cenumval_list_empty(CEnumValList *list);
|
||||
CArgNode *wapp_carg_list_get(const CArgList *list, u64 index);
|
||||
void wapp_carg_list_push_front(CArgList *list, CArgNode *node);
|
||||
void wapp_carg_list_push_back(CArgList *list, CArgNode *node);
|
||||
void wapp_carg_list_insert(CArgList *list, CArgNode *node, u64 index);
|
||||
CArgNode *wapp_carg_list_pop_front(CArgList *list);
|
||||
CArgNode *wapp_carg_list_pop_back(CArgList *list);
|
||||
CArgNode *wapp_carg_list_remove(CArgList *list, u64 index);
|
||||
void wapp_carg_list_empty(CArgList *list);
|
||||
CQualifierNode *wapp_cqualifier_list_get(const CQualifierList *list, u64 index);
|
||||
void wapp_cqualifier_list_push_front(CQualifierList *list, CQualifierNode *node);
|
||||
void wapp_cqualifier_list_push_back(CQualifierList *list, CQualifierNode *node);
|
||||
void wapp_cqualifier_list_insert(CQualifierList *list, CQualifierNode *node, u64 index);
|
||||
CQualifierNode *wapp_cqualifier_list_pop_front(CQualifierList *list);
|
||||
CQualifierNode *wapp_cqualifier_list_pop_back(CQualifierList *list);
|
||||
CQualifierNode *wapp_cqualifier_list_remove(CQualifierList *list, u64 index);
|
||||
void wapp_cqualifier_list_empty(CQualifierList *list);
|
||||
CIncludeNode *wapp_cinclude_list_get(const CIncludeList *list, u64 index);
|
||||
void wapp_cinclude_list_push_front(CIncludeList *list, CIncludeNode *node);
|
||||
void wapp_cinclude_list_push_back(CIncludeList *list, CIncludeNode *node);
|
||||
void wapp_cinclude_list_insert(CIncludeList *list, CIncludeNode *node, u64 index);
|
||||
CIncludeNode *wapp_cinclude_list_pop_front(CIncludeList *list);
|
||||
CIncludeNode *wapp_cinclude_list_pop_back(CIncludeList *list);
|
||||
CIncludeNode *wapp_cinclude_list_remove(CIncludeList *list, u64 index);
|
||||
void wapp_cinclude_list_empty(CIncludeList *list);
|
||||
CUserTypeNode *wapp_cusertype_list_get(const CUserTypeList *list, u64 index);
|
||||
void wapp_cusertype_list_push_front(CUserTypeList *list, CUserTypeNode *node);
|
||||
void wapp_cusertype_list_push_back(CUserTypeList *list, CUserTypeNode *node);
|
||||
void wapp_cusertype_list_insert(CUserTypeList *list, CUserTypeNode *node, u64 index);
|
||||
CUserTypeNode *wapp_cusertype_list_pop_front(CUserTypeList *list);
|
||||
CUserTypeNode *wapp_cusertype_list_pop_back(CUserTypeList *list);
|
||||
CUserTypeNode *wapp_cusertype_list_remove(CUserTypeList *list, u64 index);
|
||||
void wapp_cusertype_list_empty(CUserTypeList *list);
|
||||
CFuncNode *wapp_cfunc_list_get(const CFuncList *list, u64 index);
|
||||
void wapp_cfunc_list_push_front(CFuncList *list, CFuncNode *node);
|
||||
void wapp_cfunc_list_push_back(CFuncList *list, CFuncNode *node);
|
||||
void wapp_cfunc_list_insert(CFuncList *list, CFuncNode *node, u64 index);
|
||||
CFuncNode *wapp_cfunc_list_pop_front(CFuncList *list);
|
||||
CFuncNode *wapp_cfunc_list_pop_back(CFuncList *list);
|
||||
CFuncNode *wapp_cfunc_list_remove(CFuncList *list, u64 index);
|
||||
void wapp_cfunc_list_empty(CFuncList *list);
|
||||
CStructNode *wapp_cstruct_list_get(const CStructList *list, u64 index);
|
||||
void wapp_cstruct_list_push_front(CStructList *list, CStructNode *node);
|
||||
void wapp_cstruct_list_push_back(CStructList *list, CStructNode *node);
|
||||
void wapp_cstruct_list_insert(CStructList *list, CStructNode *node, u64 index);
|
||||
CStructNode *wapp_cstruct_list_pop_front(CStructList *list);
|
||||
CStructNode *wapp_cstruct_list_pop_back(CStructList *list);
|
||||
CStructNode *wapp_cstruct_list_remove(CStructList *list, u64 index);
|
||||
void wapp_cstruct_list_empty(CStructList *list);
|
||||
CMacroNode *wapp_cmacro_list_get(const CMacroList *list, u64 index);
|
||||
void wapp_cmacro_list_push_front(CMacroList *list, CMacroNode *node);
|
||||
void wapp_cmacro_list_push_back(CMacroList *list, CMacroNode *node);
|
||||
void wapp_cmacro_list_insert(CMacroList *list, CMacroNode *node, u64 index);
|
||||
CMacroNode *wapp_cmacro_list_pop_front(CMacroList *list);
|
||||
CMacroNode *wapp_cmacro_list_pop_back(CMacroList *list);
|
||||
CMacroNode *wapp_cmacro_list_remove(CMacroList *list, u64 index);
|
||||
void wapp_cmacro_list_empty(CMacroList *list);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !DBL_LIST_H
|
||||
10
ccodegen/main.c
Normal file
10
ccodegen/main.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "type_enums.h"
|
||||
#include "wapp_core.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
84
ccodegen/type_enums.h
Normal file
84
ccodegen/type_enums.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef TYPE_ENUMS_H
|
||||
#define TYPE_ENUMS_H
|
||||
|
||||
#include "wapp_core.h"
|
||||
|
||||
typedef enum {
|
||||
CTYPE_VOID,
|
||||
CTYPE_B8,
|
||||
CTYPE_CHAR,
|
||||
CTYPE_C8,
|
||||
CTYPE_C16,
|
||||
CTYPE_C32,
|
||||
CTYPE_I8,
|
||||
CTYPE_I16,
|
||||
CTYPE_I32,
|
||||
CTYPE_I64,
|
||||
CTYPE_U8,
|
||||
CTYPE_U16,
|
||||
CTYPE_U32,
|
||||
CTYPE_U64,
|
||||
CTYPE_F32,
|
||||
CTYPE_F64,
|
||||
CTYPE_F128,
|
||||
CTYPE_IPTR,
|
||||
CTYPE_UPTR,
|
||||
|
||||
COUNT_CTYPE,
|
||||
} CType;
|
||||
wapp_intern Str8RO ctypes[COUNT_CTYPE] = {
|
||||
[CTYPE_VOID] = wapp_str8_lit_ro("void"),
|
||||
[CTYPE_B8] = wapp_str8_lit_ro("b8"),
|
||||
[CTYPE_CHAR] = wapp_str8_lit_ro("char"),
|
||||
[CTYPE_C8] = wapp_str8_lit_ro("c8"),
|
||||
[CTYPE_C16] = wapp_str8_lit_ro("c16"),
|
||||
[CTYPE_C32] = wapp_str8_lit_ro("c32"),
|
||||
[CTYPE_I8] = wapp_str8_lit_ro("i8"),
|
||||
[CTYPE_I16] = wapp_str8_lit_ro("i16"),
|
||||
[CTYPE_I32] = wapp_str8_lit_ro("i32"),
|
||||
[CTYPE_I64] = wapp_str8_lit_ro("i64"),
|
||||
[CTYPE_U8] = wapp_str8_lit_ro("u8"),
|
||||
[CTYPE_U16] = wapp_str8_lit_ro("u16"),
|
||||
[CTYPE_U32] = wapp_str8_lit_ro("u32"),
|
||||
[CTYPE_U64] = wapp_str8_lit_ro("u64"),
|
||||
[CTYPE_F32] = wapp_str8_lit_ro("f32"),
|
||||
[CTYPE_F64] = wapp_str8_lit_ro("f64"),
|
||||
[CTYPE_F128] = wapp_str8_lit_ro("f128"),
|
||||
[CTYPE_IPTR] = wapp_str8_lit_ro("iptr"),
|
||||
[CTYPE_UPTR] = wapp_str8_lit_ro("uptr"),
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CQUALIFIER_NONE,
|
||||
CQUALIFIER_CONST,
|
||||
CQUALIFIER_EXTERNAL,
|
||||
CQUALIFIER_INTERNAL,
|
||||
CQUALIFIER_PERSISTENT,
|
||||
|
||||
COUNT_CQUALIFIER,
|
||||
} CQualifier;
|
||||
wapp_intern Str8RO cqualifiers[COUNT_CQUALIFIER] = {
|
||||
[CQUALIFIER_NONE] = wapp_str8_lit_ro(""),
|
||||
[CQUALIFIER_CONST] = wapp_str8_lit_ro("const "),
|
||||
[CQUALIFIER_EXTERNAL] = wapp_str8_lit_ro("wapp_extern "),
|
||||
[CQUALIFIER_INTERNAL] = wapp_str8_lit_ro("wapp_intern "),
|
||||
[CQUALIFIER_PERSISTENT] = wapp_str8_lit_ro("wapp_persist "),
|
||||
};
|
||||
|
||||
|
||||
typedef enum {
|
||||
CPOINTERTYPE_NONE,
|
||||
CPOINTERTYPE_SINGLE,
|
||||
CPOINTERTYPE_DOUBLE,
|
||||
|
||||
COUNT_CPOINTERTYPE,
|
||||
} CPointerType;
|
||||
wapp_intern Str8RO cpointertypes[COUNT_CPOINTERTYPE] = {
|
||||
[CPOINTERTYPE_NONE] = wapp_str8_lit_ro(""),
|
||||
[CPOINTERTYPE_SINGLE] = wapp_str8_lit_ro("*"),
|
||||
[CPOINTERTYPE_DOUBLE] = wapp_str8_lit_ro("**"),
|
||||
};
|
||||
|
||||
#endif // !TYPE_ENUMS_H
|
||||
13
compile
13
compile
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
CC=clang
|
||||
INCLUDE="\
|
||||
$(find src -type d | xargs -I{} echo -n "-I{} ") \
|
||||
"
|
||||
SRC="\
|
||||
$(find src -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)
|
||||
21
scripts/header_install.sh
Normal file
21
scripts/header_install.sh
Normal file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$(dirname $0)"
|
||||
LIB_SRC="$1"
|
||||
INSTALL_PREFIX="$2"
|
||||
shift 2
|
||||
INCLUDES="$@"
|
||||
|
||||
mkdir -p "$INSTALL_PREFIX"
|
||||
|
||||
BASE_INCLUDE_DIR="$(dirname "$LIB_SRC")"
|
||||
find $BASE_INCLUDE_DIR -maxdepth 1 -type f -name "*.h" -exec cp -v {} "$INSTALL_PREFIX" \;
|
||||
|
||||
cd "$SCRIPT_DIR/../src"
|
||||
for INCLUDE in $INCLUDES; do
|
||||
for f in $(find "$INCLUDE" -type f -name "*.h"); do
|
||||
DST="$INSTALL_PREFIX/$(dirname $f)"
|
||||
mkdir -p "$DST"
|
||||
cp -v "$f" "$DST"
|
||||
done
|
||||
done
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef ALIASES_H
|
||||
#define ALIASES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
|
||||
#define i8 int8_t
|
||||
#define i16 int16_t
|
||||
#define i32 int32_t
|
||||
#define i64 int64_t
|
||||
|
||||
#define f32 float
|
||||
#define f64 double
|
||||
#define f128 long double
|
||||
|
||||
#define uptr uintptr_t
|
||||
#define iptr intptr_t
|
||||
|
||||
#define internal static
|
||||
#define persistent static
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define class_mem static
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !ALIASES_H
|
||||
175
src/base/array/array.c
Normal file
175
src/base/array/array.c
Normal file
@@ -0,0 +1,175 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "./array.h"
|
||||
#include "../../common/assert/assert.h"
|
||||
#include "../mem/allocator/mem_allocator.h"
|
||||
#include "../../common/misc/misc_utils.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define _offset_pointer(PTR, OFFSET) ((void *)((uptr)(PTR) + (OFFSET)))
|
||||
|
||||
void *_array_get(GenericArray *array, u64 index, u64 item_size) {
|
||||
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided");
|
||||
wapp_runtime_assert(index < array->count, "`index` is out of bounds");
|
||||
|
||||
return _offset_pointer(array->items, array->item_size * index);
|
||||
}
|
||||
|
||||
void _array_set(GenericArray *array, u64 index, void *value, u64 item_size) {
|
||||
void *item = _array_get(array, index, item_size);
|
||||
memcpy(item, value, array->item_size);
|
||||
}
|
||||
|
||||
void _array_append_capped(GenericArray *array, void *value, u64 item_size) {
|
||||
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided");
|
||||
|
||||
if (array->count >= array->capacity) { return; }
|
||||
|
||||
u64 index = (array->count)++;
|
||||
_array_set(array, index, value, item_size);
|
||||
}
|
||||
|
||||
void _array_extend_capped(GenericArray *dst, const GenericArray *src, u64 item_size) {
|
||||
wapp_runtime_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst->magic, "`dst` is not a valid wapp array");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == src->magic, "`src` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == dst->item_size && item_size == src->item_size, "Invalid item type provided");
|
||||
|
||||
u64 remaining_capacity = dst->capacity - dst->count;
|
||||
|
||||
u64 copy_count = src->count < remaining_capacity ? src->count : remaining_capacity;
|
||||
void *dst_ptr = _offset_pointer(dst->items, dst->count * dst->item_size);
|
||||
memcpy(dst_ptr, src->items, copy_count * src->item_size);
|
||||
dst->count += copy_count;
|
||||
}
|
||||
|
||||
void _array_copy_capped(GenericArray *dst, const GenericArray *src, u64 item_size) {
|
||||
wapp_runtime_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst->magic, "`dst` is not a valid wapp array");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == src->magic, "`src` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == dst->item_size && item_size == src->item_size, "Invalid item type provided");
|
||||
|
||||
_array_clear(dst, item_size);
|
||||
u64 copy_count = src->count < dst->capacity ? src->count : dst->capacity;
|
||||
memcpy(dst->items, src->items, copy_count * src->item_size);
|
||||
dst->count = copy_count;
|
||||
}
|
||||
|
||||
GenericArray *_array_append_alloc(const Allocator *allocator, GenericArray *array, void *value, u64 item_size) {
|
||||
wapp_runtime_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided");
|
||||
|
||||
GenericArray *output = array;
|
||||
|
||||
if (array->count >= array->capacity) {
|
||||
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(array->capacity * 2);
|
||||
output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, array->item_size);
|
||||
if (!output) {
|
||||
output = array;
|
||||
goto RETURN_ARRAY_APPEND_ALLOC;
|
||||
}
|
||||
_array_copy_capped(output, array, item_size);
|
||||
}
|
||||
|
||||
_array_append_capped(output, value, item_size);
|
||||
|
||||
RETURN_ARRAY_APPEND_ALLOC:
|
||||
return output;
|
||||
}
|
||||
|
||||
GenericArray *_array_extend_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size) {
|
||||
wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst->magic, "`dst` is not a valid wapp array");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == src->magic, "`src` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == dst->item_size && item_size == src->item_size, "Invalid item type provided");
|
||||
|
||||
GenericArray *output = dst;
|
||||
|
||||
u64 remaining_capacity = dst->capacity - dst->count;
|
||||
if (src->count >= remaining_capacity) {
|
||||
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2);
|
||||
output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, dst->item_size);
|
||||
if (!output) {
|
||||
output = dst;
|
||||
goto RETURN_ARRAY_EXTEND_ALLOC;
|
||||
}
|
||||
_array_copy_capped(output, dst, item_size);
|
||||
}
|
||||
|
||||
_array_extend_capped(output, src, item_size);
|
||||
|
||||
RETURN_ARRAY_EXTEND_ALLOC:
|
||||
return output;
|
||||
}
|
||||
|
||||
GenericArray *_array_copy_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size) {
|
||||
wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == dst->magic, "`dst` is not a valid wapp array");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == src->magic, "`src` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == dst->item_size && item_size == src->item_size, "Invalid item type provided");
|
||||
|
||||
GenericArray *output = dst;
|
||||
|
||||
if (src->count >= dst->capacity) {
|
||||
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst->capacity * 2);
|
||||
output = (GenericArray *)_array_alloc_capacity(allocator, new_capacity, src->item_size);
|
||||
if (!output) {
|
||||
output = dst;
|
||||
goto RETURN_ARRAY_COPY_ALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
_array_copy_capped(output, src, item_size);
|
||||
|
||||
RETURN_ARRAY_COPY_ALLOC:
|
||||
return output;
|
||||
}
|
||||
|
||||
void *_array_pop(GenericArray *array, u64 item_size) {
|
||||
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided");
|
||||
|
||||
if (array->count == 0) { return NULL; }
|
||||
|
||||
u64 index = array->count - 1;
|
||||
void *out = _array_get(array, index, item_size);
|
||||
--(array->count);
|
||||
return out;
|
||||
}
|
||||
|
||||
void _array_clear(GenericArray *array, u64 item_size) {
|
||||
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
|
||||
wapp_runtime_assert(WAPP_ARRAY_MAGIC == array->magic, "`array` is not a valid wapp array");
|
||||
wapp_runtime_assert(item_size == array->item_size, "Invalid item type provided");
|
||||
|
||||
array->count = 0;
|
||||
}
|
||||
|
||||
GenericArray *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size) {
|
||||
wapp_runtime_assert(allocator != NULL, "`allocator` should not be NULL");
|
||||
|
||||
GenericArray *output = NULL;
|
||||
|
||||
u64 allocation_size = sizeof(GenericArray) + item_size * capacity;
|
||||
|
||||
output = wapp_mem_allocator_alloc(allocator, allocation_size);
|
||||
if (!output) {
|
||||
goto RETURN_ARRAY_ALLOC;
|
||||
}
|
||||
|
||||
output->magic = WAPP_ARRAY_MAGIC;
|
||||
output->count = 0;
|
||||
output->capacity = capacity;
|
||||
output->item_size = item_size;
|
||||
output->items = (void *)(output + 1);
|
||||
|
||||
RETURN_ARRAY_ALLOC:
|
||||
return output;
|
||||
}
|
||||
163
src/base/array/array.h
Normal file
163
src/base/array/array.h
Normal file
@@ -0,0 +1,163 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include "../mem/allocator/mem_allocator.h"
|
||||
#include "../../common/misc/misc_utils.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define WAPP_ARRAY_MAGIC (u64)0x57415f415252
|
||||
|
||||
#define _calc_array_count(TYPE, ...) wapp_misc_utils_va_args_count(TYPE, __VA_ARGS__)
|
||||
#define _calc_array_capacity(TYPE, ...) wapp_misc_utils_u64_round_up_pow2(_calc_array_count(TYPE, __VA_ARGS__) * 2)
|
||||
|
||||
#define wapp_array_alloc_capacity(ELEM_TYPE, ARRAY_TYPE, ALLOCATOR_PTR, CAPACITY) \
|
||||
((ARRAY_TYPE *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, sizeof(ELEM_TYPE)))
|
||||
|
||||
#define WAPP_DEF_ARRAY_TYPE(T, NAME) \
|
||||
typedef struct { \
|
||||
u64 magic; \
|
||||
u64 count; \
|
||||
u64 capacity; \
|
||||
u64 item_size; \
|
||||
T *items; \
|
||||
} NAME
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
#define wapp_array(ELEM_TYPE, ARRAY_TYPE, ...) ([&]() { \
|
||||
wapp_persist ELEM_TYPE items[sizeof(ELEM_TYPE) == sizeof(*((ARRAY_TYPE{}).items)) ? \
|
||||
_calc_array_capacity(ELEM_TYPE, __VA_ARGS__) : -1 \
|
||||
] = {__VA_ARGS__}; \
|
||||
\
|
||||
return ARRAY_TYPE{ \
|
||||
WAPP_ARRAY_MAGIC, \
|
||||
_calc_array_count(ELEM_TYPE, __VA_ARGS__), \
|
||||
_calc_array_capacity(ELEM_TYPE, __VA_ARGS__), \
|
||||
sizeof(ELEM_TYPE), \
|
||||
items, \
|
||||
}; \
|
||||
}())
|
||||
#define wapp_array_with_capacity(ELEM_TYPE, ARRAY_TYPE, CAPACITY) ([&]() { \
|
||||
wapp_persist ELEM_TYPE items[sizeof(ELEM_TYPE) == sizeof(*((ARRAY_TYPE{}).items)) ? \
|
||||
CAPACITY : -1] = {}; \
|
||||
\
|
||||
return ARRAY_TYPE{ \
|
||||
WAPP_ARRAY_MAGIC, \
|
||||
0, \
|
||||
CAPACITY, \
|
||||
sizeof(ELEM_TYPE), \
|
||||
items, \
|
||||
}; \
|
||||
}())
|
||||
#define wapp_array_pop(ELEM_TYPE, ARRAY_PTR) ([&]() { \
|
||||
if (ARRAY_PTR == NULL || (ARRAY_PTR)->count == 0) { \
|
||||
ELEM_TYPE result{}; \
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
return *((ELEM_TYPE *)_array_pop((GenericArray *)ARRAY_PTR, sizeof(ELEM_TYPE))); \
|
||||
}())
|
||||
#else
|
||||
#define wapp_array(ELEM_TYPE, ARRAY_TYPE, ...) \
|
||||
((ARRAY_TYPE){ \
|
||||
.magic = WAPP_ARRAY_MAGIC, \
|
||||
.count = _calc_array_count(ELEM_TYPE, __VA_ARGS__), \
|
||||
.capacity = _calc_array_capacity(ELEM_TYPE, __VA_ARGS__), \
|
||||
.item_size = sizeof(ELEM_TYPE), \
|
||||
.items = (ELEM_TYPE[sizeof(ELEM_TYPE) == sizeof(*((ARRAY_TYPE){0}.items)) ? \
|
||||
_calc_array_capacity(ELEM_TYPE, __VA_ARGS__) : \
|
||||
-1]){__VA_ARGS__} \
|
||||
})
|
||||
#define wapp_array_with_capacity(ELEM_TYPE, ARRAY_TYPE, CAPACITY) \
|
||||
((ARRAY_TYPE){ \
|
||||
.magic = WAPP_ARRAY_MAGIC, \
|
||||
.count = 0, \
|
||||
.capacity = CAPACITY, \
|
||||
.item_size = sizeof(ELEM_TYPE), \
|
||||
.items = (ELEM_TYPE[sizeof(ELEM_TYPE) == sizeof(*((ARRAY_TYPE){0}.items)) ? \
|
||||
CAPACITY : -1]){0} \
|
||||
})
|
||||
#define wapp_array_pop(ELEM_TYPE, ARRAY_PTR) \
|
||||
(ARRAY_PTR != NULL && (ARRAY_PTR)->count > 0 ? \
|
||||
*((ELEM_TYPE *)_array_pop((GenericArray *)ARRAY_PTR, sizeof(ELEM_TYPE))) : \
|
||||
(ELEM_TYPE){0} \
|
||||
)
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define wapp_array_get(ELEM_TYPE, ARRAY_PTR, INDEX) \
|
||||
((ELEM_TYPE *)_array_get((GenericArray *)ARRAY_PTR, INDEX, sizeof(ELEM_TYPE)))
|
||||
#define wapp_array_set(ELEM_TYPE, ARRAY_PTR, INDEX, VALUE_PTR) \
|
||||
_array_set((GenericArray *)ARRAY_PTR, INDEX, (void *)VALUE_PTR, sizeof(ELEM_TYPE))
|
||||
#define wapp_array_append_capped(ELEM_TYPE, ARRAY_PTR, VALUE_PTR) \
|
||||
_array_append_capped((GenericArray *)ARRAY_PTR, (void *)VALUE_PTR, sizeof(ELEM_TYPE))
|
||||
#define wapp_array_extend_capped(ELEM_TYPE, DST_ARRAY_PTR, SRC_ARRAY_PTR) \
|
||||
_array_extend_capped( \
|
||||
(GenericArray *)DST_ARRAY_PTR, (GenericArray *)SRC_ARRAY_PTR, sizeof(ELEM_TYPE) \
|
||||
)
|
||||
#define wapp_array_copy_capped(ELEM_TYPE, DST_ARRAY_PTR, SRC_ARRAY_PTR) \
|
||||
_array_copy_capped( \
|
||||
(GenericArray *)DST_ARRAY_PTR, (GenericArray *)SRC_ARRAY_PTR, sizeof(ELEM_TYPE) \
|
||||
)
|
||||
#define wapp_array_append_alloc(ELEM_TYPE, ARRAY_TYPE, ALLOCATOR_PTR, ARRAY_PTR, VALUE_PTR) \
|
||||
(ARRAY_TYPE *)_array_append_alloc( \
|
||||
ALLOCATOR_PTR, (GenericArray *)ARRAY_PTR, (void *)VALUE_PTR, sizeof(ELEM_TYPE) \
|
||||
)
|
||||
#define wapp_array_extend_alloc(ELEM_TYPE, ARRAY_TYPE, ALLOCATOR_PTR, DST_ARRAY_PTR, SRC_ARRAY_PTR) \
|
||||
(ARRAY_TYPE *)_array_extend_alloc( \
|
||||
ALLOCATOR_PTR, (GenericArray *)DST_ARRAY_PTR, (GenericArray *)SRC_ARRAY_PTR, sizeof(ELEM_TYPE) \
|
||||
)
|
||||
#define wapp_array_copy_alloc(ELEM_TYPE, ARRAY_TYPE, ALLOCATOR_PTR, DST_ARRAY_PTR, SRC_ARRAY_PTR) \
|
||||
(ARRAY_TYPE *)_array_copy_alloc( \
|
||||
ALLOCATOR_PTR, (GenericArray *)DST_ARRAY_PTR, (GenericArray *)SRC_ARRAY_PTR, sizeof(ELEM_TYPE) \
|
||||
)
|
||||
#define wapp_array_clear(ELEM_TYPE, ARRAY_PTR) \
|
||||
_array_clear((GenericArray *)ARRAY_PTR, sizeof(ELEM_TYPE))
|
||||
|
||||
WAPP_DEF_ARRAY_TYPE(void, GenericArray);
|
||||
|
||||
void *_array_get(GenericArray *array, u64 index, u64 item_size);
|
||||
void _array_set(GenericArray *array, u64 index, void *value, u64 item_size);
|
||||
void _array_append_capped(GenericArray *array, void *value, u64 item_size);
|
||||
void _array_extend_capped(GenericArray *dst, const GenericArray *src, u64 item_size);
|
||||
void _array_copy_capped(GenericArray *dst, const GenericArray *src, u64 item_size);
|
||||
GenericArray *_array_append_alloc(const Allocator *allocator, GenericArray *array, void *value, u64 item_size);
|
||||
GenericArray *_array_extend_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size);
|
||||
GenericArray *_array_copy_alloc(const Allocator *allocator, GenericArray *dst, const GenericArray *src, u64 item_size);
|
||||
void *_array_pop(GenericArray *array, u64 item_size);
|
||||
void _array_clear(GenericArray *array, u64 item_size);
|
||||
GenericArray *_array_alloc_capacity(const Allocator *allocator, u64 capacity, u64 item_size);
|
||||
|
||||
// Base array types
|
||||
typedef struct str8 Str8;
|
||||
|
||||
WAPP_DEF_ARRAY_TYPE(void *, VoidPtrArray);
|
||||
WAPP_DEF_ARRAY_TYPE(c8 , C8Array);
|
||||
WAPP_DEF_ARRAY_TYPE(c16 , C16Array);
|
||||
WAPP_DEF_ARRAY_TYPE(c32 , C32Array);
|
||||
WAPP_DEF_ARRAY_TYPE(u8 , U8Array);
|
||||
WAPP_DEF_ARRAY_TYPE(u16 , U16Array);
|
||||
WAPP_DEF_ARRAY_TYPE(u32 , U32Array);
|
||||
WAPP_DEF_ARRAY_TYPE(u64 , U64Array);
|
||||
WAPP_DEF_ARRAY_TYPE(b8 , B8Array);
|
||||
WAPP_DEF_ARRAY_TYPE(i8 , I8Array);
|
||||
WAPP_DEF_ARRAY_TYPE(i16 , I16Array);
|
||||
WAPP_DEF_ARRAY_TYPE(i32 , I32Array);
|
||||
WAPP_DEF_ARRAY_TYPE(i64 , I64Array);
|
||||
WAPP_DEF_ARRAY_TYPE(f32 , F32Array);
|
||||
WAPP_DEF_ARRAY_TYPE(f64 , F64Array);
|
||||
WAPP_DEF_ARRAY_TYPE(f128 , F128Array);
|
||||
WAPP_DEF_ARRAY_TYPE(uptr , UptrArray);
|
||||
WAPP_DEF_ARRAY_TYPE(iptr , IptrArray);
|
||||
WAPP_DEF_ARRAY_TYPE(Str8 , Str8Array);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !ARRAY_H
|
||||
255
src/base/dbl_list/dbl_list.c
Normal file
255
src/base/dbl_list/dbl_list.c
Normal file
@@ -0,0 +1,255 @@
|
||||
#include "./dbl_list.h"
|
||||
#include "../mem/allocator/mem_allocator.h"
|
||||
#include "../../common/assert/assert.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
#include <stddef.h>
|
||||
|
||||
wapp_intern GenericList _node_to_list(GenericNode *node, u64 item_size);
|
||||
wapp_intern void _dbl_list_validate(const GenericList *list, u64 item_size);
|
||||
wapp_intern void _dbl_list_node_validate(const GenericNode *node, u64 item_size);
|
||||
|
||||
GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size) {
|
||||
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
|
||||
|
||||
GenericList *list = wapp_mem_allocator_alloc(allocator, sizeof(GenericList));
|
||||
if (!list) { goto DBL_LIST_ALLOC_RETURN; }
|
||||
|
||||
memset((void *)list, 0, sizeof(GenericList));
|
||||
list->magic = WAPP_DBL_LIST_MAGIC;
|
||||
list->item_size = item_size;
|
||||
|
||||
DBL_LIST_ALLOC_RETURN:
|
||||
return list;
|
||||
}
|
||||
|
||||
GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size) {
|
||||
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
|
||||
|
||||
GenericNode *node = wapp_mem_allocator_alloc(allocator, sizeof(GenericNode));
|
||||
if (!node) { goto DBL_LIST_NODE_ALLOC_RETURN; }
|
||||
|
||||
memset((void *)node, 0, sizeof(GenericNode));
|
||||
node->magic = WAPP_DBL_NODE_MAGIC;
|
||||
node->item_size = item_size;
|
||||
|
||||
DBL_LIST_NODE_ALLOC_RETURN:
|
||||
return node;
|
||||
}
|
||||
|
||||
GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");
|
||||
|
||||
GenericNode *output = NULL;
|
||||
GenericNode *current = list->first;
|
||||
for (u64 i = 1; i <= index; ++i) {
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
output = current;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
_dbl_list_node_validate(node, item_size);
|
||||
|
||||
GenericList node_list = _node_to_list(node, item_size);
|
||||
|
||||
if (list->node_count == 0) {
|
||||
*list = node_list;
|
||||
return;
|
||||
}
|
||||
|
||||
list->node_count += node_list.node_count;
|
||||
|
||||
GenericNode *first = list->first;
|
||||
if (first) {
|
||||
first->prev = node_list.last;
|
||||
}
|
||||
|
||||
list->first = node_list.first;
|
||||
node_list.last->next = first;
|
||||
}
|
||||
|
||||
void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
_dbl_list_node_validate(node, item_size);
|
||||
|
||||
GenericList node_list = _node_to_list(node, item_size);
|
||||
|
||||
if (list->node_count == 0) {
|
||||
*list = node_list;
|
||||
return;
|
||||
}
|
||||
|
||||
list->node_count += node_list.node_count;
|
||||
|
||||
GenericNode *last = list->last;
|
||||
if (last) {
|
||||
last->next = node_list.first;
|
||||
}
|
||||
|
||||
list->last = node_list.last;
|
||||
node_list.first->prev = last;
|
||||
}
|
||||
|
||||
void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
_dbl_list_node_validate(node, item_size);
|
||||
|
||||
if (index == 0) {
|
||||
_dbl_list_push_front(list, node, item_size);
|
||||
return;
|
||||
} else if (index == list->node_count) {
|
||||
_dbl_list_push_back(list, node, item_size);
|
||||
return;
|
||||
}
|
||||
|
||||
GenericNode *dst_node = _dbl_list_get(list, index, item_size);
|
||||
if (!dst_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
GenericList node_list = _node_to_list(node, item_size);
|
||||
|
||||
list->node_count += node_list.node_count;
|
||||
|
||||
GenericNode *prev = dst_node->prev;
|
||||
|
||||
dst_node->prev = node_list.last;
|
||||
prev->next = node_list.first;
|
||||
|
||||
node_list.first->prev = prev;
|
||||
node_list.last->next = dst_node;
|
||||
}
|
||||
|
||||
GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
|
||||
GenericNode *output = NULL;
|
||||
|
||||
if (list->node_count == 0) {
|
||||
goto RETURN_I32_LIST_POP_FRONT;
|
||||
}
|
||||
|
||||
output = list->first;
|
||||
|
||||
if (list->node_count == 1) {
|
||||
*list = (GenericList){0};
|
||||
goto RETURN_I32_LIST_POP_FRONT;
|
||||
}
|
||||
|
||||
--(list->node_count);
|
||||
list->first = output->next;
|
||||
|
||||
output->prev = output->next = NULL;
|
||||
|
||||
RETURN_I32_LIST_POP_FRONT:
|
||||
return output;
|
||||
}
|
||||
|
||||
GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
|
||||
GenericNode *output = NULL;
|
||||
|
||||
if (list->node_count == 0) {
|
||||
goto RETURN_I32_LIST_POP_BACK;
|
||||
}
|
||||
|
||||
output = list->last;
|
||||
|
||||
if (list->node_count == 1) {
|
||||
*list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size};
|
||||
goto RETURN_I32_LIST_POP_BACK;
|
||||
}
|
||||
|
||||
--(list->node_count);
|
||||
list->last = output->prev;
|
||||
|
||||
output->prev = output->next = NULL;
|
||||
|
||||
RETURN_I32_LIST_POP_BACK:
|
||||
return output;
|
||||
}
|
||||
|
||||
GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
|
||||
GenericNode *output = NULL;
|
||||
|
||||
if (index == 0) {
|
||||
output = _dbl_list_pop_front(list, item_size);
|
||||
goto RETURN_I32_LIST_REMOVE;
|
||||
} else if (index == list->node_count) {
|
||||
output = _dbl_list_pop_back(list, item_size);
|
||||
goto RETURN_I32_LIST_REMOVE;
|
||||
}
|
||||
|
||||
output = _dbl_list_get(list, index, item_size);
|
||||
if (!output) {
|
||||
goto RETURN_I32_LIST_REMOVE;
|
||||
}
|
||||
|
||||
output->prev->next = output->next;
|
||||
output->next->prev = output->prev;
|
||||
|
||||
--(list->node_count);
|
||||
|
||||
output->prev = output->next = NULL;
|
||||
|
||||
RETURN_I32_LIST_REMOVE:
|
||||
return output;
|
||||
}
|
||||
|
||||
void _dbl_list_empty(GenericList *list, u64 item_size) {
|
||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
||||
_dbl_list_validate(list, item_size);
|
||||
|
||||
u64 count = list->node_count;
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
_dbl_list_pop_back(list, item_size);
|
||||
}
|
||||
}
|
||||
|
||||
wapp_intern GenericList _node_to_list(GenericNode *node, u64 item_size) {
|
||||
GenericList output = {
|
||||
.magic = WAPP_DBL_LIST_MAGIC,
|
||||
.first = node,
|
||||
.last = node,
|
||||
.node_count = 1,
|
||||
.item_size = item_size,
|
||||
};
|
||||
|
||||
while (output.first->prev != NULL) {
|
||||
output.first = output.first->prev;
|
||||
++(output.node_count);
|
||||
}
|
||||
|
||||
while (output.last->next != NULL) {
|
||||
output.last = output.last->next;
|
||||
++(output.node_count);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
wapp_intern void _dbl_list_validate(const GenericList *list, u64 item_size) {
|
||||
wapp_runtime_assert(list->magic == WAPP_DBL_LIST_MAGIC, "`list` isn't a valid wapp list type");
|
||||
wapp_runtime_assert(list->item_size == item_size, "Invalid item provided");
|
||||
}
|
||||
|
||||
wapp_intern void _dbl_list_node_validate(const GenericNode *node, u64 item_size) {
|
||||
wapp_runtime_assert(node->magic == WAPP_DBL_NODE_MAGIC, "`node` isn't a valid wapp node type");
|
||||
wapp_runtime_assert(node->item_size == item_size, "Invalid item provided");
|
||||
}
|
||||
108
src/base/dbl_list/dbl_list.h
Normal file
108
src/base/dbl_list/dbl_list.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef DBL_LIST_H
|
||||
#define DBL_LIST_H
|
||||
|
||||
#include "../mem/allocator/mem_allocator.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define WAPP_DBL_LIST_MAGIC (u64)0x57415f444c5354
|
||||
#define WAPP_DBL_NODE_MAGIC (u64)0x57415f444e44
|
||||
|
||||
#define WAPP_DEF_DBL_LIST_TYPE(T, NODE_NAME, LIST_NAME) \
|
||||
typedef struct NODE_NAME NODE_NAME; \
|
||||
struct NODE_NAME { \
|
||||
u64 magic; \
|
||||
T *item; \
|
||||
NODE_NAME *prev; \
|
||||
NODE_NAME *next; \
|
||||
u64 item_size; \
|
||||
}; \
|
||||
\
|
||||
typedef struct { \
|
||||
u64 magic; \
|
||||
NODE_NAME *first; \
|
||||
NODE_NAME *last; \
|
||||
u64 node_count; \
|
||||
u64 item_size; \
|
||||
} LIST_NAME
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
#define wapp_dbl_list(ELEM_TYPE, LIST_TYPE) \
|
||||
LIST_TYPE{WAPP_DBL_LIST_MAGIC, nullptr, nullptr, 0, sizeof(ELEM_TYPE)}
|
||||
#define wapp_dbl_list_node(ELEM_TYPE, NODE_TYPE, ELEM_PTR) \
|
||||
NODE_TYPE{WAPP_DBL_NODE_MAGIC, ELEM_PTR, nullptr, nullptr, sizeof(ELEM_TYPE)}
|
||||
#else
|
||||
#define wapp_dbl_list(ELEM_TYPE, LIST_TYPE) ( \
|
||||
(LIST_TYPE){.magic = WAPP_DBL_LIST_MAGIC, .item_size = sizeof(ELEM_TYPE)} \
|
||||
)
|
||||
#define wapp_dbl_list_node(ELEM_TYPE, NODE_TYPE, ELEM_PTR) ( \
|
||||
(NODE_TYPE){.magic = WAPP_DBL_NODE_MAGIC, .item = ELEM_PTR, .item_size = sizeof(ELEM_TYPE)} \
|
||||
)
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define wapp_dbl_list_alloc(ELEM_TYPE, LIST_TYPE, ALLOCATOR) \
|
||||
(LIST_TYPE *)_dbl_list_alloc(ALLOCATOR, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_node_alloc(ELEM_TYPE, NODE_TYPE, ALLOCATOR) \
|
||||
(NODE_TYPE *)_dbl_list_node_alloc(ALLOCATOR, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_get(ELEM_TYPE, NODE_TYPE, LIST_PTR, ELEM_INDEX) \
|
||||
(NODE_TYPE *)_dbl_list_get((GenericList *)LIST_PTR, ELEM_INDEX, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_push_front(ELEM_TYPE, LIST_PTR, NODE_PTR) \
|
||||
_dbl_list_push_front((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_push_back(ELEM_TYPE, LIST_PTR, NODE_PTR) \
|
||||
_dbl_list_push_back((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_insert(ELEM_TYPE, LIST_PTR, NODE_PTR, ELEM_INDEX) \
|
||||
_dbl_list_insert((GenericList *)LIST_PTR, (GenericNode *)NODE_PTR, ELEM_INDEX, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_pop_front(ELEM_TYPE, NODE_TYPE, LIST_PTR) \
|
||||
(NODE_TYPE *)_dbl_list_pop_front((GenericList *)LIST_PTR, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_pop_back(ELEM_TYPE, NODE_TYPE, LIST_PTR) \
|
||||
(NODE_TYPE *)_dbl_list_pop_back((GenericList *)LIST_PTR, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_remove(ELEM_TYPE, NODE_TYPE, LIST_PTR, ELEM_INDEX) \
|
||||
(NODE_TYPE *)_dbl_list_remove((GenericList *)LIST_PTR, ELEM_INDEX, sizeof(ELEM_TYPE))
|
||||
#define wapp_dbl_list_empty(ELEM_TYPE, LIST_PTR) \
|
||||
_dbl_list_empty((GenericList *)LIST_PTR, sizeof(ELEM_TYPE))
|
||||
|
||||
WAPP_DEF_DBL_LIST_TYPE(void, GenericNode, GenericList);
|
||||
|
||||
GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size);
|
||||
GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size);
|
||||
GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size);
|
||||
void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size);
|
||||
void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size);
|
||||
void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size);
|
||||
GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size);
|
||||
GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size);
|
||||
GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size);
|
||||
void _dbl_list_empty(GenericList *list, u64 item_size);
|
||||
|
||||
// Base list types
|
||||
typedef struct str8 Str8;
|
||||
|
||||
WAPP_DEF_DBL_LIST_TYPE(void *, VoidPtrNode, VoidPtrList);
|
||||
WAPP_DEF_DBL_LIST_TYPE(c8 , C8Node , C8List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(c16 , C16Node , C16List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(c32 , C32Node , C32List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(u8 , U8Node , U8List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(u16 , U16Node , U16List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(u32 , U32Node , U32List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(u64 , U64Node , U64List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(b8 , B8Node , B8List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(i8 , I8Node , I8List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(i16 , I16Node , I16List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(i32 , I32Node , I32List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(i64 , I64Node , I64List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(f32 , F32Node , F32List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(f64 , F64Node , F64List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(f128 , F128Node , F128List);
|
||||
WAPP_DEF_DBL_LIST_TYPE(uptr , UptrNode , UptrList);
|
||||
WAPP_DEF_DBL_LIST_TYPE(iptr , IptrNode , IptrList);
|
||||
WAPP_DEF_DBL_LIST_TYPE(Str8 , Str8Node , Str8List);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !DBL_LIST_H
|
||||
35
src/base/mem/allocator/mem_allocator.c
Normal file
35
src/base/mem/allocator/mem_allocator.c
Normal file
@@ -0,0 +1,35 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "mem_allocator.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/assert/assert.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) {
|
||||
wapp_debug_assert(allocator != NULL && (allocator->alloc) != NULL, "`allocator` and `allocator->alloc` should not be NULL");
|
||||
return allocator->alloc(size, allocator->obj);
|
||||
}
|
||||
|
||||
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment) {
|
||||
wapp_debug_assert(allocator != NULL && (allocator->alloc_aligned) != NULL, "`allocator` and `allocator->alloc_aligned` should not be NULL");
|
||||
return allocator->alloc_aligned(size, alignment, allocator->obj);
|
||||
}
|
||||
|
||||
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size) {
|
||||
wapp_debug_assert(allocator != NULL && (allocator->realloc) != NULL, "`allocator` and `allocator->realloc` should not be NULL");
|
||||
return allocator->realloc(ptr, old_size, new_size, allocator->obj);
|
||||
}
|
||||
|
||||
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size,
|
||||
u64 new_size, u64 alignment) {
|
||||
wapp_debug_assert(allocator != NULL && (allocator->realloc_aligned) != NULL, "`allocator` and `allocator->realloc_aligned` should not be NULL");
|
||||
return allocator->realloc_aligned(ptr, old_size, new_size, alignment, allocator->obj);
|
||||
}
|
||||
|
||||
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size) {
|
||||
if (!allocator || !(allocator->free)) {
|
||||
return;
|
||||
}
|
||||
|
||||
allocator->free(ptr, size, allocator->obj);
|
||||
}
|
||||
50
src/base/mem/allocator/mem_allocator.h
Normal file
50
src/base/mem/allocator/mem_allocator.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_ALLOCATOR_H
|
||||
#define MEM_ALLOCATOR_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef void *(MemAllocFunc)(u64 size, void *alloc_obj);
|
||||
typedef void *(MemAllocAlignedFunc)(u64 size, u64 alignment, void *alloc_obj);
|
||||
typedef void *(MemReallocFunc)(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
|
||||
typedef void *(MemReallocAlignedFunc)(void *ptr, u64 old_size, u64 new_size, u64 alignment, void *alloc_obj);
|
||||
typedef void (MemFreeFunc)(void **ptr, u64 size, void *alloc_obj);
|
||||
|
||||
typedef struct allocator Allocator;
|
||||
struct allocator {
|
||||
void *obj;
|
||||
MemAllocFunc *alloc;
|
||||
MemAllocAlignedFunc *alloc_aligned;
|
||||
MemReallocFunc *realloc;
|
||||
MemReallocAlignedFunc *realloc_aligned;
|
||||
MemFreeFunc *free;
|
||||
};
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
#define wapp_mem_allocator_invalid(ALLOCATOR) ([&]() { \
|
||||
Allocator alloc{}; \
|
||||
return memcmp(ALLOCATOR, &alloc, sizeof(Allocator)) == 0; \
|
||||
}())
|
||||
#else
|
||||
#define wapp_mem_allocator_invalid(ALLOCATOR) (memcmp(ALLOCATOR, &((Allocator){0}), sizeof(Allocator)) == 0)
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size);
|
||||
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment);
|
||||
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size);
|
||||
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size,
|
||||
u64 new_size, u64 alignment);
|
||||
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr, u64 size);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_ALLOCATOR_H
|
||||
26
src/base/mem/utils/mem_utils.c
Normal file
26
src/base/mem/utils/mem_utils.c
Normal file
@@ -0,0 +1,26 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "mem_utils.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/assert/assert.h"
|
||||
#include <stddef.h>
|
||||
|
||||
wapp_intern b8 is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
||||
wapp_debug_assert(ptr != NULL, "`ptr` should not be NULL");
|
||||
wapp_runtime_assert(is_power_of_two(alignment), "`alignment` value is not a power of two");
|
||||
|
||||
uptr p = (uptr)ptr;
|
||||
uptr align = (uptr)alignment;
|
||||
|
||||
// Similar to p % align, but it's a faster implementation that works fine
|
||||
// because align is guaranteed to be a power of 2
|
||||
uptr modulo = p & (align - 1);
|
||||
|
||||
if (modulo != 0) {
|
||||
p += align - modulo;
|
||||
}
|
||||
|
||||
return (void *)p;
|
||||
}
|
||||
19
src/base/mem/utils/mem_utils.h
Normal file
19
src/base/mem/utils/mem_utils.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_UTILS_H
|
||||
#define MEM_UTILS_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_UTILS_H
|
||||
492
src/base/strings/str8/str8.c
Normal file
492
src/base/strings/str8/str8.c
Normal file
@@ -0,0 +1,492 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "str8.h"
|
||||
#include "../../array/array.h"
|
||||
#include "../../mem/allocator/mem_allocator.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/assert/assert.h"
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define STR8_BUF_ALLOC_SIZE(CAPACITY) (sizeof(Str8) + sizeof(c8) * CAPACITY)
|
||||
|
||||
Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity) {
|
||||
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
|
||||
|
||||
Str8 *str = wapp_mem_allocator_alloc(allocator, STR8_BUF_ALLOC_SIZE(capacity));
|
||||
if (!str) {
|
||||
goto RETURN_STR8;
|
||||
}
|
||||
|
||||
str->buf = (u8 *)str + sizeof(Str8);
|
||||
str->size = 0;
|
||||
str->capacity = capacity;
|
||||
|
||||
RETURN_STR8:
|
||||
return str;
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity) {
|
||||
Str8 *out = wapp_str8_alloc_buf(allocator, capacity);
|
||||
if (out) {
|
||||
memset(out->buf, 0, capacity);
|
||||
out->size = capacity;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_alloc_cstr(const Allocator *allocator, const char *str) {
|
||||
wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
|
||||
|
||||
u64 length = strlen(str);
|
||||
Str8 *output = wapp_str8_alloc_buf(allocator, length * 2);
|
||||
if (!output) {
|
||||
goto RETURN_ALLOC_CSTR;
|
||||
}
|
||||
|
||||
output->size = length;
|
||||
memcpy(output->buf, str, length);
|
||||
|
||||
RETURN_ALLOC_CSTR:
|
||||
return output;
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str) {
|
||||
wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
|
||||
|
||||
Str8 *output = wapp_str8_alloc_buf(allocator, str->capacity);
|
||||
if (!output) {
|
||||
goto RETURN_ALLOC_STR8;
|
||||
}
|
||||
|
||||
output->size = str->size;
|
||||
memcpy(output->buf, str->buf, str->size);
|
||||
|
||||
RETURN_ALLOC_STR8:
|
||||
return output;
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_alloc_substr(const Allocator *allocator, Str8RO *str, u64 start, u64 end) {
|
||||
wapp_debug_assert(allocator != NULL && str != NULL, "`allocator` and `str` should not be NULL");
|
||||
|
||||
Str8 *output = NULL;
|
||||
|
||||
if (start >= str->size || start >= end) {
|
||||
goto RETURN_ALLOC_SUBSTR;
|
||||
}
|
||||
|
||||
if (end > str->size) {
|
||||
end = str->size;
|
||||
}
|
||||
|
||||
output = wapp_str8_alloc_buf(allocator, str->capacity);
|
||||
if (!output) {
|
||||
goto RETURN_ALLOC_SUBSTR;
|
||||
}
|
||||
|
||||
output->size = end - start;
|
||||
memcpy(output->buf, str->buf + start, output->size);
|
||||
|
||||
RETURN_ALLOC_SUBSTR:
|
||||
return output;
|
||||
}
|
||||
|
||||
void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str) {
|
||||
wapp_debug_assert(allocator != NULL && str != NULL && (*str) != NULL, "Either `allocator` is NULL or `str` is an invalid double pointer");
|
||||
wapp_mem_allocator_free(allocator, (void **)str, STR8_BUF_ALLOC_SIZE((*str)->capacity));
|
||||
}
|
||||
|
||||
c8 wapp_str8_get(const Str8 *str, u64 index) {
|
||||
if (index >= str->size) {
|
||||
return '\0';
|
||||
}
|
||||
|
||||
return str->buf[index];
|
||||
}
|
||||
|
||||
void wapp_str8_set(Str8 *str, u64 index, c8 c) {
|
||||
if (index >= str->size) {
|
||||
return;
|
||||
}
|
||||
|
||||
str->buf[index] = c;
|
||||
}
|
||||
|
||||
void wapp_str8_push_back(Str8 *str, c8 c) {
|
||||
if (!(str->size < str->capacity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
u64 index = (str->size)++;
|
||||
wapp_str8_set(str, index, c);
|
||||
}
|
||||
|
||||
b8 wapp_str8_equal(Str8RO *s1, Str8RO *s2) {
|
||||
if (s1->size != s2->size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wapp_str8_equal_to_count(s1, s2, s1->size);
|
||||
}
|
||||
|
||||
b8 wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count) {
|
||||
if (!s1 || !s2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(s1->buf, s2->buf, count) == 0;
|
||||
}
|
||||
|
||||
Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end) {
|
||||
if (start >= str->size || start >= end) {
|
||||
start = str->size;
|
||||
end = str->size;
|
||||
}
|
||||
|
||||
if (end > str->size) {
|
||||
end = str->size;
|
||||
}
|
||||
|
||||
return (Str8RO){
|
||||
.capacity = end - start,
|
||||
.size = end - start,
|
||||
.buf = str->buf + start,
|
||||
};
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_alloc_concat(const Allocator *allocator, Str8 *dst, Str8RO *src) {
|
||||
wapp_debug_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
|
||||
|
||||
Str8 *output = NULL;
|
||||
u64 remaining = dst->capacity - dst->size;
|
||||
if (src->size <= remaining) {
|
||||
output = dst;
|
||||
goto SOURCE_STRING_STR8_CONCAT;
|
||||
}
|
||||
|
||||
u64 capacity = dst->capacity + src->size;
|
||||
|
||||
output = wapp_str8_alloc_buf(allocator, capacity);
|
||||
if (!output) {
|
||||
goto RETURN_STR8_CONCAT;
|
||||
}
|
||||
|
||||
wapp_str8_concat_capped(output, dst);
|
||||
|
||||
SOURCE_STRING_STR8_CONCAT:
|
||||
wapp_str8_concat_capped(output, src);
|
||||
|
||||
RETURN_STR8_CONCAT:
|
||||
return output;
|
||||
}
|
||||
|
||||
void wapp_str8_concat_capped(Str8 *dst, Str8RO *src) {
|
||||
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||
|
||||
u64 remaining = dst->capacity - dst->size;
|
||||
u64 to_copy = remaining < src->size ? remaining : src->size;
|
||||
|
||||
memcpy(dst->buf + dst->size, src->buf, to_copy);
|
||||
dst->size += to_copy;
|
||||
}
|
||||
|
||||
void wapp_str8_copy_cstr_capped(Str8 *dst, const char *src) {
|
||||
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||
|
||||
u64 length = strlen(src);
|
||||
u64 to_copy = length <= dst->capacity ? length : dst->capacity;
|
||||
|
||||
memset(dst->buf, 0, dst->size);
|
||||
memcpy(dst->buf, src, to_copy);
|
||||
dst->size = to_copy;
|
||||
}
|
||||
|
||||
void wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src) {
|
||||
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||
|
||||
u64 to_copy = src->size <= dst->capacity ? src->size : dst->capacity;
|
||||
|
||||
memset(dst->buf, 0, dst->size);
|
||||
memcpy(dst->buf, src->buf, to_copy);
|
||||
dst->size = to_copy;
|
||||
}
|
||||
|
||||
void wapp_str8_copy_to_cstr(char *dst, Str8RO *src, u64 dst_capacity) {
|
||||
wapp_debug_assert(dst != NULL && src != NULL, "`dst` and `src` should not be NULL");
|
||||
|
||||
u64 to_copy = src->size < dst_capacity ? src->size : dst_capacity - 1;
|
||||
|
||||
memset(dst, 0, dst_capacity);
|
||||
memcpy(dst, src->buf, to_copy);
|
||||
}
|
||||
|
||||
void wapp_str8_format(Str8 *dst, const char *format, ...) {
|
||||
wapp_debug_assert(dst != NULL && format != NULL, "`dst` and `format` should not be NULL");
|
||||
|
||||
va_list args1;
|
||||
va_list args2;
|
||||
|
||||
va_start(args1, format);
|
||||
va_copy(args2, args1);
|
||||
|
||||
u64 total_size = vsnprintf(NULL, 0, format, args1);
|
||||
dst->size = total_size <= dst->capacity ? total_size : dst->capacity;
|
||||
|
||||
vsnprintf((char *)(dst->buf), dst->capacity, format, args2);
|
||||
|
||||
va_end(args1);
|
||||
va_end(args2);
|
||||
}
|
||||
|
||||
void wapp_str8_to_lower(Str8 *dst, Str8RO *src) {
|
||||
wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
|
||||
wapp_debug_assert(dst->capacity >= src->capacity, "`dst` does not have enough capacity");
|
||||
|
||||
dst->size = src->size;
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
wapp_str8_set(dst, index, (u8)tolower(wapp_str8_get(src, index)));
|
||||
++index;
|
||||
running = index < src->size;
|
||||
}
|
||||
}
|
||||
|
||||
void wapp_str8_to_upper(Str8 *dst, Str8RO *src) {
|
||||
wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
|
||||
wapp_debug_assert(dst->capacity >= src->capacity, "`dst` does not have enough capacity");
|
||||
|
||||
dst->size = src->size;
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
wapp_str8_set(dst, index, (u8)toupper(wapp_str8_get(src, index)));
|
||||
++index;
|
||||
running = index < src->size;
|
||||
}
|
||||
}
|
||||
|
||||
void wapp_str8_from_bytes(Str8 *dst, const U8Array *src) {
|
||||
wapp_debug_assert(src != NULL && dst != NULL, "`dst` and `src` should not be NULL");
|
||||
|
||||
u64 size = src->count * src->item_size;
|
||||
|
||||
wapp_debug_assert(dst->capacity >= size, "`dst` does not have enough capacity");
|
||||
|
||||
dst->size = size;
|
||||
memcpy(dst->buf, src->items, size);
|
||||
}
|
||||
|
||||
i64 wapp_str8_find(Str8RO *str, Str8RO substr) {
|
||||
if (!str || substr.size > str->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
u64 char_index = 0;
|
||||
b8 running = char_index < str->size;
|
||||
while (running) {
|
||||
const c8 *sub = str->buf + char_index;
|
||||
if (memcmp(sub, substr.buf, substr.size) == 0) {
|
||||
return char_index;
|
||||
}
|
||||
|
||||
++char_index;
|
||||
running = char_index < str->size;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
i64 wapp_str8_rfind(Str8RO *str, Str8RO substr) {
|
||||
if (!str || substr.size > str->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
i64 char_index = str->size - substr.size;
|
||||
b8 running = char_index >= 0;
|
||||
while (running) {
|
||||
const c8 *sub = str->buf + char_index;
|
||||
if (memcmp(sub, substr.buf, substr.size) == 0) {
|
||||
return char_index;
|
||||
}
|
||||
|
||||
--char_index;
|
||||
running = char_index >= 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Str8List *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) {
|
||||
wapp_debug_assert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL");
|
||||
|
||||
Str8List *output = wapp_dbl_list_alloc(Str8, Str8List, allocator);
|
||||
|
||||
if (delimiter->size > str->size) {
|
||||
Str8 *full = wapp_str8_alloc_str8(allocator, str);
|
||||
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
|
||||
if (node) {
|
||||
node->item = full;
|
||||
wapp_dbl_list_push_back(Str8, output, node);
|
||||
}
|
||||
|
||||
goto RETURN_STR8_SPLIT;
|
||||
}
|
||||
|
||||
i64 start = 0;
|
||||
i64 end = 0;
|
||||
i64 splits = 0;
|
||||
Str8 *rest = wapp_str8_alloc_str8(allocator, str);
|
||||
Str8 *before_str;
|
||||
|
||||
while ((end = wapp_str8_find(rest, *delimiter)) != -1) {
|
||||
if (max_splits > 0 && splits >= max_splits) {
|
||||
break;
|
||||
}
|
||||
|
||||
before_str = wapp_str8_alloc_substr(allocator, str, start, start + end);
|
||||
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
|
||||
if (node && before_str) {
|
||||
node->item = before_str;
|
||||
wapp_dbl_list_push_back(Str8, output, node);
|
||||
}
|
||||
|
||||
wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8));
|
||||
rest = wapp_str8_alloc_substr(allocator, str, start + end + delimiter->size, str->size);
|
||||
start += end + delimiter->size;
|
||||
|
||||
++splits;
|
||||
}
|
||||
|
||||
// Ensure the last part of the string after the delimiter is added to the list
|
||||
rest = wapp_str8_alloc_substr(allocator, str, start, str->size);
|
||||
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
|
||||
if (node && rest) {
|
||||
node->item = rest;
|
||||
wapp_dbl_list_push_back(Str8, output, node);
|
||||
}
|
||||
|
||||
RETURN_STR8_SPLIT:
|
||||
return output;
|
||||
}
|
||||
|
||||
Str8List *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits) {
|
||||
wapp_debug_assert(allocator != NULL && str != NULL && delimiter != NULL, "`allocator`, `str` and `delimiter` should not be NULL");
|
||||
|
||||
Str8List *output = wapp_dbl_list_alloc(Str8, Str8List, allocator);
|
||||
|
||||
if (delimiter->size > str->size) {
|
||||
Str8 *full = wapp_str8_alloc_str8(allocator, str);
|
||||
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
|
||||
if (node && full) {
|
||||
node->item = full;
|
||||
wapp_dbl_list_push_back(Str8, output, node);
|
||||
}
|
||||
|
||||
goto RETURN_STR8_SPLIT;
|
||||
}
|
||||
|
||||
i64 end = 0;
|
||||
i64 splits = 0;
|
||||
Str8 *rest = wapp_str8_alloc_str8(allocator, str);
|
||||
Str8 *after_str;
|
||||
|
||||
while ((end = wapp_str8_rfind(rest, *delimiter)) != -1) {
|
||||
if (max_splits > 0 && splits >= max_splits) {
|
||||
break;
|
||||
}
|
||||
|
||||
after_str = wapp_str8_alloc_substr(allocator, rest, end + delimiter->size, str->size);
|
||||
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
|
||||
if (node) {
|
||||
node->item = after_str;
|
||||
wapp_dbl_list_push_front(Str8, output, node);
|
||||
}
|
||||
|
||||
wapp_mem_allocator_free(allocator, (void **)&rest, sizeof(Str8));
|
||||
rest = wapp_str8_alloc_substr(allocator, rest, 0, end);
|
||||
|
||||
++splits;
|
||||
}
|
||||
|
||||
rest = wapp_str8_alloc_substr(allocator, str, 0, rest->size);
|
||||
Str8Node *node = wapp_dbl_list_node_alloc(Str8, Str8Node, allocator);
|
||||
if (node && rest) {
|
||||
node->item = rest;
|
||||
wapp_dbl_list_push_front(Str8, output, node);
|
||||
}
|
||||
|
||||
RETURN_STR8_SPLIT:
|
||||
return output;
|
||||
}
|
||||
|
||||
Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter) {
|
||||
wapp_debug_assert(allocator != NULL && list != NULL && delimiter != NULL, "`allocator`, `list` and `delimiter` should not be NULL");
|
||||
|
||||
u64 capacity = wapp_str8_list_total_size(list) + (delimiter->size * (list->node_count - 1));
|
||||
Str8 *output = wapp_str8_alloc_buf(allocator, capacity * 2);
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
Str8Node *node;
|
||||
u64 node_index = 0;
|
||||
b8 running = node_index < list->node_count;
|
||||
while (running) {
|
||||
node = wapp_dbl_list_get(Str8, Str8Node, list, node_index);
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
wapp_str8_concat_capped(output, node->item);
|
||||
|
||||
// NOTE (Abdelrahman): Comparison extracted to variable to silence
|
||||
// MSVC Spectre mitigation warnings
|
||||
b8 not_last = node_index + 1 < list->node_count;
|
||||
if (not_last) {
|
||||
wapp_str8_concat_capped(output, delimiter);
|
||||
}
|
||||
|
||||
++node_index;
|
||||
running = node_index < list->node_count;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
u64 wapp_str8_list_total_size(const Str8List *list) {
|
||||
if (!list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
Str8Node* node;
|
||||
u64 node_index = 0;
|
||||
u64 output = 0;
|
||||
b8 running = node_index < list->node_count;
|
||||
while (running) {
|
||||
node = wapp_dbl_list_get(Str8, Str8Node, list, node_index);
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
output += node->item->size;
|
||||
++node_index;
|
||||
running = node_index < list->node_count;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
149
src/base/strings/str8/str8.h
Normal file
149
src/base/strings/str8/str8.h
Normal file
@@ -0,0 +1,149 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef STR8_H
|
||||
#define STR8_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/assert/assert.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include "../../array/array.h"
|
||||
#include "../../dbl_list/dbl_list.h"
|
||||
#include "../../mem/allocator/mem_allocator.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef struct str8 Str8;
|
||||
struct str8 {
|
||||
u64 capacity;
|
||||
u64 size;
|
||||
c8 *buf;
|
||||
};
|
||||
|
||||
typedef const Str8 Str8RO;
|
||||
|
||||
/**
|
||||
* Utilities to be used with printf functions
|
||||
*/
|
||||
#define WAPP_STR8_SPEC "%.*s"
|
||||
#define wapp_str8_varg(STRING) (int)((STRING).size), (STRING).buf
|
||||
|
||||
/**
|
||||
* Str8 stack buffers
|
||||
*/
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
// Uses a lambda to achieve the same behaviour achieved by the C macro
|
||||
#define wapp_str8_buf(CAPACITY) ([&](){ \
|
||||
wapp_persist c8 buf[CAPACITY] = {}; \
|
||||
memset(buf, 0, CAPACITY); \
|
||||
return Str8{CAPACITY, 0, buf}; \
|
||||
}())
|
||||
|
||||
// Uses a lambda to achieve the same behaviour achieved by the C macro
|
||||
#define wapp_str8_lit(STRING) ([&]() { \
|
||||
wapp_persist c8 buf[sizeof(STRING) * 2] = {}; \
|
||||
memcpy(buf, STRING, sizeof(STRING)); \
|
||||
return Str8{(sizeof(STRING) - 1) * 2, sizeof(STRING) - 1, buf}; \
|
||||
}())
|
||||
|
||||
#define wapp_str8_lit_ro(STRING) Str8RO{sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING}
|
||||
#define wapp_str8_lit_ro_initialiser_list(STRING) {sizeof(STRING) - 1, sizeof(STRING) - 1, (c8 *)STRING}
|
||||
#else
|
||||
#define wapp_str8_buf(CAPACITY) ((Str8){.capacity = CAPACITY, .size = 0, .buf = (c8[CAPACITY]){0}})
|
||||
|
||||
// Utilises the fact that memcpy returns pointer to dest buffer and that getting
|
||||
// address of compound literals is valid in C to create a string on the stack
|
||||
#define wapp_str8_lit(STRING) ((Str8){.capacity = (sizeof(STRING) - 1) * 2, \
|
||||
.size = sizeof(STRING) - 1, \
|
||||
.buf = memcpy(&((c8 [sizeof(STRING) * 2]){0}), STRING, sizeof(STRING))})
|
||||
#define wapp_str8_lit_ro(STRING) ((Str8RO){.capacity = sizeof(STRING) - 1, \
|
||||
.size = sizeof(STRING) - 1, \
|
||||
.buf = (c8 *)STRING})
|
||||
// To be used only when initialising a static storage variable in compilers that don't support
|
||||
// initialisers with the syntax of wapp_str8_lit_ro (e.g. gcc). Should only be used when necessary
|
||||
// and only be assigned to a Str8RO variable to avoid any attempt at modifying the string
|
||||
#define wapp_str8_lit_ro_initialiser_list(STRING) {.capacity = sizeof(STRING) - 1, \
|
||||
.size = sizeof(STRING) - 1, \
|
||||
.buf = (c8 *)STRING}
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
/**
|
||||
* Str8 allocated buffers
|
||||
*/
|
||||
Str8 *wapp_str8_alloc_buf(const Allocator *allocator, u64 capacity);
|
||||
Str8 *wapp_str8_alloc_and_fill_buf(const Allocator *allocator, u64 capacity);
|
||||
Str8 *wapp_str8_alloc_cstr(const Allocator *allocator, const char *str);
|
||||
Str8 *wapp_str8_alloc_str8(const Allocator *allocator, Str8RO *str);
|
||||
Str8 *wapp_str8_alloc_substr(const Allocator *allocator, Str8RO *str, u64 start, u64 end);
|
||||
Str8 *wapp_str8_alloc_concat(const Allocator *allocator, Str8 *dst, Str8RO *src);
|
||||
// Only needed for allocators like malloc where each allocation has to be freed on its own.
|
||||
// No need to use it for allocators like Arena.
|
||||
void wapp_str8_dealloc_buf(const Allocator *allocator, Str8 **str);
|
||||
|
||||
/**
|
||||
* Str8 utilities
|
||||
*/
|
||||
c8 wapp_str8_get(Str8RO *str, u64 index);
|
||||
void wapp_str8_set(Str8 *str, u64 index, c8 c);
|
||||
void wapp_str8_push_back(Str8 *str, c8 c);
|
||||
b8 wapp_str8_equal(Str8RO *s1, Str8RO *s2);
|
||||
b8 wapp_str8_equal_to_count(Str8RO* s1, Str8RO* s2, u64 count);
|
||||
Str8 wapp_str8_slice(Str8RO *str, u64 start, u64 end);
|
||||
void wapp_str8_concat_capped(Str8 *dst, Str8RO *src);
|
||||
void wapp_str8_copy_cstr_capped(Str8 *dst, const char *src);
|
||||
void wapp_str8_copy_str8_capped(Str8 *dst, Str8RO *src);
|
||||
void wapp_str8_copy_to_cstr(char *dst, Str8RO *src, u64 dst_capacity);
|
||||
void wapp_str8_format(Str8 *dst, const char *format, ...);
|
||||
void wapp_str8_to_lower(Str8 *dst, Str8RO *src);
|
||||
void wapp_str8_to_upper(Str8 *dst, Str8RO *src);
|
||||
void wapp_str8_from_bytes(Str8 *dst, const U8Array *src);
|
||||
|
||||
/**
|
||||
* Str8 find functions
|
||||
*/
|
||||
i64 wapp_str8_find(Str8RO *str, Str8RO substr);
|
||||
i64 wapp_str8_rfind(Str8RO *str, Str8RO substr);
|
||||
|
||||
/**
|
||||
* Str8 split and join
|
||||
*/
|
||||
#define wapp_str8_split(ALLOCATOR, STR, DELIMITER) wapp_str8_split_with_max(ALLOCATOR, STR, DELIMITER, -1)
|
||||
#define wapp_str8_rsplit(ALLOCATOR, STR, DELIMITER) wapp_str8_rsplit_with_max(ALLOCATOR, STR, DELIMITER, -1)
|
||||
Str8List *wapp_str8_split_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits);
|
||||
Str8List *wapp_str8_rsplit_with_max(const Allocator *allocator, Str8RO *str, Str8RO *delimiter, i64 max_splits);
|
||||
Str8 *wapp_str8_join(const Allocator *allocator, const Str8List *list, Str8RO *delimiter);
|
||||
|
||||
/**
|
||||
* Str8 list utilities
|
||||
*/
|
||||
u64 wapp_str8_list_total_size(const Str8List *list);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_lvalue(T&&) {
|
||||
return std::is_lvalue_reference<T>{};
|
||||
}
|
||||
|
||||
#define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node(Str8, Str8Node, [&]() { \
|
||||
wapp_persist Str8 str = wapp_str8_lit(STRING); \
|
||||
return &str; \
|
||||
}())
|
||||
#define wapp_str8_node_from_str8(STRING) wapp_dbl_list_node(Str8, Str8Node, [&]() { \
|
||||
if (is_lvalue(STRING)) { return &STRING; } \
|
||||
\
|
||||
wapp_persist Str8 str = STRING; \
|
||||
return &str; \
|
||||
}())
|
||||
#else
|
||||
#define wapp_str8_node_from_cstr(STRING) wapp_dbl_list_node(Str8, Str8Node, &wapp_str8_lit(STRING))
|
||||
#define wapp_str8_node_from_str8(STRING) wapp_dbl_list_node(Str8, Str8Node, &(STRING))
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !STR8_H
|
||||
13
src/base/wapp_base.c
Normal file
13
src/base/wapp_base.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_BASE_C
|
||||
#define WAPP_BASE_C
|
||||
|
||||
#include "wapp_base.h"
|
||||
#include "array/array.c"
|
||||
#include "dbl_list/dbl_list.c"
|
||||
#include "mem/allocator/mem_allocator.c"
|
||||
#include "mem/utils/mem_utils.c"
|
||||
#include "strings/str8/str8.c"
|
||||
|
||||
#endif // !WAPP_BASE_C
|
||||
13
src/base/wapp_base.h
Normal file
13
src/base/wapp_base.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_BASE_H
|
||||
#define WAPP_BASE_H
|
||||
|
||||
#include "dbl_list/dbl_list.h"
|
||||
#include "array/array.h"
|
||||
#include "mem/allocator/mem_allocator.h"
|
||||
#include "mem/utils/mem_utils.h"
|
||||
#include "strings/str8/str8.h"
|
||||
#include "../common/wapp_common.h"
|
||||
|
||||
#endif // !WAPP_BASE_H
|
||||
67
src/common/aliases/aliases.h
Normal file
67
src/common/aliases/aliases.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef ALIASES_H
|
||||
#define ALIASES_H
|
||||
|
||||
#include "../platform/platform.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(WAPP_PLATFORM_C) && WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C11_VERSION && !defined(WAPP_PLATFORM_APPLE)
|
||||
#include <uchar.h>
|
||||
|
||||
#if WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C23_VERSION
|
||||
#define c8 char8_t
|
||||
#else
|
||||
#define c8 uint8_t
|
||||
#endif // !WAPP_PLATFORM_C23_VERSION
|
||||
|
||||
#define c16 char16_t
|
||||
#define c32 char32_t
|
||||
#else
|
||||
#define c8 uint8_t
|
||||
#define c16 uint16_t
|
||||
#define c32 uint32_t
|
||||
#endif // !WAPP_PLATFORM_C
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
|
||||
#define b8 uint8_t
|
||||
|
||||
#ifndef WAPP_PLATFORM_CPP
|
||||
|
||||
#ifndef false
|
||||
#define false (b8)0
|
||||
#endif // !false
|
||||
|
||||
#ifndef true
|
||||
#define true (b8)1
|
||||
#endif // !true
|
||||
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define i8 int8_t
|
||||
#define i16 int16_t
|
||||
#define i32 int32_t
|
||||
#define i64 int64_t
|
||||
|
||||
#define f32 float
|
||||
#define f64 double
|
||||
#define f128 long double
|
||||
|
||||
#define uptr uintptr_t
|
||||
#define iptr intptr_t
|
||||
|
||||
#define wapp_extern extern
|
||||
#define wapp_intern static
|
||||
#define wapp_persist static
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
#define wapp_class_mem static
|
||||
#define BEGIN_C_LINKAGE extern "C" {
|
||||
#define END_C_LINKAGE }
|
||||
#endif // WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !ALIASES_H
|
||||
61
src/common/assert/assert.h
Normal file
61
src/common/assert/assert.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_ASSERT_H
|
||||
#define WAPP_ASSERT_H
|
||||
|
||||
#include "../aliases/aliases.h"
|
||||
#include "../platform/platform.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define wapp_static_assert(EXPR, MSG) extern char ASSERTION_FAILED[EXPR ? 1 : -1]
|
||||
|
||||
#ifndef WAPP_NO_RUNTIME_ASSERT
|
||||
#define wapp_runtime_assert(EXPR, MSG) __wapp_runtime_assert(EXPR, MSG)
|
||||
#else
|
||||
#define wapp_runtime_assert(EXPR, MSG)
|
||||
#endif
|
||||
|
||||
#ifdef WAPP_DEBUG_ASSERT
|
||||
#define wapp_debug_assert(EXPR, MSG) wapp_runtime_assert(EXPR, MSG)
|
||||
#else
|
||||
#define wapp_debug_assert(EXPR, MSG)
|
||||
#endif
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
#define __wapp_runtime_assert(EXPR, MSG) do { \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
if (!(EXPR)) { \
|
||||
__pragma(warning(pop)) \
|
||||
__runtime_assert_failed(EXPR, MSG); \
|
||||
} \
|
||||
} while(false)
|
||||
#else
|
||||
#define __wapp_runtime_assert(EXPR, MSG) do { \
|
||||
if (!(EXPR)) { \
|
||||
__runtime_assert_failed(EXPR, MSG); \
|
||||
} \
|
||||
} while(false)
|
||||
#endif // !WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#define __runtime_assert_failed(EXPR, MSG) do { \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
"%s:%d (In function `%s`): Assertion failed (%" PRIu32 ")\nDiagnostic: %s\n\n", \
|
||||
__FILE__, __LINE__, __func__, \
|
||||
EXPR, MSG \
|
||||
); \
|
||||
abort(); \
|
||||
} while(false)
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !WAPP_ASSERT_H
|
||||
51
src/common/misc/misc_utils.h
Normal file
51
src/common/misc/misc_utils.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MISC_UTILS_H
|
||||
#define MISC_UTILS_H
|
||||
|
||||
#include "../aliases/aliases.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define KB(SIZE) (SIZE * 1024ull)
|
||||
#define MB(SIZE) (KB(SIZE) * 1024)
|
||||
#define GB(SIZE) (MB(SIZE) * 1024)
|
||||
#define TB(SIZE) (GB(SIZE) * 1024)
|
||||
|
||||
#define wapp_misc_utils_padding_size(SIZE) u8 reserved_padding[sizeof(void *) - ((SIZE) % sizeof(void *))]
|
||||
|
||||
#define U64_RSHIFT_OR_1(X) (((u64)X) | (((u64)X) >> 1))
|
||||
#define U64_RSHIFT_OR_2(X) (((u64)X) | (((u64)X) >> 2))
|
||||
#define U64_RSHIFT_OR_4(X) (((u64)X) | (((u64)X) >> 4))
|
||||
#define U64_RSHIFT_OR_8(X) (((u64)X) | (((u64)X) >> 8))
|
||||
#define U64_RSHIFT_OR_16(X) (((u64)X) | (((u64)X) >> 16))
|
||||
#define U64_RSHIFT_OR_32(X) (((u64)X) | (((u64)X) >> 32))
|
||||
#define wapp_misc_utils_u64_round_up_pow2(X) ( \
|
||||
( \
|
||||
U64_RSHIFT_OR_32( \
|
||||
U64_RSHIFT_OR_16( \
|
||||
U64_RSHIFT_OR_8( \
|
||||
U64_RSHIFT_OR_4( \
|
||||
U64_RSHIFT_OR_2( \
|
||||
U64_RSHIFT_OR_1(X - 1) \
|
||||
) \
|
||||
) \
|
||||
) \
|
||||
) \
|
||||
) \
|
||||
) + 1 \
|
||||
)
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#define wapp_misc_utils_va_args_count(T, ...) (std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value)
|
||||
#else
|
||||
#define wapp_misc_utils_va_args_count(T, ...) (sizeof((T[]){__VA_ARGS__})/sizeof(T))
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MISC_UTILS_H
|
||||
114
src/common/platform/platform.h
Normal file
114
src/common/platform/platform.h
Normal file
@@ -0,0 +1,114 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#define WAPP_PLATFORM_ANDROID
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__FreeBSD__)
|
||||
#define WAPP_PLATFORM_FREE_BSD
|
||||
#define WAPP_PLATFORM_BSD
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__NetBSD__)
|
||||
#define WAPP_PLATFORM_NET_BSD
|
||||
#define WAPP_PLATFORM_BSD
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__OpenBSD__)
|
||||
#define WAPP_PLATFORM_OPEN_BSD
|
||||
#define WAPP_PLATFORM_BSD
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__DragonFly__)
|
||||
#define WAPP_PLATFORM_DRAGON_FLY
|
||||
#define WAPP_PLATFORM_BSD
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__bsdi__)
|
||||
#define WAPP_PLATFORM_BSD
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__linux__) || defined(linux) || defined(__linux) || defined(__gnu_linux__)
|
||||
#define WAPP_PLATFORM_LINUX
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__GNU__) || defined(__gnu_hurd__)
|
||||
#define WAPP_PLATFORM_GNU
|
||||
#define WAPP_PLATFORM_POSIX
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
#include <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
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define WAPP_PLATFORM_CPP
|
||||
#define WAPP_PLATFORM_CPP_VERSION __cplusplus
|
||||
#define WAPP_PLATFORM_CPP98_VERSION 199711L
|
||||
#define WAPP_PLATFORM_CPP11_VERSION 201103L
|
||||
#define WAPP_PLATFORM_CPP14_VERSION 201402L
|
||||
#define WAPP_PLATFORM_CPP17_VERSION 201703L
|
||||
#define WAPP_PLATFORM_CPP20_VERSION 202002L
|
||||
#define WAPP_PLATFORM_CPP23_VERSION 202302L
|
||||
|
||||
#if WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP98_VERSION
|
||||
#define WAPP_PLATFORM_CPP98
|
||||
#elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP11_VERSION
|
||||
#define WAPP_PLATFORM_CPP11
|
||||
#elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP14_VERSION
|
||||
#define WAPP_PLATFORM_CPP14
|
||||
#elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP17_VERSION
|
||||
#define WAPP_PLATFORM_CPP17
|
||||
#elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP20_VERSION
|
||||
#define WAPP_PLATFORM_CPP20
|
||||
#elif WAPP_PLATFORM_CPP_VERSION == WAPP_PLATFORM_CPP23_VERSION
|
||||
#define WAPP_PLATFORM_CPP23
|
||||
#else
|
||||
#error "Unrecognised C++ version"
|
||||
#endif
|
||||
#else
|
||||
#define WAPP_PLATFORM_C
|
||||
|
||||
#if defined(__STDC_VERSION__)
|
||||
#define WAPP_PLATFORM_C_VERSION __STDC_VERSION__
|
||||
#define WAPP_PLATFORM_C99_VERSION 199901L
|
||||
#define WAPP_PLATFORM_C11_VERSION 201112L
|
||||
#define WAPP_PLATFORM_C17_VERSION 201710L
|
||||
#define WAPP_PLATFORM_C23_VERSION 202311L
|
||||
|
||||
#if WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C99_VERSION
|
||||
#define WAPP_PLATFORM_C99
|
||||
#elif WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C11_VERSION
|
||||
#define WAPP_PLATFORM_C11
|
||||
#elif WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C17_VERSION
|
||||
#define WAPP_PLATFORM_C17
|
||||
#elif WAPP_PLATFORM_C_VERSION == WAPP_PLATFORM_C23_VERSION
|
||||
#define WAPP_PLATFORM_C23
|
||||
#else
|
||||
#error "Unrecognised C version"
|
||||
#endif
|
||||
#else
|
||||
#define WAPP_PLATFORM_C89
|
||||
#endif
|
||||
#endif // !__cplusplus
|
||||
|
||||
#endif // !PLATFORM_H
|
||||
11
src/common/wapp_common.h
Normal file
11
src/common/wapp_common.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_COMMON_H
|
||||
#define WAPP_COMMON_H
|
||||
|
||||
#include "aliases/aliases.h"
|
||||
#include "assert/assert.h"
|
||||
#include "misc/misc_utils.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#endif // !WAPP_COMMON_H
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,233 +0,0 @@
|
||||
#include "mem_arena.h"
|
||||
#include "aliases.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 1024
|
||||
|
||||
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 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) {
|
||||
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_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;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_destroy(BaseArena *arena) {
|
||||
if (!arena) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (arena->buf) {
|
||||
free(arena->buf);
|
||||
}
|
||||
|
||||
arena->buf = arena->offset = NULL;
|
||||
arena->capacity = 0;
|
||||
arena->prev = arena->next = NULL;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef MEM_ARENA_H
|
||||
#define MEM_ARENA_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct growing_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_clear(Arena *arena);
|
||||
void wapp_mem_arena_destroy(Arena **arena);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !MEM_ARENA_H
|
||||
@@ -1,28 +0,0 @@
|
||||
#include "mem_utils.h"
|
||||
#include "aliases.h"
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
|
||||
|
||||
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(is_power_of_two(alignment));
|
||||
|
||||
uptr p = (uptr)ptr;
|
||||
uptr align = (uptr)alignment;
|
||||
|
||||
// Similar to p % align, but it's a faster implementation that works fine
|
||||
// because align is guaranteed to be a power of 2
|
||||
uptr modulo = p & (align - 1);
|
||||
|
||||
if (modulo != 0) {
|
||||
p += align - modulo;
|
||||
}
|
||||
|
||||
return (void *)p;
|
||||
}
|
||||
@@ -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
|
||||
146
src/os/allocators/arena/mem_arena.c
Normal file
146
src/os/allocators/arena/mem_arena.c
Normal file
@@ -0,0 +1,146 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "mem_arena.h"
|
||||
#include "../../mem/mem_os.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/assert/assert.h"
|
||||
#include "../../../common/misc/misc_utils.h"
|
||||
#include "../../../base/mem/utils/mem_utils.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;
|
||||
b8 committed;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
wapp_misc_utils_padding_size(sizeof(u8 *) * 2 + sizeof(u64) + sizeof(b8));
|
||||
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
b8 wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, b8 zero_buffer) {
|
||||
if (!arena || *arena || base_capacity == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*arena = (Arena *)calloc(1, sizeof(Arena));
|
||||
Arena *arena_ptr = *arena;
|
||||
if (!arena_ptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 arena_capacity = wapp_misc_utils_u64_round_up_pow2(
|
||||
base_capacity >= ARENA_MINIMUM_CAPACITY ?
|
||||
base_capacity :
|
||||
ARENA_MINIMUM_CAPACITY
|
||||
);
|
||||
|
||||
arena_ptr->buf = (u8 *)wapp_mem_util_alloc(NULL, arena_capacity, WAPP_MEM_ACCESS_READ_WRITE, flags,
|
||||
zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED);
|
||||
|
||||
if (!(arena_ptr->buf)) {
|
||||
wapp_mem_arena_destroy(arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
arena_ptr->capacity = arena_capacity;
|
||||
arena_ptr->offset = arena_ptr->buf;
|
||||
arena_ptr->committed = (flags & WAPP_MEM_ALLOC_COMMIT) == WAPP_MEM_ALLOC_COMMIT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
|
||||
return wapp_mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
|
||||
wapp_debug_assert(arena != NULL, "`arena` should not be NULL");
|
||||
|
||||
u8 *alloc_start = arena->offset;
|
||||
|
||||
u8 *output = wapp_mem_util_align_forward((void *)alloc_start, alignment);
|
||||
if (output + size >= arena->buf + arena->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arena->offset = output + size;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
if (!(arena->committed)) {
|
||||
wapp_mem_util_alloc(alloc_start, (uptr)(arena->offset) - (uptr)(alloc_start),
|
||||
WAPP_MEM_ACCESS_READ_WRITE, WAPP_MEM_ALLOC_COMMIT,
|
||||
WAPP_MEM_INIT_UNINITIALISED);
|
||||
}
|
||||
#endif // ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
memset(output, 0, size);
|
||||
|
||||
return (void *)output;
|
||||
}
|
||||
|
||||
void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 old_size, u64 new_size) {
|
||||
if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset ||
|
||||
arena->offset + new_size >= arena->buf + arena->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *new_ptr = wapp_mem_arena_alloc(arena, new_size);
|
||||
if (!new_ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 copy_size = new_size <= old_size ? new_size : old_size;
|
||||
memcpy(new_ptr, ptr, copy_size);
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment) {
|
||||
if ((u8*)ptr < arena->buf || (u8*)ptr > arena->offset ||
|
||||
arena->offset + new_size >= arena->buf + arena->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *new_ptr = wapp_mem_arena_alloc_aligned(arena, new_size, alignment);
|
||||
if (!new_ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 copy_size = new_size <= old_size ? new_size : old_size;
|
||||
memcpy(new_ptr, ptr, copy_size);
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void wapp_mem_arena_clear(Arena *arena) {
|
||||
wapp_debug_assert(arena != NULL, "`arena` should not be NULL");
|
||||
|
||||
memset(arena->buf, 0, arena->offset - arena->buf);
|
||||
arena->offset = arena->buf;
|
||||
}
|
||||
|
||||
void wapp_mem_arena_destroy(Arena **arena) {
|
||||
wapp_debug_assert(arena != NULL && (*arena) != NULL, "`arena` double pointer is not valid");
|
||||
|
||||
Arena *arena_ptr = *arena;
|
||||
if (arena_ptr->buf) {
|
||||
wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity);
|
||||
}
|
||||
|
||||
arena_ptr->buf = arena_ptr->offset = NULL;
|
||||
arena_ptr->capacity = 0;
|
||||
|
||||
free(*arena);
|
||||
*arena = NULL;
|
||||
}
|
||||
42
src/os/allocators/arena/mem_arena.h
Normal file
42
src/os/allocators/arena/mem_arena.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_ARENA_H
|
||||
#define MEM_ARENA_H
|
||||
|
||||
#include "../../mem/mem_os.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef struct arena Arena;
|
||||
|
||||
#define wapp_mem_arena_init(arena_dptr, base_capacity) \
|
||||
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, false))
|
||||
#define wapp_mem_arena_init_commit(arena_dptr, base_capacity) \
|
||||
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
|
||||
#define wapp_mem_arena_init_zero(arena_dptr, base_capacity) \
|
||||
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
|
||||
#define wapp_mem_arena_init_commit_and_zero(arena_dptr, base_capacity) \
|
||||
(wapp_mem_arena_init_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
|
||||
|
||||
/**
|
||||
* Arena initialisation function. `wapp_mem_arena_init_custom` provides the most
|
||||
* control over how the Arena is initialised. Wrapper macros are provided for
|
||||
* easier use.
|
||||
*/
|
||||
b8 wapp_mem_arena_init_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, b8 zero_buffer);
|
||||
void *wapp_mem_arena_alloc(Arena *arena, u64 size);
|
||||
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment);
|
||||
void *wapp_mem_arena_realloc(Arena *arena, void *ptr, u64 old_size, u64 new_size);
|
||||
void *wapp_mem_arena_realloc_aligned(Arena *arena, void *ptr, u64 old_size, u64 new_size, u64 alignment);
|
||||
void wapp_mem_arena_clear(Arena *arena);
|
||||
void wapp_mem_arena_destroy(Arena **arena);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_ARENA_H
|
||||
59
src/os/allocators/arena/mem_arena_allocator.c
Normal file
59
src/os/allocators/arena/mem_arena_allocator.c
Normal file
@@ -0,0 +1,59 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "mem_arena_allocator.h"
|
||||
#include "mem_arena.h"
|
||||
#include "../../mem/mem_os.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
|
||||
wapp_intern inline void *mem_arena_alloc(u64 size, void *alloc_obj);
|
||||
wapp_intern inline void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
|
||||
wapp_intern inline void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
|
||||
wapp_intern inline void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
|
||||
void *alloc_obj);
|
||||
|
||||
|
||||
Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, b8 zero_buffer) {
|
||||
Allocator allocator = {0};
|
||||
b8 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};
|
||||
}
|
||||
|
||||
|
||||
wapp_intern inline void *mem_arena_alloc(u64 size, void *alloc_obj) {
|
||||
Arena *arena = (Arena *)alloc_obj;
|
||||
return wapp_mem_arena_alloc(arena, size);
|
||||
}
|
||||
|
||||
wapp_intern 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);
|
||||
}
|
||||
|
||||
wapp_intern 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);
|
||||
}
|
||||
|
||||
wapp_intern 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);
|
||||
}
|
||||
43
src/os/allocators/arena/mem_arena_allocator.h
Normal file
43
src/os/allocators/arena/mem_arena_allocator.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_ARENA_ALLOCATOR_H
|
||||
#define MEM_ARENA_ALLOCATOR_H
|
||||
|
||||
#include "../../mem/mem_os.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include "../../../base/mem/allocator/mem_allocator.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define wapp_mem_arena_allocator_init(base_capacity) \
|
||||
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE, false))
|
||||
#define wapp_mem_arena_allocator_init_commit(base_capacity) \
|
||||
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
|
||||
#define wapp_mem_arena_allocator_init_zero(base_capacity) \
|
||||
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
|
||||
#define wapp_mem_arena_allocator_init_commit_and_zero(base_capacity) \
|
||||
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
|
||||
|
||||
/**
|
||||
* Wraps an Arena in an Allocator object. It attempts to initialise the Arena
|
||||
* and, if successful, defines the operations supported by it to be used by the
|
||||
* Allocator.
|
||||
*
|
||||
* An Arena allocator only supports normal allocation and aligned allocation.
|
||||
* Reallocation, aligned reallocation and freeing aren't implemented.
|
||||
*
|
||||
* The `wapp_mem_arena_allocator_init_custom` provides the most control over how
|
||||
* the Arena is initialised. Wrapper macros are provided for easier use.
|
||||
*/
|
||||
Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, b8 zero_buffer);
|
||||
void wapp_mem_arena_allocator_clear(Allocator *allocator);
|
||||
void wapp_mem_arena_allocator_destroy(Allocator *allocator);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_ARENA_ALLOCATOR_H
|
||||
135
src/os/cpath/cpath.c
Normal file
135
src/os/cpath/cpath.c
Normal file
@@ -0,0 +1,135 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "cpath.h"
|
||||
#include "../allocators/arena/mem_arena_allocator.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/misc/misc_utils.h"
|
||||
#include "../../base/dbl_list/dbl_list.h"
|
||||
#include "../../base/mem/allocator/mem_allocator.h"
|
||||
#include "../../base/strings/str8/str8.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts) {
|
||||
if (!dst || !parts) {
|
||||
return CPATH_JOIN_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (parts->node_count == 0) {
|
||||
return CPATH_JOIN_EMPTY_PARTS;
|
||||
}
|
||||
|
||||
Str8 separator = wapp_str8_buf(4);
|
||||
wapp_str8_push_back(&separator, WAPP_PATH_SEP);
|
||||
|
||||
u64 required_capacity = parts->node_count * separator.size + wapp_str8_list_total_size(parts);
|
||||
if (dst->capacity < required_capacity) {
|
||||
return CPATH_JOIN_INSUFFICIENT_DST_CAPACITY;
|
||||
}
|
||||
|
||||
// Handle first node
|
||||
const Str8Node *first_node = wapp_dbl_list_get(Str8, Str8Node, parts, 0);
|
||||
wapp_str8_copy_str8_capped(dst, first_node->item);
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
const Str8Node *node = first_node;
|
||||
u64 node_index = 1;
|
||||
b8 running = node_index < parts->node_count;
|
||||
while (running && node->next) {
|
||||
node = node->next;
|
||||
if (node->item->size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst->size > 0) {
|
||||
char dst_last = wapp_str8_get(dst, dst->size - 1);
|
||||
char node_start = wapp_str8_get(node->item, 0);
|
||||
b8 add_path_sep = dst_last != WAPP_PATH_SEP && node_start != WAPP_PATH_SEP;
|
||||
|
||||
if (add_path_sep) {
|
||||
wapp_str8_concat_capped(dst, &separator);
|
||||
}
|
||||
}
|
||||
|
||||
wapp_str8_concat_capped(dst, node->item);
|
||||
|
||||
++node_index;
|
||||
running = node_index < parts->node_count;
|
||||
}
|
||||
|
||||
return CPATH_JOIN_SUCCESS;
|
||||
}
|
||||
|
||||
Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels) {
|
||||
Str8 *output = NULL;
|
||||
if (!allocator || !path) {
|
||||
goto RETURN_DIRUP;
|
||||
}
|
||||
|
||||
b8 absolute = wapp_str8_get(path, 0) == WAPP_PATH_SEP;
|
||||
Str8 separator = wapp_str8_buf(4);
|
||||
wapp_str8_push_back(&separator, WAPP_PATH_SEP);
|
||||
|
||||
if (path->size == 0) {
|
||||
output = wapp_str8_alloc_buf(allocator, 16);
|
||||
if (!output) {
|
||||
goto RETURN_DIRUP;
|
||||
}
|
||||
|
||||
wapp_str8_push_back(output, absolute ? WAPP_PATH_SEP : '.');
|
||||
goto RETURN_DIRUP;
|
||||
}
|
||||
|
||||
if (levels < 1) {
|
||||
output = wapp_str8_alloc_str8(allocator, path);
|
||||
goto RETURN_DIRUP;
|
||||
}
|
||||
|
||||
Allocator tmp_arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&tmp_arena)) {
|
||||
goto RETURN_DIRUP;
|
||||
}
|
||||
|
||||
Str8List *parts = wapp_str8_split(&tmp_arena, path, &separator);
|
||||
if (!parts) {
|
||||
goto RETURN_DIRUP;
|
||||
}
|
||||
|
||||
if (levels >= parts->node_count) {
|
||||
output = wapp_str8_alloc_buf(allocator, 16);
|
||||
if (!output) {
|
||||
goto LIST_CLEANUP_DIRUP;
|
||||
}
|
||||
|
||||
wapp_str8_push_back(output, absolute ? WAPP_PATH_SEP : '.');
|
||||
} else {
|
||||
for (u64 i = 0; i < levels; ++i) {
|
||||
wapp_dbl_list_pop_back(Str8, Str8Node, parts);
|
||||
}
|
||||
|
||||
u64 alignment = sizeof(void *) * 2;
|
||||
u64 alloc_size = wapp_str8_list_total_size(parts) + parts->node_count * separator.size;
|
||||
u64 modulo = alloc_size & (alignment - 1);
|
||||
alloc_size += alignment - modulo;
|
||||
|
||||
output = wapp_str8_alloc_buf(allocator, alloc_size);
|
||||
if (output) {
|
||||
if (absolute) {
|
||||
wapp_str8_push_back(output, WAPP_PATH_SEP);
|
||||
}
|
||||
|
||||
Str8 *joined = wapp_str8_join(&tmp_arena, parts, &separator);
|
||||
if (joined) {
|
||||
wapp_str8_concat_capped(output, joined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LIST_CLEANUP_DIRUP:
|
||||
wapp_mem_arena_allocator_destroy(&tmp_arena);
|
||||
|
||||
RETURN_DIRUP:
|
||||
return output;
|
||||
}
|
||||
45
src/os/cpath/cpath.h
Normal file
45
src/os/cpath/cpath.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef CPATH_H
|
||||
#define CPATH_H
|
||||
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
#include "../../base/mem/allocator/mem_allocator.h"
|
||||
#include "../../base/strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
#include <limits.h>
|
||||
#define WAPP_PATH_SEP '/'
|
||||
#define WAPP_PATH_MAX PATH_MAX
|
||||
#elif defined(WAPP_PLATFORM_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define WAPP_PATH_SEP '\\'
|
||||
#define WAPP_PATH_MAX MAX_PATH
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
|
||||
#define wapp_cpath_dirname(ALLOCATOR, PATH) dirup(ALLOCATOR, PATH, 1)
|
||||
#define wapp_cpath_dirup(ALLOCATOR, PATH, COUNT) dirup(ALLOCATOR, PATH, COUNT)
|
||||
|
||||
enum {
|
||||
CPATH_JOIN_SUCCESS = 0,
|
||||
CPATH_JOIN_INVALID_ARGS,
|
||||
CPATH_JOIN_EMPTY_PARTS,
|
||||
CPATH_JOIN_INSUFFICIENT_DST_CAPACITY,
|
||||
};
|
||||
|
||||
u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts);
|
||||
Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !CPATH_H
|
||||
109
src/os/file/file.c
Normal file
109
src/os/file/file.c
Normal file
@@ -0,0 +1,109 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "file.h"
|
||||
#include "../cpath/cpath.h"
|
||||
#include "../../common/assert/assert.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../base/array/array.h"
|
||||
#include "../../base/strings/str8/str8.h"
|
||||
#include <stdio.h>
|
||||
|
||||
File *wapp_file_open(Str8RO *filepath, FileAccessMode mode) {
|
||||
wapp_persist const char *modes[FILE_ACCESS_MODE_COUNT] = {
|
||||
[WAPP_FA_MODE_R] = "r",
|
||||
[WAPP_FA_MODE_W] = "w",
|
||||
[WAPP_FA_MODE_A] = "a",
|
||||
[WAPP_FA_MODE_R_EX] = "r+",
|
||||
[WAPP_FA_MODE_W_EX] = "w+",
|
||||
[WAPP_FA_MODE_A_EX] = "a+",
|
||||
[WAPP_FA_MODE_RB] = "rb",
|
||||
[WAPP_FA_MODE_WB] = "wb",
|
||||
[WAPP_FA_MODE_AB] = "ab",
|
||||
[WAPP_FA_MODE_RB_EX] = "rb+",
|
||||
[WAPP_FA_MODE_WB_EX] = "wb+",
|
||||
[WAPP_FA_MODE_AB_EX] = "ab+",
|
||||
[WAPP_FA_MODE_WX] = "wx",
|
||||
[WAPP_FA_MODE_WX_EX] = "wx+",
|
||||
[WAPP_FA_MODE_WBX] = "wbx",
|
||||
[WAPP_FA_MODE_WBX_EX] = "wbx+",
|
||||
};
|
||||
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
|
||||
wapp_debug_assert(filepath->size < WAPP_PATH_MAX, "`filepath` exceeds max path limit.");
|
||||
|
||||
memset(tmp, 0, WAPP_PATH_MAX);
|
||||
memcpy(tmp, filepath->buf, filepath->size);
|
||||
|
||||
return fopen((const char *)tmp, modes[mode]);
|
||||
}
|
||||
|
||||
u64 wapp_file_get_current_position(File *file) {
|
||||
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
|
||||
return (u64)ftell(file);
|
||||
}
|
||||
|
||||
i32 wapp_file_seek(File *file, u64 offset, FileSeekOrigin origin) {
|
||||
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
|
||||
// TODO (Abdelrahman): Revisit conversion to long
|
||||
return fseek(file, (long)offset, origin);
|
||||
}
|
||||
|
||||
u64 wapp_file_get_length(File *file) {
|
||||
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
|
||||
|
||||
u64 current = wapp_file_get_current_position(file);
|
||||
|
||||
wapp_file_seek(file, 0, WAPP_SEEK_END);
|
||||
|
||||
u64 output = ftell(file);
|
||||
|
||||
// Restore position
|
||||
wapp_file_seek(file, current, WAPP_SEEK_START);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
u64 wapp_file_read(GenericArray *dst_buf, File *file, u64 item_count) {
|
||||
wapp_debug_assert(dst_buf != NULL && file != NULL,
|
||||
"`dst_buf` and `file` should not be NULL.");
|
||||
|
||||
u64 file_length = wapp_file_get_length(file);
|
||||
u64 item_size = dst_buf->item_size;
|
||||
u64 dst_byte_capacity = dst_buf->capacity * item_size;
|
||||
u64 req_byte_count = item_count * item_size;
|
||||
u64 copy_byte_count = 0;
|
||||
|
||||
if (req_byte_count <= file_length && req_byte_count <= dst_byte_capacity) {
|
||||
copy_byte_count = req_byte_count;
|
||||
} else {
|
||||
copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity;
|
||||
}
|
||||
|
||||
u64 count = fread(dst_buf->items, sizeof(u8), copy_byte_count, file);
|
||||
if (ferror(file)) { return 0; }
|
||||
|
||||
dst_buf->count = count / item_size;
|
||||
|
||||
return dst_buf->count;
|
||||
}
|
||||
|
||||
u64 wapp_file_write(const GenericArray *src_buf, File *file, u64 item_count) {
|
||||
wapp_debug_assert(src_buf != NULL && file != NULL,
|
||||
"`src_buf` and `file` should not be NULL.");
|
||||
|
||||
u64 item_size = src_buf->item_size;
|
||||
u64 src_byte_count = src_buf->count * item_size;
|
||||
u64 req_byte_count = item_count * item_size;
|
||||
u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count;
|
||||
|
||||
return fwrite(src_buf->items, sizeof(u8), to_copy, file);
|
||||
}
|
||||
|
||||
i32 wapp_file_flush(File *file) {
|
||||
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
|
||||
return fflush(file);
|
||||
}
|
||||
|
||||
i32 wapp_file_close(File *file) {
|
||||
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
|
||||
return fclose(file);
|
||||
}
|
||||
56
src/os/file/file.h
Normal file
56
src/os/file/file.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../base/strings/str8/str8.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef FILE File;
|
||||
|
||||
typedef enum {
|
||||
WAPP_FA_MODE_R, // Equivalent to r
|
||||
WAPP_FA_MODE_W, // Equivalent to w
|
||||
WAPP_FA_MODE_A, // Equivalent to a
|
||||
WAPP_FA_MODE_R_EX, // Equivalent to r+
|
||||
WAPP_FA_MODE_W_EX, // Equivalent to w+
|
||||
WAPP_FA_MODE_A_EX, // Equivalent to a+
|
||||
WAPP_FA_MODE_RB, // Equivalent to rb
|
||||
WAPP_FA_MODE_WB, // Equivalent to wb
|
||||
WAPP_FA_MODE_AB, // Equivalent to ab
|
||||
WAPP_FA_MODE_RB_EX, // Equivalent to rb+
|
||||
WAPP_FA_MODE_WB_EX, // Equivalent to wb+
|
||||
WAPP_FA_MODE_AB_EX, // Equivalent to ab+
|
||||
WAPP_FA_MODE_WX, // Equivalent to wx
|
||||
WAPP_FA_MODE_WX_EX, // Equivalent to wx+
|
||||
WAPP_FA_MODE_WBX, // Equivalent to wbx
|
||||
WAPP_FA_MODE_WBX_EX, // Equivalent to wbx+
|
||||
|
||||
FILE_ACCESS_MODE_COUNT,
|
||||
} FileAccessMode;
|
||||
|
||||
typedef enum {
|
||||
WAPP_SEEK_START = SEEK_SET,
|
||||
WAPP_SEEK_CURRENT = SEEK_CUR,
|
||||
WAPP_SEEK_END = SEEK_END,
|
||||
} FileSeekOrigin;
|
||||
|
||||
File *wapp_file_open(Str8RO *filename, FileAccessMode mode);
|
||||
u64 wapp_file_get_current_position(File *file);
|
||||
i32 wapp_file_seek(File *file, u64 offset, FileSeekOrigin origin);
|
||||
u64 wapp_file_get_length(File *file);
|
||||
u64 wapp_file_read(GenericArray *dst_buf, File *file, u64 item_count);
|
||||
u64 wapp_file_write(const GenericArray *src_buf, File *file, u64 item_count);
|
||||
i32 wapp_file_flush(File *file);
|
||||
i32 wapp_file_close(File *file);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !FILE_H
|
||||
30
src/os/mem/mem_os.c
Normal file
30
src/os/mem/mem_os.c
Normal file
@@ -0,0 +1,30 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "mem_os.h"
|
||||
#include "mem_os_ops.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
#include "win/mem_os_win.h"
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
#include "posix/mem_os_posix.h"
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
|
||||
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) {
|
||||
void *output = mem_util_allocate(addr, size, access, flags, type);
|
||||
|
||||
if (type == WAPP_MEM_INIT_INITIALISED) {
|
||||
memset(output, 0, size);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void wapp_mem_util_free(void *ptr, u64 size) {
|
||||
mem_util_free(ptr, size);
|
||||
}
|
||||
33
src/os/mem/mem_os.h
Normal file
33
src/os/mem/mem_os.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_OS_H
|
||||
#define MEM_OS_H
|
||||
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
|
||||
#include "mem_os_ops.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#if defined(WAPP_PLATFORM_WINDOWS)
|
||||
#include "win/mem_os_win.h"
|
||||
#elif defined(WAPP_PLATFORM_POSIX)
|
||||
#include "posix/mem_os_posix.h"
|
||||
#else
|
||||
#error "Unrecognised platform"
|
||||
#endif
|
||||
|
||||
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type);
|
||||
void wapp_mem_util_free(void *ptr, u64 size);
|
||||
|
||||
wapp_extern void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type);
|
||||
wapp_extern void mem_util_free(void *ptr, u64 size);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_OS_H
|
||||
30
src/os/mem/mem_os_ops.h
Normal file
30
src/os/mem/mem_os_ops.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_OS_OPS_H
|
||||
#define MEM_OS_OPS_H
|
||||
|
||||
#include "../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef enum mem_access {
|
||||
WAPP_MEM_ACCESS_NONE,
|
||||
WAPP_MEM_ACCESS_READ_ONLY,
|
||||
WAPP_MEM_ACCESS_EXEC_ONLY,
|
||||
WAPP_MEM_ACCESS_READ_WRITE,
|
||||
WAPP_MEM_ACCESS_READ_EXEC,
|
||||
WAPP_MEM_ACCESS_READ_WRITE_EXEC,
|
||||
} MemAccess;
|
||||
|
||||
typedef enum mem_init_type {
|
||||
WAPP_MEM_INIT_UNINITIALISED,
|
||||
WAPP_MEM_INIT_INITIALISED,
|
||||
} MemInitType;
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_OS_OPS_H
|
||||
36
src/os/mem/posix/mem_os_posix.c
Normal file
36
src/os/mem/posix/mem_os_posix.c
Normal file
@@ -0,0 +1,36 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include "mem_os_posix.h"
|
||||
#include "../mem_os_ops.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
wapp_intern const i32 access_types[] = {
|
||||
[WAPP_MEM_ACCESS_NONE] = PROT_NONE,
|
||||
[WAPP_MEM_ACCESS_READ_ONLY] = PROT_READ,
|
||||
[WAPP_MEM_ACCESS_EXEC_ONLY] = PROT_EXEC,
|
||||
[WAPP_MEM_ACCESS_READ_WRITE] = PROT_READ | PROT_WRITE,
|
||||
[WAPP_MEM_ACCESS_READ_EXEC] = PROT_READ | PROT_EXEC,
|
||||
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
};
|
||||
|
||||
void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) {
|
||||
(void)type;
|
||||
i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE;
|
||||
|
||||
#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU) || defined(WAPP_PLATFORM_NET_BSD)
|
||||
alloc_flags |= MAP_NORESERVE;
|
||||
#endif
|
||||
|
||||
return mmap(addr, size, access_types[access], alloc_flags, -1, 0);
|
||||
}
|
||||
|
||||
void mem_util_free(void *ptr, u64 size) {
|
||||
munmap(ptr, size);
|
||||
}
|
||||
|
||||
#endif // !WAPP_PLATFORM_POSIX
|
||||
35
src/os/mem/posix/mem_os_posix.h
Normal file
35
src/os/mem/posix/mem_os_posix.h
Normal file
@@ -0,0 +1,35 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_OS_POSIX_H
|
||||
#define MEM_OS_POSIX_H
|
||||
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include <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 WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_OS_POSIX_H
|
||||
37
src/os/mem/win/mem_os_win.c
Normal file
37
src/os/mem/win/mem_os_win.c
Normal file
@@ -0,0 +1,37 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#include "mem_os_win.h"
|
||||
#include "../mem_os_ops.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <memoryapi.h>
|
||||
|
||||
wapp_intern 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
|
||||
29
src/os/mem/win/mem_os_win.h
Normal file
29
src/os/mem/win/mem_os_win.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef MEM_OS_WIN_H
|
||||
#define MEM_OS_WIN_H
|
||||
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <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 WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !MEM_OS_WIN_H
|
||||
101
src/os/shell/commander/commander.c
Normal file
101
src/os/shell/commander/commander.c
Normal file
@@ -0,0 +1,101 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "commander.h"
|
||||
#include "commander_output.h"
|
||||
#include "../utils/shell_utils.h"
|
||||
#include "../../allocators/arena/mem_arena_allocator.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/misc/misc_utils.h"
|
||||
#include "../../../base/dbl_list/dbl_list.h"
|
||||
#include "../../../base/mem/allocator/mem_allocator.h"
|
||||
#include "../../../base/strings/str8/str8.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CMD_BUF_LEN 8192
|
||||
#define OUT_BUF_LEN 4096
|
||||
|
||||
wapp_intern inline CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf);
|
||||
wapp_intern inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf);
|
||||
|
||||
CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd) {
|
||||
if (!cmd) {
|
||||
return CMD_NO_EXIT(SHELL_ERR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
Allocator arena = wapp_mem_arena_allocator_init(KB(500));
|
||||
|
||||
Str8 *cmd_str = wapp_str8_join(&arena, cmd, &wapp_str8_lit_ro(" "));
|
||||
if (!cmd_str) {
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
return CMD_NO_EXIT(SHELL_ERR_ALLOCATION_FAIL);
|
||||
}
|
||||
|
||||
// Redirect output
|
||||
cmd_str = wapp_str8_alloc_concat(&arena, cmd_str, &wapp_str8_lit_ro(" 2>&1"));
|
||||
|
||||
CMDResult output = execute_command(cmd_str, out_handling, out_buf);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
wapp_intern inline CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf) {
|
||||
char cmd_buf[CMD_BUF_LEN] = {0};
|
||||
wapp_str8_copy_to_cstr(cmd_buf, cmd, CMD_BUF_LEN);
|
||||
|
||||
FILE *fp = wapp_shell_utils_popen(cmd_buf, "r");
|
||||
if (!fp) {
|
||||
return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL);
|
||||
}
|
||||
|
||||
CMDResult output;
|
||||
|
||||
CMDError err = get_command_output(fp, out_handling, out_buf);
|
||||
if (err > SHELL_ERR_NO_ERROR) {
|
||||
output = CMD_NO_EXIT(err);
|
||||
goto EXECUTE_COMMAND_CLOSE;
|
||||
}
|
||||
|
||||
i32 st = EXIT_SUCCESS;
|
||||
err = get_output_status(fp, &st);
|
||||
if (err > SHELL_ERR_NO_ERROR) {
|
||||
output = CMD_NO_EXIT(err);
|
||||
goto EXECUTE_COMMAND_CLOSE;
|
||||
}
|
||||
|
||||
// Process is already closed in get_output_status
|
||||
fp = NULL;
|
||||
|
||||
output = (CMDResult){
|
||||
.exited = true,
|
||||
.exit_code = st,
|
||||
.error = SHELL_ERR_NO_ERROR,
|
||||
};
|
||||
|
||||
EXECUTE_COMMAND_CLOSE:
|
||||
if (fp) {
|
||||
wapp_shell_utils_pclose(fp);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
wapp_intern inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf) {
|
||||
Str8 out = wapp_str8_buf(OUT_BUF_LEN);
|
||||
|
||||
out.size = fread((void *)out.buf, sizeof(u8), out.capacity, fp);
|
||||
if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) {
|
||||
if (out.size >= out_buf->capacity) {
|
||||
return SHELL_ERR_OUT_BUF_FULL;
|
||||
}
|
||||
|
||||
wapp_str8_concat_capped(out_buf, &out);
|
||||
} else if (out_handling == SHELL_OUTPUT_PRINT) {
|
||||
printf(WAPP_STR8_SPEC, wapp_str8_varg(out));
|
||||
}
|
||||
|
||||
return SHELL_ERR_NO_ERROR;
|
||||
}
|
||||
27
src/os/shell/commander/commander.h
Normal file
27
src/os/shell/commander/commander.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef COMMANDER_H
|
||||
#define COMMANDER_H
|
||||
|
||||
#include "commander_output.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include "../../../base/strings/str8/str8.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define CMD_NO_EXIT(ERR) ((CMDResult){.exited = false, .exit_code = EXIT_FAILURE, .error = ERR})
|
||||
|
||||
CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd);
|
||||
|
||||
wapp_extern CMDError get_output_status(FILE *fp, i32 *status_out);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !COMMANDER_H
|
||||
44
src/os/shell/commander/commander_output.h
Normal file
44
src/os/shell/commander/commander_output.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef COMMANDER_OUTPUT_H
|
||||
#define COMMANDER_OUTPUT_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef enum {
|
||||
SHELL_OUTPUT_DISCARD,
|
||||
SHELL_OUTPUT_PRINT,
|
||||
SHELL_OUTPUT_CAPTURE,
|
||||
} CMDOutHandling;
|
||||
|
||||
typedef enum {
|
||||
SHELL_ERR_NO_ERROR,
|
||||
SHELL_ERR_INVALID_ARGS,
|
||||
SHELL_ERR_ALLOCATION_FAIL,
|
||||
SHELL_ERR_PROC_START_FAIL,
|
||||
SHELL_ERR_OUT_BUF_FULL,
|
||||
SHELL_ERR_PROC_EXIT_FAIL,
|
||||
} CMDError;
|
||||
|
||||
typedef struct commander_result CMDResult;
|
||||
struct commander_result {
|
||||
i32 exit_code;
|
||||
CMDError error;
|
||||
b8 exited;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
#include "../../../../common/misc/misc_utils.h"
|
||||
wapp_misc_utils_padding_size(sizeof(b8) + sizeof(i32) + sizeof(CMDError));
|
||||
#endif // !WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !COMMANDER_OUTPUT_H
|
||||
25
src/os/shell/commander/posix/commander_posix.c
Normal file
25
src/os/shell/commander/posix/commander_posix.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include "../commander_output.h"
|
||||
#include "../../utils/shell_utils.h"
|
||||
#include <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
|
||||
24
src/os/shell/commander/win/commander_win.c
Normal file
24
src/os/shell/commander/win/commander_win.c
Normal file
@@ -0,0 +1,24 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#include "../commander_output.h"
|
||||
#include "../../utils/shell_utils.h"
|
||||
#include <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
|
||||
36
src/os/shell/termcolour/posix/termcolour_posix.c
Normal file
36
src/os/shell/termcolour/posix/termcolour_posix.c
Normal file
@@ -0,0 +1,36 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../../common/platform/platform.h"
|
||||
#include "../../../../base/strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
|
||||
#include "../terminal_colours.h"
|
||||
#include <stdio.h>
|
||||
|
||||
wapp_intern Str8RO colours[COUNT_TERM_COLOUR] = {
|
||||
[WAPP_TERM_COLOUR_FG_BLACK] = wapp_str8_lit_ro_initialiser_list("\033[30m"),
|
||||
[WAPP_TERM_COLOUR_FG_RED] = wapp_str8_lit_ro_initialiser_list("\033[31m"),
|
||||
[WAPP_TERM_COLOUR_FG_GREEN] = wapp_str8_lit_ro_initialiser_list("\033[32m"),
|
||||
[WAPP_TERM_COLOUR_FG_BLUE] = wapp_str8_lit_ro_initialiser_list("\033[34m"),
|
||||
[WAPP_TERM_COLOUR_FG_CYAN] = wapp_str8_lit_ro_initialiser_list("\033[36m"),
|
||||
[WAPP_TERM_COLOUR_FG_MAGENTA] = wapp_str8_lit_ro_initialiser_list("\033[35m"),
|
||||
[WAPP_TERM_COLOUR_FG_YELLOW] = wapp_str8_lit_ro_initialiser_list("\033[33m"),
|
||||
[WAPP_TERM_COLOUR_FG_WHITE] = wapp_str8_lit_ro_initialiser_list("\033[37m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_BLACK] = wapp_str8_lit_ro_initialiser_list("\033[90m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_RED] = wapp_str8_lit_ro_initialiser_list("\033[91m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_GREEN] = wapp_str8_lit_ro_initialiser_list("\033[92m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_BLUE] = wapp_str8_lit_ro_initialiser_list("\033[94m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_CYAN] = wapp_str8_lit_ro_initialiser_list("\033[96m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] = wapp_str8_lit_ro_initialiser_list("\033[95m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_YELLOW] = wapp_str8_lit_ro_initialiser_list("\033[93m"),
|
||||
[WAPP_TERM_COLOUR_FG_BR_WHITE] = wapp_str8_lit_ro_initialiser_list("\033[97m"),
|
||||
[WAPP_TERM_COLOUR_CLEAR] = wapp_str8_lit_ro_initialiser_list("\033[0m"),
|
||||
};
|
||||
|
||||
void print_coloured_text(Str8RO *text, TerminalColour colour) {
|
||||
printf(WAPP_STR8_SPEC WAPP_STR8_SPEC, wapp_str8_varg(colours[colour]), wapp_str8_varg((*text)));
|
||||
}
|
||||
|
||||
#endif // !WAPP_PLATFORM_POSIX
|
||||
18
src/os/shell/termcolour/termcolour.c
Normal file
18
src/os/shell/termcolour/termcolour.c
Normal file
@@ -0,0 +1,18 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "termcolour.h"
|
||||
#include "terminal_colours.h"
|
||||
#include "../../../base/strings/str8/str8.h"
|
||||
|
||||
void wapp_shell_termcolour_print_text(Str8RO *text, TerminalColour colour) {
|
||||
if (colour < WAPP_TERM_COLOUR_FG_BLACK || colour > WAPP_TERM_COLOUR_FG_BR_WHITE) {
|
||||
return;
|
||||
}
|
||||
|
||||
print_coloured_text(text, colour);
|
||||
}
|
||||
|
||||
void wapp_shell_termcolour_clear_colour(void) {
|
||||
Str8RO empty = wapp_str8_lit_ro("");
|
||||
print_coloured_text(&empty, WAPP_TERM_COLOUR_CLEAR);
|
||||
}
|
||||
24
src/os/shell/termcolour/termcolour.h
Normal file
24
src/os/shell/termcolour/termcolour.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef TERM_COLOUR_H
|
||||
#define TERM_COLOUR_H
|
||||
|
||||
#include "terminal_colours.h"
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include "../../../base/strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
void wapp_shell_termcolour_print_text(Str8RO *text, TerminalColour colour);
|
||||
void wapp_shell_termcolour_clear_colour(void);
|
||||
|
||||
wapp_extern void print_coloured_text(Str8RO *text, TerminalColour colour);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !TERM_COLOUR_H
|
||||
39
src/os/shell/termcolour/terminal_colours.h
Normal file
39
src/os/shell/termcolour/terminal_colours.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef TERMINAL_COLOURS_H
|
||||
#define TERMINAL_COLOURS_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef enum {
|
||||
WAPP_TERM_COLOUR_FG_BLACK,
|
||||
WAPP_TERM_COLOUR_FG_RED,
|
||||
WAPP_TERM_COLOUR_FG_GREEN,
|
||||
WAPP_TERM_COLOUR_FG_BLUE,
|
||||
WAPP_TERM_COLOUR_FG_CYAN,
|
||||
WAPP_TERM_COLOUR_FG_MAGENTA,
|
||||
WAPP_TERM_COLOUR_FG_YELLOW,
|
||||
WAPP_TERM_COLOUR_FG_WHITE,
|
||||
WAPP_TERM_COLOUR_FG_BR_BLACK,
|
||||
WAPP_TERM_COLOUR_FG_BR_RED,
|
||||
WAPP_TERM_COLOUR_FG_BR_GREEN,
|
||||
WAPP_TERM_COLOUR_FG_BR_BLUE,
|
||||
WAPP_TERM_COLOUR_FG_BR_CYAN,
|
||||
WAPP_TERM_COLOUR_FG_BR_MAGENTA,
|
||||
WAPP_TERM_COLOUR_FG_BR_YELLOW,
|
||||
WAPP_TERM_COLOUR_FG_BR_WHITE,
|
||||
WAPP_TERM_COLOUR_CLEAR,
|
||||
|
||||
COUNT_TERM_COLOUR,
|
||||
} TerminalColour;
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !TERMINAL_COLOURS_H
|
||||
73
src/os/shell/termcolour/win/termcolour_win.c
Normal file
73
src/os/shell/termcolour/win/termcolour_win.c
Normal file
@@ -0,0 +1,73 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "../../../../common/aliases/aliases.h"
|
||||
#include "../../../../common/platform/platform.h"
|
||||
#include "../../../../base/strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
|
||||
#include "../terminal_colours.h"
|
||||
#include "../../../../../common/misc/misc_utils.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
typedef struct termcolour_data TermcolourData;
|
||||
struct termcolour_data {
|
||||
HANDLE handle;
|
||||
WORD default_colour;
|
||||
WORD current_colour;
|
||||
|
||||
wapp_misc_utils_padding_size(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
|
||||
};
|
||||
|
||||
wapp_intern void init_data(TermcolourData *data);
|
||||
|
||||
wapp_intern WORD colours[COUNT_TERM_COLOUR] = {
|
||||
[WAPP_TERM_COLOUR_FG_BLACK] = 0,
|
||||
[WAPP_TERM_COLOUR_FG_RED] = FOREGROUND_RED,
|
||||
[WAPP_TERM_COLOUR_FG_GREEN] = FOREGROUND_GREEN,
|
||||
[WAPP_TERM_COLOUR_FG_BLUE] = FOREGROUND_BLUE,
|
||||
[WAPP_TERM_COLOUR_FG_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE,
|
||||
[WAPP_TERM_COLOUR_FG_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE,
|
||||
[WAPP_TERM_COLOUR_FG_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN,
|
||||
[WAPP_TERM_COLOUR_FG_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
|
||||
[WAPP_TERM_COLOUR_FG_BR_BLACK] = FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||
[WAPP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||
};
|
||||
|
||||
void print_coloured_text(Str8RO *text, TerminalColour colour) {
|
||||
wapp_persist TermcolourData data = {0};
|
||||
if (data.handle == 0) {
|
||||
init_data(&data);
|
||||
}
|
||||
|
||||
if (colour == WAPP_TERM_COLOUR_CLEAR) {
|
||||
data.current_colour = data.default_colour;
|
||||
} else {
|
||||
data.current_colour = colours[colour];
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(data.handle, data.current_colour);
|
||||
printf(WAPP_STR8_SPEC, wapp_str8_varg((*text)));
|
||||
}
|
||||
|
||||
wapp_intern 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
|
||||
26
src/os/shell/utils/shell_utils.h
Normal file
26
src/os/shell/utils/shell_utils.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef SHELL_UTILS_H
|
||||
#define SHELL_UTILS_H
|
||||
|
||||
#include "../../../common/aliases/aliases.h"
|
||||
#include "../../../common/platform/platform.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
#define wapp_shell_utils_popen _popen
|
||||
#define wapp_shell_utils_pclose _pclose
|
||||
#else
|
||||
#define wapp_shell_utils_popen popen
|
||||
#define wapp_shell_utils_pclose pclose
|
||||
#endif /* ifdef WAPP_PLATFORM_WINDOWS */
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !SHELL_UTILS_H
|
||||
22
src/os/wapp_os.c
Normal file
22
src/os/wapp_os.c
Normal file
@@ -0,0 +1,22 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_OS_C
|
||||
#define WAPP_OS_C
|
||||
|
||||
#include "wapp_os.h"
|
||||
#include "file/file.c"
|
||||
#include "shell/termcolour/posix/termcolour_posix.c"
|
||||
#include "shell/termcolour/win/termcolour_win.c"
|
||||
#include "shell/termcolour/termcolour.c"
|
||||
#include "shell/commander/posix/commander_posix.c"
|
||||
#include "shell/commander/win/commander_win.c"
|
||||
#include "shell/commander/commander.c"
|
||||
#include "cpath/cpath.c"
|
||||
#include "allocators/arena/mem_arena.c"
|
||||
#include "allocators/arena/mem_arena_allocator.c"
|
||||
#include "mem/posix/mem_os_posix.c"
|
||||
#include "mem/win/mem_os_win.c"
|
||||
#include "mem/mem_os.c"
|
||||
#include "../base/wapp_base.c"
|
||||
|
||||
#endif // !WAPP_OS_C
|
||||
22
src/os/wapp_os.h
Normal file
22
src/os/wapp_os.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_CORE_H
|
||||
#define WAPP_CORE_H
|
||||
|
||||
#include "file/file.h"
|
||||
#include "shell/termcolour/termcolour.h"
|
||||
#include "shell/termcolour/terminal_colours.h"
|
||||
#include "shell/commander/commander.h"
|
||||
#include "shell/commander/commander_output.h"
|
||||
#include "shell/utils/shell_utils.h"
|
||||
#include "cpath/cpath.h"
|
||||
#include "allocators/arena/mem_arena.h"
|
||||
#include "allocators/arena/mem_arena_allocator.h"
|
||||
#include "mem/posix/mem_os_posix.h"
|
||||
#include "mem/win/mem_os_win.h"
|
||||
#include "mem/mem_os_ops.h"
|
||||
#include "mem/mem_os.h"
|
||||
#include "../common/wapp_common.h"
|
||||
#include "../base/wapp_base.h"
|
||||
|
||||
#endif // !WAPP_CORE_H
|
||||
8
src/prng/wapp_prng.c
Normal file
8
src/prng/wapp_prng.c
Normal file
@@ -0,0 +1,8 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_PRNG_C
|
||||
#define WAPP_PRNG_C
|
||||
|
||||
#include "xorshift/xorshift.c"
|
||||
|
||||
#endif // !WAPP_PRNG_C
|
||||
9
src/prng/wapp_prng.h
Normal file
9
src/prng/wapp_prng.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_PRNG_H
|
||||
#define WAPP_PRNG_H
|
||||
|
||||
#include "xorshift/xorshift.h"
|
||||
#include "../common/wapp_common.h"
|
||||
|
||||
#endif // !WAPP_PRNG_H
|
||||
135
src/prng/xorshift/xorshift.c
Normal file
135
src/prng/xorshift/xorshift.c
Normal file
@@ -0,0 +1,135 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "xorshift.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/assert/assert.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef struct split_mix_64_state SplitMix64State;
|
||||
struct split_mix_64_state {
|
||||
u64 seed;
|
||||
};
|
||||
|
||||
wapp_intern u64 rol64(u64 x, u64 bits);
|
||||
wapp_intern u64 split_mix_64(SplitMix64State *state);
|
||||
wapp_intern void seed_os_generator(void);
|
||||
wapp_intern u64 generate_random_number(void);
|
||||
|
||||
XOR256State wapp_prng_xorshift_init_state(void) {
|
||||
wapp_persist b8 seeded = false;
|
||||
if (!seeded) {
|
||||
seeded = true;
|
||||
seed_os_generator();
|
||||
}
|
||||
|
||||
SplitMix64State sm64 = {.seed = generate_random_number()};
|
||||
|
||||
return (XOR256State){
|
||||
.x = split_mix_64(&sm64),
|
||||
.y = split_mix_64(&sm64),
|
||||
.z = split_mix_64(&sm64),
|
||||
.w = split_mix_64(&sm64),
|
||||
};
|
||||
}
|
||||
|
||||
u64 wapp_prng_xorshift_256(XOR256State *state) {
|
||||
u64 t = state->x ^ (state->x << 11);
|
||||
|
||||
state->x = state->y;
|
||||
state->y = state->z;
|
||||
state->z = state->w;
|
||||
state->w = (state->w ^ (state->w >> 19)) ^ (t ^ (t >> 8));
|
||||
|
||||
return state->w;
|
||||
}
|
||||
|
||||
u64 wapp_prng_xorshift_256ss(XOR256State *state) {
|
||||
const u64 result = rol64(state->z * 5, 7) * 9;
|
||||
const u64 t = state->z << 17;
|
||||
|
||||
state->y ^= state->w;
|
||||
state->x ^= state->z;
|
||||
state->z ^= state->y;
|
||||
state->w ^= state->x;
|
||||
|
||||
state->y ^= t;
|
||||
state->x = rol64(state->x, 45);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 wapp_prng_xorshift_256p(XOR256State *state) {
|
||||
const u64 result = state->w + state->x;
|
||||
const u64 t = state->z << 17;
|
||||
|
||||
state->y ^= state->w;
|
||||
state->x ^= state->z;
|
||||
state->z ^= state->y;
|
||||
state->w ^= state->x;
|
||||
|
||||
state->y ^= t;
|
||||
state->x = rol64(state->x, 45);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wapp_intern u64 rol64(u64 x, u64 bits) {
|
||||
return (x << bits) | (x >> (64 - bits));
|
||||
}
|
||||
|
||||
wapp_intern u64 split_mix_64(SplitMix64State *state) {
|
||||
state->seed += 0x9E3779B97f4A7C15;
|
||||
|
||||
u64 result = state->seed;
|
||||
result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9;
|
||||
result = (result ^ (result >> 27)) * 0x94D049BB133111EB;
|
||||
|
||||
return result ^ (result >> 31);
|
||||
}
|
||||
|
||||
#if defined(WAPP_PLATFORM_C) && WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C11_VERSION
|
||||
#ifdef WAPP_PLATFORM_POSIX
|
||||
wapp_intern void seed_os_generator(void) {
|
||||
struct timespec ts = {0};
|
||||
int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
wapp_runtime_assert(result == 0, "Invalid seed value");
|
||||
|
||||
srand48(ts.tv_nsec);
|
||||
}
|
||||
|
||||
wapp_intern u64 generate_random_number(void) {
|
||||
return lrand48();
|
||||
}
|
||||
#else
|
||||
wapp_intern void seed_os_generator(void) {
|
||||
struct timespec ts = {0};
|
||||
int result = timespec_get(&ts, TIME_UTC);
|
||||
wapp_runtime_assert(result != 0, "Invalid seed value");
|
||||
|
||||
srand(ts.tv_nsec);
|
||||
}
|
||||
|
||||
wapp_intern u64 generate_random_number(void) {
|
||||
i32 n1 = rand();
|
||||
i32 n2 = rand();
|
||||
|
||||
return (((u64)n1) << 32 | (u64)n2);
|
||||
}
|
||||
#endif // !WAPP_PLATFORM_POSIX
|
||||
#else
|
||||
wapp_intern void seed_os_generator(void) {
|
||||
time_t result = time(NULL);
|
||||
wapp_runtime_assert(result != (time_t)(-1), "Invalid seed value");
|
||||
|
||||
srand(result);
|
||||
}
|
||||
|
||||
wapp_intern u64 generate_random_number(void) {
|
||||
i32 n1 = rand();
|
||||
i32 n2 = rand();
|
||||
|
||||
return (((u64)n1) << 32 | (u64)n2);
|
||||
}
|
||||
#endif // !WAPP_PLATFORM_C
|
||||
30
src/prng/xorshift/xorshift.h
Normal file
30
src/prng/xorshift/xorshift.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef XORSHIFT_H
|
||||
#define XORSHIFT_H
|
||||
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
typedef struct xor_256_state XOR256State;
|
||||
struct xor_256_state {
|
||||
u64 x;
|
||||
u64 y;
|
||||
u64 z;
|
||||
u64 w;
|
||||
};
|
||||
|
||||
XOR256State wapp_prng_xorshift_init_state(void);
|
||||
u64 wapp_prng_xorshift_256(XOR256State *state);
|
||||
u64 wapp_prng_xorshift_256ss(XOR256State *state);
|
||||
u64 wapp_prng_xorshift_256p(XOR256State *state);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !XORSHIFT_H
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef BASIC_STRING_H
|
||||
#define BASIC_STRING_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct bstr BasicString;
|
||||
struct bstr {
|
||||
u64 size;
|
||||
const char *buf;
|
||||
};
|
||||
|
||||
typedef struct strvw StringView;
|
||||
struct strvw {
|
||||
const u64 size;
|
||||
const char *buf;
|
||||
};
|
||||
|
||||
#define new_string(STR) \
|
||||
{ .size = strlen(STR), .buf = STR }
|
||||
#define wapp_bstr_new(STR) ((BasicString)new_string(STR))
|
||||
#define wapp_strvw_new(STR) ((StringView)new_string(STR))
|
||||
#define wapp_string_print(STR) (printf("%.*s\n", (i32)STR.size, STR.buf))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !BASIC_STRING_H
|
||||
@@ -1,174 +0,0 @@
|
||||
#include "dstr.h"
|
||||
#include "aliases.h"
|
||||
#include "mem_arena.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Use this scalar to allocate extra memory in order to avoid having to
|
||||
// constantly reallocate
|
||||
#define CAPACITY_SCALAR 8
|
||||
#define MINIMUM_DSTR_CAPACITY 1024
|
||||
|
||||
struct dstr {
|
||||
u64 capacity;
|
||||
u64 size;
|
||||
char buf[];
|
||||
};
|
||||
|
||||
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena) {
|
||||
if (!arena) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
String *out =
|
||||
(String *)wapp_mem_arena_alloc(arena, sizeof(String) + capacity + 1);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->capacity = capacity;
|
||||
out->size = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
String *wapp_dstr_from_string(const char *str, Arena *arena) {
|
||||
if (!str || !arena) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64 length = strlen(str);
|
||||
u64 capacity = length * CAPACITY_SCALAR;
|
||||
capacity =
|
||||
capacity >= MINIMUM_DSTR_CAPACITY ? capacity : MINIMUM_DSTR_CAPACITY;
|
||||
|
||||
String *out = wapp_dstr_with_capacity(capacity, arena);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->size = length;
|
||||
strncpy(out->buf, str, length + 1);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
StringUpdate wapp_dstr_update(String **dst, const char *src, Arena *arena) {
|
||||
if (!dst || !(*dst)) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
u64 length = strlen(src);
|
||||
|
||||
String *str = *dst;
|
||||
|
||||
if (length >= str->capacity) {
|
||||
if (!arena) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
String *new_str = wapp_dstr_from_string(src, arena);
|
||||
if (!new_str) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
return (StringUpdate){.updated = true, .str = new_str};
|
||||
}
|
||||
|
||||
memset(str->buf, 0, str->capacity);
|
||||
|
||||
str->size = length;
|
||||
|
||||
strncpy(str->buf, src, length + 1);
|
||||
|
||||
return (StringUpdate){.updated = true, .str = *dst};
|
||||
}
|
||||
|
||||
StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena) {
|
||||
if (!dst || !(*dst)) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
u64 src_length = strlen(src);
|
||||
if (src_length == 0) {
|
||||
return (StringUpdate){.updated = false, .str = *dst};
|
||||
}
|
||||
|
||||
u64 new_length = (*dst)->size + src_length;
|
||||
|
||||
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);
|
||||
|
||||
return wapp_dstr_update(dst, str, arena);
|
||||
}
|
||||
|
||||
void wapp_dstr_clear(String *str) {
|
||||
if (!str || str->size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(str->buf, 0, str->capacity);
|
||||
str->size = 0;
|
||||
}
|
||||
|
||||
void wapp_dstr_print(const String *str) {
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%.*s\n", (i32)str->size, str->buf);
|
||||
}
|
||||
|
||||
i64 wapp_dstr_find(const String *str, const char *substr) {
|
||||
if (!str || !substr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 substr_length = strlen(substr);
|
||||
if (substr_length == 0 || substr_length > str->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *s1;
|
||||
for (u64 i = 0; i < str->size; ++i) {
|
||||
if (i + substr_length > str->size) {
|
||||
break;
|
||||
}
|
||||
|
||||
s1 = &(str->buf[i]);
|
||||
|
||||
if (strncmp(s1, substr, substr_length) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
u64 wapp_dstr_length(const String *str) {
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return str->size;
|
||||
}
|
||||
|
||||
u64 wapp_dstr_capacity(const String *str) {
|
||||
if (!str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return str->capacity;
|
||||
}
|
||||
|
||||
const char *wapp_dstr_to_cstr(const String *str) {
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return str->buf;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef DSTR_H
|
||||
#define DSTR_H
|
||||
|
||||
#include "aliases.h"
|
||||
#include "mem_arena.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef struct dstr String;
|
||||
|
||||
typedef struct string_update StringUpdate;
|
||||
struct string_update {
|
||||
bool updated;
|
||||
String *str;
|
||||
};
|
||||
|
||||
String *wapp_dstr_with_capacity(u64 capacity, Arena *arena);
|
||||
String *wapp_dstr_from_string(const char *str, Arena *arena);
|
||||
StringUpdate wapp_dstr_update(String **dst, const char *src, Arena *arena);
|
||||
StringUpdate wapp_dstr_concat(String **dst, const char *src, Arena *arena);
|
||||
void wapp_dstr_clear(String *str);
|
||||
void wapp_dstr_print(const String *str);
|
||||
i64 wapp_dstr_find(const String *str, const char *substr);
|
||||
u64 wapp_dstr_length(const String *str);
|
||||
u64 wapp_dstr_capacity(const String *str);
|
||||
const char *wapp_dstr_to_cstr(const String *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // !DSTR_H
|
||||
55
src/testing/tester/tester.c
Normal file
55
src/testing/tester/tester.c
Normal file
@@ -0,0 +1,55 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "tester.h"
|
||||
#include "../../common/aliases/aliases.h"
|
||||
#include "../../os/shell/termcolour/termcolour.h"
|
||||
#include "../../base/strings/str8/str8.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
wapp_intern 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");
|
||||
}
|
||||
|
||||
wapp_intern void handle_test_result(TestFuncResult result) {
|
||||
TerminalColour colour;
|
||||
Str8 result_text = wapp_str8_buf(64);
|
||||
|
||||
if (result.passed) {
|
||||
colour = WAPP_TERM_COLOUR_FG_BR_GREEN;
|
||||
wapp_str8_copy_cstr_capped(&result_text, "PASSED");
|
||||
} else {
|
||||
colour = WAPP_TERM_COLOUR_FG_BR_RED;
|
||||
wapp_str8_copy_cstr_capped(&result_text, "FAILED");
|
||||
}
|
||||
|
||||
printf("[");
|
||||
wapp_shell_termcolour_print_text(&result_text, colour);
|
||||
wapp_shell_termcolour_clear_colour();
|
||||
printf("] " WAPP_STR8_SPEC "\n", wapp_str8_varg(result.name));
|
||||
|
||||
if (!result.passed) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
38
src/testing/tester/tester.h
Normal file
38
src/testing/tester/tester.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef TESTER_H
|
||||
#define TESTER_H
|
||||
|
||||
#include "../../common/misc/misc_utils.h"
|
||||
#include "../../common/platform/platform.h"
|
||||
#include "../../base/strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
|
||||
#define wapp_tester_result(PASSED) (TestFuncResult{wapp_str8_lit_ro(__func__), PASSED})
|
||||
#else
|
||||
#define wapp_tester_result(PASSED) ((TestFuncResult){.name = wapp_str8_lit_ro(__func__), .passed = PASSED})
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define wapp_tester_run_tests(...) run_tests(__VA_ARGS__, NULL)
|
||||
|
||||
typedef struct test_func_result TestFuncResult;
|
||||
struct test_func_result {
|
||||
Str8 name;
|
||||
b8 passed;
|
||||
|
||||
#ifdef WAPP_PLATFORM_WINDOWS
|
||||
wapp_misc_utils_padding_size(sizeof(Str8RO) + sizeof(b8));
|
||||
#endif // WAPP_PLATFORM_WINDOWS
|
||||
};
|
||||
|
||||
typedef TestFuncResult(TestFunc)(void);
|
||||
|
||||
void run_tests(TestFunc *func1, ...);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !TESTER_H
|
||||
10
src/testing/wapp_testing.c
Normal file
10
src/testing/wapp_testing.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_TESTING_C
|
||||
#define WAPP_TESTING_C
|
||||
|
||||
#include "wapp_testing.h"
|
||||
#include "tester/tester.c"
|
||||
#include "../os/wapp_os.c"
|
||||
|
||||
#endif // !WAPP_TESTING_C
|
||||
10
src/testing/wapp_testing.h
Normal file
10
src/testing/wapp_testing.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_TESTING_H
|
||||
#define WAPP_TESTING_H
|
||||
|
||||
#include "tester/tester.h"
|
||||
#include "../common/wapp_common.h"
|
||||
#include "../os/wapp_os.h"
|
||||
|
||||
#endif // !WAPP_TESTING_H
|
||||
58
src/uuid/uuid.c
Normal file
58
src/uuid/uuid.c
Normal file
@@ -0,0 +1,58 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "uuid.h"
|
||||
#include "../common/aliases/aliases.h"
|
||||
#include "../common/assert/assert.h"
|
||||
#include "../base/strings/str8/str8.h"
|
||||
#include "../prng/xorshift/xorshift.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#define UUID_STR_FORMAT ("%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.12" PRIx64)
|
||||
|
||||
typedef struct uuid4 UUID4;
|
||||
struct uuid4 {
|
||||
u64 high;
|
||||
u64 low;
|
||||
};
|
||||
|
||||
wapp_intern UUID4 generate_uuid4(void);
|
||||
wapp_intern void uuid4_to_uuid(const UUID4* uuid4, WUUID *uuid);
|
||||
|
||||
WUUID *wapp_uuid_init_uuid4(WUUID *uuid) {
|
||||
wapp_debug_assert(uuid != NULL, "`uuid` should not be NULL");
|
||||
|
||||
UUID4 uuid4 = generate_uuid4();
|
||||
uuid4_to_uuid(&uuid4, uuid);
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
wapp_intern UUID4 generate_uuid4(void) {
|
||||
wapp_persist XOR256State state = {0};
|
||||
wapp_persist b8 initialised = false;
|
||||
|
||||
if (!initialised) {
|
||||
initialised = true;
|
||||
state = wapp_prng_xorshift_init_state();
|
||||
}
|
||||
|
||||
UUID4 uuid = (UUID4){
|
||||
.high = wapp_prng_xorshift_256(&state),
|
||||
.low = wapp_prng_xorshift_256(&state),
|
||||
};
|
||||
|
||||
uuid.high = (uuid.high & 0xffffffffffff0fff) | 0x0000000000004000;
|
||||
uuid.low = (uuid.low & 0x3fffffffffffffff) | 0x8000000000000000;
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
wapp_intern void uuid4_to_uuid(const UUID4* uuid4, WUUID *uuid) {
|
||||
u64 group1 = uuid4->high >> 32;
|
||||
u64 group2 = (uuid4->high << 32) >> 48;
|
||||
u64 group3 = (uuid4->high << 48) >> 48;
|
||||
u64 group4 = uuid4->low >> 48;
|
||||
u64 group5 = (uuid4->low << 16) >> 16;
|
||||
|
||||
wapp_str8_format(&(uuid->uuid), UUID_STR_FORMAT, group1, group2, group3, group4, group5);
|
||||
}
|
||||
37
src/uuid/uuid.h
Normal file
37
src/uuid/uuid.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef UUID_H
|
||||
#define UUID_H
|
||||
|
||||
#include "../common/aliases/aliases.h"
|
||||
#include "../common/platform/platform.h"
|
||||
#include "../base/strings/str8/str8.h"
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
BEGIN_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#define UUID_BUF_LENGTH 48
|
||||
#define WAPP_UUID_SPEC WAPP_STR8_SPEC
|
||||
#define wapp_uuid_varg(WUUID) wapp_str8_varg((WUUID).uuid)
|
||||
|
||||
typedef struct wapp_uuid WUUID;
|
||||
struct wapp_uuid {
|
||||
Str8 uuid;
|
||||
};
|
||||
|
||||
#define wapp_uuid_gen_uuid4() *(wapp_uuid_init_uuid4(&wapp_uuid_create()))
|
||||
|
||||
/* Low level UUID API */
|
||||
|
||||
#define wapp_uuid_create() ((WUUID){.uuid = wapp_str8_buf(UUID_BUF_LENGTH)})
|
||||
|
||||
// Just returns the same pointer that was passed in with the UUID initialised.
|
||||
// Fails when passed a NULL pointer.
|
||||
WUUID *wapp_uuid_init_uuid4(WUUID *uuid);
|
||||
|
||||
#ifdef WAPP_PLATFORM_CPP
|
||||
END_C_LINKAGE
|
||||
#endif // !WAPP_PLATFORM_CPP
|
||||
|
||||
#endif // !UUID_H
|
||||
10
src/uuid/wapp_uuid.c
Normal file
10
src/uuid/wapp_uuid.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_UUID_C
|
||||
#define WAPP_UUID_C
|
||||
|
||||
#include "uuid.c"
|
||||
#include "../base/wapp_base.c"
|
||||
#include "../prng/wapp_prng.c"
|
||||
|
||||
#endif // !WAPP_UUID_C
|
||||
11
src/uuid/wapp_uuid.h
Normal file
11
src/uuid/wapp_uuid.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_UUID_H
|
||||
#define WAPP_UUID_H
|
||||
|
||||
#include "uuid.h"
|
||||
#include "../common/wapp_common.h"
|
||||
#include "../base/wapp_base.h"
|
||||
#include "../prng/wapp_prng.h"
|
||||
|
||||
#endif // !WAPP_UUID_H
|
||||
13
src/wapp.c
Normal file
13
src/wapp.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_C
|
||||
#define WAPP_C
|
||||
|
||||
#include "wapp.h"
|
||||
#include "base/wapp_base.c"
|
||||
#include "os/wapp_os.c"
|
||||
#include "prng/wapp_prng.c"
|
||||
#include "uuid/uuid.c"
|
||||
#include "testing/wapp_testing.c"
|
||||
|
||||
#endif // !WAPP_C
|
||||
13
src/wapp.h
Normal file
13
src/wapp.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef WAPP_H
|
||||
#define WAPP_H
|
||||
|
||||
#include "common/wapp_common.h"
|
||||
#include "base/wapp_base.h"
|
||||
#include "os/wapp_os.h"
|
||||
#include "prng/wapp_prng.h"
|
||||
#include "uuid/wapp_uuid.h"
|
||||
#include "testing/wapp_testing.h"
|
||||
|
||||
#endif // !WAPP_H
|
||||
17
tests/allocator/test_allocator.c
Normal file
17
tests/allocator/test_allocator.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "test_allocator.h"
|
||||
#include "wapp.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
TestFuncResult test_arena_allocator(void) {
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(4096);
|
||||
b8 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);
|
||||
}
|
||||
17
tests/allocator/test_allocator.cc
Normal file
17
tests/allocator/test_allocator.cc
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "test_allocator.h"
|
||||
#include "wapp.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
TestFuncResult test_arena_allocator(void) {
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(4096);
|
||||
b8 result = allocator.obj != nullptr && allocator.alloc != nullptr &&
|
||||
allocator.alloc_aligned != nullptr &&
|
||||
allocator.realloc != nullptr && allocator.realloc_aligned != nullptr &&
|
||||
allocator.free == nullptr;
|
||||
void *ptr = wapp_mem_allocator_alloc(&allocator, 20);
|
||||
result = result && (ptr != nullptr);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
8
tests/allocator/test_allocator.h
Normal file
8
tests/allocator/test_allocator.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef TEST_ALLOCATOR_H
|
||||
#define TEST_ALLOCATOR_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_arena_allocator(void);
|
||||
|
||||
#endif // !TEST_ALLOCATOR_H
|
||||
111
tests/arena/test_arena.c
Normal file
111
tests/arena/test_arena.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "test_arena.h"
|
||||
#include "wapp.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARENA_CAPACITY KB(16)
|
||||
|
||||
wapp_intern Arena *arena = NULL;
|
||||
wapp_intern i32 count = 20;
|
||||
wapp_intern i32 *array = NULL;
|
||||
|
||||
TestFuncResult test_arena_init(void) {
|
||||
b8 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);
|
||||
b8 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));
|
||||
b8 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);
|
||||
b8 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);
|
||||
b8 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);
|
||||
b8 result = arena == NULL;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
111
tests/arena/test_arena.cc
Normal file
111
tests/arena/test_arena.cc
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "test_arena.h"
|
||||
#include "wapp.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARENA_CAPACITY KB(16)
|
||||
|
||||
wapp_intern Arena *arena = nullptr;
|
||||
wapp_intern i32 count = 20;
|
||||
wapp_intern i32 *array = nullptr;
|
||||
|
||||
TestFuncResult test_arena_init(void) {
|
||||
b8 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 = nullptr;
|
||||
u64 capacity = GB(512);
|
||||
b8 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 = (i32 *)wapp_mem_arena_alloc(arena, count * sizeof(i32));
|
||||
b8 result = array != nullptr;
|
||||
|
||||
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 = (u8 *)wapp_mem_arena_alloc(arena, ARENA_CAPACITY * 2);
|
||||
b8 result = bytes == nullptr;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_arena_realloc_bigger_size(void) {
|
||||
u64 old_count = 10;
|
||||
u64 new_count = 20;
|
||||
i32 *bytes = (i32 *)wapp_mem_arena_alloc(arena, old_count * sizeof(i32));
|
||||
|
||||
for (u64 i = 0; i < old_count; ++i) {
|
||||
bytes[i] = (i32)i;
|
||||
}
|
||||
|
||||
i32 *new_bytes = (i32 *)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 = (i32 *)wapp_mem_arena_alloc(arena, old_count * sizeof(i32));
|
||||
|
||||
for (u64 i = 0; i < old_count; ++i) {
|
||||
bytes[i] = (i32)i;
|
||||
}
|
||||
|
||||
i32 *new_bytes = (i32 *)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);
|
||||
b8 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);
|
||||
b8 result = arena == nullptr;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
15
tests/arena/test_arena.h
Normal file
15
tests/arena/test_arena.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef TEST_ARENA_H
|
||||
#define TEST_ARENA_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
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);
|
||||
|
||||
#endif // !TEST_ARENA_H
|
||||
270
tests/array/test_i32_array.c
Normal file
270
tests/array/test_i32_array.c
Normal file
@@ -0,0 +1,270 @@
|
||||
#include "test_i32_array.h"
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_i32_array(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6, 7);
|
||||
result = array.count == 7 && array.capacity == 16;
|
||||
|
||||
i32 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
item = wapp_array_get(i32, &array, index);
|
||||
result = result && item && *item == (i32)(index + 1);
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_with_capacity(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array_with_capacity(i32, I32Array, 64);
|
||||
result = array.count == 0 && array.capacity == 64;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_get(void) {
|
||||
b8 result = true;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
i32 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
item = wapp_array_get(i32, &array, index);
|
||||
result = result && item && *item == (i32)index;
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_set(void) {
|
||||
b8 result = true;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
i32 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
i32 num = (i32)(index * 2);
|
||||
wapp_array_set(i32, &array, index, &num);
|
||||
item = wapp_array_get(i32, &array, index);
|
||||
result = result && item && *item == (i32)(index * 2);
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_append_capped(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array_with_capacity(i32, I32Array, 64);
|
||||
wapp_array_append_capped(i32, &array, &((i32){10}));
|
||||
|
||||
result = array.count == 1;
|
||||
i32 *item = wapp_array_get(i32, &array, 0);
|
||||
result = result && item && *item == 10;
|
||||
|
||||
array = wapp_array(i32, I32Array, 1);
|
||||
wapp_array_append_capped(i32, &array, &((i32){10}));
|
||||
|
||||
result = result && array.count == 2;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_extend_capped(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array1 = wapp_array(i32, I32Array, 1, 2, 3, 4);
|
||||
I32Array array2 = wapp_array(i32, I32Array, 10, 20);
|
||||
|
||||
result = array1.count == 4 && array2.count == 2;
|
||||
|
||||
wapp_array_extend_capped(i32, &array1, &array2);
|
||||
|
||||
result = result && array1.count == 6;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_copy_capped(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array src = wapp_array(i32, I32Array, 1, 2, 3, 4, 5);
|
||||
I32Array dst1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6);
|
||||
I32Array dst2 = wapp_array(i32, I32Array, 1, 2);
|
||||
|
||||
u64 expected_count = 5;
|
||||
wapp_array_copy_capped(i32, &dst1, &src);
|
||||
result = dst1.count == expected_count;
|
||||
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
result = result && *wapp_array_get(i32, &src, index) == *wapp_array_get(i32, &dst1, index);
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
expected_count = 4;
|
||||
wapp_array_copy_capped(i32, &dst2, &src);
|
||||
result = result && dst2.count == expected_count;
|
||||
|
||||
index = 0;
|
||||
running = true;
|
||||
while (running) {
|
||||
result = result && *wapp_array_get(i32, &src, index) == *wapp_array_get(i32, &dst2, index);
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_alloc_capacity(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
u64 capacity = 32;
|
||||
I32Array *array = wapp_array_alloc_capacity(i32, I32Array, &allocator, capacity);
|
||||
|
||||
result = array && array->capacity == capacity;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_append_alloc(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
I32Array array1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
I32Array array2 = wapp_array(i32, I32Array, 1, 2);
|
||||
|
||||
I32Array *arr_ptr = wapp_array_append_alloc(i32, I32Array, &allocator, &array1, &((i32){10}));
|
||||
result = arr_ptr == &array1;
|
||||
|
||||
u64 count = 4;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
i32 num = (i32)index;
|
||||
arr_ptr = wapp_array_append_alloc(i32, I32Array, &allocator, &array2, &num);
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
result = result && arr_ptr != &array2;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_extend_alloc(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
I32Array array1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
I32Array array2 = wapp_array(i32, I32Array, 1, 2);
|
||||
I32Array array3 = wapp_array(i32, I32Array, 1, 2, 3, 4);
|
||||
|
||||
I32Array *arr_ptr = wapp_array_extend_alloc(i32, I32Array, &allocator, &array1, &array3);
|
||||
result = arr_ptr == &array1;
|
||||
|
||||
arr_ptr = wapp_array_extend_alloc(i32, I32Array, &allocator, &array2, &array3);
|
||||
result = result && arr_ptr != &array2;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_copy_alloc(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
I32Array src = wapp_array(i32, I32Array, 1, 2, 3, 4, 5);
|
||||
I32Array dst1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6);
|
||||
I32Array dst2 = wapp_array(i32, I32Array, 1, 2);
|
||||
I32Array *array_ptr = NULL;
|
||||
|
||||
u64 expected_count = 5;
|
||||
array_ptr = wapp_array_copy_alloc(i32, I32Array, &allocator, &dst1, &src);
|
||||
result = array_ptr->count == expected_count && array_ptr == &dst1;
|
||||
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
result = result && *wapp_array_get(i32, &src, index) == *wapp_array_get(i32, array_ptr, index);
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
expected_count = 5;
|
||||
array_ptr = wapp_array_copy_alloc(i32, I32Array, &allocator, &dst2, &src);
|
||||
result = result && array_ptr->count == expected_count && array_ptr != &dst2;
|
||||
|
||||
index = 0;
|
||||
running = true;
|
||||
while (running) {
|
||||
result = result && *wapp_array_get(i32, &src, index) == *wapp_array_get(i32, array_ptr, index);
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_pop(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array1 = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
I32Array array2 = wapp_array_with_capacity(i32, I32Array, 32);
|
||||
|
||||
i32 item1 = wapp_array_pop(i32, &array1);
|
||||
i32 item2 = wapp_array_pop(i32, &array2);
|
||||
|
||||
result = item1 == 8 && item2 == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_clear(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
result = array.count == 9;
|
||||
|
||||
wapp_array_clear(i32, &array);
|
||||
|
||||
result = result && array.count == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
273
tests/array/test_i32_array.cc
Normal file
273
tests/array/test_i32_array.cc
Normal file
@@ -0,0 +1,273 @@
|
||||
#include "test_i32_array.h"
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_i32_array(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6, 7);
|
||||
result = array.count == 7 && array.capacity == 16;
|
||||
|
||||
i32 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
item = wapp_array_get(i32, &array, index);
|
||||
result = result && item && (*item == (i32)(index + 1));
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_with_capacity(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array_with_capacity(i32, I32Array, 64);
|
||||
result = array.count == 0 && array.capacity == 64;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_get(void) {
|
||||
b8 result = true;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
i32 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
item = wapp_array_get(i32, &array, index);
|
||||
result = result && item && (*item == (i32)index);
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_set(void) {
|
||||
b8 result = true;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
|
||||
i32 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
i32 num = (i32)(index * 2);
|
||||
wapp_array_set(i32, &array, index, &num);
|
||||
item = wapp_array_get(i32, &array, index);
|
||||
result = result && item && (*item == (i32)(index * 2));
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_append_capped(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array_with_capacity(i32, I32Array, 64);
|
||||
i32 item1 = 10;
|
||||
wapp_array_append_capped(i32, &array, &item1);
|
||||
|
||||
result = array.count == 1;
|
||||
i32 *item = wapp_array_get(i32, &array, 0);
|
||||
result = result && item && *item == 10;
|
||||
|
||||
array = wapp_array(i32, I32Array, 1);
|
||||
i32 item2 = 10;
|
||||
wapp_array_append_capped(i32, &array, &item2);
|
||||
|
||||
result = result && array.count == 2;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_extend_capped(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array1 = wapp_array(i32, I32Array, 1, 2, 3, 4);
|
||||
I32Array array2 = wapp_array(i32, I32Array, 10, 20);
|
||||
|
||||
result = array1.count == 4 && array2.count == 2;
|
||||
|
||||
wapp_array_extend_capped(i32, &array1, &array2);
|
||||
|
||||
result = result && array1.count == 6;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_copy_capped(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array src = wapp_array(i32, I32Array, 1, 2, 3, 4, 5);
|
||||
I32Array dst1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6);
|
||||
I32Array dst2 = wapp_array(i32, I32Array, 1, 2);
|
||||
|
||||
u64 expected_count = 5;
|
||||
wapp_array_copy_capped(i32, &dst1, &src);
|
||||
result = dst1.count == expected_count;
|
||||
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
result = result && (*wapp_array_get(i32, &src, index) == *wapp_array_get(i32, &dst1, index));
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
expected_count = 4;
|
||||
wapp_array_copy_capped(i32, &dst2, &src);
|
||||
result = result && dst2.count == expected_count;
|
||||
|
||||
index = 0;
|
||||
running = true;
|
||||
while (running) {
|
||||
result = result && (*wapp_array_get(i32, &src, index) == *wapp_array_get(i32, &dst2, index));
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_alloc_capacity(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
u64 capacity = 32;
|
||||
I32Array *array = wapp_array_alloc_capacity(i32, I32Array, &allocator, capacity);
|
||||
|
||||
result = array && array->capacity == capacity;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_append_alloc(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
I32Array array1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
I32Array array2 = wapp_array(i32, I32Array, 1, 2);
|
||||
|
||||
i32 num = 10;
|
||||
I32Array *arr_ptr = wapp_array_append_alloc(i32, I32Array, &allocator, &array1, &num);
|
||||
result = arr_ptr == &array1;
|
||||
|
||||
u64 count = 4;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
num = (i32)index;
|
||||
arr_ptr = wapp_array_append_alloc(i32, I32Array, &allocator, &array2, &num);
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
result = result && arr_ptr != &array2;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_extend_alloc(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
I32Array array1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
I32Array array2 = wapp_array(i32, I32Array, 1, 2);
|
||||
I32Array array3 = wapp_array(i32, I32Array, 1, 2, 3, 4);
|
||||
|
||||
I32Array *arr_ptr = wapp_array_extend_alloc(i32, I32Array, &allocator, &array1, &array3);
|
||||
result = arr_ptr == &array1;
|
||||
|
||||
arr_ptr = wapp_array_extend_alloc(i32, I32Array, &allocator, &array2, &array3);
|
||||
result = result && arr_ptr != &array2;
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_copy_alloc(void) {
|
||||
b8 result;
|
||||
|
||||
Allocator allocator = wapp_mem_arena_allocator_init(MB(4));
|
||||
I32Array src = wapp_array(i32, I32Array, 1, 2, 3, 4, 5);
|
||||
I32Array dst1 = wapp_array(i32, I32Array, 1, 2, 3, 4, 5, 6);
|
||||
I32Array dst2 = wapp_array(i32, I32Array, 1, 2);
|
||||
I32Array *array_ptr = nullptr;
|
||||
|
||||
u64 expected_count = 5;
|
||||
array_ptr = wapp_array_copy_alloc(i32, I32Array, &allocator, &dst1, &src);
|
||||
result = array_ptr->count == expected_count && array_ptr == &dst1;
|
||||
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
result = result && (*wapp_array_get(i32, &src, index) == *wapp_array_get(i32, array_ptr, index));
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
expected_count = 5;
|
||||
array_ptr = wapp_array_copy_alloc(i32, I32Array, &allocator, &dst2, &src);
|
||||
result = result && array_ptr->count == expected_count && array_ptr != &dst2;
|
||||
|
||||
index = 0;
|
||||
running = true;
|
||||
while (running) {
|
||||
result = result && (*wapp_array_get(i32, &src, index) == *wapp_array_get(i32, array_ptr, index));
|
||||
|
||||
++index;
|
||||
running = index < expected_count;
|
||||
}
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&allocator);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_clear(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
result = array.count == 9;
|
||||
|
||||
wapp_array_clear(i32, &array);
|
||||
|
||||
result = result && array.count == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_i32_array_pop(void) {
|
||||
b8 result;
|
||||
|
||||
I32Array array1 = wapp_array(i32, I32Array, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
||||
I32Array array2 = wapp_array_with_capacity(i32, I32Array, 32);
|
||||
|
||||
i32 item1 = wapp_array_pop(i32, &array1);
|
||||
i32 item2 = wapp_array_pop(i32, &array2);
|
||||
|
||||
result = item1 == 8 && item2 == 0;
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
20
tests/array/test_i32_array.h
Normal file
20
tests/array/test_i32_array.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef TEST_INT_ARRAY_H
|
||||
#define TEST_INT_ARRAY_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_i32_array(void);
|
||||
TestFuncResult test_i32_array_with_capacity(void);
|
||||
TestFuncResult test_i32_array_get(void);
|
||||
TestFuncResult test_i32_array_set(void);
|
||||
TestFuncResult test_i32_array_append_capped(void);
|
||||
TestFuncResult test_i32_array_extend_capped(void);
|
||||
TestFuncResult test_i32_array_copy_capped(void);
|
||||
TestFuncResult test_i32_array_alloc_capacity(void);
|
||||
TestFuncResult test_i32_array_append_alloc(void);
|
||||
TestFuncResult test_i32_array_extend_alloc(void);
|
||||
TestFuncResult test_i32_array_copy_alloc(void);
|
||||
TestFuncResult test_i32_array_pop(void);
|
||||
TestFuncResult test_i32_array_clear(void);
|
||||
|
||||
#endif // !TEST_INT_ARRAY_H
|
||||
25
tests/array/test_str8_array.c
Normal file
25
tests/array/test_str8_array.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "test_str8_array.h"
|
||||
|
||||
TestFuncResult test_str8_array(void) {
|
||||
b8 result;
|
||||
|
||||
Str8 expected[] = {wapp_str8_lit("Hello"), wapp_str8_lit("Hi"), wapp_str8_lit("Bye")};
|
||||
Str8Array array = wapp_array(Str8, Str8Array, wapp_str8_lit("Hello"), wapp_str8_lit("Hi"), wapp_str8_lit("Bye"));
|
||||
result = array.count == 3 && array.capacity == 8;
|
||||
|
||||
Str8 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
item = wapp_array_get(Str8, &array, index);
|
||||
result = result && item && (wapp_str8_equal(item, &expected[index]));
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
30
tests/array/test_str8_array.cc
Normal file
30
tests/array/test_str8_array.cc
Normal file
@@ -0,0 +1,30 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#include "test_str8_array.h"
|
||||
|
||||
TestFuncResult test_str8_array(void) {
|
||||
b8 result;
|
||||
|
||||
Str8 expected[] = {wapp_str8_lit("Hello"), wapp_str8_lit("Hi"), wapp_str8_lit("Bye")};
|
||||
|
||||
Str8 str1 = wapp_str8_lit("Hello");
|
||||
Str8 str2 = wapp_str8_lit("Hi");
|
||||
Str8 str3 = wapp_str8_lit("Bye");
|
||||
Str8Array array = wapp_array(Str8, Str8Array, str1, str2, str3);
|
||||
|
||||
result = array.count == 3 && array.capacity == 8;
|
||||
|
||||
Str8 *item;
|
||||
u64 count = array.count;
|
||||
u64 index = 0;
|
||||
b8 running = true;
|
||||
while (running) {
|
||||
item = wapp_array_get(Str8, &array, index);
|
||||
result = result && item && (wapp_str8_equal(item, &expected[index]));
|
||||
|
||||
++index;
|
||||
running = index < count;
|
||||
}
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
10
tests/array/test_str8_array.h
Normal file
10
tests/array/test_str8_array.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// vim:fileencoding=utf-8:foldmethod=marker
|
||||
|
||||
#ifndef TEST_STR8_ARRAY_H
|
||||
#define TEST_STR8_ARRAY_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_str8_array(void);
|
||||
|
||||
#endif // !TEST_STR8_ARRAY_H
|
||||
181
tests/cpath/test_cpath.c
Normal file
181
tests/cpath/test_cpath.c
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "test_cpath.h"
|
||||
#include "wapp.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAIN_BUF_SIZE 4096
|
||||
#define TMP_BUF_SIZE 1024
|
||||
|
||||
TestFuncResult test_cpath_join_path(void) {
|
||||
b8 result;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 out = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
wapp_str8_format(&expected, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&tmp, "%c", WAPP_PATH_SEP);
|
||||
|
||||
Str8List parts = wapp_dbl_list(Str8, Str8List);
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_str8(tmp));
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_cstr("home"));
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_cstr("abdelrahman"));
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_cstr("Documents"));
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
|
||||
wapp_str8_format(&expected, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_str8_concat_capped(&tmp, &wapp_str8_lit_ro("home"));
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
wapp_dbl_list_push_front(Str8, &parts, &wapp_str8_node_from_str8(tmp));
|
||||
|
||||
wapp_str8_format(&expected, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_str8_format(&tmp, "home%c", WAPP_PATH_SEP);
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
wapp_dbl_list_push_front(Str8, &parts, &wapp_str8_node_from_cstr("home"));
|
||||
|
||||
wapp_str8_format(&expected, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_empty(Str8, &parts);
|
||||
|
||||
wapp_str8_format(&tmp, "%chome", WAPP_PATH_SEP);
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_str8(tmp));
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_cstr(""));
|
||||
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_cstr(""));
|
||||
|
||||
wapp_str8_format(&expected, "%s", "");
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_back(Str8, Str8Node, &parts);
|
||||
wapp_dbl_list_push_back(Str8, &parts, &wapp_str8_node_from_cstr("home"));
|
||||
|
||||
wapp_str8_copy_cstr_capped(&expected, "home");
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_cpath_dirname(void) {
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&arena)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
b8 result;
|
||||
Str8 *output = NULL;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
// CASE 1
|
||||
wapp_str8_format(&tmp, "%c", WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 2
|
||||
wapp_str8_format(&expected, "%s", ".");
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &wapp_str8_lit("home"));
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 3
|
||||
output = wapp_cpath_dirname(&arena, &wapp_str8_lit(""));
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 4
|
||||
wapp_str8_format(&tmp, "%chome%ctest", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 5
|
||||
wapp_str8_format(&tmp, "%chome%ctest%c", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_cpath_dirup(void) {
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&arena)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
b8 result;
|
||||
Str8 *output = NULL;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
// CASE 1
|
||||
wapp_str8_format(&tmp, "%c", WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 2
|
||||
wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 3
|
||||
wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_copy_cstr_capped(&expected, ".");
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 4
|
||||
wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 2);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 5
|
||||
wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_copy_cstr_capped(&expected, "home");
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 2);
|
||||
result = result && output != NULL && wapp_str8_equal(output, &expected);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
204
tests/cpath/test_cpath.cc
Normal file
204
tests/cpath/test_cpath.cc
Normal file
@@ -0,0 +1,204 @@
|
||||
#include "test_cpath.h"
|
||||
#include "wapp.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAIN_BUF_SIZE 4096
|
||||
#define TMP_BUF_SIZE 1024
|
||||
|
||||
TestFuncResult test_cpath_join_path(void) {
|
||||
b8 result;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 out = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
wapp_str8_format(&expected, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&tmp, "%c", WAPP_PATH_SEP);
|
||||
|
||||
Str8List parts = wapp_dbl_list(Str8, Str8List);
|
||||
|
||||
Str8Node tmp_node = wapp_str8_node_from_str8(tmp);
|
||||
wapp_dbl_list_push_back(Str8, &parts, &tmp_node);
|
||||
|
||||
Str8Node home_node = wapp_str8_node_from_cstr("home");
|
||||
wapp_dbl_list_push_back(Str8, &parts, &home_node);
|
||||
|
||||
Str8Node user_node = wapp_str8_node_from_cstr("abdelrahman");
|
||||
wapp_dbl_list_push_back(Str8, &parts, &user_node);
|
||||
|
||||
Str8Node docs_node = wapp_str8_node_from_cstr("Documents");
|
||||
wapp_dbl_list_push_back(Str8, &parts, &docs_node);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
|
||||
wapp_str8_format(&expected, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
Str8RO str = wapp_str8_lit_ro("home");
|
||||
wapp_str8_concat_capped(&tmp, &str);
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
|
||||
Str8Node tmp_node_2 = wapp_str8_node_from_str8(tmp);
|
||||
wapp_dbl_list_push_front(Str8, &parts, &tmp_node_2);
|
||||
|
||||
wapp_str8_format(&expected, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_str8_format(&tmp, "home%c", WAPP_PATH_SEP);
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
|
||||
Str8Node home_node_2 = wapp_str8_node_from_cstr("home");
|
||||
wapp_dbl_list_push_front(Str8, &parts, &home_node_2);
|
||||
|
||||
wapp_str8_format(&expected, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_empty(Str8, &parts);
|
||||
|
||||
wapp_str8_format(&tmp, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
Str8Node tmp_node_3 = wapp_str8_node_from_str8(tmp);
|
||||
wapp_dbl_list_push_back(Str8, &parts, &tmp_node_3);
|
||||
|
||||
Str8Node empty_node = wapp_str8_node_from_cstr("");
|
||||
wapp_dbl_list_push_back(Str8, &parts, &empty_node);
|
||||
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_front(Str8, Str8Node, &parts);
|
||||
|
||||
Str8Node empty_node_2 = wapp_str8_node_from_cstr("");
|
||||
wapp_dbl_list_push_back(Str8, &parts, &empty_node_2);
|
||||
|
||||
wapp_str8_format(&expected, "%s", "");
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
wapp_dbl_list_pop_back(Str8, Str8Node, &parts);
|
||||
|
||||
Str8Node home_node_3 = wapp_str8_node_from_cstr("home");
|
||||
wapp_dbl_list_push_back(Str8, &parts, &home_node_3);
|
||||
|
||||
wapp_str8_copy_cstr_capped(&expected, "home");
|
||||
|
||||
wapp_cpath_join_path(&out, &parts);
|
||||
result = result && wapp_str8_equal(&out, &expected);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_cpath_dirname(void) {
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&arena)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
b8 result;
|
||||
Str8 *output = nullptr;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
// CASE 1
|
||||
wapp_str8_format(&tmp, "%c", WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 2
|
||||
wapp_str8_format(&expected, "%s", ".");
|
||||
|
||||
Str8 path = wapp_str8_lit("home");
|
||||
output = wapp_cpath_dirname(&arena, &path);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 3
|
||||
path = wapp_str8_lit("");
|
||||
output = wapp_cpath_dirname(&arena, &path);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 4
|
||||
wapp_str8_format(&tmp, "%chome%ctest", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 5
|
||||
wapp_str8_format(&tmp, "%chome%ctest%c", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirname(&arena, &tmp);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
|
||||
TestFuncResult test_cpath_dirup(void) {
|
||||
Allocator arena = wapp_mem_arena_allocator_init(MB(8));
|
||||
if (wapp_mem_allocator_invalid(&arena)) {
|
||||
return wapp_tester_result(false);
|
||||
}
|
||||
|
||||
b8 result;
|
||||
Str8 *output = nullptr;
|
||||
|
||||
Str8 expected = wapp_str8_buf(MAIN_BUF_SIZE);
|
||||
Str8 tmp = wapp_str8_buf(TMP_BUF_SIZE);
|
||||
|
||||
// CASE 1
|
||||
wapp_str8_format(&tmp, "%c", WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 2
|
||||
wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%c", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 3
|
||||
wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_copy_cstr_capped(&expected, ".");
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 3);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 4
|
||||
wapp_str8_format(&tmp, "%chome%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_format(&expected, "%chome", WAPP_PATH_SEP);
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 2);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
// CASE 5
|
||||
wapp_str8_format(&tmp, "home%cabdelrahman%cDocuments", WAPP_PATH_SEP, WAPP_PATH_SEP);
|
||||
wapp_str8_copy_cstr_capped(&expected, "home");
|
||||
|
||||
output = wapp_cpath_dirup(&arena, &tmp, 2);
|
||||
result = result && output != nullptr && wapp_str8_equal(output, &expected);
|
||||
|
||||
wapp_mem_arena_allocator_destroy(&arena);
|
||||
|
||||
return wapp_tester_result(result);
|
||||
}
|
||||
10
tests/cpath/test_cpath.h
Normal file
10
tests/cpath/test_cpath.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef TEST_CPATH_H
|
||||
#define TEST_CPATH_H
|
||||
|
||||
#include "wapp.h"
|
||||
|
||||
TestFuncResult test_cpath_join_path(void);
|
||||
TestFuncResult test_cpath_dirname(void);
|
||||
TestFuncResult test_cpath_dirup(void);
|
||||
|
||||
#endif // !TEST_CPATH_H
|
||||
62
tests/shell_commander/test_shell_commander.c
Normal file
62
tests/shell_commander/test_shell_commander.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "test_shell_commander.h"
|
||||
#include "wapp.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
TestFuncResult test_commander_cmd_success(void) {
|
||||
Str8List cmd = wapp_dbl_list(Str8, Str8List);
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr("echo"));
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr("hello world"));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd);
|
||||
b8 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) {
|
||||
Str8List cmd = wapp_dbl_list(Str8, Str8List);
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr("grep"));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd);
|
||||
b8 failed = result.exited && result.exit_code != EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_NO_ERROR;
|
||||
|
||||
return wapp_tester_result(failed);
|
||||
}
|
||||
|
||||
TestFuncResult test_commander_cmd_out_buf_success(void) {
|
||||
Str8 buf = wapp_str8_buf(64);
|
||||
Str8 expected = wapp_str8_buf(64);
|
||||
char msg[] = "hello world";
|
||||
wapp_str8_copy_cstr_capped(&expected, msg);
|
||||
|
||||
Str8List cmd = wapp_dbl_list(Str8, Str8List);
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr("echo"));
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr(msg));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd);
|
||||
b8 succeeded = result.exited && result.exit_code == EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_NO_ERROR && wapp_str8_equal_to_count(&buf, &expected, strlen(msg));
|
||||
|
||||
return wapp_tester_result(succeeded);
|
||||
}
|
||||
|
||||
TestFuncResult test_commander_cmd_out_buf_failure(void) {
|
||||
Str8 buf = wapp_str8_buf(4);
|
||||
Str8 expected = wapp_str8_buf(64);
|
||||
char msg[] = "hello world";
|
||||
wapp_str8_copy_cstr_capped(&expected, msg);
|
||||
|
||||
Str8List cmd = wapp_dbl_list(Str8, Str8List);
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr("echo"));
|
||||
wapp_dbl_list_push_back(Str8, &cmd, &wapp_str8_node_from_cstr(msg));
|
||||
|
||||
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd);
|
||||
b8 failed = !result.exited && result.exit_code != EXIT_SUCCESS &&
|
||||
result.error == SHELL_ERR_OUT_BUF_FULL && !wapp_str8_equal(&buf, &expected);
|
||||
|
||||
return wapp_tester_result(failed);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user