3 Commits

Author SHA1 Message Date
Abdelrahman Said
1108ed686e Switch to using snprintf instead of sprintf 2024-10-07 08:01:33 +01:00
36e88ba84d Remove old strings implementation 2024-10-06 22:41:43 +01:00
0617ca2316 Update compile script 2024-10-06 22:06:57 +01:00
126 changed files with 1617 additions and 8737 deletions

View File

@@ -1,2 +0,0 @@
CompileFlags:
Add: -ferror-limit=0

View File

@@ -1,81 +0,0 @@
name: Release
on:
push:
branches:
- main # or your default branch
jobs:
release:
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch full history
tags: true # fetch all tags
- name: Check/Create Tag
id: tag
run: |
VERSION=$(cat VERSION | tr -d '[:space:]') # read version and trim whitespace
echo "Version: $VERSION"
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "Tag v$VERSION already exists. Skipping release."
exit 0
fi
# Tag does not exist → create it
echo "Creating tag v$VERSION"
git tag "v$VERSION"
git push origin "v$VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build Artifacts
if: steps.tag.outputs.version
run: |
chmod +x ./package
./package
ls -l dist/
- name: Create Release
if: steps.tag.outputs.version
id: create_release
run: |
VERSION="${{ steps.tag.outputs.version }}"
RESPONSE=$(curl -s -X POST \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/json" \
"https://git.thewizardapprentice.com/api/v1/repos/${{ gitea.repository }}/releases" \
-d '{
"tag_name": "v'"$VERSION"'",
"name": "wapp-v'"$VERSION"'",
"body": "Automated release for wapp-v'"$VERSION"'",
"draft": false,
"prerelease": false
}')
echo "$RESPONSE"
RELEASE_ID=$(echo $RESPONSE | jq -r '.id')
echo "release_id=$RELEASE_ID" >> $GITHUB_OUTPUT
- name: Upload Artifacts
if: steps.tag.outputs.version
run: |
RELEASE_ID="${{ steps.create_release.outputs.release_id }}"
for FILE in dist/*; do
FILENAME=$(basename "$FILE")
echo "Uploading $FILENAME"
curl -X POST \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
--data-binary @"$FILE" \
"https://git.thewizardapprentice.com/api/v1/repos/${{ gitea.repository }}/releases/$RELEASE_ID/assets?name=$FILENAME"
done
- name: Cleanup
if: steps.tag.outputs.version
run: rm -rf dist/*

6
.gitignore vendored
View File

@@ -1,14 +1,10 @@
.cache
.vscode
.venv
test
test.*
*.dSYM
.DS_Store
*.pdb
*.obj
compile_commands.json
libwapp-build
dist
*.vs
__pycache__
libwapp.so

201
LICENSE
View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2026] [Abdelrahman Said]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

180
Makefile
View File

@@ -1,180 +0,0 @@
.PHONY: help full base os prng testing uuid all clean builddir build-test run-test install build-lib
# 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_BASENAME := wapp
override OBJ_OUT := $(BUILD_DIR)/$(LIB_BASENAME).o
override LIB_STATIC_NAME := lib$(LIB_BASENAME).a
override LIB_OUT := $(BUILD_DIR)/$(LIB_STATIC_NAME)
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_BASENAME)
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 += -DWAPP_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)"
@rm -rf "$(INCLUDE_INSTALL)"
@rm -f "$(LIB_INSTALL)/$(LIB_STATIC_NAME)"
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)"

View File

@@ -1,5 +1,3 @@
# Wizard Apprentice Standard Library
**Wizard Apprentice Standard Library** (`wapp`) is a lightweight collection of reusable utilities for **C and C++** projects.
For more information about the library and how to use it, check the [wiki](https://git.thewizardapprentice.com/abdelrahman/wizapp-stdlib/wiki).
A collection of useful C/C++ utilities for my projects

View File

@@ -1 +0,0 @@
1.0.0

57
build
View File

@@ -1,58 +1,3 @@
#!/bin/bash
# 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
bear -- ./compile $@

View File

@@ -1,74 +1,58 @@
Param(
[switch]$Release
[switch]$Release
)
$Compiler = "cl.exe"
$Linker = "lib.exe"
$GeneralFlags = "/Wall /WX /wd4996 /wd4464 /wd5105 /EHs"
$CStd = "/std:c11"
$CppStd = "/std:c++14"
$LibraryFlags = "/c"
$GeneralFlags = "/Wall /WX /wd4996"
$LibraryFlags = "/LD"
$Kernel = (Get-ChildItem Env:OS).Value
$Machine = (Get-ChildItem Env:PROCESSOR_ARCHITECTURE).Value
$Platform = "${Kernel}_${Machine}"
$IncludeDirs = "/I src"
$SrcFiles = "src/wapp.c"
$IncludeDirs = Get-ChildItem -Path src -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
$SrcFiles = Get-ChildItem -Path src -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
$TestIncludeDirs = Get-ChildItem -Path tests -Recurse -Directory -ErrorAction SilentlyContinue -Force | %{$("/I " + '"' + $_.FullName + '"')}
$TestCSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
$TestCppSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.cc -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
$TestSrcFiles = Get-ChildItem -Path tests -Recurse -Filter *.c -ErrorAction SilentlyContinue -Force | %{$('"' + $_.FullName + '"')}
If ($Release -eq $True) {
$GeneralFlags += " /O2 /Og"
$BuildType = "Release"
$GeneralFlags += " /O2 /Og"
$BuildType = "release"
} Else {
$GeneralFlags += " /Zi /Od /fsanitize=address"
$BuildType = "Debug"
$GeneralFlags += " /Zi /Od /fsanitize=address"
$BuildType = "debug"
}
$BuildDir = "./libwapp-build/${Platform}-${BuildType}"
$BuildDir = "./libwapp-build/windows-$BuildType"
$ObjDir = "$BuildDir/objects"
$OutDir = "$BuildDir/output"
$TestsDir = "$BuildDir/tests"
$LibOutput = "$OutDir/libwapp.lib"
$OutBasename = "libwapp"
$Objects = "/Fo:$ObjDir/"
$LibOutputFlags = "/OUT:$LibOutput"
$Outputs = "/Fd:$OutDir/$OutBasename /Fe:$OutDir/$OutBasename"
$TestCOutputBasename = "wapptest"
$TestCOutputFlags = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestCOutputBasename"
$TestCppOutputBasename = "wapptestcc"
$TestCppOutputFlags = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestCppOutputBasename"
$TestOutBasename = "wapptest"
$TestOutputs = "/Fo:$TestsDir/ /Fe:$TestsDir/$TestOutBasename"
If (Test-Path $BuildDir) {
Remove-Item $BuildDir -Recurse -Force
Remove-Item $BuildDir -Recurse -Force
}
mkdir -p $ObjDir > $null
mkdir -p $OutDir > $null
mkdir -p $TestsDir > $null
# Build and run C tests
Invoke-Expression "$Compiler $GeneralFlags $CStd $IncludeDirs $TestIncludeDirs $SrcFiles $TestCSrcFiles $TestCOutputFlags" -ErrorAction Stop
Invoke-Expression "$TestsDir/$TestCOutputBasename.exe"
# Build and run tests
Invoke-Expression "$Compiler $GeneralFlags $IncludeDirs $TestIncludeDirs $SrcFiles $TestSrcFiles $TestOutputs" -ErrorAction Stop
Invoke-Expression "$TestsDir/$TestOutBasename.exe"
$Status = $LASTEXITCODE
Remove-Item $TestsDir -Recurse -Force
If ($Status -ne 0) {
Remove-Item $TestsDir -Recurse -Force
Write-Error "Tests failed"
Exit 1
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
Invoke-Expression "$Compiler $GeneralFlags $LibraryFlags $IncludeDirs $SrcFiles $Objects $Outputs"

61
compile Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
BUILD_TYPE="debug"
while [[ $# > 0 ]];do
case $1 in
--release)
BUILD_TYPE="release"
shift
;;
*|-*|--*)
echo "Unknown option $1"
exit 1
;;
esac
done
CC=clang
CFLAGS="-Wall -Werror -pedantic"
LIBFLAGS="-fPIC -shared"
INCLUDE="$(find src -type d | xargs -I{} echo -n "-I{} ")"
SRC="$(find src -type f -name "*.c" | xargs -I{} echo -n "{} ")"
TEST_INCLUDE="$(find tests -type d | xargs -I{} echo -n "-I{} ")"
TEST_SRC="$(find tests -type f -name "*.c" | xargs -I{} echo -n "{} ")"
BUILD_DIR="libwapp-build/posix-$BUILD_TYPE"
if [[ -d $BUILD_DIR ]]; then
rm -rf $BUILD_DIR
fi
mkdir -p $BUILD_DIR
if [[ $BUILD_TYPE == "release" ]]; then
CFLAGS+=" -O3"
else
CFLAGS+=" -g -fsanitize=address -fsanitize=undefined"
fi
OUT="$BUILD_DIR/libwapp.so"
TEST_OUT="$BUILD_DIR/wapptest"
# Compile tests
if [[ $(echo $TEST_SRC | xargs) != "" ]]; then
(set -x ; $CC $CFLAGS $INCLUDE $TEST_INCLUDE $SRC $TEST_SRC -o $TEST_OUT)
fi
# Run tests and exit on failure
if [[ -f $TEST_OUT ]]; then
$TEST_OUT
STATUS="$?"
rm $TEST_OUT
if [[ $STATUS != "0" ]]; then
exit 1
fi
fi
# Compile library
(set -x ; $CC $CFLAGS $LIBFLAGS $INCLUDE $SRC -o $OUT)

11
package
View File

@@ -1,11 +0,0 @@
#!/bin/bash
cp -r src wapp
mkdir -p dist
ARCHIVE_NAME="wapp-v$(cat VERSION)"
tar -czvf dist/$ARCHIVE_NAME.tar.gz wapp
zip -r dist/$ARCHIVE_NAME.zip wapp
rm -rf wapp

View File

@@ -1,21 +0,0 @@
#!/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

View File

@@ -1,266 +0,0 @@
// 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 _array_header(ARRAY) (ArrayHeader *)(wapp_pointer_offset(ARRAY, (i64)sizeof(ArrayHeader) * -1))
wapp_persist inline void _array_validate(const GenericArray array, u64 item_size);
u64 _array_count(GenericArray array) {
wapp_debug_assert(array != NULL, "`array` should not be NULL");
ArrayHeader *header = _array_header(array);
wapp_runtime_assert(WAPP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
return header->count;
}
u64 _array_capacity(GenericArray array) {
wapp_debug_assert(array != NULL, "`array` should not be NULL");
ArrayHeader *header = _array_header(array);
wapp_runtime_assert(WAPP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
return header->capacity;
}
u64 _array_item_size(GenericArray array) {
wapp_debug_assert(array != NULL, "`array` should not be NULL");
ArrayHeader *header = _array_header(array);
wapp_runtime_assert(WAPP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
return header->item_size;
}
void _array_set_count(GenericArray array, u64 count) {
wapp_debug_assert(array != NULL, "`array` should not be NULL");
ArrayHeader *header = _array_header(array);
wapp_runtime_assert(WAPP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
header->count = count;
}
void *_array_get(GenericArray array, u64 index, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size);
ArrayHeader *header = _array_header(array);
wapp_runtime_assert(index < header->count, "`index` is out of bounds");
return wapp_pointer_offset(array, header->item_size * index);
}
void _array_set(GenericArray array, u64 index, void *value, u64 item_size) {
void *item = _array_get(array, index, item_size);
ArrayHeader *header = _array_header(array);
memcpy(item, value, header->item_size);
}
void _array_append_capped(GenericArray array, void *value, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size);
ArrayHeader *header = _array_header(array);
if (header->count >= header->capacity) { return; }
u64 index = (header->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");
_array_validate(dst, item_size);
_array_validate(src, item_size);
ArrayHeader *src_header = _array_header(src);
ArrayHeader *dst_header = _array_header(dst);
u64 remaining_capacity = dst_header->capacity - dst_header->count;
u64 copy_count = src_header->count < remaining_capacity ? src_header->count : remaining_capacity;
void *dst_ptr = wapp_pointer_offset(dst, dst_header->count * dst_header->item_size);
memcpy(dst_ptr, src, copy_count * src_header->item_size);
dst_header->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");
_array_validate(dst, item_size);
_array_validate(src, item_size);
_array_clear(dst, item_size);
ArrayHeader *src_header = _array_header(src);
ArrayHeader *dst_header = _array_header(dst);
u64 copy_count = src_header->count < dst_header->capacity ? src_header->count : dst_header->capacity;
memcpy((void *)dst, (void *)src, copy_count * src_header->item_size);
dst_header->count = copy_count;
}
GenericArray _array_append_alloc(const Allocator *allocator, GenericArray array, void *value,
ArrayInitFlags flags, u64 item_size) {
wapp_runtime_assert(allocator != NULL && array != NULL, "`allocator` and `array` should not be NULL");
_array_validate(array, item_size);
GenericArray output = array;
ArrayHeader *header = _array_header(array);
if (header->count >= header->capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(header->capacity * 2);
output = (GenericArray )_array_alloc_capacity(allocator, new_capacity, flags,
header->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);
if ((flags & ARRAY_INIT_FILLED) == ARRAY_INIT_FILLED) {
_array_set_count(output, _array_capacity(output));
}
RETURN_ARRAY_APPEND_ALLOC:
return output;
}
GenericArray _array_extend_alloc(const Allocator *allocator, GenericArray dst, const GenericArray src,
ArrayInitFlags flags, u64 item_size) {
wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
_array_validate(dst, item_size);
_array_validate(src, item_size);
GenericArray output = dst;
ArrayHeader *src_header = _array_header(src);
ArrayHeader *dst_header = _array_header(dst);
u64 remaining_capacity = dst_header->capacity - dst_header->count;
if (src_header->count >= remaining_capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst_header->capacity * 2);
output = (GenericArray )_array_alloc_capacity(allocator, new_capacity,
flags, dst_header->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);
if ((flags & ARRAY_INIT_FILLED) == ARRAY_INIT_FILLED) {
_array_set_count(output, _array_capacity(output));
}
RETURN_ARRAY_EXTEND_ALLOC:
return output;
}
GenericArray _array_copy_alloc(const Allocator *allocator, GenericArray dst, const GenericArray src,
ArrayInitFlags flags, u64 item_size) {
wapp_runtime_assert(allocator != NULL && dst != NULL && src != NULL, "`allocator`, `dst` and `src` should not be NULL");
_array_validate(dst, item_size);
_array_validate(src, item_size);
GenericArray output = dst;
ArrayHeader *src_header = _array_header(src);
ArrayHeader *dst_header = _array_header(dst);
if (src_header->count >= dst_header->capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(dst_header->capacity * 2);
output = (GenericArray )_array_alloc_capacity(allocator, new_capacity,
flags, src_header->item_size);
if (!output) {
output = dst;
goto RETURN_ARRAY_COPY_ALLOC;
}
}
_array_copy_capped(output, src, item_size);
if ((flags & ARRAY_INIT_FILLED) == ARRAY_INIT_FILLED) {
_array_set_count(output, _array_capacity(output));
}
RETURN_ARRAY_COPY_ALLOC:
return output;
}
void *_array_pop(GenericArray array, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size);
ArrayHeader *header = _array_header(array);
if (header->count == 0) { return NULL; }
u64 index = header->count - 1;
void *out = _array_get(array, index, item_size);
--(header->count);
return out;
}
void _array_clear(GenericArray array, u64 item_size) {
wapp_runtime_assert(array != NULL, "`array` should not be NULL");
_array_validate(array, item_size);
ArrayHeader *header = _array_header(array);
header->count = 0;
}
u64 _array_calc_alloc_size(u64 capacity, u64 item_size) {
return sizeof(ArrayHeader) + item_size * capacity;
}
GenericArray _array_alloc_capacity(const Allocator *allocator, u64 capacity, ArrayInitFlags flags,
u64 item_size) {
wapp_runtime_assert(allocator != NULL, "`allocator` should not be NULL");
GenericArray output = NULL;
u64 allocation_size = _array_calc_alloc_size(capacity, item_size);
void *buffer = wapp_mem_allocator_alloc(allocator, allocation_size);
if (!buffer) {
goto RETURN_ARRAY_ALLOC;
}
output = _array_from_preallocated_buffer(buffer, allocation_size, flags, item_size);
RETURN_ARRAY_ALLOC:
return output;
}
GenericArray _array_from_preallocated_buffer(void *buffer, u64 buffer_size, ArrayInitFlags flags,
u64 item_size) {
wapp_runtime_assert(buffer != NULL, "`buffer` should not be NULL");
i64 data_buffer_size = (i64)buffer_size - (i64)(sizeof(ArrayHeader));
if (data_buffer_size <= 0) {
return NULL;
}
u64 item_capacity = (u64)data_buffer_size / item_size;
ArrayHeader *header = (ArrayHeader *)buffer;
GenericArray output = (u8 *)(header + 1);
header->magic = WAPP_ARRAY_MAGIC;
header->count = flags & ARRAY_INIT_FILLED ? item_capacity : 0;
header->capacity = item_capacity;
header->item_size = item_size;
return output;
}
wapp_persist inline void _array_validate(const GenericArray array, u64 item_size) {
ArrayHeader *header = _array_header(array);
wapp_runtime_assert(WAPP_ARRAY_MAGIC == header->magic, "`array` is not a valid wapp array");
wapp_runtime_assert(item_size == header->item_size, "Invalid item type provided");
}

View File

@@ -1,216 +0,0 @@
// 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)
typedef struct Str8 Str8;
// NOTE (Abdelrahman): Typedefs to distinguish arrays from regular pointers
typedef void *GenericArray;
typedef void **VoidPtrArray;
typedef c8 *C8Array;
typedef c16 *C16Array;
typedef c32 *C32Array;
typedef u8 *U8Array;
typedef u16 *U16Array;
typedef u32 *U32Array;
typedef u64 *U64Array;
typedef b8 *B8Array;
typedef i8 *I8Array;
typedef i16 *I16Array;
typedef i32 *I32Array;
typedef i64 *I64Array;
typedef f32 *F32Array;
typedef f64 *F64Array;
typedef f128 *F128Array;
typedef uptr *UptrArray;
typedef iptr *IptrArray;
typedef Str8 *Str8Array;
typedef enum {
ARRAY_INIT_NONE = 0,
ARRAY_INIT_FILLED = 1 << 1,
} ArrayInitFlags;
#ifdef WAPP_PLATFORM_CPP
#define wapp_array(TYPE, ...) ([&]() { \
u64 capacity = _calc_array_capacity(TYPE, __VA_ARGS__); \
\
TYPE items[_calc_array_capacity(TYPE, __VA_ARGS__)] = {__VA_ARGS__}; \
\
wapp_persist u8 array[ \
sizeof(ArrayHeader) + _calc_array_capacity(TYPE, __VA_ARGS__) * sizeof(TYPE) \
] = {0}; \
ArrayHeader *header = (ArrayHeader *)array; \
header->magic = WAPP_ARRAY_MAGIC; \
header->count = _calc_array_count(TYPE, __VA_ARGS__); \
header->capacity = _calc_array_capacity(TYPE, __VA_ARGS__); \
header->item_size = sizeof(TYPE); \
\
u8 *buf = (u8 *)(header + 1); \
memcpy(buf, items, capacity * sizeof(TYPE)); \
return (TYPE *)buf; \
}())
#define wapp_array_with_capacity(TYPE, CAPACITY, FLAGS) ([&]() { \
wapp_persist u8 array[ \
sizeof(ArrayHeader) + CAPACITY * sizeof(TYPE) \
] = {0}; \
ArrayHeader *header = (ArrayHeader *)array; \
header->magic = WAPP_ARRAY_MAGIC; \
header->count = (FLAGS & ARRAY_INIT_FILLED) ? CAPACITY : 0; \
header->capacity = CAPACITY; \
header->item_size = sizeof(TYPE); \
\
return (TYPE *)(header + 1); \
}())
#define wapp_array_pop(TYPE, ARRAY) ([&]() { \
if (ARRAY == NULL || _array_count((GenericArray)ARRAY) == 0) { \
TYPE result{}; \
return result; \
} \
\
return *((TYPE *)_array_pop((GenericArray)ARRAY, sizeof(TYPE))); \
}())
#else
#define _stack_array(TYPE, SIZE) struct {ArrayHeader header; \
TYPE items[SIZE]; \
wapp_misc_utils_reserve_padding(sizeof(ArrayHeader) + \
sizeof(TYPE) * SIZE);}
#define wapp_array(TYPE, ...) \
((TYPE *)( \
(_stack_array(TYPE, _calc_array_capacity(TYPE, __VA_ARGS__))){ \
.header = { \
.magic = WAPP_ARRAY_MAGIC, \
.count = _calc_array_count(TYPE, __VA_ARGS__), \
.capacity = _calc_array_capacity(TYPE, __VA_ARGS__), \
.item_size = sizeof(TYPE), \
}, \
.items = {__VA_ARGS__}, \
}.items \
))
#define wapp_array_with_capacity(TYPE, CAPACITY, FLAGS) \
((TYPE *)( \
(_stack_array(TYPE, CAPACITY)){ \
.header = { \
.magic = WAPP_ARRAY_MAGIC, \
.count = (FLAGS & ARRAY_INIT_FILLED) ? CAPACITY : 0, \
.capacity = CAPACITY, \
.item_size = sizeof(TYPE), \
}, \
.items = {0}, \
}.items \
))
#define wapp_array_pop(TYPE, ARRAY) \
(ARRAY == NULL || _array_count((GenericArray)ARRAY) == 0 ? \
(TYPE){0} : \
*((TYPE *)_array_pop((GenericArray)ARRAY, sizeof(TYPE))) \
)
#endif // !WAPP_PLATFORM_CPP
#define wapp_array_count(ARRAY) \
(_array_count((GenericArray)ARRAY))
#define wapp_array_capacity(ARRAY) \
(_array_capacity((GenericArray)ARRAY))
#define wapp_array_item_size(ARRAY) \
(_array_item_size((GenericArray)ARRAY))
#define wapp_array_set_count(ARRAY, COUNT) \
(_array_set_count((GenericArray)ARRAY, COUNT))
#define wapp_array_get(TYPE, ARRAY, INDEX) \
((TYPE *)_array_get((GenericArray)ARRAY, \
INDEX, \
sizeof(TYPE)))
#define wapp_array_set(TYPE, ARRAY, INDEX, VALUE_PTR) \
(_array_set((GenericArray)ARRAY, \
INDEX, \
(u8 *)VALUE_PTR, \
sizeof(TYPE)))
#define wapp_array_append_capped(TYPE, ARRAY, VALUE_PTR) \
(_array_append_capped((GenericArray)ARRAY, \
(u8 *)VALUE_PTR, \
sizeof(TYPE)))
#define wapp_array_extend_capped(TYPE, DST_ARRAY, SRC_ARRAY) \
(_array_extend_capped((GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \
sizeof(TYPE)))
#define wapp_array_copy_capped(TYPE, DST_ARRAY, SRC_ARRAY) \
(_array_copy_capped((GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \
sizeof(TYPE)))
#define wapp_array_append_alloc(TYPE, ALLOCATOR_PTR, ARRAY, VALUE_PTR, FLAGS) \
((TYPE *)_array_append_alloc(ALLOCATOR_PTR, \
(GenericArray)ARRAY, \
(u8 *)VALUE_PTR, \
FLAGS, \
sizeof(TYPE)))
#define wapp_array_extend_alloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \
((TYPE *)_array_extend_alloc(ALLOCATOR_PTR, \
(GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \
FLAGS, \
sizeof(TYPE)))
#define wapp_array_copy_alloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY, FLAGS) \
((TYPE *)_array_copy_alloc(ALLOCATOR_PTR, \
(GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \
FLAGS, \
sizeof(TYPE)))
#define wapp_array_clear(TYPE, ARRAY) \
(_array_clear((GenericArray)ARRAY, \
sizeof(TYPE)))
#define wapp_array_calc_alloc_size(TYPE, CAPACITY) _array_calc_alloc_size(CAPACITY, sizeof(TYPE))
#define wapp_array_alloc_capacity(TYPE, ALLOCATOR_PTR, CAPACITY, FLAGS) \
((TYPE *)_array_alloc_capacity(ALLOCATOR_PTR, CAPACITY, FLAGS, sizeof(TYPE)))
#define wapp_array_from_preallcated_buffer(TYPE, BUFFER, BUFFER_SIZE) \
((TYPE *)_array_from_preallcated_buffer(BUFFER, BUFFER_SIZE, sizeof(TYPE)))
typedef struct header ArrayHeader;
struct header {
u64 magic;
u64 count;
u64 capacity;
u64 item_size;
};
u64 _array_count(GenericArray array);
u64 _array_capacity(GenericArray array);
u64 _array_item_size(GenericArray array);
void _array_set_count(GenericArray array, u64 count);
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,
ArrayInitFlags flags, u64 item_size);
GenericArray _array_extend_alloc(const Allocator *allocator, GenericArray dst, const GenericArray src,
ArrayInitFlags flags, u64 item_size);
GenericArray _array_copy_alloc(const Allocator *allocator, GenericArray dst, const GenericArray src,
ArrayInitFlags flags, u64 item_size);
void *_array_pop(GenericArray array, u64 item_size);
void _array_clear(GenericArray array, u64 item_size);
u64 _array_calc_alloc_size(u64 capacity, u64 item_size);
GenericArray _array_alloc_capacity(const Allocator *allocator, u64 capacity, ArrayInitFlags flags,
u64 item_size);
GenericArray _array_from_preallocated_buffer(void *buffer, u64 buffer_size, ArrayInitFlags flags,
u64 item_size);
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !ARRAY_H

View File

@@ -1,259 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#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 inline void _dbl_list_validate(const GenericList *list, u64 item_size);
wapp_intern inline void _dbl_list_node_validate(const GenericList *list, 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, void *item, 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->item = item;
node->header.magic = WAPP_DBL_NODE_MAGIC;
node->header.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->header.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(list, 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->header.prev = node_list.last;
}
list->first = node_list.first;
node_list.last->header.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(list, 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->header.next = node_list.first;
}
list->last = node_list.last;
node_list.first->header.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(list, 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->header.prev;
dst_node->header.prev = node_list.last;
prev->header.next = node_list.first;
node_list.first->header.prev = prev;
node_list.last->header.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_LIST_POP_FRONT;
}
output = list->first;
if (list->node_count == 1) {
*list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size};
goto RETURN_LIST_POP_FRONT;
}
--(list->node_count);
list->first = output->header.next;
output->header.prev = output->header.next = NULL;
RETURN_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_LIST_POP_BACK;
}
output = list->last;
if (list->node_count == 1) {
*list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size};
goto RETURN_LIST_POP_BACK;
}
--(list->node_count);
list->last = output->header.prev;
output->header.prev = output->header.next = NULL;
RETURN_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_LIST_REMOVE;
} else if (index == list->node_count) {
output = _dbl_list_pop_back(list, item_size);
goto RETURN_LIST_REMOVE;
}
output = _dbl_list_get(list, index, item_size);
if (!output) {
goto RETURN_LIST_REMOVE;
}
output->header.prev->header.next = output->header.next;
output->header.next->header.prev = output->header.prev;
--(list->node_count);
output->header.prev = output->header.next = NULL;
RETURN_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->header.prev != NULL) {
output.first = output.first->header.prev;
++(output.node_count);
}
while (output.last->header.next != NULL) {
output.last = output.last->header.next;
++(output.node_count);
}
return output;
}
wapp_intern inline 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 inline void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size) {
wapp_runtime_assert(node->header.magic == WAPP_DBL_NODE_MAGIC, "`node` isn't a valid wapp node type");
wapp_runtime_assert(list->item_size == node->header.item_size, "Mismatched `list` and `node` types");
wapp_runtime_assert(node->header.item_size == item_size, "Invalid item provided");
}

View File

@@ -1,184 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#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
typedef struct GenericNode GenericNode;
typedef struct {
u64 magic;
u64 item_size;
GenericNode *prev;
GenericNode *next;
} NodeHeader;
struct GenericNode {
NodeHeader header;
void *item;
};
typedef struct {
u64 magic;
u64 node_count;
u64 item_size;
GenericNode *first;
GenericNode *last;
} GenericList;
// NOTE (Abdelrahman): GenericList typedefs for readability
typedef GenericList VoidPtrList;
typedef GenericList C8List;
typedef GenericList C16List;
typedef GenericList C32List;
typedef GenericList U8List;
typedef GenericList U16List;
typedef GenericList U32List;
typedef GenericList U64List;
typedef GenericList B8List;
typedef GenericList I8List;
typedef GenericList I16List;
typedef GenericList I32List;
typedef GenericList I64List;
typedef GenericList F32List;
typedef GenericList F64List;
typedef GenericList F128List;
typedef GenericList UptrList;
typedef GenericList IptrList;
typedef GenericList Str8List;
// NOTE (Abdelrahman): GenericNode typedefs for readability
typedef GenericNode VoidPtrNode;
typedef GenericNode C8Node;
typedef GenericNode C16Node;
typedef GenericNode C32Node;
typedef GenericNode U8Node;
typedef GenericNode U16Node;
typedef GenericNode U32Node;
typedef GenericNode U64Node;
typedef GenericNode B8Node;
typedef GenericNode I8Node;
typedef GenericNode I16Node;
typedef GenericNode I32Node;
typedef GenericNode I64Node;
typedef GenericNode F32Node;
typedef GenericNode F64Node;
typedef GenericNode F128Node;
typedef GenericNode UptrNode;
typedef GenericNode IptrNode;
typedef GenericNode Str8Node;
#ifdef WAPP_PLATFORM_CPP
#define wapp_dbl_list(TYPE) \
GenericList{WAPP_DBL_LIST_MAGIC, 0, sizeof(TYPE), nullptr, nullptr}
#define _dbl_list_node(TYPE, ITEM_PTR) ([&]() { \
wapp_persist GenericNode node = { \
NodeHeader{WAPP_DBL_NODE_MAGIC, sizeof(TYPE), nullptr, nullptr}, \
ITEM_PTR, \
}; \
\
return &node; \
}())
#else
#define wapp_dbl_list(TYPE) ( \
(GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = sizeof(TYPE)} \
)
#define _dbl_list_node(TYPE, ITEM_PTR) ( \
&((GenericNode){.header = {.magic = WAPP_DBL_NODE_MAGIC, .item_size = sizeof(TYPE)}, \
.item = ITEM_PTR}) \
)
#endif // !WAPP_PLATFORM_CPP
#define wapp_dbl_list_alloc(TYPE, ALLOCATOR) \
(_dbl_list_alloc(ALLOCATOR, sizeof(TYPE)))
#define wapp_dbl_list_get(TYPE, LIST_PTR, ITEM_INDEX) \
((TYPE *)(_dbl_list_get(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item))
#define wapp_dbl_list_get_node(TYPE, LIST_PTR, ITEM_INDEX) \
(_dbl_list_get(LIST_PTR, ITEM_INDEX, sizeof(TYPE)))
#define wapp_dbl_list_get_node_item(TYPE, NODE_PTR) \
((TYPE *)( \
(NODE_PTR == NULL) ? \
NULL : \
(NODE_PTR)->item \
))
#define wapp_dbl_list_push_front(TYPE, LIST_PTR, ITEM_PTR) \
(_dbl_list_push_front(LIST_PTR, _dbl_list_node(TYPE, ITEM_PTR), sizeof(TYPE)))
#define wapp_dbl_list_push_back(TYPE, LIST_PTR, ITEM_PTR) \
(_dbl_list_push_back(LIST_PTR, _dbl_list_node(TYPE, ITEM_PTR), sizeof(TYPE)))
#define wapp_dbl_list_insert(TYPE, LIST_PTR, ITEM_PTR, ITEM_INDEX) \
(_dbl_list_insert(LIST_PTR, _dbl_list_node(TYPE, ITEM_PTR), \
ITEM_INDEX, sizeof(TYPE)))
#define wapp_dbl_list_push_front_alloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \
(_dbl_list_push_front(LIST_PTR, _dbl_list_node_alloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
sizeof(TYPE)))
#define wapp_dbl_list_push_back_alloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR) \
(_dbl_list_push_back(LIST_PTR, _dbl_list_node_alloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
sizeof(TYPE)))
#define wapp_dbl_list_insert_alloc(TYPE, ALLOCATOR, LIST_PTR, ITEM_PTR, ITEM_INDEX) \
(_dbl_list_insert(LIST_PTR, _dbl_list_node_alloc(ALLOCATOR, ITEM_PTR, sizeof(TYPE)), \
ITEM_INDEX, sizeof(TYPE)))
#define wapp_dbl_list_pop_front(TYPE, LIST_PTR) \
((TYPE *)( \
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
NULL : \
_dbl_list_pop_front(LIST_PTR, sizeof(TYPE))->item \
))
#define wapp_dbl_list_pop_back(TYPE, LIST_PTR) \
((TYPE *)( \
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
NULL : \
_dbl_list_pop_back(LIST_PTR, sizeof(TYPE))->item \
))
#define wapp_dbl_list_remove(TYPE, LIST_PTR, ITEM_INDEX) \
((TYPE *)( \
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \
NULL : \
_dbl_list_remove(LIST_PTR, ITEM_INDEX, sizeof(TYPE))->item \
))
#define wapp_dbl_list_pop_front_node(TYPE, LIST_PTR) \
( \
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
NULL : \
_dbl_list_pop_front(LIST_PTR, sizeof(TYPE)) \
)
#define wapp_dbl_list_pop_back_node(TYPE, LIST_PTR) \
( \
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0) ? \
NULL : \
_dbl_list_pop_back(LIST_PTR, sizeof(TYPE)) \
)
#define wapp_dbl_list_remove_node(TYPE, LIST_PTR, ITEM_INDEX) \
( \
(LIST_PTR == NULL || (LIST_PTR)->node_count == 0 || ITEM_INDEX >= (LIST_PTR)->node_count) ? \
NULL : \
_dbl_list_remove(LIST_PTR, ITEM_INDEX, sizeof(TYPE)) \
)
#define wapp_dbl_list_empty(TYPE, LIST_PTR) \
(_dbl_list_empty(LIST_PTR, sizeof(TYPE)))
GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size);
GenericNode *_dbl_list_node_alloc(const Allocator *allocator, void *item, 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);
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !DBL_LIST_H

View File

@@ -1,35 +0,0 @@
// 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);
}

View File

@@ -1,50 +0,0 @@
// 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

View File

@@ -1,25 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "mem_utils.h"
#include "../../../common/aliases/aliases.h"
#include "../../../common/assert/assert.h"
#include "../../../common/misc/misc_utils.h"
#include <stddef.h>
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
wapp_debug_assert(ptr != NULL, "`ptr` should not be NULL");
wapp_runtime_assert(wapp_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;
}

View File

@@ -1,19 +0,0 @@
// 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

View File

@@ -1,85 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "queue.h"
#include "../array/array.h"
#include "../../common/assert/assert.h"
#include "../../common/misc/misc_utils.h"
#include <string.h>
void _queue_push(GenericQueue *queue, void *item, u64 item_size) {
wapp_debug_assert(queue != NULL, "`queue` should not be NULL");
wapp_runtime_assert(item_size == wapp_array_item_size(queue->items), "Invalid type");
u64 capacity = wapp_array_capacity(queue->items);
if (queue->count >= capacity) { return; }
u64 index = (queue->back)++;
_array_set(queue->items, index, item, item_size);
++(queue->count);
if (queue->back >= capacity) {
queue->back = 0;
}
}
GenericQueue *_queue_push_alloc(const Allocator *allocator, GenericQueue *queue, void *item, u64 item_size) {
wapp_debug_assert(allocator != NULL && queue != NULL && item != NULL,
"`allocator`, `queue` and `item` should not be NULL");
wapp_runtime_assert(item_size == wapp_array_item_size(queue->items), "Invalid type");
GenericQueue *output = queue;
u64 capacity = wapp_array_capacity(queue->items);
if (queue->count >= capacity) {
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(capacity * 2);
u64 array_size = _array_calc_alloc_size(new_capacity, item_size);
u64 alloc_size = sizeof(GenericQueue) + array_size;
void *buffer = wapp_mem_allocator_alloc(allocator, alloc_size);
if (!buffer) {
goto RETURN_QUEUE_PUSH_ALLOC;
}
memset((void *)buffer, 0, alloc_size);
output = (GenericQueue *)buffer;
output->items = _array_from_preallocated_buffer((void *)(output + 1), array_size, ARRAY_INIT_FILLED, item_size);
// NOTE (Abdelrahman): When the queue is full, the front and back indices should
// always be the same
u64 front_count = capacity - queue->front;
u64 back_count = queue->back;
void *copy_boundary = (void *)((uptr)(queue->items) + (queue->front * item_size));
memcpy(output->items, copy_boundary, front_count * item_size);
if (back_count > 0) {
void *back_copy_dst = (void *)((uptr)(output->items) + (front_count * item_size));
memcpy(back_copy_dst, queue->items, back_count * item_size);
}
output->front = 0;
output->back = front_count + back_count;
output->count = queue->count;
}
_queue_push(output, item, item_size);
RETURN_QUEUE_PUSH_ALLOC:
return output;
}
void *_queue_pop(GenericQueue *queue, u64 item_size) {
wapp_debug_assert(queue != NULL, "`queue` should not be NULL");
wapp_runtime_assert(item_size == wapp_array_item_size(queue->items), "Invalid type");
if (queue->count == 0) { return NULL; }
u64 index = (queue->front)++;
--(queue->count);
u64 capacity = wapp_array_capacity(queue->items);
if (queue->front >= capacity) {
queue->front = 0;
}
return _array_get(queue->items, index, item_size);
}

View File

@@ -1,100 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef QUEUE_H
#define QUEUE_H
#include "../array/array.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
typedef struct {
GenericArray items;
u64 front;
u64 back;
u64 count;
} GenericQueue;
// NOTE (Abdelrahman): GenericQueue typedefs for readability
typedef GenericQueue VoidPtrQueue;
typedef GenericQueue C8Queue;
typedef GenericQueue C16Queue;
typedef GenericQueue C32Queue;
typedef GenericQueue U8Queue;
typedef GenericQueue U16Queue;
typedef GenericQueue U32Queue;
typedef GenericQueue U64Queue;
typedef GenericQueue B8Queue;
typedef GenericQueue I8Queue;
typedef GenericQueue I16Queue;
typedef GenericQueue I32Queue;
typedef GenericQueue I64Queue;
typedef GenericQueue F32Queue;
typedef GenericQueue F64Queue;
typedef GenericQueue F128Queue;
typedef GenericQueue UptrQueue;
typedef GenericQueue IptrQueue;
typedef GenericQueue Str8Queue;
#ifdef WAPP_PLATFORM_CPP
#define wapp_queue(TYPE, CAPACITY) ([&]() { \
wapp_persist GenericArray arr = wapp_array_with_capacity(TYPE, CAPACITY, ARRAY_INIT_FILLED); \
wapp_persist GenericQueue queue = { \
arr, \
0, \
0, \
0, \
}; \
\
return queue; \
}())
#define wapp_queue_alloc(TYPE, ALLOCATOR_PTR, CAPACITY) ([&]() { \
wapp_persist GenericQueue queue = { \
wapp_array_alloc_capacity(TYPE, ALLOCATOR_PTR, CAPACITY, ARRAY_INIT_FILLED), \
0, \
0, \
0, \
}; \
\
return queue; \
}())
#else
#define wapp_queue(TYPE, CAPACITY) ((GenericQueue){ \
.items = wapp_array_with_capacity(TYPE, CAPACITY, ARRAY_INIT_FILLED), \
.front = 0, \
.back = 0, \
.count = 0, \
})
#define wapp_queue_alloc(TYPE, ALLOCATOR_PTR, CAPACITY) ((GenericQueue){ \
.items = wapp_array_alloc_capacity(TYPE, ALLOCATOR_PTR, CAPACITY, ARRAY_INIT_FILLED), \
.front = 0, \
.back = 0, \
.count = 0, \
})
#endif // !WAPP_PLATFORM_CPP
#define wapp_queue_capacity(QUEUE_PTR) (wapp_array_capacity((QUEUE_PTR)->items))
#define wapp_queue_item_size(QUEUE_PTR) (wapp_array_item_size((QUEUE_PTR)->items))
#define wapp_queue_push(TYPE, QUEUE_PTR, VALUE_PTR) ( \
_queue_push(QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \
)
#define wapp_queue_push_alloc(TYPE, ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR) ( \
_queue_push_alloc(ALLOCATOR_PTR, QUEUE_PTR, VALUE_PTR, sizeof(TYPE)) \
)
#define wapp_queue_pop(TYPE, QUEUE_PTR) ( \
(TYPE *)_queue_pop(QUEUE_PTR, sizeof(TYPE)) \
)
void _queue_push(GenericQueue *queue, void *item, u64 item_size);
GenericQueue *_queue_push_alloc(const Allocator *allocator, GenericQueue *queue, void *item, u64 item_size);
void *_queue_pop(GenericQueue *queue, u64 item_size);
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !QUEUE_H

View File

@@ -1,480 +0,0 @@
// 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 = wapp_array_count(src) * wapp_array_item_size(src);
wapp_debug_assert(dst->capacity >= size, "`dst` does not have enough capacity");
dst->size = size;
memcpy(dst->buf, src, 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, allocator);
if (delimiter->size > str->size) {
Str8 *full = wapp_str8_alloc_str8(allocator, str);
if (full) {
wapp_dbl_list_push_back_alloc(Str8, allocator, output, full);
}
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);
if (before_str) {
wapp_dbl_list_push_back_alloc(Str8, allocator, output, before_str);
}
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);
if (rest) {
wapp_dbl_list_push_back_alloc(Str8, allocator, output, rest);
}
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, allocator);
if (delimiter->size > str->size) {
Str8 *full = wapp_str8_alloc_str8(allocator, str);
if (full) {
wapp_dbl_list_push_back_alloc(Str8, allocator, output, full);
}
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);
if (after_str) {
wapp_dbl_list_push_front_alloc(Str8, allocator, output, after_str);
}
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);
if (rest) {
wapp_dbl_list_push_front_alloc(Str8, allocator, output, rest);
}
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
Str8 *node;
u64 node_index = 0;
b8 running = node_index < list->node_count;
while (running) {
node = wapp_dbl_list_get(Str8, list, node_index);
if (!node) {
break;
}
wapp_str8_concat_capped(output, node);
// 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
Str8 *node;
u64 node_index = 0;
u64 output = 0;
b8 running = node_index < list->node_count;
while (running) {
node = wapp_dbl_list_get(Str8, list, node_index);
if (!node) {
break;
}
output += node->size;
++node_index;
running = node_index < list->node_count;
}
return output;
}

View File

@@ -1,130 +0,0 @@
// 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
#endif // !WAPP_PLATFORM_CPP
#endif // !STR8_H

View File

@@ -1,14 +0,0 @@
// 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 "queue/queue.c"
#include "mem/allocator/mem_allocator.c"
#include "mem/utils/mem_utils.c"
#include "strings/str8/str8.c"
#endif // !WAPP_BASE_C

View File

@@ -1,14 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef WAPP_BASE_H
#define WAPP_BASE_H
#include "array/array.h"
#include "dbl_list/dbl_list.h"
#include "queue/queue.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

View File

@@ -1,67 +1,33 @@
// 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>
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#if WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C23_VERSION
typedef char8_t c8;
#else
typedef uint8_t c8;
#endif // !WAPP_PLATFORM_C23_VERSION
#define i8 int8_t
#define i16 int16_t
#define i32 int32_t
#define i64 int64_t
typedef char16_t c16;
typedef char32_t c32;
#else
typedef uint8_t c8;
typedef uint16_t c16;
typedef uint32_t c32;
#endif // !WAPP_PLATFORM_C
#define f32 float
#define f64 double
#define f128 long double
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#define uptr uintptr_t
#define iptr intptr_t
typedef uint8_t b8;
#define external extern
#define internal static
#define persistent static
#ifndef WAPP_PLATFORM_CPP
#ifndef false
#define false (b8)0
#endif // !false
#ifndef true
#define true (b8)1
#endif // !true
#endif // !WAPP_PLATFORM_CPP
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef float f32;
typedef double f64;
typedef long double f128;
typedef uintptr_t uptr;
typedef intptr_t iptr;
#define wapp_extern extern
#define wapp_intern static
#define wapp_persist static
#ifdef WAPP_PLATFORM_CPP
#define wapp_class_mem static
#ifdef __cplusplus
#define class_mem static
#define BEGIN_C_LINKAGE extern "C" {
#define END_C_LINKAGE }
#endif // WAPP_PLATFORM_CPP
#endif // __cplusplus
#endif // !ALIASES_H

View File

@@ -1,61 +0,0 @@
// 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

View File

@@ -1,63 +1,13 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef MISC_UTILS_H
#define MISC_UTILS_H
#include "../aliases/aliases.h"
#include "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 KiB(SIZE) (((u64)SIZE) << 10)
#define MiB(SIZE) (((u64)SIZE) << 20)
#define GiB(SIZE) (((u64)SIZE) << 30)
#define TiB(SIZE) (((u64)SIZE) << 40)
#define PiB(SIZE) (((u64)SIZE) << 50)
#define EiB(SIZE) (((u64)SIZE) << 60)
#define KB(SIZE) (((u64)SIZE) * 1000llu)
#define MB(SIZE) (KB(SIZE) * 1000llu)
#define GB(SIZE) (MB(SIZE) * 1000llu)
#define TB(SIZE) (GB(SIZE) * 1000llu)
#define PB(SIZE) (TB(SIZE) * 1000llu)
#define EB(SIZE) (PB(SIZE) * 1000llu)
#define wapp_misc_utils_reserve_padding(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 \
)
#define wapp_is_power_of_two(NUM) ((NUM & (NUM - 1)) == 0)
#define wapp_pointer_offset(PTR, OFFSET) ((void *)((uptr)(PTR) + (OFFSET)))
#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
#define wapp_misc_utils_padding_size(SIZE) u8 reserved_padding[sizeof(void *) - ((SIZE) % sizeof(void *))]
#endif // !MISC_UTILS_H

View File

@@ -1,114 +1,61 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef PLATFORM_H
#define PLATFORM_H
#if defined(__ANDROID__)
#define WAPP_PLATFORM_ANDROID
#define WAPP_PLATFORM_POSIX
#define WAPP_PLATFORM_ANDROID
#define WAPP_PLATFORM_POSIX
#elif defined(__FreeBSD__)
#define WAPP_PLATFORM_FREE_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#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
#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
#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
#define WAPP_PLATFORM_DRAGON_FLY
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__bsdi__)
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#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
#define WAPP_PLATFORM_LINUX
#define WAPP_PLATFORM_POSIX
#elif defined(__GNU__) || defined(__gnu_hurd__)
#define WAPP_PLATFORM_GNU
#define WAPP_PLATFORM_POSIX
#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
#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
#define WAPP_PLATFORM_WINDOWS64
#define WAPP_PLATFORM_WINDOWS
#elif defined(_WIN32)
#define WAPP_PLATFORM_WINDOWS32
#define WAPP_PLATFORM_WINDOWS
#define WAPP_PLATFORM_WINDOWS32
#define WAPP_PLATFORM_WINDOWS
#elif defined(__CYGWIN__)
#define WAPP_PLATFORM_CYGWIN
#define WAPP_PLATFORM_WINDOWS
#define WAPP_PLATFORM_CYGWIN
#define WAPP_PLATFORM_WINDOWS
#elif defined(__unix__) || defined(__unix)
#define WAPP_PLATFORM_UNIX
#define WAPP_PLATFORM_POSIX
#define WAPP_PLATFORM_UNIX
#define WAPP_PLATFORM_POSIX
#else
#error "Unrecognised platform"
#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

View File

@@ -1,11 +0,0 @@
// 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

View File

@@ -0,0 +1,49 @@
#include "mem_allocator.h"
#include <stdlib.h>
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator API definitions
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size) {
if (!allocator || !(allocator->alloc)) {
return NULL;
}
return allocator->alloc(size, allocator->obj);
}
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment) {
if (!allocator || !(allocator->alloc_aligned)) {
return NULL;
}
return allocator->alloc_aligned(size, alignment, allocator->obj);
}
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size) {
if (!allocator || !(allocator->realloc)) {
return NULL;
}
return allocator->realloc(ptr, old_size, new_size, allocator->obj);
}
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size,
u64 new_size, u64 alignment) {
if (!allocator || !(allocator->realloc_aligned)) {
return NULL;
}
return allocator->realloc_aligned(ptr, old_size, new_size, alignment, allocator->obj);
}
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr) {
if (!allocator || !(allocator->free)) {
return;
}
allocator->free(ptr, allocator->obj);
}

View File

@@ -0,0 +1,55 @@
#ifndef MEM_ALLOCATOR_H
#define MEM_ALLOCATOR_H
#include "aliases.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator function pointer types
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
typedef void *(MemAllocFunc)(u64 size, void *alloc_obj);
typedef void *(MemAllocAlignedFunc)(u64 size, u64 alignment, void *alloc_obj);
typedef void *(MemReallocFunc)(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
typedef void *(MemReallocAlignedFunc)(void *ptr, u64 old_size, u64 new_size, u64 alignment, void *alloc_obj);
typedef void(MemFreeFunc)(void **ptr, void *alloc_obj);
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator type
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
typedef struct allocator Allocator;
struct allocator {
void *obj;
MemAllocFunc *alloc;
MemAllocAlignedFunc *alloc_aligned;
MemReallocFunc *realloc;
MemReallocAlignedFunc *realloc_aligned;
MemFreeFunc *free;
};
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Allocator API declarations
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
void *wapp_mem_allocator_alloc(const Allocator *allocator, u64 size);
void *wapp_mem_allocator_alloc_aligned(const Allocator *allocator, u64 size, u64 alignment);
void *wapp_mem_allocator_realloc(const Allocator *allocator, void *ptr, u64 old_size, u64 new_size);
void *wapp_mem_allocator_realloc_aligned(const Allocator *allocator, void *ptr, u64 old_size,
u64 new_size, u64 alignment);
void wapp_mem_allocator_free(const Allocator *allocator, void **ptr);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_ALLOCATOR_H

View File

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

View File

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

View File

@@ -0,0 +1,71 @@
#include "mem_arena_allocator.h"
#include "mem_arena.h"
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Arena Allocator wrappers declarations
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
internal inline void *mem_arena_alloc(u64 size, void *alloc_obj);
internal inline void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
internal inline void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
internal inline void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
void *alloc_obj);
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Arena Allocator API definitions
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, bool zero_buffer) {
Allocator allocator = {0};
bool initialised = wapp_mem_arena_init_custom((Arena **)(&allocator.obj), base_capacity, flags, zero_buffer);
if (!initialised) {
return allocator;
}
allocator.alloc = mem_arena_alloc;
allocator.alloc_aligned = mem_arena_alloc_aligned;
allocator.realloc = mem_arena_realloc;
allocator.realloc_aligned = mem_arena_realloc_aligned;
return allocator;
}
void wapp_mem_arena_allocator_clear(Allocator *allocator) {
wapp_mem_arena_clear((Arena *)(allocator->obj));
}
void wapp_mem_arena_allocator_destroy(Allocator *allocator) {
wapp_mem_arena_destroy((Arena **)(&(allocator->obj)));
*allocator = (Allocator){0};
}
/***************************************************************************/ //
////////////////////////////////////////////////////////////////////////////////
////// Arena Allocator wrappers definitions
////////////////////////////////////////////////////////////////////////////////
/***************************************************************************/ //
internal inline void *mem_arena_alloc(u64 size, void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_alloc(arena, size);
}
internal inline void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_alloc_aligned(arena, size, alignment);
}
internal inline void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_realloc(arena, ptr, old_size, new_size);
}
internal inline void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_realloc_aligned(arena, ptr, old_size, new_size, alignment);
}

View File

@@ -0,0 +1,41 @@
#ifndef MEM_ARENA_ALLOCATOR_H
#define MEM_ARENA_ALLOCATOR_H
#include "aliases.h"
#include "mem_utils.h"
#include "mem_allocator.h"
#include <stdbool.h>
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
#define wapp_mem_arena_allocator_init(base_capacity) \
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE, false))
#define wapp_mem_arena_allocator_init_commit(base_capacity) \
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
#define wapp_mem_arena_allocator_init_zero(base_capacity) \
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
#define wapp_mem_arena_allocator_init_commit_and_zero(base_capacity) \
(wapp_mem_arena_allocator_init_custom(base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
/**
* Wraps an Arena in an Allocator object. It attempts to initialise the Arena
* and, if successful, defines the operations supported by it to be used by the
* Allocator.
*
* An Arena allocator only supports normal allocation and aligned allocation.
* Reallocation, aligned reallocation and freeing aren't implemented.
*
* The `wapp_mem_arena_allocator_init_custom` provides the most control over how
* the Arena is initialised. Wrapper macros are provided for easier use.
*/
Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, bool zero_buffer);
void wapp_mem_arena_allocator_clear(Allocator *allocator);
void wapp_mem_arena_allocator_destroy(Allocator *allocator);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_ARENA_ALLOCATOR_H

View File

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

View File

@@ -0,0 +1,16 @@
#ifndef MEM_LIBC_H
#define MEM_LIBC_H
#include "mem_allocator.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
Allocator wapp_mem_libc_allocator(void);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_LIBC_H

View File

@@ -1,192 +0,0 @@
// 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 <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 KiB(16) // Allocate minimum of 4 pages
typedef enum {
ARENA_STORAGE_TYPE_ALLOCATED,
ARENA_STORAGE_TYPE_BUFFER,
} ArenaStorageType;
struct Arena {
u8 *buf;
u8 *offset;
u8 *prev_offset;
u64 capacity;
ArenaStorageType type;
b8 committed;
wapp_misc_utils_reserve_padding(sizeof(u8 *) * 3 + sizeof(u64) + sizeof(ArenaStorageType) + sizeof(b8));
};
b8 wapp_mem_arena_init_buffer(Arena **arena, u8 *buffer, u64 buffer_size) {
if (!arena || *arena || buffer_size < sizeof(Arena)) {
return false;
}
*arena = (Arena *)buffer;
Arena *arena_ptr = *arena;
arena_ptr->buf = (u8 *)(arena_ptr + 1);
arena_ptr->offset = arena_ptr->buf;
arena_ptr->prev_offset = NULL;
arena_ptr->capacity = buffer_size - sizeof(Arena);
arena_ptr->type = ARENA_STORAGE_TYPE_BUFFER;
arena_ptr->committed = true;
return true;
}
b8 wapp_mem_arena_init_allocated_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, b8 zero_buffer) {
if (!arena || *arena || base_capacity == 0) {
return false;
}
u64 size = sizeof(Arena) + (base_capacity >= ARENA_MINIMUM_CAPACITY ? base_capacity : ARENA_MINIMUM_CAPACITY);
u64 alloc_size = wapp_misc_utils_u64_round_up_pow2(size);
u8 *allocated = (u8 *)wapp_os_mem_alloc(NULL, alloc_size, WAPP_MEM_ACCESS_READ_WRITE, flags,
zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED);
if (!allocated) {
return false;
}
b8 committed = (flags & WAPP_MEM_ALLOC_COMMIT) == WAPP_MEM_ALLOC_COMMIT;
#ifdef WAPP_PLATFORM_WINDOWS
if (!committed) {
wapp_os_mem_alloc(allocated, sizeof(Arena), WAPP_MEM_ACCESS_READ_WRITE, WAPP_MEM_ALLOC_COMMIT,
WAPP_MEM_INIT_INITIALISED);
}
#endif // ifdef WAPP_PLATFORM_WINDOWS
if (!wapp_mem_arena_init_buffer(arena, allocated, alloc_size)) {
wapp_mem_arena_destroy(arena);
return false;
}
Arena *arena_ptr = *arena;
arena_ptr->type = ARENA_STORAGE_TYPE_ALLOCATED;
arena_ptr->committed = committed;
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->type == ARENA_STORAGE_TYPE_ALLOCATED && !(arena->committed)) {
wapp_os_mem_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) {
wapp_debug_assert(arena != NULL, "`arena` should not be NULL");
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) {
wapp_debug_assert(arena != NULL, "`arena` should not be NULL");
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_temp_begin(Arena *arena) {
wapp_debug_assert(arena != NULL, "`arena` should not be NULL");
if (arena->prev_offset != NULL) {
return;
}
arena->prev_offset = arena->offset;
}
void wapp_mem_arena_temp_end(Arena *arena) {
wapp_debug_assert(arena != NULL, "`arena` should not be NULL");
if (arena->prev_offset == NULL) {
return;
}
arena->offset = arena->prev_offset;
arena->prev_offset = NULL;
}
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->type == ARENA_STORAGE_TYPE_ALLOCATED) {
wapp_os_mem_free(*arena, sizeof(Arena) + arena_ptr->capacity);
}
*arena = NULL;
}

View File

@@ -1,45 +0,0 @@
// 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_allocated(arena_dptr, base_capacity) \
(wapp_mem_arena_init_allocated_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, false))
#define wapp_mem_arena_init_allocated_commit(arena_dptr, base_capacity) \
(wapp_mem_arena_init_allocated_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, false))
#define wapp_mem_arena_init_allocated_zero(arena_dptr, base_capacity) \
(wapp_mem_arena_init_allocated_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE, true))
#define wapp_mem_arena_init_allocated_commit_and_zero(arena_dptr, base_capacity) \
(wapp_mem_arena_init_allocated_custom(arena_dptr, base_capacity, WAPP_MEM_ALLOC_RESERVE | WAPP_MEM_ALLOC_COMMIT, true))
/**
* Arena initialisation function. `wapp_mem_arena_init_allocated_custom` provides the most
* control over how the Arena is initialised. Wrapper macros are provided for
* easier use.
*/
b8 wapp_mem_arena_init_allocated_custom(Arena **arena, u64 base_capacity, MemAllocFlags flags, b8 zero_buffer);
b8 wapp_mem_arena_init_buffer(Arena **arena, u8 *buffer, u64 buffer_size);
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_temp_begin(Arena *arena);
void wapp_mem_arena_temp_end(Arena *arena);
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

View File

@@ -1,87 +0,0 @@
// 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"
#include "../../../common/assert/assert.h"
wapp_intern void initialise_arena_allocator(Allocator *allocator);
wapp_intern void *mem_arena_alloc(u64 size, void *alloc_obj);
wapp_intern void *mem_arena_alloc_aligned(u64 size, u64 alignment, void *alloc_obj);
wapp_intern void *mem_arena_realloc(void *ptr, u64 old_size, u64 new_size, void *alloc_obj);
wapp_intern void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
void *alloc_obj);
Allocator wapp_mem_arena_allocator_init_with_buffer(u8 *buffer, u64 buffer_size) {
Allocator allocator = {0};
b8 initialised = wapp_mem_arena_init_buffer((Arena **)(&allocator.obj), buffer, buffer_size);
if (!initialised) {
return allocator;
}
initialise_arena_allocator(&allocator);
return allocator;
}
Allocator wapp_mem_arena_allocator_init_custom(u64 base_capacity, MemAllocFlags flags, b8 zero_buffer) {
Allocator allocator = {0};
b8 initialised = wapp_mem_arena_init_allocated_custom((Arena **)(&allocator.obj), base_capacity, flags, zero_buffer);
if (!initialised) {
return allocator;
}
initialise_arena_allocator(&allocator);
return allocator;
}
void wapp_mem_arena_allocator_temp_begin(const Allocator *allocator) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
wapp_mem_arena_temp_begin((Arena *)(allocator->obj));
}
void wapp_mem_arena_allocator_temp_end(const Allocator *allocator) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
wapp_mem_arena_temp_end((Arena *)(allocator->obj));
}
void wapp_mem_arena_allocator_clear(Allocator *allocator) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
wapp_mem_arena_clear((Arena *)(allocator->obj));
}
void wapp_mem_arena_allocator_destroy(Allocator *allocator) {
wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL");
wapp_mem_arena_destroy((Arena **)(&(allocator->obj)));
*allocator = (Allocator){0};
}
wapp_intern void initialise_arena_allocator(Allocator *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;
}
wapp_intern void *mem_arena_alloc(u64 size, void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_alloc(arena, size);
}
wapp_intern 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 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 void *mem_arena_realloc_aligned(void *ptr, u64 old_size, u64 new_size, u64 alignment,
void *alloc_obj) {
Arena *arena = (Arena *)alloc_obj;
return wapp_mem_arena_realloc_aligned(arena, ptr, old_size, new_size, alignment);
}

View File

@@ -1,46 +0,0 @@
// 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);
Allocator wapp_mem_arena_allocator_init_with_buffer(u8 *buffer, u64 buffer_size);
void wapp_mem_arena_allocator_temp_begin(const Allocator *allocator);
void wapp_mem_arena_allocator_temp_end(const Allocator *allocator);
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

View File

@@ -1,136 +1,92 @@
// 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 "aliases.h"
#include <stdarg.h>
#include <stdbool.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;
}
void join_root_and_leaf(const char *root, const char *leaf, char *dst);
if (parts->node_count == 0) {
return CPATH_JOIN_EMPTY_PARTS;
}
void join_path(char *dst, u64 count, ...) {
va_list args;
Str8 separator = wapp_str8_buf(4);
wapp_str8_push_back(&separator, WAPP_PATH_SEP);
va_start(args, count);
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;
}
for (u64 i = 0; i < count; ++i) {
join_root_and_leaf(dst, va_arg(args, const char *), dst);
}
// Handle first node
Str8 *first_node = wapp_dbl_list_get(Str8, parts, 0);
wapp_str8_copy_str8_capped(dst, first_node);
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
// MSVC Spectre mitigation warnings
Str8 *node = first_node;
u64 node_index = 1;
b8 running = node_index < parts->node_count;
while (running) {
node = wapp_dbl_list_get(Str8, parts, node_index);
if (node->size == 0) {
goto CPATH_JOIN_LOOP_END;
}
if (dst->size > 0) {
char dst_last = wapp_str8_get(dst, dst->size - 1);
char node_start = wapp_str8_get(node, 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);
CPATH_JOIN_LOOP_END:
++node_index;
running = node_index < parts->node_count;
}
return CPATH_JOIN_SUCCESS;
va_end(args);
}
Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels) {
Str8 *output = NULL;
if (!allocator || !path) {
goto RETURN_DIRUP;
}
void dirup(char *dst, u64 levels, const char *path) {
if (levels < 1) {
return;
}
b8 absolute = wapp_str8_get(path, 0) == WAPP_PATH_SEP;
Str8 separator = wapp_str8_buf(4);
wapp_str8_push_back(&separator, WAPP_PATH_SEP);
u64 copy_count = 0;
u64 sep_count = 0;
if (path->size == 0) {
output = wapp_str8_alloc_buf(allocator, 16);
if (!output) {
goto RETURN_DIRUP;
}
u64 full_length;
u64 length;
length = full_length = strlen(path);
wapp_str8_push_back(output, absolute ? WAPP_PATH_SEP : '.');
goto RETURN_DIRUP;
}
if (length > 1 && path[length - 1] == PATH_SEP) {
--length;
}
if (levels < 1) {
output = wapp_str8_alloc_str8(allocator, path);
goto RETURN_DIRUP;
}
for (i64 i = length - 1; i >= 0; --i) {
if (path[i] == PATH_SEP) {
++sep_count;
copy_count = i + 1;
Allocator tmp_arena = wapp_mem_arena_allocator_init(MiB(8));
if (wapp_mem_allocator_invalid(&tmp_arena)) {
goto RETURN_DIRUP;
}
if (sep_count == levels) {
break;
}
}
}
Str8List *parts = wapp_str8_split(&tmp_arena, path, &separator);
if (!parts) {
goto RETURN_DIRUP;
}
char tmp[256];
snprintf(tmp, 2, "%c", PATH_SEP);
// NOTE (Abdelrahman): Conditions stored in variables to silence MSVC warning C5045
bool insufficient_levels = sep_count < levels;
bool path_to_copy_is_separator = strncmp(path, tmp, copy_count) != 0;
if (insufficient_levels && path_to_copy_is_separator) {
copy_count = 0;
}
if (levels >= parts->node_count) {
output = wapp_str8_alloc_buf(allocator, 16);
if (!output) {
goto LIST_CLEANUP_DIRUP;
}
if (dst == path) {
memset(&dst[copy_count], 0, full_length - copy_count);
} else {
u64 dst_length = strlen(dst);
memset(dst, 0, dst_length);
strncpy(dst, path, copy_count);
}
wapp_str8_push_back(output, absolute ? WAPP_PATH_SEP : '.');
} else {
for (u64 i = 0; i < levels; ++i) {
wapp_dbl_list_pop_back(Str8, parts);
}
u64 alignment = sizeof(void *) * 2;
u64 alloc_size = wapp_str8_list_total_size(parts) + parts->node_count * separator.size;
u64 modulo = alloc_size & (alignment - 1);
alloc_size += alignment - modulo;
output = wapp_str8_alloc_buf(allocator, alloc_size);
if (output) {
if (absolute) {
wapp_str8_push_back(output, 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;
u64 final_length = strlen(dst);
if (final_length > 1) {
dst[final_length - 1] = '\0';
} else if (final_length == 0) {
dst[0] = '.';
}
}
void join_root_and_leaf(const char *root, const char *leaf, char *dst) {
u64 root_length = strlen(root);
u64 leaf_length = strlen(leaf);
memcpy(dst, root, root_length);
if (leaf_length == 0) {
return;
}
u64 copy_start = root_length;
if (root_length > 0 && root[root_length - 1] != PATH_SEP && leaf[0] != PATH_SEP) {
dst[root_length] = PATH_SEP;
++copy_start;
}
memcpy(&(dst[copy_start]), leaf, leaf_length);
}

View File

@@ -1,45 +1,32 @@
// 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"
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#ifdef WAPP_PLATFORM_POSIX
#include <limits.h>
#define WAPP_PATH_SEP '/'
#define WAPP_PATH_MAX PATH_MAX
#define PATH_SEP '/'
#elif defined(WAPP_PLATFORM_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#define WAPP_PATH_SEP '\\'
#define WAPP_PATH_MAX MAX_PATH
#define PATH_SEP '\\'
#else
#error "Unrecognised platform"
#endif
#define wapp_cpath_dirname(ALLOCATOR, PATH) dirup(ALLOCATOR, PATH, 1)
#define wapp_cpath_dirup(ALLOCATOR, PATH, COUNT) dirup(ALLOCATOR, PATH, COUNT)
#define NUMPARTS(...) (sizeof((const char *[]){"", __VA_ARGS__}) / sizeof(const char *) - 1)
enum {
CPATH_JOIN_SUCCESS = 0,
CPATH_JOIN_INVALID_ARGS,
CPATH_JOIN_EMPTY_PARTS,
CPATH_JOIN_INSUFFICIENT_DST_CAPACITY,
};
#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)
u32 wapp_cpath_join_path(Str8 *dst, const Str8List *parts);
Str8 *dirup(const Allocator *allocator, Str8RO *path, u64 levels);
void join_path(char *dst, u64 count, ...);
void dirup(char *dst, u64 levels, const char *path);
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#endif // !CPATH_H

View File

@@ -1,129 +0,0 @@
// 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"
WFile *wapp_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode) {
wapp_debug_assert(allocator != NULL && filepath != NULL, "`allocator` and `filepath` should not be NULL");
wapp_debug_assert(filepath->size < WAPP_PATH_MAX, "`filepath` exceeds max path limit.");
return _file_open(allocator, filepath, mode);
}
i64 wapp_file_get_current_position(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return _file_seek(file, 0, WAPP_SEEK_CURRENT);
}
i64 wapp_file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return _file_seek(file, offset, origin);
}
i64 wapp_file_get_length(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
i64 current = wapp_file_get_current_position(file);
_file_seek(file, 0, WAPP_SEEK_END);
i64 output = wapp_file_get_current_position(file);
// Restore position
_file_seek(file, current, WAPP_SEEK_START);
return output;
}
u64 wapp_file_read(void *dst_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(dst_buf != NULL && file != NULL,
"`dst_buf` and `file` should not be NULL.");
i64 file_length = wapp_file_get_length(file);
if (file_length < 0) {
return 0;
}
return _file_read(dst_buf, byte_count, file, file_length);
}
i64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(src_buf != NULL && file != NULL,
"`src_buf` and `file` should not be NULL.");
return _file_write(src_buf, file, byte_count);
}
u64 wapp_file_read_array(GenericArray dst_buf, WFile *file, u64 item_count) {
wapp_debug_assert(dst_buf != NULL && file != NULL,
"`dst_buf` and `file` should not be NULL.");
i64 _file_length = wapp_file_get_length(file);
if (_file_length < 0) {
return 0;
}
u64 file_length = (u64)_file_length;
u64 item_size = wapp_array_item_size(dst_buf);
u64 dst_byte_capacity = wapp_array_capacity(dst_buf) * 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 byte_count = _file_read(dst_buf, copy_byte_count, file, file_length);
if (byte_count == 0) {
return 0;
}
wapp_array_set_count(dst_buf, byte_count / item_size);
return wapp_array_count(dst_buf);
}
i64 wapp_file_write_array(const GenericArray src_buf, WFile *file, u64 item_count) {
wapp_debug_assert(src_buf != NULL && file != NULL,
"`src_buf` and `file` should not be NULL.");
u64 item_size = wapp_array_item_size(src_buf);
u64 src_byte_count = wapp_array_count(src_buf) * 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;
i64 bytes_written = _file_write(src_buf, file, to_copy);
if (bytes_written < 0) {
return 0;
}
return (u64)bytes_written / item_size;
}
i32 wapp_file_flush(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return _file_flush(file);
}
i32 wapp_file_close(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return _file_close(file);
}
i32 wapp_file_rename(Str8RO *old_filepath, Str8RO *new_filepath) {
wapp_debug_assert(old_filepath != NULL && new_filepath != NULL,
"`old_filepath` and `new_filepath` should not be NULL");
wapp_debug_assert(old_filepath->size < WAPP_PATH_MAX, "`old_filepath` exceeds max path limit.");
wapp_debug_assert(new_filepath->size < WAPP_PATH_MAX, "`new_filepath` exceeds max path limit.");
return _file_rename(old_filepath, new_filepath);
}
i32 wapp_file_remove(Str8RO *filepath) {
wapp_debug_assert(filepath != NULL, "`filepath` should not be NULL");
wapp_debug_assert(filepath->size < WAPP_PATH_MAX, "`filepath` exceeds max path limit.");
return _file_remove(filepath);
}

View File

@@ -1,63 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef FILE_H
#define FILE_H
#include "../../base/mem/allocator/mem_allocator.h"
#include "../../common/aliases/aliases.h"
#include "../../base/strings/str8/str8.h"
#ifdef WAPP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
typedef struct WFile WFile;
typedef enum {
WAPP_ACCESS_READ, // Equivalent to r
WAPP_ACCESS_WRITE, // Equivalent to w
WAPP_ACCESS_APPEND, // Equivalent to a
WAPP_ACCESS_READ_EX, // Equivalent to r+
WAPP_ACCESS_WRITE_EX, // Equivalent to w+
WAPP_ACCESS_APPEND_EX, // Equivalent to a+
WAPP_ACCESS_WRITE_FAIL_ON_EXIST, // Equivalent to wx
WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX, // Equivalent to wx+
FILE_ACCESS_MODE_COUNT,
} FileAccessMode;
typedef enum {
WAPP_SEEK_START,
WAPP_SEEK_CURRENT,
WAPP_SEEK_END,
FILE_SEEK_ORIGIN_COUNT,
} FileSeekOrigin;
WFile *wapp_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode);
i64 wapp_file_get_current_position(WFile *file);
i64 wapp_file_seek(WFile *file, i64 offset, FileSeekOrigin origin);
i64 wapp_file_get_length(WFile *file);
u64 wapp_file_read(void *dst_buf, WFile *file, u64 byte_count);
i64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count);
u64 wapp_file_read_array(GenericArray dst_buf, WFile *file, u64 item_count);
i64 wapp_file_write_array(const GenericArray src_buf, WFile *file, u64 item_count);
i32 wapp_file_flush(WFile *file);
i32 wapp_file_close(WFile *file);
i32 wapp_file_rename(Str8RO *old_filepath, Str8RO *new_filepath);
i32 wapp_file_remove(Str8RO *filepath);
extern WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode);
extern i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin);
extern u64 _file_read(void *dst_buf, u64 byte_count, WFile *file, u64 file_length);
extern i64 _file_write(const void *src_buf, WFile *file, u64 byte_count);
extern i32 _file_flush(WFile *file);
extern i32 _file_close(WFile *file);
extern i32 _file_rename(Str8RO *old_filepath, Str8RO *new_filepath);
extern i32 _file_remove(Str8RO *filepath);
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !FILE_H

View File

@@ -1,119 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "file_posix.h"
#include "../../../common/platform/platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "../file.h"
#include "../../cpath/cpath.h"
#include "../../../common/aliases/aliases.h"
#include "../../../base/array/array.h"
#include "../../../base/strings/str8/str8.h"
#ifdef WAPP_PLATFORM_APPLE
#define _FILE_OFFSET_BITS 64
#define lseek64 lseek
#endif // !WAPP_PLATFORM_APPLE
#define __USE_LARGEFILE64
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
wapp_intern i32 file_flags[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = O_RDONLY,
[WAPP_ACCESS_WRITE] = O_WRONLY | O_CREAT,
[WAPP_ACCESS_APPEND] = O_WRONLY | O_APPEND | O_CREAT,
[WAPP_ACCESS_READ_EX] = O_RDWR,
[WAPP_ACCESS_WRITE_EX] = O_RDWR | O_CREAT,
[WAPP_ACCESS_APPEND_EX] = O_RDWR | O_APPEND | O_CREAT,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = O_WRONLY | O_CREAT | O_EXCL,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = O_RDWR | O_CREAT | O_EXCL,
};
wapp_intern mode_t file_modes[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = 0,
[WAPP_ACCESS_WRITE] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_APPEND] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_READ_EX] = 0,
[WAPP_ACCESS_WRITE_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_APPEND_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
};
wapp_intern i32 file_seek_origins[FILE_SEEK_ORIGIN_COUNT] = {
[WAPP_SEEK_START] = SEEK_SET,
[WAPP_SEEK_CURRENT] = SEEK_CUR,
[WAPP_SEEK_END] = SEEK_END,
};
WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode) {
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
i32 fd = open((const char *)tmp, file_flags[mode], file_modes[mode]);
if (fd < 0) {
return NULL;
}
WFile *output = wapp_mem_allocator_alloc(allocator, sizeof(WFile));
if (output) {
output->fd = fd;
}
return output;
}
i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
return lseek64(file->fd, offset, file_seek_origins[origin]);
}
u64 _file_read(void *dst_buf, u64 byte_count, WFile *file, u64 file_length) {
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
i64 count = read(file->fd, dst_buf, copy_byte_count);
if (count < 0) { return 0; }
return count;
}
i64 _file_write(const void *src_buf, WFile *file, u64 byte_count) {
return write(file->fd, src_buf, byte_count);
}
i32 _file_flush(WFile *file) {
return fsync(file->fd);
}
i32 _file_close(WFile *file) {
return close(file->fd);
}
i32 _file_rename(Str8RO *old_filepath, Str8RO *new_filepath) {
wapp_persist c8 old_tmp[WAPP_PATH_MAX] = {0};
wapp_persist c8 new_tmp[WAPP_PATH_MAX] = {0};
memset(old_tmp, 0, WAPP_PATH_MAX);
memcpy(old_tmp, old_filepath->buf, old_filepath->size);
memset(new_tmp, 0, WAPP_PATH_MAX);
memcpy(new_tmp, new_filepath->buf, new_filepath->size);
i32 link_result = link((const char *)old_tmp, (const char *)new_tmp);
if (link_result == 0) {
_file_remove(old_filepath);
}
return link_result;
}
i32 _file_remove(Str8RO *filepath) {
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
return unlink((const char *)tmp);
}
#endif // !WAPP_PLATFORM_POSIX

View File

@@ -1,27 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef FILE_POSIX_H
#define FILE_POSIX_H
#include "../../../common/aliases/aliases.h"
#include "../../../common/platform/platform.h"
#ifdef WAPP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#ifdef WAPP_PLATFORM_POSIX
#define END_OF_LINE "\n"
struct WFile {
i32 fd;
};
#endif // !WAPP_PLATFORM_POSIX
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !FILE_POSIX_H

View File

@@ -1,159 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "file_win.h"
#include "../../../common/platform/platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "../file.h"
#include "../../cpath/cpath.h"
#include "../../../common/aliases/aliases.h"
#include "../../../base/array/array.h"
#include "../../../base/strings/str8/str8.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <fileapi.h>
#include <intsafe.h>
wapp_intern DWORD file_accesses[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = FILE_READ_DATA,
[WAPP_ACCESS_WRITE] = FILE_WRITE_DATA,
[WAPP_ACCESS_APPEND] = FILE_APPEND_DATA,
[WAPP_ACCESS_READ_EX] = FILE_READ_DATA | FILE_WRITE_DATA,
[WAPP_ACCESS_WRITE_EX] = FILE_READ_DATA | FILE_WRITE_DATA,
[WAPP_ACCESS_APPEND_EX] = FILE_READ_DATA | FILE_APPEND_DATA,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = FILE_WRITE_DATA,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = FILE_READ_DATA | FILE_WRITE_DATA,
};
wapp_intern DWORD creation_dispositions[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = OPEN_EXISTING,
[WAPP_ACCESS_WRITE] = CREATE_ALWAYS,
[WAPP_ACCESS_APPEND] = OPEN_ALWAYS,
[WAPP_ACCESS_READ_EX] = OPEN_EXISTING,
[WAPP_ACCESS_WRITE_EX] = CREATE_ALWAYS,
[WAPP_ACCESS_APPEND_EX] = OPEN_ALWAYS,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = CREATE_NEW,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = CREATE_NEW,
};
wapp_intern DWORD sharing_modes[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = FILE_SHARE_READ | FILE_SHARE_WRITE,
[WAPP_ACCESS_WRITE] = FILE_SHARE_READ,
[WAPP_ACCESS_APPEND] = FILE_SHARE_READ,
[WAPP_ACCESS_READ_EX] = FILE_SHARE_READ | FILE_SHARE_WRITE,
[WAPP_ACCESS_WRITE_EX] = FILE_SHARE_READ,
[WAPP_ACCESS_APPEND_EX] = FILE_SHARE_READ,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = FILE_SHARE_READ,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = FILE_SHARE_READ,
};
wapp_intern DWORD file_seek_origins[FILE_SEEK_ORIGIN_COUNT] = {
[WAPP_SEEK_START] = FILE_BEGIN,
[WAPP_SEEK_CURRENT] = FILE_CURRENT,
[WAPP_SEEK_END] = FILE_END,
};
WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode) {
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
HANDLE fh = CreateFileA((LPCSTR)tmp,
file_accesses[mode],
sharing_modes[mode],
NULL,
creation_dispositions[mode],
FILE_ATTRIBUTE_NORMAL,
NULL);
if (fh == INVALID_HANDLE_VALUE) {
return NULL;
}
WFile *output = wapp_mem_allocator_alloc(allocator, sizeof(WFile));
if (output) {
output->fh = fh;
}
return output;
}
i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
LARGE_INTEGER distance = {0};
LARGE_INTEGER output = {0};
distance.QuadPart = offset;
if (!SetFilePointerEx(file->fh, distance, &output, file_seek_origins[origin])) {
return -1;
}
return output.QuadPart;
}
u64 _file_read(void* dst_buf, u64 byte_count, WFile* file, u64 file_length) {
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
wapp_debug_assert(copy_byte_count <= DWORD_MAX, "Attempting to read large number of bytes at once");
DWORD read_count = 0;
if (!ReadFile(file->fh, dst_buf, (DWORD)copy_byte_count, &read_count, NULL)) {
return 0;
}
return (u64)read_count;
}
i64 _file_write(const void *src_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(byte_count <= DWORD_MAX, "Attempting to write large number of bytes at once");
DWORD write_count = 0;
if (!WriteFile(file->fh, src_buf, (DWORD)byte_count, &write_count, NULL)) {
return 0;
}
return (i64)write_count;
}
i32 _file_flush(WFile *file) {
if (!FlushFileBuffers(file->fh)) {
return -1;
}
return 0;
}
i32 _file_close(WFile *file) {
if (!CloseHandle(file->fh)) {
return -1;
}
return 0;
}
i32 _file_rename(Str8RO *old_filepath, Str8RO *new_filepath) {
wapp_persist c8 old_tmp[WAPP_PATH_MAX] = {0};
wapp_persist c8 new_tmp[WAPP_PATH_MAX] = {0};
memset(old_tmp, 0, WAPP_PATH_MAX);
memcpy(old_tmp, old_filepath->buf, old_filepath->size);
memset(new_tmp, 0, WAPP_PATH_MAX);
memcpy(new_tmp, new_filepath->buf, new_filepath->size);
if (!MoveFile((LPCSTR)old_tmp, (LPCSTR)new_tmp)) {
return -1;
}
return 0;
}
i32 _file_remove(Str8RO *filepath) {
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
if (!DeleteFile((LPCSTR)tmp)) {
return -1;
}
return 0;
}
#endif // !WAPP_PLATFORM_WINDOWS

View File

@@ -1,31 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef FILE_WIN_H
#define FILE_WIN_H
#include "../../../common/aliases/aliases.h"
#include "../../../common/platform/platform.h"
#ifdef WAPP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#ifdef WAPP_PLATFORM_WINDOWS
#define END_OF_LINE "\r\n"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <fileapi.h>
struct WFile {
HANDLE fh;
};
#endif // !WAPP_PLATFORM_WINDOWS
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !FILE_WIN_H

View File

@@ -1,30 +0,0 @@
// 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_os_mem_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) {
void *output = os_mem_allocate(addr, size, access, flags, type);
if (type == WAPP_MEM_INIT_INITIALISED) {
memset(output, 0, size);
}
return output;
}
void wapp_os_mem_free(void *ptr, u64 size) {
os_mem_free(ptr, size);
}

View File

@@ -1,33 +0,0 @@
// 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_os_mem_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type);
void wapp_os_mem_free(void *ptr, u64 size);
wapp_extern void *os_mem_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type);
wapp_extern void os_mem_free(void *ptr, u64 size);
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !MEM_OS_H

View File

@@ -1,30 +0,0 @@
// 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

53
src/os/mem/mem_utils.c Normal file
View File

@@ -0,0 +1,53 @@
#include "mem_utils.h"
#include "mem_utils_ops.h"
#include "aliases.h"
#include "platform.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if defined(WAPP_PLATFORM_WINDOWS)
#include "mem_utils_win.h"
#elif defined(WAPP_PLATFORM_POSIX)
#include "mem_utils_posix.h"
#else
#error "Unrecognised platform"
#endif
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
if (!ptr) {
return NULL;
}
assert(is_power_of_two(alignment));
uptr p = (uptr)ptr;
uptr align = (uptr)alignment;
// Similar to p % align, but it's a faster implementation that works fine
// because align is guaranteed to be a power of 2
uptr modulo = p & (align - 1);
if (modulo != 0) {
p += align - modulo;
}
return (void *)p;
}
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) {
void *output = mem_util_allocate(addr, size, access, flags, type);
if (type == WAPP_MEM_INIT_INITIALISED) {
memset(output, 0, size);
}
return output;
}
void wapp_mem_util_free(void *ptr, u64 size) {
mem_util_free(ptr, size);
}

32
src/os/mem/mem_utils.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef MEM_UTILS_H
#define MEM_UTILS_H
#include "aliases.h"
#include "platform.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
#include "mem_utils_ops.h"
#if defined(WAPP_PLATFORM_WINDOWS)
#include "mem_utils_win.h"
#elif defined(WAPP_PLATFORM_POSIX)
#include "mem_utils_posix.h"
#else
#error "Unrecognised platform"
#endif
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
void *wapp_mem_util_alloc(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type);
void wapp_mem_util_free(void *ptr, u64 size);
external void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type);
external void mem_util_free(void *ptr, u64 size);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_UTILS_H

View File

@@ -0,0 +1,26 @@
#ifndef MEM_UTILS_OPS_H
#define MEM_UTILS_OPS_H
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
typedef enum mem_access {
WAPP_MEM_ACCESS_NONE,
WAPP_MEM_ACCESS_READ_ONLY,
WAPP_MEM_ACCESS_EXEC_ONLY,
WAPP_MEM_ACCESS_READ_WRITE,
WAPP_MEM_ACCESS_READ_EXEC,
WAPP_MEM_ACCESS_READ_WRITE_EXEC,
} MemAccess;
typedef enum mem_init_type {
WAPP_MEM_INIT_UNINITIALISED,
WAPP_MEM_INIT_INITIALISED,
} MemInitType;
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !MEM_UTILS_OPS_H

View File

@@ -1,36 +0,0 @@
// 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 *os_mem_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 os_mem_free(void *ptr, u64 size) {
munmap(ptr, size);
}
#endif // !WAPP_PLATFORM_POSIX

View File

@@ -1,35 +0,0 @@
// 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

View File

@@ -0,0 +1,33 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "mem_utils_ops.h"
#include "mem_utils_posix.h"
#include <sys/mman.h>
internal const i32 access_types[] = {
[WAPP_MEM_ACCESS_NONE] = PROT_NONE,
[WAPP_MEM_ACCESS_READ_ONLY] = PROT_READ,
[WAPP_MEM_ACCESS_EXEC_ONLY] = PROT_EXEC,
[WAPP_MEM_ACCESS_READ_WRITE] = PROT_READ | PROT_WRITE,
[WAPP_MEM_ACCESS_READ_EXEC] = PROT_READ | PROT_EXEC,
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC,
};
void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) {
i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE;
#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU) || defined(WAPP_PLATFORM_NET_BSD)
alloc_flags |= MAP_NORESERVE;
#endif
return mmap(addr, size, access_types[access], alloc_flags, -1, 0);
}
void mem_util_free(void *ptr, u64 size) {
munmap(ptr, size);
}
#endif // !WAPP_PLATFORM_POSIX

View File

@@ -0,0 +1,33 @@
#ifndef MEM_UTILS_POSIX_H
#define MEM_UTILS_POSIX_H
#include "platform.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !__cplusplus
#ifdef WAPP_PLATFORM_POSIX
#include <sys/mman.h>
typedef enum mem_alloc_flags {
#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU)
WAPP_MEM_ALLOC_RESERVE = 0,
WAPP_MEM_ALLOC_COMMIT = MAP_POPULATE,
#elif defined(WAPP_PLATFORM_FREE_BSD)
WAPP_MEM_ALLOC_RESERVE = 0,
WAPP_MEM_ALLOC_COMMIT = MAP_PREFAULT_READ,
#elif defined(WAPP_PLATFORM_BSD) || defined(WAPP_PLATFORM_UNIX) || defined(WAPP_PLATFORM_APPLE)
WAPP_MEM_ALLOC_RESERVE = 0,
WAPP_MEM_ALLOC_COMMIT = 0,
#endif
} MemAllocFlags;
#endif // !WAPP_PLATFORM_POSIX
#ifdef __cplusplus
END_C_LINKAGE
#endif // !__cplusplus
#endif // !MEM_UTILS_POSIX_H

View File

@@ -1,37 +0,0 @@
// 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 *os_mem_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 os_mem_free(void *ptr, u64 size) {
VirtualFree(ptr, size, MEM_RELEASE);
}
#endif // !WAPP_PLATFORM_WINDOWS

View File

@@ -1,29 +0,0 @@
// 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

View File

@@ -0,0 +1,35 @@
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "mem_utils_ops.h"
#include "mem_utils_win.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <memoryapi.h>
internal const i32 access_types[] = {
[WAPP_MEM_ACCESS_NONE] = PAGE_NOACCESS,
[WAPP_MEM_ACCESS_READ_ONLY] = PAGE_READONLY,
[WAPP_MEM_ACCESS_EXEC_ONLY] = PAGE_EXECUTE,
[WAPP_MEM_ACCESS_READ_WRITE] = PAGE_READWRITE,
[WAPP_MEM_ACCESS_READ_EXEC] = PAGE_EXECUTE_READ,
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE,
};
void *mem_util_allocate(void *addr, u64 size, MemAccess access, MemAllocFlags flags, MemInitType type) {
// Ensure memory is committed if it's meant to be initialised
if (type == WAPP_MEM_INIT_INITIALISED) {
flags |= WAPP_MEM_ALLOC_COMMIT;
}
return VirtualAlloc(addr, (SIZE_T)size, flags, access_types[access]);
}
void mem_util_free(void *ptr, u64 size) {
VirtualFree(ptr, size, MEM_RELEASE);
}
#endif // !WAPP_PLATFORM_WINDOWS

View File

@@ -0,0 +1,27 @@
#ifndef MEM_UTILS_WIN_H
#define MEM_UTILS_WIN_H
#include "platform.h"
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !__cplusplus
#ifdef WAPP_PLATFORM_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <memoryapi.h>
typedef enum mem_alloc_flags {
WAPP_MEM_ALLOC_RESERVE = MEM_RESERVE,
WAPP_MEM_ALLOC_COMMIT = MEM_COMMIT,
} MemAllocFlags;
#endif // !WAPP_PLATFORM_WINDOWS
#ifdef __cplusplus
END_C_LINKAGE
#endif // !__cplusplus
#endif // !MEM_UTILS_WIN_H

View File

@@ -1,15 +1,8 @@
// 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 "aliases.h"
#include "shell_utils.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -17,85 +10,109 @@
#define CMD_BUF_LEN 8192
#define OUT_BUF_LEN 4096
wapp_intern CMDResult execute_command(Str8RO *cmd, CMDOutHandling out_handling, Str8 *out_buf);
wapp_intern CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf);
internal inline CMDError build_command_from_args(char *cmd, u64 buf_len, va_list args);
internal inline CMDResult execute_command(const char *cmd, CMDOutHandling out_handling, char *out_buf,
u64 buf_size);
internal inline CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, char *out_buf,
u64 buf_size);
CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd) {
if (!cmd) {
return CMD_NO_EXIT(SHELL_ERR_INVALID_ARGS);
}
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...) {
va_list args;
va_start(args, buf_size);
Allocator arena = wapp_mem_arena_allocator_init(KiB(500));
char cmd[CMD_BUF_LEN] = {0};
CMDError err = build_command_from_args(cmd, CMD_BUF_LEN, args);
if (err > SHELL_ERR_NO_ERROR) {
va_end(args);
return CMD_NO_EXIT(err);
}
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);
}
va_end(args);
// 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;
return execute_command(cmd, out_handling, out_buf, buf_size);
}
wapp_intern 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);
internal inline CMDError build_command_from_args(char *cmd, u64 buf_len,
va_list args) {
u64 size = 0;
u64 arg_len = 0;
FILE *fp = wapp_shell_utils_popen(cmd_buf, "r");
if (!fp) {
return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL);
}
const char *arg = va_arg(args, const char *);
while (arg) {
arg_len = strlen(arg);
if (arg_len >= buf_len - size) {
return SHELL_ERR_CMD_BUF_FULL;
}
CMDResult output;
strcat(cmd, arg);
cmd[size + arg_len] = ' ';
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;
}
size += arg_len + 1;
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;
}
arg = va_arg(args, const char *);
}
// Process is already closed in get_output_status
fp = NULL;
return SHELL_ERR_NO_ERROR;
}
output = (CMDResult){
.exited = true,
.exit_code = st,
.error = SHELL_ERR_NO_ERROR,
};
internal inline CMDResult execute_command(const char *cmd,
CMDOutHandling out_handling,
char *out_buf, u64 buf_size) {
FILE *fp = wapp_shell_utils_popen(cmd, "r");
if (!fp) {
return CMD_NO_EXIT(SHELL_ERR_PROC_START_FAIL);
}
CMDResult output;
CMDError err = get_command_output(fp, out_handling, out_buf, buf_size);
if (err > SHELL_ERR_NO_ERROR) {
output = CMD_NO_EXIT(err);
goto EXECUTE_COMMAND_CLOSE;
}
i32 st = EXIT_SUCCESS;
err = get_output_status(fp, &st);
if (err > SHELL_ERR_NO_ERROR) {
output = CMD_NO_EXIT(err);
goto EXECUTE_COMMAND_CLOSE;
}
// Process is already closed in get_output_status
fp = NULL;
output = (CMDResult){
.exited = true,
.exit_code = st,
.error = SHELL_ERR_NO_ERROR,
};
EXECUTE_COMMAND_CLOSE:
if (fp) {
wapp_shell_utils_pclose(fp);
}
return output;
if (fp) {
wapp_shell_utils_pclose(fp);
}
return output;
}
wapp_intern CMDError get_command_output(FILE *fp, CMDOutHandling out_handling, Str8 *out_buf) {
Str8 out = wapp_str8_buf(OUT_BUF_LEN);
internal inline CMDError get_command_output(FILE *fp,
CMDOutHandling out_handling,
char *out_buf, u64 buf_size) {
char out[OUT_BUF_LEN] = {0};
u64 max_out_length = OUT_BUF_LEN - 1;
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;
}
u64 buf_filled = 0;
while (fgets(out, (i32)max_out_length, fp)) {
if (out_handling == SHELL_OUTPUT_CAPTURE && out_buf != NULL) {
buf_filled += strlen(out);
if (buf_filled >= buf_size) {
return SHELL_ERR_OUT_BUF_FULL;
}
wapp_str8_concat_capped(out_buf, &out);
} else if (out_handling == SHELL_OUTPUT_PRINT) {
printf(WAPP_STR8_SPEC, wapp_str8_varg(out));
}
strcat(out_buf, out);
} else if (out_handling == SHELL_OUTPUT_PRINT) {
printf("%s", out);
}
}
return SHELL_ERR_NO_ERROR;
return SHELL_ERR_NO_ERROR;
}

View File

@@ -1,27 +1,26 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef COMMANDER_H
#define COMMANDER_H
#include "aliases.h"
#include "commander_output.h"
#include "../../../common/aliases/aliases.h"
#include "../../../common/platform/platform.h"
#include "../../../base/strings/str8/str8.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#define CMD_NO_EXIT(ERR) ((CMDResult){.exited = false, .exit_code = EXIT_FAILURE, .error = ERR})
#define wapp_shell_commander_execute(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, ...) \
run_command(HANDLE_OUTPUT, OUT_BUF, BUF_SIZE, __VA_ARGS__, "2>&1", NULL)
CMDResult wapp_shell_commander_execute(CMDOutHandling out_handling, Str8 *out_buf, const Str8List *cmd);
CMDResult run_command(CMDOutHandling out_handling, char *out_buf, u64 buf_size, ...);
wapp_extern CMDError get_output_status(FILE *fp, i32 *status_out);
external CMDError get_output_status(FILE *fp, i32 *status_out);
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#endif // !COMMANDER_H

View File

@@ -1,42 +1,42 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef COMMANDER_OUTPUT_H
#define COMMANDER_OUTPUT_H
#include "../../../common/aliases/aliases.h"
#include "../../../common/platform/platform.h"
#include "../../../common/misc/misc_utils.h"
#include "aliases.h"
#include "platform.h"
#include <stdbool.h>
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
typedef enum {
SHELL_OUTPUT_DISCARD,
SHELL_OUTPUT_PRINT,
SHELL_OUTPUT_CAPTURE,
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,
SHELL_ERR_NO_ERROR,
SHELL_ERR_CMD_BUF_FULL,
SHELL_ERR_PROC_START_FAIL,
SHELL_ERR_OUT_BUF_FULL,
SHELL_ERR_PROC_EXIT_FAIL,
} CMDError;
typedef struct CMDResult CMDResult;
struct CMDResult {
i32 exit_code;
CMDError error;
b8 exited;
typedef struct commander_result CMDResult;
struct commander_result {
i32 exit_code;
CMDError error;
bool exited;
wapp_misc_utils_reserve_padding(sizeof(b8) + sizeof(i32) + sizeof(CMDError));
#ifdef WAPP_PLATFORM_WINDOWS
#include "misc_utils.h"
wapp_misc_utils_padding_size(sizeof(bool) + sizeof(i32) + sizeof(CMDError));
#endif // !WAPP_PLATFORM_WINDOWS
};
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#endif // !COMMANDER_OUTPUT_H

View File

@@ -1,25 +1,23 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "../../../../common/aliases/aliases.h"
#include "../../../../common/platform/platform.h"
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "../commander_output.h"
#include "../../utils/shell_utils.h"
#include "commander_output.h"
#include "shell_utils.h"
#include <stdio.h>
#include <stdlib.h>
CMDError get_output_status(FILE *fp, i32 *status_out) {
*status_out = wapp_shell_utils_pclose(fp);
*status_out = wapp_shell_utils_pclose(fp);
if (!WIFEXITED(*status_out)) {
return SHELL_ERR_PROC_EXIT_FAIL;
}
if (!WIFEXITED(*status_out)) {
return SHELL_ERR_PROC_EXIT_FAIL;
}
*status_out = WEXITSTATUS(*status_out);
*status_out = WEXITSTATUS(*status_out);
return SHELL_ERR_NO_ERROR;
return SHELL_ERR_NO_ERROR;
}
#endif // !WAPP_PLATFORM_POSIX

View File

@@ -1,24 +1,22 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "../../../../common/aliases/aliases.h"
#include "../../../../common/platform/platform.h"
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "../commander_output.h"
#include "../../utils/shell_utils.h"
#include "commander_output.h"
#include "shell_utils.h"
#include <stdio.h>
CMDError get_output_status(FILE *fp, i32 *status_out) {
if (!feof(fp)) {
// Ensure process is closed on failure
wapp_shell_utils_pclose(fp);
return SHELL_ERR_PROC_EXIT_FAIL;
}
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);
*status_out = wapp_shell_utils_pclose(fp);
return SHELL_ERR_NO_ERROR;
return SHELL_ERR_NO_ERROR;
}
#endif // !WAPP_PLATFORM_WINDOWS

View File

@@ -1,36 +1,33 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "../../../../common/aliases/aliases.h"
#include "../../../../common/platform/platform.h"
#include "../../../../base/strings/str8/str8.h"
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_POSIX
#include "../terminal_colours.h"
#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"),
internal const char *colours[COUNT_TERM_COLOUR] = {
[WAPP_TERM_COLOUR_FG_BLACK] = "\033[30m",
[WAPP_TERM_COLOUR_FG_RED] = "\033[31m",
[WAPP_TERM_COLOUR_FG_GREEN] = "\033[32m",
[WAPP_TERM_COLOUR_FG_BLUE] = "\033[34m",
[WAPP_TERM_COLOUR_FG_CYAN] = "\033[36m",
[WAPP_TERM_COLOUR_FG_MAGENTA] = "\033[35m",
[WAPP_TERM_COLOUR_FG_YELLOW] = "\033[33m",
[WAPP_TERM_COLOUR_FG_WHITE] = "\033[37m",
[WAPP_TERM_COLOUR_FG_BR_BLACK] = "\033[90m",
[WAPP_TERM_COLOUR_FG_BR_RED] = "\033[91m",
[WAPP_TERM_COLOUR_FG_BR_GREEN] = "\033[92m",
[WAPP_TERM_COLOUR_FG_BR_BLUE] = "\033[94m",
[WAPP_TERM_COLOUR_FG_BR_CYAN] = "\033[96m",
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] = "\033[95m",
[WAPP_TERM_COLOUR_FG_BR_YELLOW] = "\033[93m",
[WAPP_TERM_COLOUR_FG_BR_WHITE] = "\033[97m",
[WAPP_TERM_COLOUR_CLEAR] = "\033[0m",
};
void print_coloured_text(Str8RO *text, TerminalColour colour) {
printf(WAPP_STR8_SPEC WAPP_STR8_SPEC, wapp_str8_varg(colours[colour]), wapp_str8_varg((*text)));
void print_coloured_text(const char *text, TerminalColour colour) {
printf("%s%s", colours[colour], text);
}
#endif // !WAPP_PLATFORM_POSIX

View File

@@ -1,18 +1,14 @@
// 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;
}
void wapp_shell_termcolour_print_text(const char *text, TerminalColour colour) {
if (colour < WAPP_TERM_COLOUR_FG_BLACK || colour > WAPP_TERM_COLOUR_FG_BR_WHITE) {
return;
}
print_coloured_text(text, colour);
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);
print_coloured_text("", WAPP_TERM_COLOUR_CLEAR);
}

View File

@@ -1,24 +1,20 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef TERM_COLOUR_H
#define TERM_COLOUR_H
#include "aliases.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
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
void wapp_shell_termcolour_print_text(Str8RO *text, TerminalColour colour);
void wapp_shell_termcolour_print_text(const char *text, TerminalColour colour);
void wapp_shell_termcolour_clear_colour(void);
wapp_extern void print_coloured_text(Str8RO *text, TerminalColour colour);
external void print_coloured_text(const char *text, TerminalColour colour);
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#endif // !TERM_COLOUR_H

View File

@@ -1,39 +1,34 @@
// 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
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
typedef enum {
WAPP_TERM_COLOUR_FG_BLACK,
WAPP_TERM_COLOUR_FG_RED,
WAPP_TERM_COLOUR_FG_GREEN,
WAPP_TERM_COLOUR_FG_BLUE,
WAPP_TERM_COLOUR_FG_CYAN,
WAPP_TERM_COLOUR_FG_MAGENTA,
WAPP_TERM_COLOUR_FG_YELLOW,
WAPP_TERM_COLOUR_FG_WHITE,
WAPP_TERM_COLOUR_FG_BR_BLACK,
WAPP_TERM_COLOUR_FG_BR_RED,
WAPP_TERM_COLOUR_FG_BR_GREEN,
WAPP_TERM_COLOUR_FG_BR_BLUE,
WAPP_TERM_COLOUR_FG_BR_CYAN,
WAPP_TERM_COLOUR_FG_BR_MAGENTA,
WAPP_TERM_COLOUR_FG_BR_YELLOW,
WAPP_TERM_COLOUR_FG_BR_WHITE,
WAPP_TERM_COLOUR_CLEAR,
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,
COUNT_TERM_COLOUR,
} TerminalColour;
#ifdef WAPP_PLATFORM_CPP
#ifdef __cplusplus
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // __cplusplus
#endif // !TERMINAL_COLOURS_H

View File

@@ -1,73 +1,70 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "../../../../common/aliases/aliases.h"
#include "../../../../common/platform/platform.h"
#include "../../../../base/strings/str8/str8.h"
#include "aliases.h"
#include "platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "../terminal_colours.h"
#include "../../../../common/misc/misc_utils.h"
#include "misc_utils.h"
#include "terminal_colours.h"
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
typedef struct TermcolourData TermcolourData;
struct TermcolourData {
HANDLE handle;
WORD default_colour;
WORD current_colour;
typedef struct termcolour_data TermcolourData;
struct termcolour_data {
HANDLE handle;
WORD default_colour;
WORD current_colour;
wapp_misc_utils_reserve_padding(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
wapp_misc_utils_padding_size(sizeof(HANDLE) + sizeof(WORD) + sizeof(WORD));
};
wapp_intern void init_data(TermcolourData *data);
internal 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,
internal WORD colours[COUNT_TERM_COLOUR] = {
[WAPP_TERM_COLOUR_FG_BLACK] = 0,
[WAPP_TERM_COLOUR_FG_RED] = FOREGROUND_RED,
[WAPP_TERM_COLOUR_FG_GREEN] = FOREGROUND_GREEN,
[WAPP_TERM_COLOUR_FG_BLUE] = FOREGROUND_BLUE,
[WAPP_TERM_COLOUR_FG_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE,
[WAPP_TERM_COLOUR_FG_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE,
[WAPP_TERM_COLOUR_FG_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN,
[WAPP_TERM_COLOUR_FG_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
[WAPP_TERM_COLOUR_FG_BR_BLACK] = FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_MAGENTA] = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
[WAPP_TERM_COLOUR_FG_BR_WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
};
void print_coloured_text(Str8RO *text, TerminalColour colour) {
wapp_persist TermcolourData data = {0};
if (data.handle == 0) {
init_data(&data);
}
void print_coloured_text(const char *text, TerminalColour colour) {
persistent TermcolourData data = {0};
if (data.handle == 0) {
init_data(&data);
}
if (colour == WAPP_TERM_COLOUR_CLEAR) {
data.current_colour = data.default_colour;
} else {
data.current_colour = colours[colour];
}
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)));
SetConsoleTextAttribute(data.handle, data.current_colour);
printf("%s", text);
}
wapp_intern void init_data(TermcolourData *data) {
// create handle
data->handle = GetStdHandle(STD_OUTPUT_HANDLE);
internal void init_data(TermcolourData *data) {
// create handle
data->handle = GetStdHandle(STD_OUTPUT_HANDLE);
// get console colour information
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(data->handle, &csbi);
data->default_colour = csbi.wAttributes;
data->current_colour = data->default_colour;
// get console colour information
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(data->handle, &csbi);
data->default_colour = csbi.wAttributes;
data->current_colour = data->default_colour;
}
#endif // !WAPP_PLATFORM_WINDOWS

View File

@@ -1,26 +1,15 @@
// 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 "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
#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
#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

View File

@@ -1,24 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef WAPP_OS_C
#define WAPP_OS_C
#include "wapp_os.h"
#include "file/file.c"
#include "file/posix/file_posix.c"
#include "file/win/file_win.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

View File

@@ -1,24 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef WAPP_CORE_H
#define WAPP_CORE_H
#include "file/file.h"
#include "file/posix/file_posix.h"
#include "file/win/file_win.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

View File

@@ -1,8 +0,0 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef WAPP_PRNG_C
#define WAPP_PRNG_C
#include "xorshift/xorshift.c"
#endif // !WAPP_PRNG_C

View File

@@ -1,9 +0,0 @@
// 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

View File

@@ -1,135 +0,0 @@
// 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 SplitMix64State SplitMix64State;
struct SplitMix64State {
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

View File

@@ -1,30 +0,0 @@
// 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 XOR256State XOR256State;
struct XOR256State {
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

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

@@ -0,0 +1,52 @@
#include "tester.h"
#include "aliases.h"
#include "termcolour.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
internal void handle_test_result(TestFuncResult result);
void run_tests(TestFunc *func1, ...) {
printf("\n");
handle_test_result(func1());
va_list args;
va_start(args, func1);
TestFunc *func = va_arg(args, TestFunc *);
while (func) {
TestFuncResult result = func();
handle_test_result(result);
func = va_arg(args, TestFunc *);
}
va_end(args);
printf("\n");
}
internal void handle_test_result(TestFuncResult result) {
TerminalColour colour;
const char *result_text;
if (result.passed) {
colour = WAPP_TERM_COLOUR_FG_BR_GREEN;
result_text = "PASSED";
} else {
colour = WAPP_TERM_COLOUR_FG_BR_RED;
result_text = "FAILED";
}
printf("[");
wapp_shell_termcolour_print_text(result_text, colour);
wapp_shell_termcolour_clear_colour();
printf("] %s\n", result.name);
if (!result.passed) {
exit(EXIT_FAILURE);
}
}

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

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

View File

@@ -1,55 +0,0 @@
// 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);
}
}

View File

@@ -1,36 +0,0 @@
// 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 TestFuncResult TestFuncResult;
struct TestFuncResult {
Str8 name;
b8 passed;
wapp_misc_utils_reserve_padding(sizeof(Str8) + sizeof(b8));
};
typedef TestFuncResult(TestFunc)(void);
void run_tests(TestFunc *func1, ...);
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !TESTER_H

View File

@@ -1,10 +0,0 @@
// 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

View File

@@ -1,10 +0,0 @@
// 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

View File

@@ -1,58 +0,0 @@
// 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);
}

View File

@@ -1,39 +0,0 @@
// 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 WUUID WUUID;
struct WUUID {
Str8 uuid;
};
// TODO (Abdelrahman): Update UUID implementation to work properly with C++ and tests for validation
#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

View File

@@ -1,10 +0,0 @@
// 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

View File

@@ -1,11 +0,0 @@
// 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

View File

@@ -1,13 +0,0 @@
// 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

View File

@@ -1,13 +0,0 @@
// 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

View File

@@ -1,67 +1,37 @@
#include "test_allocator.h"
#include "wapp.h"
#include "libc/mem_libc_allocator.h"
#include "mem_allocator.h"
#include "mem_arena_allocator.h"
#include "tester.h"
#include <stdbool.h>
#include <stdlib.h>
// NOTE (Abdelrahman): Cannot query size of Arena here so it's hardcoded. Similarly, since arena
// allocation are aligned to power of 2 boundaries, the number of i32 values needed is hardcoded.
#define TEMP_BUF_SIZE (40 + sizeof(i32) * 8)
TestFuncResult test_libc_allocator(void) {
Allocator allocator = wapp_mem_libc_allocator();
bool result = allocator.obj == NULL && allocator.alloc != NULL &&
allocator.alloc_aligned == NULL && allocator.realloc != NULL &&
allocator.realloc_aligned == NULL && allocator.free != NULL;
void *ptr = wapp_mem_allocator_alloc(&allocator, 20);
result = result && (ptr != NULL);
wapp_intern u8 temp_buf[TEMP_BUF_SIZE] = {0};
wapp_intern Allocator temp_allocator = {0};
if (ptr != NULL) {
wapp_mem_allocator_free(&allocator, &ptr);
result = result && (ptr == NULL);
}
return wapp_tester_result(result);
}
TestFuncResult test_arena_allocator(void) {
Allocator allocator = wapp_mem_arena_allocator_init(4096);
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);
Allocator allocator = wapp_mem_arena_allocator_init(4096);
bool result = allocator.obj != NULL && allocator.alloc != NULL &&
allocator.alloc_aligned != NULL &&
allocator.realloc != NULL && allocator.realloc_aligned != NULL &&
allocator.free == NULL;
void *ptr = wapp_mem_allocator_alloc(&allocator, 20);
result = result && (ptr != NULL);
wapp_mem_arena_allocator_destroy(&allocator);
wapp_mem_arena_allocator_destroy(&allocator);
return wapp_tester_result(result);
}
TestFuncResult test_arena_allocator_with_buffer(void) {
u8 buffer[KiB(4)] = {0};
Allocator allocator = wapp_mem_arena_allocator_init_with_buffer(buffer, KiB(4));
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);
}
TestFuncResult test_arena_allocator_temp_begin(void) {
temp_allocator = wapp_mem_arena_allocator_init_with_buffer(temp_buf, TEMP_BUF_SIZE);
i32 *num1 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
b8 result = num1 != NULL;
wapp_mem_arena_allocator_temp_begin(&temp_allocator);
i32 *num2 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
result = result && num2 != NULL;
i32 *num3 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
result = result && num3 == NULL;
return wapp_tester_result(result);
}
TestFuncResult test_arena_allocator_temp_end(void) {
wapp_mem_arena_allocator_temp_end(&temp_allocator);
i32 *num1 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
b8 result = num1 != NULL;
i32 *num2 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
result = result && num2 == NULL;
wapp_mem_arena_allocator_destroy(&temp_allocator);
return wapp_tester_result(result);
return wapp_tester_result(result);
}

View File

@@ -1,67 +0,0 @@
#include "test_allocator.h"
#include "wapp.h"
#include <stdlib.h>
// NOTE (Abdelrahman): Cannot query size of Arena here so it's hardcoded. Similarly, since arena
// allocation are aligned to power of 2 boundaries, the number of i32 values needed is hardcoded.
#define TEMP_BUF_SIZE (40 + sizeof(i32) * 8)
wapp_intern u8 temp_buf[TEMP_BUF_SIZE] = {};
wapp_intern Allocator temp_allocator = {};
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);
}
TestFuncResult test_arena_allocator_with_buffer(void) {
u8 buffer[KiB(4)] = {0};
Allocator allocator = wapp_mem_arena_allocator_init_with_buffer(buffer, KiB(4));
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);
}
TestFuncResult test_arena_allocator_temp_begin(void) {
temp_allocator = wapp_mem_arena_allocator_init_with_buffer(temp_buf, TEMP_BUF_SIZE);
i32 *num1 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
b8 result = num1 != NULL;
wapp_mem_arena_allocator_temp_begin(&temp_allocator);
i32 *num2 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
result = result && num2 != NULL;
i32 *num3 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
result = result && num3 == NULL;
return wapp_tester_result(result);
}
TestFuncResult test_arena_allocator_temp_end(void) {
wapp_mem_arena_allocator_temp_end(&temp_allocator);
i32 *num1 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
b8 result = num1 != NULL;
i32 *num2 = (i32 *)wapp_mem_allocator_alloc(&temp_allocator, sizeof(i32));
result = result && num2 == NULL;
wapp_mem_arena_allocator_destroy(&temp_allocator);
return wapp_tester_result(result);
}

View File

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

View File

@@ -1,168 +1,115 @@
#include "test_arena.h"
#include "wapp.h"
#include "aliases.h"
#include "mem_arena.h"
#include "misc_utils.h"
#include "tester.h"
#include <stdbool.h>
#include <stdlib.h>
#define ARENA_CAPACITY KiB(16)
#define ARENA_BUF_SIZE KiB(4)
// NOTE (Abdelrahman): Cannot query size of Arena here so it's hardcoded. Similarly, since arena
// allocation are aligned to power of 2 boundaries, the number of i32 values needed is hardcoded.
#define TEMP_BUF_SIZE (40 + sizeof(i32) * 8)
#define ARENA_CAPACITY KB(16)
wapp_intern Arena *arena = NULL;
wapp_intern i32 count = 20;
wapp_intern i32 *array = NULL;
wapp_intern Arena *buf_arena = NULL;
wapp_intern u8 buf[ARENA_BUF_SIZE] = {0};
wapp_intern Arena *temp_arena = NULL;
wapp_intern u8 temp_buf[TEMP_BUF_SIZE] = {0};
internal Arena *arena = NULL;
internal i32 count = 20;
internal i32 *array = NULL;
TestFuncResult test_arena_init_buffer(void) {
b8 result = wapp_mem_arena_init_buffer(&buf_arena, buf, ARENA_BUF_SIZE);
return wapp_tester_result(result);
}
TestFuncResult test_arena_init(void) {
bool result = wapp_mem_arena_init(&arena, ARENA_CAPACITY);
TestFuncResult test_arena_init_allocated(void) {
b8 result = wapp_mem_arena_init_allocated(&arena, ARENA_CAPACITY);
return wapp_tester_result(result);
return wapp_tester_result(result);
}
TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void) {
Arena *large_arena = NULL;
u64 capacity = GiB(512);
b8 result = wapp_mem_arena_init_allocated(&large_arena, capacity);
if (result) {
wapp_mem_arena_destroy(&large_arena);
}
Arena *large_arena = NULL;
u64 capacity = GB(512);
bool result = wapp_mem_arena_init(&large_arena, capacity);
if (result) {
wapp_mem_arena_destroy(&large_arena);
}
return wapp_tester_result(result);
}
TestFuncResult test_arena_alloc_with_buffer(void) {
i32 *arr = (i32 *)wapp_mem_arena_alloc(arena, count * sizeof(i32));
b8 result = arr != NULL;
for (i32 i = 0; i < count; ++i) {
arr[i] = i * 10;
}
return wapp_tester_result(result);
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;
array = wapp_mem_arena_alloc(arena, count * sizeof(i32));
bool result = array != NULL;
for (i32 i = 0; i < count; ++i) {
array[i] = i * 10;
}
for (i32 i = 0; i < count; ++i) {
array[i] = i * 10;
}
return wapp_tester_result(result);
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;
u8 *bytes = wapp_mem_arena_alloc(arena, ARENA_CAPACITY * 2);
bool result = bytes == NULL;
return wapp_tester_result(result);
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));
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;
}
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);
}
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);
}
}
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);
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));
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;
}
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);
}
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);
}
}
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_temp_begin(void) {
b8 result = wapp_mem_arena_init_buffer(&temp_arena, temp_buf, TEMP_BUF_SIZE);
i32 *num1 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num1 != NULL;
wapp_mem_arena_temp_begin(temp_arena);
i32 *num2 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num2 != NULL;
i32 *num3 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num3 == NULL;
return wapp_tester_result(result);
}
TestFuncResult test_arena_temp_end(void) {
wapp_mem_arena_temp_end(temp_arena);
i32 *num1 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
b8 result = num1 != NULL;
i32 *num2 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num2 == NULL;
wapp_mem_arena_destroy(&temp_arena);
return wapp_tester_result(result);
return wapp_tester_result(true);
}
TestFuncResult test_arena_clear(void) {
wapp_mem_arena_clear(arena);
b8 result = true;
wapp_mem_arena_clear(arena);
bool result = true;
for (i32 i = 0; i < count; ++i) {
if (array[i] != 0) {
result = false;
break;
}
}
for (i32 i = 0; i < count; ++i) {
if (array[i] != 0) {
result = false;
break;
}
}
return wapp_tester_result(result);
return wapp_tester_result(result);
}
TestFuncResult test_arena_destroy_buffer(void) {
wapp_mem_arena_destroy(&buf_arena);
b8 result = buf_arena == NULL;
TestFuncResult test_arena_destroy(void) {
wapp_mem_arena_destroy(&arena);
bool result = arena == NULL;
return wapp_tester_result(result);
}
TestFuncResult test_arena_destroy_allocated(void) {
wapp_mem_arena_destroy(&arena);
b8 result = arena == NULL;
return wapp_tester_result(result);
return wapp_tester_result(result);
}

View File

@@ -1,168 +0,0 @@
#include "test_arena.h"
#include "wapp.h"
#include <stdlib.h>
#define ARENA_CAPACITY KiB(16)
#define ARENA_BUF_SIZE KiB(4)
// NOTE (Abdelrahman): Cannot query size of Arena here so it's hardcoded. Similarly, since arena
// allocation are aligned to power of 2 boundaries, the number of i32 values needed is hardcoded.
#define TEMP_BUF_SIZE (40 + sizeof(i32) * 8)
wapp_intern Arena *arena = NULL;
wapp_intern i32 count = 20;
wapp_intern i32 *array = NULL;
wapp_intern Arena *buf_arena = NULL;
wapp_intern u8 buf[ARENA_BUF_SIZE] = {};
wapp_intern Arena *temp_arena = NULL;
wapp_intern u8 temp_buf[TEMP_BUF_SIZE] = {};
TestFuncResult test_arena_init_buffer(void) {
b8 result = wapp_mem_arena_init_buffer(&buf_arena, buf, ARENA_BUF_SIZE);
return wapp_tester_result(result);
}
TestFuncResult test_arena_init_allocated(void) {
b8 result = wapp_mem_arena_init_allocated(&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 = GiB(512);
b8 result = wapp_mem_arena_init_allocated(&large_arena, capacity);
if (result) {
wapp_mem_arena_destroy(&large_arena);
}
return wapp_tester_result(result);
}
TestFuncResult test_arena_alloc_with_buffer(void) {
i32 *arr = (i32 *)wapp_mem_arena_alloc(arena, count * sizeof(i32));
b8 result = arr != NULL;
for (i32 i = 0; i < count; ++i) {
arr[i] = i * 10;
}
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_temp_begin(void) {
b8 result = wapp_mem_arena_init_buffer(&temp_arena, temp_buf, TEMP_BUF_SIZE);
i32 *num1 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num1 != NULL;
wapp_mem_arena_temp_begin(temp_arena);
i32 *num2 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num2 != NULL;
i32 *num3 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num3 == NULL;
return wapp_tester_result(result);
}
TestFuncResult test_arena_temp_end(void) {
wapp_mem_arena_temp_end(temp_arena);
i32 *num1 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
b8 result = num1 != NULL;
i32 *num2 = (i32 *)wapp_mem_arena_alloc(temp_arena, sizeof(i32));
result = result && num2 == NULL;
wapp_mem_arena_destroy(&temp_arena);
return wapp_tester_result(result);
}
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_buffer(void) {
wapp_mem_arena_destroy(&buf_arena);
b8 result = buf_arena == NULL;
return wapp_tester_result(result);
}
TestFuncResult test_arena_destroy_allocated(void) {
wapp_mem_arena_destroy(&arena);
b8 result = arena == nullptr;
return wapp_tester_result(result);
}

View File

@@ -1,20 +1,23 @@
#ifndef TEST_ARENA_H
#define TEST_ARENA_H
#include "wapp.h"
#include "tester.h"
TestFuncResult test_arena_init_buffer(void);
TestFuncResult test_arena_init_allocated(void);
#ifdef __cplusplus
BEGIN_C_LINKAGE
#endif // __cplusplus
TestFuncResult test_arena_init(void);
TestFuncResult test_arena_init_succeeds_when_reserving_very_large_size(void);
TestFuncResult test_arena_alloc_with_buffer(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_temp_begin(void);
TestFuncResult test_arena_temp_end(void);
TestFuncResult test_arena_destroy_buffer(void);
TestFuncResult test_arena_destroy_allocated(void);
TestFuncResult test_arena_destroy(void);
#ifdef __cplusplus
END_C_LINKAGE
#endif // __cplusplus
#endif // !TEST_ARENA_H

Some files were not shown because too many files have changed in this diff Show More