Compare commits

...

81 Commits

Author SHA1 Message Date
gary 10830fb412 Merge commit 'cc499028fb6b9a2138538c771d4de8fbf41a7835' as 'deps/ox'
Build / build (push) Failing after 5s
2026-05-06 01:15:12 -05:00
gary cc499028fb Squashed 'deps/ox/' content from commit d4807cd2
git-subtree-dir: deps/ox
git-subtree-split: d4807cd2a0cd64843824959c24479e1ba54459f0
2026-05-06 01:15:12 -05:00
gary 572b8b2c78 [ox] Remove Ox 2026-05-06 01:15:07 -05:00
gary 88e901e214 [keel] Cleanup
Build / build (push) Successful in 1m9s
2026-04-29 01:55:32 -05:00
gary d42e10fcbe [olympic] Cleanup pkg-gba 2026-04-29 01:52:59 -05:00
gary bc88333a59 [studio/modlib] Update ImGui drag/drop, other cleanup 2026-04-29 01:50:39 -05:00
gary 4048753205 [ox/std] Add call and logCatch for safe calling of throwing functions 2026-04-29 01:47:15 -05:00
gary 5c146c6660 [ox/std] Add call and logCatch for safe calling of throwing functions 2026-04-29 01:45:56 -05:00
gary 0885919dbd [ox/std] Cleanup 2026-04-29 01:44:43 -05:00
gary 8c7d8cd08b [ox/model] Cleanup TypeNameCatcher and TypeInfoCatcher 2026-04-29 01:42:53 -05:00
gary 110d4a2e6a [keel] Cleanup
Build / build (push) Successful in 1m16s
2026-02-07 15:29:53 -06:00
gary e29a50d0dc [ox] Rename UniquePtr to UPtr 2026-02-07 14:17:55 -06:00
gary 93d16cafb2 [ox/std] Add Error::throwException() 2026-02-07 14:15:15 -06:00
gary 54d7c706eb [studio] Make FileInfo free resources on close
Build / build (push) Successful in 1m15s
2026-02-06 21:36:39 -06:00
gary c9cb186462 [studio] Cleanup useless complexity
Build / build (push) Successful in 1m16s
2026-02-06 21:28:46 -06:00
gary f204d01a3d [studio] FileInfo: reset file info when opening
Build / build (push) Successful in 1m12s
2026-02-05 22:22:07 -06:00
gary 62337bd29e [studio] FileInfo: Rename ID to Asset ID, allow for no value of fields
Build / build (push) Successful in 1m12s
2026-02-05 22:15:00 -06:00
gary 7b24b33849 [nostalgia] Update release notes
Build / build (push) Successful in 1m11s
2026-02-05 21:40:10 -06:00
gary 86c2c26d8d [studio] Fix warning
Build / build (push) Successful in 1m11s
2026-02-05 21:35:39 -06:00
gary f8b2700ea7 [studio] Add Get Info file dialog
Build / build (push) Failing after 1m9s
2026-02-05 21:32:36 -06:00
gary 7848cbbbff [nostalgia/gfx/keel] Cleanup
Build / build (push) Successful in 1m9s
2026-02-03 02:22:58 -06:00
gary 96c5223e44 [ox/std] Fix possible false positive in HashMap::operator==
Build / build (push) Successful in 1m13s
2026-01-30 21:03:58 -06:00
gary d19b848427 [ox/std] Reduce AnyPtr to 2/3 the size
Build / build (push) Successful in 1m13s
2026-01-30 20:54:17 -06:00
gary c812051ec0 [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 1m11s
2026-01-30 00:31:19 -06:00
gary 3c07eb2df7 [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 1m7s
2026-01-29 19:30:32 -06:00
gary ca851e1059 [ox] Cleanup some expensive headers
Build / build (push) Successful in 1m7s
2026-01-28 22:55:26 -06:00
gary 11e75cb6ca [ox/std] Add Error::reoriginate
Build / build (push) Successful in 1m13s
2026-01-28 00:46:55 -06:00
gary 8c4add57e4 [ox/std] Fix build
Build / build (push) Successful in 1m17s
2026-01-28 00:45:26 -06:00
gary 5e1698a321 [ox/std] Cleanup serialize code
Build / build (push) Failing after 52s
2026-01-27 23:15:53 -06:00
gary 3e95bc0842 [ox/model] Update style for ModelHandlerAdaptor 2026-01-27 23:09:53 -06:00
gary 58e19fad48 [ox] Cleanup MetalClawWriter and FieldBitmapWriter 2026-01-27 23:05:03 -06:00
gary a3a56b24e8 [ox/std] Fix is_integer_v 2026-01-27 23:03:07 -06:00
gary 7681830ca6 [ox] Remove some unnecessary const_casts 2026-01-27 23:01:36 -06:00
gary 46a7331754 [ox/mc] Cleanup, fix possible overflow bug
Build / build (push) Successful in 1m8s
2026-01-26 00:55:55 -06:00
gary 56c19ad2a6 [ox/std] Add remove_pointer_t alias 2026-01-26 00:46:12 -06:00
gary c6ecadf9a8 [ox/mc] Cleanup
Build / build (push) Successful in 1m10s
2026-01-26 00:21:16 -06:00
gary 2ed469f2dd [ox] Cleanup
Build / build (push) Successful in 1m11s
2026-01-25 23:58:46 -06:00
gary 53aea9731d [ox] Cleanup
Build / build (push) Successful in 1m9s
2026-01-25 23:46:54 -06:00
gary 0e028ff653 [ox] Cleanup
Build / build (push) Successful in 1m10s
2026-01-25 22:05:49 -06:00
gary 07688a2c29 [ox] Remove oxExpect macro
Build / build (push) Successful in 1m9s
2026-01-25 21:52:26 -06:00
gary 9ce4d3f8c7 [keel,nostalgia/gfx] Minor cleanup of tests 2026-01-25 21:51:10 -06:00
gary 4aa8255c55 [ox] Update formatting in recently edited files
Build / build (push) Successful in 1m11s
2026-01-25 21:26:44 -06:00
gary bfdfc10425 [nostalgia/gfx] Update panic
Build / build (push) Successful in 1m11s
2026-01-25 21:11:54 -06:00
gary cdd574d873 [ox] Change panic and assert to use std::source_location 2026-01-25 21:11:22 -06:00
gary bc05bd12e5 [ox/model] Rename and fix isBString helpers
Build / build (push) Successful in 1m8s
2026-01-25 02:06:14 -06:00
gary b754c66cf5 [ox] Remove enable_if
Build / build (push) Successful in 1m8s
2026-01-23 01:38:53 -06:00
gary 6a42303239 [ox/std] Slight optimization 2026-01-23 01:38:31 -06:00
gary 7477ede222 [ox/std] Cleanup some enable_ifs
Build / build (push) Successful in 1m7s
2026-01-21 23:35:19 -06:00
gary 65e3153dda [ox/std] Add Union_c concept 2026-01-21 23:35:02 -06:00
gary 53a224cf8f [ox/std] Cleanup 2026-01-21 23:34:36 -06:00
gary 592e641ba9 [ox/std] Fix writeItoa to work with max length 64 bit ints
Build / build (push) Successful in 1m8s
2026-01-21 23:28:13 -06:00
gary 689da4a019 [ox] Update docs
Build / build (push) Successful in 1m10s
2026-01-21 21:04:17 -06:00
gary bdf7755ee2 [nostalgia/developer-handbook] Update developer handbook 2026-01-21 21:03:47 -06:00
gary 63f627377d [ox/std] Remove excess char from intToStr return
Build / build (push) Successful in 1m9s
2026-01-20 01:29:37 -06:00
gary ff9002ad9a [nostalgia/developer-handbook] Update error handling section
Build / build (push) Successful in 1m8s
2026-01-20 01:22:05 -06:00
gary 4d0da022cf [ox] Update error handling docs
Build / build (push) Successful in 1m8s
2026-01-20 00:47:51 -06:00
gary 02332d99b5 [ox] Fix issues in String Types section of docs
Build / build (push) Successful in 1m8s
2026-01-20 00:26:38 -06:00
gary a566ed2a8b [ox/std] Fix writeItoa to work with negatives
Build / build (push) Successful in 1m9s
2026-01-19 23:00:16 -06:00
gary 815c3d19bf [ox/std] Make StringLiteral constructors non-explicit
Build / build (push) Successful in 1m8s
2026-01-19 21:00:58 -06:00
gary 522bb14f18 [ox/std] Fix intToStr to have room for negatives 2026-01-19 21:00:12 -06:00
gary f40d5515f9 [ox] Add strings section to docs
Build / build (push) Successful in 1m11s
2026-01-18 19:00:24 -06:00
gary 941d1d90dc [ox/std] Add Vector::reserveResize
Build / build (push) Successful in 1m15s
2026-01-07 21:48:04 -06:00
gary 3e880dcdcc [nostalgia/gfx/studio] Remove unused EBO management
Build / build (push) Successful in 1m16s
2026-01-07 21:33:16 -06:00
gary 03328ac10f [turbine/glfw] Fix to handle null click handler
Build / build (push) Successful in 1m9s
2025-12-03 20:44:01 -06:00
gary 63d0abaa3c [nostalgia/gfx/gba] Remove teagba scroll bg function call
Build / build (push) Successful in 1m15s
2025-11-22 23:53:18 -06:00
gary ef2a8cda77 [teagba] Remove bg scroll, cleanup 2025-11-22 23:53:04 -06:00
gary 671fa54f6f [ox/std] Make ox::Vector::push_back comply with std::vector::push_back
Build / build (push) Successful in 1m12s
2025-09-10 23:47:36 -05:00
gary 517432679b [nostalgia/gfx/studio] Cleanup includes
Build / build (push) Successful in 1m15s
2025-09-04 22:40:58 -05:00
gary b31c01f724 [keel,studio] Cleanup 2025-09-04 22:37:01 -05:00
gary f41213f13f [ox/std] Fix channel format for oxLogError
Build / build (push) Successful in 1m8s
2025-09-04 21:11:52 -05:00
gary 28be7c4650 [ox/fs] Fix write functions to take SpanViews 2025-09-04 21:11:52 -05:00
gary 2f340b13b2 [ox/std] Fix Windows GCC build
Build / build (push) Successful in 1m15s
2025-09-04 01:21:13 -05:00
gary 312c818866 [nostalgia/gfx/studio] Remove unused variable
Build / build (push) Successful in 1m10s
2025-08-29 22:18:37 -05:00
gary 0d69d0c4a2 [ox/std] Remove oxDebug line
Build / build (push) Successful in 1m18s
2025-08-19 21:02:13 -05:00
gary 81a0b8c820 [ox/mc] Remove an oxDebug line
Build / build (push) Failing after 22s
2025-08-19 20:59:51 -05:00
gary 172b5aee90 [ox/oc] Remove an oxDebug line
Build / build (push) Failing after 17s
2025-08-19 20:58:32 -05:00
gary 2b5338a9df [nostalgia] Improve Makefile dependency handling
Build / build (push) Failing after 9s
2025-08-17 14:10:45 -05:00
gary 8a430faf4c [keel] Cleanup
Build / build (push) Successful in 1m19s
2025-08-12 22:57:13 -05:00
gary e59382dd60 [keel] Address undefined behavior 2025-08-12 22:39:08 -05:00
gary 3006e77ef3 [ox/std] Add and integrate std::launder
Build / build (push) Successful in 1m30s
2025-08-12 22:37:21 -05:00
gary 59c112a69c [studio] Fix navigate back not to iterate on the first item twice
Build / build (push) Successful in 1m55s
2025-08-09 15:15:34 -05:00
265 changed files with 3395 additions and 2999 deletions
+35 -3
View File
@@ -1,7 +1,7 @@
BC_VAR_PROJECT_NAME=nostalgia BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia BC_VAR_PROJECT_NAME_CAP=Nostalgia
BC_VAR_DEVENV_ROOT=util BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore BUILDCORE_PATH=deps/ox/deps/buildcore
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin) ifeq ($(BC_VAR_OS),darwin)
@@ -13,8 +13,21 @@ else
endif endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP} PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: git-setup-ox-remote
git-setup-ox-remote:
git remote add -f ox-master git@git.drinkingtea.net:drinkingtea/ox.git
.PHONY: git-pull-ox
git-pull-ox:
git fetch ox-master master
git subtree pull --prefix deps/ox ox-master master --squash
.PHONY: git-push-ox
git-push-ox:
git subtree push --prefix=deps/ox ox-master master
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac .PHONY: pkg-mac
@@ -26,25 +39,44 @@ generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player .PHONY: build-player
build-player: build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run .PHONY: run
run: build-player run: build-player
${PROJECT_PLAYER} sample_project ${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio .PHONY: run-studio
run-studio: build run-studio: build-studio
${PROJECT_STUDIO} ${PROJECT_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba ${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug .PHONY: debug
debug: build debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project ${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
configure-gba: configure-gba:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH} ${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}
-12
View File
@@ -1,12 +0,0 @@
{
"log_functions": [
{
"function": "ox::trace::gdblogger::captureLogFunc",
"ignore_frames": 3,
"file_var": "file",
"line_var": "line",
"channel_var": "ch",
"msg_var": "msg"
}
]
}
+20
View File
@@ -0,0 +1,20 @@
name: Build
run-name: ${{ gitea.actor }} build and test
on: [push]
jobs:
build:
runs-on: olympic
steps:
- name: Check out repository code
uses: actions/checkout@v3
- run: make purge configure-debug
- run: make build
- run: make test
- run: make purge configure-asan
- run: make build
- run: make test
- run: make purge configure-release
- run: make build
- run: make test
- run: make install
+2
View File
@@ -3,7 +3,9 @@ build/gba
build/*-asan build/*-asan
build/*-debug build/*-debug
build/*-release build/*-release
.current_build
tags tags
compile_commands.json
conanbuildinfo.cmake conanbuildinfo.cmake
conanbuildinfo.txt conanbuildinfo.txt
conaninfo.txt conaninfo.txt
-11
View File
@@ -1,11 +0,0 @@
language: cpp
sudo: false
dist: trusty
compiler:
- clang
- gcc
addons:
apt:
packages:
- cmake
script: ./scripts/cibuild
+9 -2
View File
@@ -3,8 +3,8 @@ set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
project(Ox CXX) project(Ox CXX)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) include(deps/buildcore/base.cmake)
include(address_sanitizer)
if(NOT DEFINED OX_RUN_TESTS) if(NOT DEFINED OX_RUN_TESTS)
set(OX_RUN_TESTS ON) set(OX_RUN_TESTS ON)
@@ -78,6 +78,13 @@ include_directories(src)
install(FILES OxConfig.cmake DESTINATION lib/cmake/ox) install(FILES OxConfig.cmake DESTINATION lib/cmake/ox)
install(
DIRECTORY
include/ox
DESTINATION
include
)
if(OX_USE_STDLIB) if(OX_USE_STDLIB)
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include") set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
add_subdirectory(deps/jsoncpp) add_subdirectory(deps/jsoncpp)
+15 -65
View File
@@ -1,68 +1,18 @@
OS=$(shell uname | tr [:upper:] [:lower:]) BC_VAR_PROJECT_NAME=ox
HOST_ENV=${OS}-$(shell uname -m) BC_VAR_PROJECT_NAME_CAP=Ox
DEVENV=devenv$(shell pwd | sed 's/\//-/g') BC_VAR_DEVENV_ROOT=util
DEVENV_IMAGE=wombatant/devenv BUILDCORE_PATH=deps/buildcore
ifneq ($(shell which docker 2>&1),) include ${BUILDCORE_PATH}/base.mk
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
endif
endif
all: .PHONY: git-setup-buildcore-remote
${ENV_RUN} ./scripts/run-make build git-setup-buildcore-remote:
preinstall: git remote add -f buildcore-master git@git.drinkingtea.net:drinkingtea/buildcore.git
${ENV_RUN} ./scripts/run-make build preinstall
install:
${ENV_RUN} ./scripts/run-make build install
clean:
${ENV_RUN} ./scripts/run-make build clean
purge:
${ENV_RUN} rm -rf build
test:
${ENV_RUN} ./scripts/run-make build test
devenv: .PHONY: git-pull-buildcore
docker pull ${DEVENV_IMAGE} git-pull-buildcore:
docker run -d -v $(shell pwd):/usr/src/project \ git fetch buildcore-master master
-e LOCAL_USER_ID=$(shell id -u ${USER}) \ git subtree pull --prefix deps/buildcore buildcore-master master --squash
--name ${DEVENV} -t ${DEVENV_IMAGE} bash
devenv-destroy:
docker rm -f ${DEVENV}
devenv-shell:
${ENV_RUN} bash
configure-release: .PHONY: git-push-buildcore
${ENV_RUN} rm -rf build/${HOST_ENV}-release git-push-buildcore:
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} git subtree push --prefix=deps/buildcore buildcore-master master
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s ${HOST_ENV}-release build/current
configure-debug:
${ENV_RUN} rm -rf build/${HOST_ENV}-debug
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} debug
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s ${HOST_ENV}-debug build/current
configure-asan:
${ENV_RUN} rm -rf build/${HOST_ENV}-asan
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} asan
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s ${HOST_ENV}-asan build/current
configure-windows:
${ENV_RUN} rm -rf build/windows
${ENV_RUN} ./scripts/setup_build windows
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s windows build/current
configure-windows-debug:
${ENV_RUN} rm -rf build/windows
${ENV_RUN} ./scripts/setup_build windows debug
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s windows build/current
configure-gba:
${ENV_RUN} rm -rf build/gba-release
${ENV_RUN} ./scripts/setup_build gba
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s gba-release build/current
-24
View File
@@ -1,24 +0,0 @@
set(CMAKE_SYSTEM_NAME "Generic")
set(DEVKITARM $ENV{DEVKITARM})
if(NOT DEVKITARM)
message(FATAL_ERROR "DEVKITARM environment variable not set")
endif()
set(CMAKE_C_COMPILER ${DEVKITARM}/bin/arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER ${DEVKITARM}/bin/arm-none-eabi-g++)
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
set(LINKER_FLAGS "-specs=gba.specs")
add_definitions (
-DARM7
)
include(FindPackageHandleStandardArgs)
-18
View File
@@ -1,18 +0,0 @@
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
# cross compilers to use for C and C++
set(CMAKE_C_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
# set 1st to dir with the cross compiler's C/C++ headers/libs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands to
# search for headers/libs in the target environment and
# search for programs in the build host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-52
View File
@@ -1,52 +0,0 @@
# This file belongs Nick Overdijk, and is from https://github.com/NickNick/wubwubcmake
# The MIT License (MIT)
#
# Copyright (c) 2013 Nick Overdijk
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" ON)
option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" OFF)
if(USE_ASAN)
include(CheckCXXSourceCompiles)
# If the compiler understands -fsanitize=address, add it to the flags (gcc since 4.8 & clang since version 3.2)
set(CMAKE_REQUIRED_FLAGS_BAK "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize=address")
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FSANA_SUPPORTED)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
if(FLAG_FSANA_SUPPORTED)
set(asan_flag "-fsanitize=address")
else(FLAG_FSANA_SUPPORTED)
# Alternatively, try if it understands -faddress-sanitizer (clang until version 3.2)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -faddress-sanitizer")
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FASAN_SUPPORTED)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
if(FLAG_FASAN_SUPPORTED)
set(asan_flag "-faddress-sanitizer")
endif(FLAG_FASAN_SUPPORTED)
endif(FLAG_FSANA_SUPPORTED)
if(FLAG_FSANA_SUPPORTED OR FLAG_FASAN_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${asan_flag}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${asan_flag}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${asan_flag}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${asan_flag}")
endif()
endif(USE_ASAN)
+212 -5
View File
@@ -28,10 +28,7 @@ All components have a platform indicator next to them:
Ox provides ```ox::Error``` to report errors. Ox provides ```ox::Error``` to report errors.
```ox::Error``` is a struct that has overloaded operators to behave like an ```ox::Error``` is a struct that has overloaded operators to behave like an
integer error code, plus some extra fields to enhance debuggability. integer error code, plus some extra fields to enhance debuggability.
If instantiated through the ```OxError(x)``` macro, it will also include the ```ox::Error```s will also include the file and line of the error.
file and line of the error.
The ```OxError(x)``` macro should only be used for the initial instantiation of
an ```ox::Error```.
In addition to ```ox::Error``` there is also the template ```ox::Result<T>```. In addition to ```ox::Error``` there is also the template ```ox::Result<T>```.
```ox::Result``` simply wraps the type T value in a struct that also includes ```ox::Result``` simply wraps the type T value in a struct that also includes
@@ -49,7 +46,7 @@ ox::Result<int> foo(int i) noexcept {
if (i < 10) { if (i < 10) {
return i + 1; // implicitly calls ox::Result<T>::Result(T) return i + 1; // implicitly calls ox::Result<T>::Result(T)
} }
return OxError(1); // implicitly calls ox::Result<T>::Result(ox::Error) return ox::Error(1); // implicitly calls ox::Result<T>::Result(ox::Error)
} }
int caller1() { int caller1() {
@@ -181,6 +178,216 @@ variant for creating a non-const value.
* ```OX_REQUIRE_M``` - OX_REQUIRE Mutable * ```OX_REQUIRE_M``` - OX_REQUIRE Mutable
### Ox String Types
Ox has six different major string types.
These types are divided into two categories: store types and view types.
String stores maintain a copy of the string data, whereas view types only
maintain a reference to the data.
Views should be used where you otherwise might use a const reference to a
string store type.
Having all of these different string types may sound like an interoperability
nightmare, but taking string view types extensively where applicable makes the
imagined interoperability issues virtually non-existent.
#### String Store Types
##### String / BasicString
```ox::String```, or really ```ox::BasicString```, is Ox's version of
```std::string```.
Like ```std::string```, ```String``` allocates to store the string data.
Also like ```std::string```, ```String``` allows for small string
optimization for strings under 8 bytes.
Unlike ```std::string```, the template that ```String``` is based on,
```BasicString```, takes a parameter that allows adjusting to different size
small string buffers.
```ox::String``` is an alias to ```ox::BasicString<8>```.
```cpp
// s can hold up to 100 bytes, plus one for a null terminator before allocating
ox::BasicString<100> s;
```
Also unlike ```std::string```, ```ox::String``` has an explicit C-string conversion
constructor.
This prevents accidental instantiations of ```String```.
Consider the following:
```cpp
void fStd(std::string const&);
void fOx(ox::String const&);
int main() {
// implicit and silent instantiation of std::string, which includes an
// allocation
fStd("123456789");
// Will fail to compile:
fOx("123456789");
// But explicit String instantiation will work:
fOx(ox::String{"123456789"});
}
```
##### IString
```IString```, or "inline string", is like ```BasicString```, but it will cut
off strings that exceed that limit.
```cpp
ox::IString<5> s; // s can hold up to 5 characters, plus a null terminator
s = "12345"; // valid
s = "123456"; // will compile and run, but will get cut off at '5'
```
This is useful for certain string categories that have fixed lengths, like UUID
strings or for numbers.
Ox makes use of ```IString``` in the following ways:
```cpp
using UUIDStr = ox::IString<36>;
// and
template<Integer_c Integer>
[[nodiscard]]
constexpr auto intToStr(Integer v) noexcept {
constexpr auto Cap = [] {
auto out = 0;
switch (sizeof(Integer)) {
case 1:
out = 3;
break;
case 2:
out = 5;
break;
case 4:
out = 10;
break;
case 8:
out = 21;
break;
}
return out + ox::is_signed_v<Integer>;
}();
ox::IString<Cap> out;
std::ignore = out.resize(out.cap());
ox::CharBuffWriter w{{out.data(), out.cap()}};
std::ignore = writeItoa(v, w);
std::ignore = out.resize(w.tellp());
return out;
}
```
##### StringParam
```StringParam``` is a weird type.
Because ```String::String(const char*)``` is explicit, it becomes a pain for
functions to take ```String```s.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::String p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // invalid - will not compile
Type t2{s}; // invalid - will not compile
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
```StringParam``` has implicit conversion constructors, and will appropriately
move from r-value ```String```s or create a ```String``` if not passed
ownership of an existing ```String```.
Think of ```StringParam``` as a way to opt-in to implicit instantiation with
strings.
```StringParam``` can access the string as a view through the ```view()```
function, and the ```String``` inside can be accessed by moving from the
```StringParam```.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::StringParam p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // valid
Type t2{s}; // valid
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
#### String View Types
##### StringView
```ox::StringView``` is Ox's version of ```std::string_view```.
```StringView``` contains a pointer to a string, along with its size.
This should be the normal type taken when a function needs a string that will
exist until it returns.
##### CStringView
```CStringView``` is like ```StringView```, but it comes with the promise that
the string ends with a null terminator.
Accordingly, it has a ```c_str()``` function in addition to the ```data()```
function that ```StringView``` has.
```CStringView``` should be used when wrapping a C API that only takes C
strings.
##### StringLiteral
```StringLiteral``` is a string view type, but it kind of straddles the line
between view and store types.
Creating a ```StringLiteral``` is a promise that you are passing a string
literal into the constructor.
This means you can treat it like a store, that can be safely used as a copy of
the data.
Functions that take ```StringLiteral```s are allowed to assume that the data
will have no lifetime concerns and hold onto it without any need to make a
copy.
It has a consteval constructor to enforce the promise that it is a compile time
string.
```cpp
void f(ox::StringLiteral const&);
int main() {
f("123456789"); // valid
f(ox::String{"123456789"}.c_str()); // invalid - will not compile
}
```
#### Other Variants
There are a few convenience aliases as well.
* StringCR = String const&
* StringViewCR = StringView const&
* CStringViewCR = CStringView const&
* CString = const char*
String views do not generally need const references, but it does make debugging
easier, as we can skip the constructor call if a string view already exists.
These kind of aliases probably should not exist for most types, but strings are
fundamental and ease of use is desirable.
### Logging and Output ### Logging and Output
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros. Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.
-8
View File
@@ -1,8 +0,0 @@
#! /usr/bin/env bash
set -e
make -j release
make -j debug
make -j
make -j test
-8
View File
@@ -1,8 +0,0 @@
#! /usr/bin/env bash
set -e
for f in $(find $1 -maxdepth 1 -mindepth 1 -type d)
do
cmake --build "$f" --target $2 --
done
-34
View File
@@ -1,34 +0,0 @@
#! /usr/bin/env bash
set -e
project=$(pwd)/
TARGET=$1
BUILD_TYPE=$2
if [[ $TARGET == windows ]]; then
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/Mingw.cmake"
elif [[ $TARGET == gba ]]; then
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/GBA.cmake -DOX_USE_STDLIB=OFF -DCMAKE_INSTALL_PREFIX=$DEVKITARM"
fi
if [[ $BUILD_TYPE == asan ]]; then
buildTypeArgs="-DUSE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug"
buildDir="build/${TARGET}-asan"
elif [[ $BUILD_TYPE == debug ]]; then
buildTypeArgs="-DCMAKE_BUILD_TYPE=Debug"
buildDir="build/${TARGET}-debug"
else
buildTypeArgs="-DCMAKE_BUILD_TYPE=Release"
buildDir="build/${TARGET}-release"
fi
mkdir -p $buildDir
pushd $buildDir
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-GNinja \
$buildTypeArgs \
$toolchain \
$project
popd
+27 -1
View File
@@ -1 +1,27 @@
add_subdirectory(ox) if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(OX_OS_WINDOWS TRUE)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(OX_OS_FREEBSD TRUE)
else()
set(OX_OS_FREEBSD FALSE)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(OX_OS_LINUX TRUE)
else()
set(OX_OS_LINUX FALSE)
endif()
if(OX_USE_STDLIB)
add_subdirectory(oc)
endif()
add_subdirectory(clargs)
add_subdirectory(claw)
add_subdirectory(event)
add_subdirectory(fs)
add_subdirectory(logconn)
add_subdirectory(mc)
add_subdirectory(model)
add_subdirectory(preloader)
add_subdirectory(std)
@@ -7,7 +7,7 @@ endif()
add_library( add_library(
OxClArgs OxClArgs
clargs.cpp src/clargs.cpp
) )
set_property( set_property(
@@ -27,11 +27,16 @@ target_link_libraries(
OxStd OxStd
) )
target_include_directories(
OxClArgs PUBLIC
include
)
install( install(
FILES DIRECTORY
clargs.hpp include/ox
DESTINATION DESTINATION
include/ox/clargs include
) )
install( install(
@@ -7,7 +7,7 @@
*/ */
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include "clargs.hpp" #include <ox/clargs/clargs.hpp>
namespace ox { namespace ox {
@@ -1,8 +1,8 @@
add_library( add_library(
OxClaw OxClaw
read.cpp src/read.cpp
write.cpp src/write.cpp
) )
if(NOT MSVC) if(NOT MSVC)
@@ -27,7 +27,20 @@ target_link_libraries(
# ) # )
#endif() #endif()
install(TARGETS OxClaw target_include_directories(
OxClaw PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxClaw
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
) )
@@ -52,8 +52,7 @@ Error readClaw(ox::BufferView buff, T &val) {
{ {
ox::BufferReader br({header.data, header.dataSize}); ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br); MetalClawReader reader(br);
ModelHandlerInterface handler(&reader); return model(reader.interface(), &val);
return model(&handler, &val);
} }
case ClawFormat::Organic: case ClawFormat::Organic:
{ {
@@ -8,11 +8,11 @@
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include "read.hpp" #include <ox/claw/read.hpp>
namespace ox { namespace ox {
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept { Result<StringView> readClawTypeId(BufferView const buff) noexcept {
auto buffRaw = buff.data(); auto buffRaw = buff.data();
auto buffLen = buff.size(); auto buffLen = buff.size();
size_t outSz{}; size_t outSz{};
@@ -43,7 +43,7 @@ ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
return {{buff.data() + fmtSz, outSz - fmtSz - 1}}; return {{buff.data() + fmtSz, outSz - fmtSz - 1}};
} }
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept { Result<ClawHeader> readClawHeader(BufferView const buff) noexcept {
auto buffRaw = buff.data(); auto buffRaw = buff.data();
auto buffLen = buff.size(); auto buffLen = buff.size();
const auto s1End = ox::strchr(buffRaw, ';', buffLen); const auto s1End = ox::strchr(buffRaw, ';', buffLen);
@@ -87,7 +87,7 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
return hdr; return hdr;
} }
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept { Result<BufferView> stripClawHeader(BufferView const buff) noexcept {
OX_REQUIRE(header, readClawHeader(buff)); OX_REQUIRE(header, readClawHeader(buff));
return {{header.data, header.dataSize}}; return {{header.data, header.dataSize}};
} }
@@ -106,15 +106,14 @@ Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
{ {
ox::BufferReader br({header.data, header.dataSize}); ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br); MetalClawReader reader(br);
ModelHandlerInterface handler(&reader); OX_RETURN_ERROR(model(reader.interface(), &obj));
OX_RETURN_ERROR(model(&handler, &obj));
return obj; return obj;
} }
case ClawFormat::Organic: case ClawFormat::Organic:
{ {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
OrganicClawReader reader({header.data, header.dataSize}); OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(&reader); ModelHandlerInterface handler(reader);
OX_RETURN_ERROR(model(&handler, &obj)); OX_RETURN_ERROR(model(&handler, &obj));
return obj; return obj;
#else #else
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "write.hpp" #include <ox/claw/write.hpp>
namespace ox::detail { namespace ox::detail {
@@ -135,7 +135,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf"); constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3"); constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1})); OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
oxExpect(actual, expected); ox::expect(actual, expected);
return ox::Error{}; return ox::Error{};
} }
}, },
+51
View File
@@ -0,0 +1,51 @@
add_library(
OxEvent
src/signal.cpp
)
if(NOT MSVC)
target_compile_options(OxEvent PRIVATE -Wsign-conversion)
target_compile_options(OxEvent PRIVATE -Wconversion)
endif()
if(NOT OX_BARE_METAL)
set_property(
TARGET
OxEvent
PROPERTY
POSITION_INDEPENDENT_CODE ON
)
endif()
target_compile_definitions(
OxEvent PUBLIC
$<$<BOOL:${OX_USE_STDLIB}>:OX_USE_STDLIB>
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
)
target_link_libraries(
OxEvent PUBLIC
OxStd
)
target_include_directories(
OxEvent PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxEvent
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
add_subdirectory(test)
endif()
@@ -122,7 +122,7 @@ class Signal {
} }
}; };
mutable Vector<UniquePtr<BaseSlot>> m_slots; mutable Vector<UPtr<BaseSlot>> m_slots;
public: public:
~Signal() noexcept; ~Signal() noexcept;
@@ -303,7 +303,7 @@ class Signal<Error(Args...)> {
} }
}; };
mutable Vector<UniquePtr<BaseSlot>> m_slots; mutable Vector<UPtr<BaseSlot>> m_slots;
public: public:
~Signal() noexcept; ~Signal() noexcept;
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "signal.hpp" #include <ox/event/signal.hpp>
namespace ox { namespace ox {
@@ -5,14 +5,12 @@ endif()
add_library( add_library(
OxFS OxFS
ptrarith/nodebuffer.hpp src/filestore/filestoretemplate.cpp
ptrarith/ptr.hpp src/filesystem/filelocation.cpp
filestore/filestoretemplate.cpp src/filesystem/pathiterator.cpp
filesystem/filelocation.cpp src/filesystem/directory.cpp
filesystem/pathiterator.cpp src/filesystem/filesystem.cpp
filesystem/directory.cpp src/filesystem/passthroughfs.cpp
filesystem/filesystem.cpp
filesystem/passthroughfs.cpp
) )
if(NOT MSVC) if(NOT MSVC)
@@ -33,10 +31,22 @@ target_link_libraries(
OxMetalClaw OxMetalClaw
) )
target_include_directories(
OxFS PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
if(NOT OX_BARE_METAL) if(NOT OX_BARE_METAL)
add_executable( add_executable(
oxfs-tool oxfs-tool
tool.cpp src/tool.cpp
) )
target_link_libraries( target_link_libraries(
@@ -52,29 +62,6 @@ if(NOT OX_BARE_METAL)
) )
endif() endif()
install(
FILES
filestore/filestoretemplate.hpp
DESTINATION
include/ox/fs/filestore
)
install(
FILES
filesystem/filesystem.hpp
filesystem/pathiterator.hpp
DESTINATION
include/ox/fs/filesystem
)
install(
FILES
ptrarith/nodebuffer.hpp
ptrarith/ptr.hpp
DESTINATION
include/ox/fs/ptrarith
)
install( install(
TARGETS TARGETS
OxFS OxFS
@@ -87,7 +87,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile); return writeFilePath(path, buffer, size, FileType::NormalFile);
} }
Error write(StringViewCR path, ox::Span<char> const&buff) noexcept { Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile); return write(path, buff.data(), buff.size(), FileType::NormalFile);
} }
@@ -95,7 +95,7 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile); return write(inode, buffer, size, FileType::NormalFile);
} }
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept { Error write(uint64_t inode, ox::SpanView<char> const&buff) noexcept {
return write(inode, buff.data(), buff.size(), FileType::NormalFile); return write(inode, buff.data(), buff.size(), FileType::NormalFile);
} }
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "filestoretemplate.hpp" #include <ox/fs/filestore/filestoretemplate.hpp>
namespace ox { namespace ox {
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "directory.hpp" #include <ox/fs/filesystem/directory.hpp>
namespace ox { namespace ox {
@@ -8,7 +8,7 @@
#include <ox/model/modelops.hpp> #include <ox/model/modelops.hpp>
#include "filelocation.hpp" #include <ox/fs/filesystem/filelocation.hpp>
namespace ox { namespace ox {
@@ -9,7 +9,7 @@
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/utility.hpp> #include <ox/std/utility.hpp>
#include "filesystem.hpp" #include <ox/fs/filesystem/filesystem.hpp>
namespace ox { namespace ox {
@@ -8,7 +8,7 @@
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include "passthroughfs.hpp" #include <ox/fs/filesystem/passthroughfs.hpp>
#if defined(OX_HAS_PASSTHROUGHFS) #if defined(OX_HAS_PASSTHROUGHFS)
@@ -9,7 +9,7 @@
#include <ox/std/memops.hpp> #include <ox/std/memops.hpp>
#include <ox/std/strops.hpp> #include <ox/std/strops.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include "pathiterator.hpp" #include <ox/fs/filesystem/pathiterator.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage) OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
+1 -1
View File
@@ -34,7 +34,7 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
} }
} }
static ox::Result<ox::UniquePtr<ox::FileSystem>> loadFs(const char *path) noexcept { static ox::Result<ox::UPtr<ox::FileSystem>> loadFs(const char *path) noexcept {
OX_REQUIRE(buff, loadFsBuff(path)); OX_REQUIRE(buff, loadFsBuff(path));
return {ox::make_unique<ox::FileSystem32>(buff.data, buff.size)}; return {ox::make_unique<ox::FileSystem32>(buff.data, buff.size)};
} }
@@ -74,9 +74,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
ox::PathIterator it(path); ox::PathIterator it(path);
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error"); oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "usr"); ox::expect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error"); oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "share"); ox::expect(buff, "share");
return ox::Error(0); return ox::Error(0);
} }
}, },
@@ -175,8 +175,8 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen); auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed."); oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
ox::FileStore32 fileStore(list, buffLen); ox::FileStore32 fileStore(list, buffLen);
oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed."); oxAssert(fileStore.write(4, str1, str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed."); oxAssert(fileStore.write(5, str2, str2Len, 1), "FileStore::write 2 failed.");
char str1Read[str1Len]; char str1Read[str1Len];
size_t str1ReadSize = 0; size_t str1ReadSize = 0;
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
add_library( add_library(
OxLogConn OxLogConn
logconn.cpp src/logconn.cpp
) )
set_property( set_property(
@@ -24,12 +24,16 @@ target_link_libraries(
$<$<BOOL:${OX_OS_WINDOWS}>:ws2_32> $<$<BOOL:${OX_OS_WINDOWS}>:ws2_32>
) )
target_include_directories(
OxLogConn PUBLIC
include
)
install( install(
FILES DIRECTORY
circularbuff.hpp include/ox
logconn.hpp
DESTINATION DESTINATION
include/ox/logconn include
) )
install( install(
@@ -23,7 +23,7 @@
#endif #endif
#include "logconn.hpp" #include <ox/logconn/logconn.hpp>
namespace ox { namespace ox {
@@ -1,8 +1,7 @@
add_library( add_library(
OxMetalClaw OxMetalClaw
presenceindicator.cpp src/read.cpp
read.cpp src/write.cpp
write.cpp
) )
if(NOT MSVC) if(NOT MSVC)
@@ -25,20 +24,20 @@ if(NOT OX_BARE_METAL)
) )
endif() endif()
install( target_include_directories(
FILES OxMetalClaw PUBLIC
intops.hpp include
err.hpp
mc.hpp
presenceindicator.hpp
read.hpp
types.hpp
write.hpp
DESTINATION
include/ox/mc
) )
install(TARGETS OxMetalClaw install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxMetalClaw
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
) )
@@ -18,25 +18,25 @@
namespace ox::mc { namespace ox::mc {
template<typename T> template<Integer_c T>
static constexpr auto Bits = sizeof(T) << 3; static constexpr auto Bits = sizeof(T) << 3;
/** /**
* Returns highest bit other than possible signed bit. * Returns highest bit other than possible signed bit.
* Bit numbering starts at 0. * Bit numbering starts at 0.
*/ */
template<typename I> template<Integer_c I>
[[nodiscard]] [[nodiscard]]
constexpr std::size_t highestBit(I val) noexcept { constexpr size_t highestBit(I const val) noexcept {
unsigned shiftStart = sizeof(I) * 8 - 1; unsigned shiftStart = sizeof(I) * 8 - 1;
// find most significant non-sign indicator bit // find the most significant non-sign indicator bit
std::size_t highestBit = 0; size_t highestBit = 0;
// start at one bit lower if signed // start at one bit lower if signed
if constexpr(is_signed_v<I>) { if constexpr(is_signed_v<I>) {
--shiftStart; --shiftStart;
} }
for (auto i = shiftStart; i > 0; --i) { for (auto i = shiftStart; i > 0; --i) {
const auto bitValue = (val >> i) & 1; auto const bitValue = (val >> i) & 1;
if (bitValue) { if (bitValue) {
highestBit = i; highestBit = i;
break; break;
@@ -45,7 +45,7 @@ constexpr std::size_t highestBit(I val) noexcept {
return highestBit; return highestBit;
} }
static_assert(highestBit(int8_t(0b10000000)) == 0); static_assert(highestBit(static_cast<int8_t>(0b10000000)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-1)) == 0); static_assert(highestBit(~static_cast<int8_t>(-1)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-2)) == 0); static_assert(highestBit(~static_cast<int8_t>(-2)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-3)) == 1); static_assert(highestBit(~static_cast<int8_t>(-3)) == 1);
@@ -53,42 +53,39 @@ static_assert(highestBit(1) == 0);
static_assert(highestBit(2) == 1); static_assert(highestBit(2) == 1);
static_assert(highestBit(4) == 2); static_assert(highestBit(4) == 2);
static_assert(highestBit(8) == 3); static_assert(highestBit(8) == 3);
static_assert(highestBit(uint64_t(1) << 31) == 31); static_assert(highestBit(static_cast<uint64_t>(1) << 31) == 31);
static_assert(highestBit(uint64_t(1) << 63) == 63); static_assert(highestBit(static_cast<uint64_t>(1) << 63) == 63);
struct McInt { struct McInt {
ox::Array<uint8_t, 9> data{}; Array<uint8_t, 9> data{};
// length of integer in bytes // length of integer in bytes
std::size_t length = 0; size_t length = 0;
}; };
template<typename I> template<Integer_c I>
[[nodiscard]] [[nodiscard]]
constexpr McInt encodeInteger(I pInput) noexcept { constexpr McInt encodeInteger(I const pInput) noexcept {
auto const input = ox::ResizedInt_t<I, 64>{pInput}; auto const input = ResizedInt_t<I, 64>{pInput};
McInt out; McInt out;
const auto inputNegative = is_signed_v<I> && input < 0; auto const inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid // move input to uint64_t to allow consistent bit manipulation and to avoid
// overflow concerns // overflow concerns
uint64_t val = 0; auto const val = std::bit_cast<uint64_t>(input);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&val, &input, sizeof(input));
OX_ALLOW_UNSAFE_BUFFERS_END
if (val) { if (val) {
// bits needed to represent number factoring in space possibly // bits needed to represent number factoring in space possibly
// needed for signed bit // needed for signed bit
const auto highBit = inputNegative ? highestBit(~val) : highestBit(val); auto const highBit = inputNegative ? highestBit(~val) : highestBit(val);
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0); auto const bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
// bytes needed to store value // bytes needed to store value
std::size_t bytes = bits / 8 + (bits % 8 != 0); size_t bytes = bits / 8 + (bits % 8 != 0);
const auto bitsAvailable = bytes * 8; // bits available to integer value auto const bitsAvailable = bytes * 8; // bits available to integer value
const auto bitsNeeded = bits + bytes; auto const bitsNeeded = bits + bytes;
// factor in bits needed for bytesIndicator (does not affect bytesIndicator) // factor in bits needed for bytesIndicator (does not affect bytesIndicator)
// bits for integer + bits needed to represent bytes > bits available // bits for integer + bits needed to represent bytes > bits available
if (bitsNeeded > bitsAvailable && bytes != 9) { if (bitsNeeded > bitsAvailable && bytes != 9) {
++bytes; ++bytes;
} }
const auto bytesIndicator = onMask<uint8_t>(bytes - 1); auto const bytesIndicator = onMask<uint8_t>(bytes - 1);
// ensure we are copying from little endian representation // ensure we are copying from little endian representation
LittleEndian<uint64_t> leVal = val; LittleEndian<uint64_t> leVal = val;
if (inputNegative) { if (inputNegative) {
@@ -103,9 +100,9 @@ constexpr McInt encodeInteger(I pInput) noexcept {
out.data[1] |= 0b1000'0000; out.data[1] |= 0b1000'0000;
} }
} else { } else {
const auto valBits = bytes * 8; auto const valBits = bytes * 8;
uint64_t negBit = inputNegative ? 1 : 0; uint64_t const negBit = inputNegative ? 1 : 0;
auto intermediate = auto const intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes | static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator); static_cast<uint64_t>(bytesIndicator);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
@@ -122,8 +119,8 @@ constexpr McInt encodeInteger(I pInput) noexcept {
* length integer. * length integer.
*/ */
[[nodiscard]] [[nodiscard]]
constexpr std::size_t countBytes(unsigned b) noexcept { constexpr size_t countBytes(unsigned const b) noexcept {
std::size_t i = 0; size_t i = 0;
while ((b >> i) & 1) ++i; while ((b >> i) & 1) ++i;
return i + 1; return i + 1;
} }
@@ -138,39 +135,39 @@ static_assert(countBytes(0b0011'1111) == 7);
static_assert(countBytes(0b0111'1111) == 8); static_assert(countBytes(0b0111'1111) == 8);
static_assert(countBytes(0b1111'1111) == 9); static_assert(countBytes(0b1111'1111) == 9);
template<typename I> template<Integer_c I>
constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept { constexpr Result<I> decodeInteger(Reader_c auto &rdr, size_t &bytesRead) noexcept {
uint8_t firstByte = 0; uint8_t firstByte = 0;
OX_RETURN_ERROR(rdr.read(&firstByte, 1)); OX_RETURN_ERROR(rdr.read(&firstByte, 1));
OX_RETURN_ERROR(rdr.seekg(-1, ox::ios_base::cur)); OX_RETURN_ERROR(rdr.seekg(-1, ox::ios_base::cur));
const auto bytes = countBytes(firstByte); auto const bytes = countBytes(firstByte);
if (bytes == 9) { if (bytes == 9) {
*bytesRead = bytes; bytesRead = bytes;
I out = 0; I out = 0;
OX_RETURN_ERROR(rdr.seekg(1, ox::ios_base::cur)); OX_RETURN_ERROR(rdr.seekg(1, ox::ios_base::cur));
OX_RETURN_ERROR(rdr.read(&out, sizeof(I))); OX_RETURN_ERROR(rdr.read(&out, sizeof(I)));
return fromLittleEndian<I>(out); return fromLittleEndian<I>(out);
} }
*bytesRead = bytes; bytesRead = bytes;
uint64_t decoded = 0; uint64_t decoded = 0;
OX_RETURN_ERROR(rdr.read(&decoded, bytes)); OX_RETURN_ERROR(rdr.read(&decoded, bytes));
decoded >>= bytes; decoded >>= bytes;
// move sign bit // move sign bit
if constexpr(is_signed_v<I>) { if constexpr(is_signed_v<I>) {
const auto negBit = bytes * 8 - bytes - 1; auto const negBit = bytes * 8 - bytes - 1;
// move sign // move sign
const auto negative = (decoded >> negBit) == 1; auto const negative = (decoded >> negBit) == 1;
if (negative) { if (negative) {
// fill in all bits between encoded sign and real sign with 1s // fill in all bits between encoded sign and real sign with 1s
// split it up because the 32-bit ARM can't shift more than 32 bits // split it up because the 32-bit ARM can't shift more than 32 bits
ox::Array<uint32_t, 2> d = {}; Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff; //d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32; //d[1] = decoded >> 32;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&d[0], &decoded, sizeof(decoded)); ox::memcpy(&d[0], &decoded, sizeof(decoded));
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
auto bit = negBit; auto bit = negBit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) { for (; bit < ox::min<size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit; d[0] |= 1 << bit;
} }
bit -= 32; bit -= 32;
@@ -179,7 +176,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
} }
I out = 0; I out = 0;
if constexpr(ox::defines::BigEndian) { if constexpr(ox::defines::BigEndian) {
const auto d0Tmp = d[0]; auto const d0Tmp = d[0];
d[0] = d[1]; d[0] = d[1];
d[1] = d0Tmp; d[1] = d0Tmp;
} }
@@ -192,11 +189,11 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
return static_cast<I>(decoded); return static_cast<I>(decoded);
} }
template<typename I> template<Integer_c I>
Result<I> decodeInteger(McInt m) noexcept { Result<I> decodeInteger(McInt const &m) noexcept {
std::size_t bytesRead{}; size_t bytesRead{};
BufferReader br({reinterpret_cast<const char*>(m.data.data()), 9}); BufferReader br({reinterpret_cast<const char*>(m.data.data()), 9});
return decodeInteger<I>(br, &bytesRead); return decodeInteger<I>(br, bytesRead);
} }
} }
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/array.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/span.hpp>
#include <ox/std/types.hpp>
#include <ox/std/reader.hpp>
#include "err.hpp"
namespace ox {
template<Reader_c Reader>
class FieldBitmapReader {
protected:
mutable size_t m_mapBlockIdx = ~size_t{};
mutable uint64_t m_mapBlock{};
size_t m_mapStart{};
Reader &m_reader;
public:
explicit constexpr FieldBitmapReader(Reader &reader) noexcept:
m_mapStart(reader.tellg()),
m_reader(reader) {
}
constexpr Result<bool> get(size_t idx) const noexcept {
constexpr auto blockBits = sizeof(m_mapBlock);
auto const blockIdx = idx / blockBits;
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
OX_RETURN_ERROR(loadMapBlock(blockIdx));
}
idx %= blockBits;
return (m_mapBlock >> idx) & 1;
}
private:
constexpr Error loadMapBlock(size_t const idx) const noexcept {
OX_REQUIRE(g, m_reader.tellg());
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
Array<char, sizeof(m_mapBlock)> mapBlock{};
OX_RETURN_ERROR(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
// Warning: narrow-conv
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
m_mapBlock = 0;
for (uint64_t i{}; auto b : mapBlock) {
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
i += 8;
}
m_mapBlockIdx = idx;
return {};
}
};
class FieldBitmapWriter {
protected:
Span<char> m_map;
size_t m_mapLen{};
public:
explicit constexpr FieldBitmapWriter(Span<char> const &map) noexcept:
m_map(map),
m_mapLen(m_map.size()) {
}
constexpr auto setBuffer(Span<char> const &map) noexcept {
m_map = map;
m_mapLen = map.size();
}
constexpr Result<bool> get(size_t const i) const noexcept {
if (i / 8 < m_mapLen) {
return (std::bit_cast<uint8_t>(m_map[i / 8]) >> (i % 8)) & 1;
}
return Error{McPresenceMapOverflow};
}
constexpr Error setFields(int const fields) noexcept {
m_mapLen = static_cast<size_t>((fields / 8 + 1) - (fields % 8 == 0));
if (m_mapLen > m_map.size()) [[unlikely]] {
return Error{McPresenceMapOverflow};
}
return {};
}
constexpr void setMaxLen(int const maxLen) noexcept {
m_mapLen = static_cast<size_t>(maxLen);
}
constexpr int64_t getMaxLen() const noexcept {
return static_cast<int64_t>(m_mapLen);
}
constexpr Error set(size_t const i, bool const on) noexcept {
if (i / 8 < m_mapLen) {
char &actual = m_map[i / 8];
uint8_t v = std::bit_cast<uint8_t>(actual);
if (on) {
v |= 1 << (i % 8);
} else {
v &= ~static_cast<uint8_t>(1 << (i % 8));
}
actual = std::bit_cast<char>(v);
return {};
}
return Error{McPresenceMapOverflow};
}
};
}
@@ -32,58 +32,58 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
private: private:
FieldBitmapReader<Reader> m_fieldPresence; FieldBitmapReader<Reader> m_fieldPresence;
std::size_t m_fields = 0; size_t m_fields{};
std::size_t m_field = 0; size_t m_field{};
ox::Optional<int> m_unionIdx; Optional<int> const m_unionIdx{};
Reader &m_reader; Reader &m_reader;
public: public:
explicit constexpr MetalClawReaderTemplate( explicit constexpr MetalClawReaderTemplate(
Reader &reader, Reader &reader,
ox::Optional<int> const&unionIdx = {}) noexcept; Optional<int> const &unionIdx = {}) noexcept;
constexpr ~MetalClawReaderTemplate() noexcept; constexpr ~MetalClawReaderTemplate() noexcept;
constexpr Error field(const char*, int8_t *val) noexcept; constexpr Error field(CString, int8_t *val) noexcept;
constexpr Error field(const char*, int16_t *val) noexcept; constexpr Error field(CString, int16_t *val) noexcept;
constexpr Error field(const char*, int32_t *val) noexcept; constexpr Error field(CString, int32_t *val) noexcept;
constexpr Error field(const char*, int64_t *val) noexcept; constexpr Error field(CString, int64_t *val) noexcept;
constexpr Error field(const char*, uint8_t *val) noexcept; constexpr Error field(CString, uint8_t *val) noexcept;
constexpr Error field(const char*, uint16_t *val) noexcept; constexpr Error field(CString, uint16_t *val) noexcept;
constexpr Error field(const char*, uint32_t *val) noexcept; constexpr Error field(CString, uint32_t *val) noexcept;
constexpr Error field(const char*, uint64_t *val) noexcept; constexpr Error field(CString, uint64_t *val) noexcept;
constexpr Error field(const char*, bool *val) noexcept; constexpr Error field(CString, bool *val) noexcept;
// array handler // array handler
constexpr Error field(const char*, auto *val, std::size_t len) noexcept; constexpr Error field(CString, auto *val, size_t valLen) noexcept;
// map handler // map handler
template<typename T> template<typename T>
constexpr Error field(const char*, HashMap<String, T> *val) noexcept; constexpr Error field(CString, HashMap<String, T> *val) noexcept;
// array handler, with callback to allow handling individual elements // array handler, with callback to allow handling individual elements
template<typename T, typename CB> template<typename T, typename CB>
constexpr Error field(const char*, CB cb) noexcept; constexpr Error field(CString, CB cb) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char*, T *val) noexcept; constexpr Error field(CString, T *val) noexcept;
template<typename U, bool force> template<typename U, bool force>
constexpr Error field(const char*, UnionView<U, force> val) noexcept; constexpr Error field(CString, UnionView<U, force> val) noexcept;
template<std::size_t SmallStringSize> template<size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept; constexpr Error field(CString, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L> template<size_t L>
constexpr Error field(const char*, IString<L> *val) noexcept; constexpr Error field(CString, IString<L> *val) noexcept;
constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept; constexpr Error fieldCString(CString, char *val, size_t buffLen) noexcept;
constexpr Error fieldCString(const char*, char **val) noexcept; constexpr Error fieldCString(CString, char **val) noexcept;
constexpr Error fieldCString(const char*, char **val, std::size_t buffLen) noexcept; constexpr Error fieldCString(CString, char **val, size_t buffLen) noexcept;
/** /**
* Reads an array length from the current location in the buffer. * Reads an array length from the current location in the buffer.
@@ -101,13 +101,13 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
const char *name = T::TypeName, const char *name = T::TypeName,
int version = T::TypeVersion, int version = T::TypeVersion,
const Vector<String>& = {}, const Vector<String>& = {},
std::size_t fields = ModelFieldCount_v<T>) noexcept; size_t fields = ModelFieldCount_v<T>) noexcept;
/** /**
* Returns a MetalClawReader to parse a child object. * Returns a MetalClawReader to parse a child object.
*/ */
[[nodiscard]] [[nodiscard]]
constexpr MetalClawReaderTemplate<Reader> child(const char *name, ox::Optional<int> unionIdx = {}) noexcept; constexpr MetalClawReaderTemplate<Reader> child(const char *name, Optional<int> unionIdx = {}) noexcept;
/** /**
* Indicates whether or not the next field to be read is present. * Indicates whether or not the next field to be read is present.
@@ -122,20 +122,20 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
constexpr bool fieldPresent(int fieldNo) const noexcept; constexpr bool fieldPresent(int fieldNo) const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr int whichFieldPresent(const char *name, const ModelUnion&) const noexcept; constexpr int whichFieldPresent(const char *name, ModelUnion const&) const noexcept;
constexpr void nextField() noexcept; constexpr void nextField() noexcept;
private: private:
template<typename I> template<typename I>
constexpr Error readInteger(I *val) noexcept; constexpr Error readInteger(I &val) noexcept;
}; };
template<Reader_c Reader> template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate( constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
Reader &reader, Reader &reader,
ox::Optional<int> const&unionIdx) noexcept: Optional<int> const &unionIdx) noexcept:
m_fieldPresence(reader), m_fieldPresence(reader),
m_unionIdx(unionIdx), m_unionIdx(unionIdx),
m_reader(reader) { m_reader(reader) {
@@ -149,50 +149,50 @@ constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int8_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int16_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int32_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int64_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint8_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint16_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint32_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint64_t *val) noexcept {
return readInteger(val); return readInteger(*val);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field)); auto const result = m_fieldPresence.get(static_cast<size_t>(m_field));
*val = result.value; *val = result.value;
OX_RETURN_ERROR(result); OX_RETURN_ERROR(result);
} }
@@ -202,18 +202,19 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) n
// array handler // array handler
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { const char *name, auto *val, size_t const valLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead)); OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
// read the list // read the list
if (valLen >= len) { if (valLen >= len) {
auto reader = child({}); auto reader = child({});
auto &handler = *reader.interface(); auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len))); OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (std::size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field({}, &val[i])); OX_RETURN_ERROR(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
@@ -230,18 +231,18 @@ OX_ALLOW_UNSAFE_BUFFERS_END
template<Reader_c Reader> template<Reader_c Reader>
template<typename T> template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, HashMap<String, T> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
OX_REQUIRE(g, m_reader.tellg()); OX_REQUIRE(g, m_reader.tellg());
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead)); OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
OX_RETURN_ERROR(m_reader.seekg(g)); OX_RETURN_ERROR(m_reader.seekg(g));
// read the list // read the list
auto reader = child(""); auto reader = child("");
auto &handler = *reader.interface(); auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len))); OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
// this loop body needs to be in a lambda because of the potential alloca call // this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto &val) { constexpr auto loopBody = [](auto &handler, auto &val) {
OX_REQUIRE(keyLen, handler.stringLength(nullptr)); OX_REQUIRE(keyLen, handler.stringLength(nullptr));
@@ -250,7 +251,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<Stri
OX_RETURN_ERROR(handler.fieldCString("", &wkeyPtr, keyLen + 1)); OX_RETURN_ERROR(handler.fieldCString("", &wkeyPtr, keyLen + 1));
return handler.field("", &val[wkeyPtr]); return handler.field("", &val[wkeyPtr]);
}; };
for (std::size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(loopBody(handler, *val)); OX_RETURN_ERROR(loopBody(handler, *val));
} }
} }
@@ -263,9 +264,9 @@ template<Reader_c Reader>
template<typename T> template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
if constexpr(isVector_v<T>) { if constexpr(isVector_v<T>) {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
// set size of val if the field is present, don't worry about it if not // set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
OX_REQUIRE(len, arrayLength(name, false)); OX_REQUIRE(len, arrayLength(name, false));
OX_RETURN_ERROR(ox::resizeVector(*val, len)); OX_RETURN_ERROR(ox::resizeVector(*val, len));
return field(name, val->data(), val->size()); return field(name, val->data(), val->size());
@@ -275,9 +276,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
++m_field; ++m_field;
return {}; return {};
} else if constexpr(isArray_v<T>) { } else if constexpr(isArray_v<T>) {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
// set size of val if the field is present, don't worry about it if not // set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
OX_REQUIRE(len, arrayLength(name, false)); OX_REQUIRE(len, arrayLength(name, false));
if (len > val->size()) { if (len > val->size()) {
return ox::Error(1, "Input array is too long"); return ox::Error(1, "Input array is too long");
@@ -288,8 +289,8 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
++m_field; ++m_field;
return {}; return {};
} else { } else {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val) { if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
auto reader = child(""); auto reader = child("");
OX_RETURN_ERROR(model(reader.interface(), val)); OX_RETURN_ERROR(model(reader.interface(), val));
} }
@@ -301,9 +302,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
template<Reader_c Reader> template<Reader_c Reader>
template<typename U, bool force> template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) { if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx())); auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
OX_RETURN_ERROR(model(reader.interface(), val.get())); OX_RETURN_ERROR(model(reader.interface(), val.get()));
} }
@@ -313,13 +314,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U,
} }
template<Reader_c Reader> template<Reader_c Reader>
template<std::size_t SmallStringSize> template<size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, BasicString<SmallStringSize> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead)); OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
const auto cap = size; const auto cap = size;
*val = BasicString<SmallStringSize>(cap); *val = BasicString<SmallStringSize>(cap);
auto data = val->data(); auto data = val->data();
@@ -334,13 +335,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
} }
template<Reader_c Reader> template<Reader_c Reader>
template<std::size_t L> template<size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, IString<L> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead)); OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
*val = IString<L>(); *val = IString<L>();
OX_RETURN_ERROR(val->resize(size)); OX_RETURN_ERROR(val->resize(size));
auto const data = val->data(); auto const data = val->data();
@@ -355,11 +356,12 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { CString, char *val, size_t const buffLen) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead)); OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
if (size > buffLen) { if (size > buffLen) {
return ox::Error(McOutputBuffEnded); return ox::Error(McOutputBuffEnded);
} }
@@ -374,11 +376,11 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead)); OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
// re-allocate in case too small // re-allocate in case too small
safeDelete(*val); safeDelete(*val);
*val = new char[size + 1]; *val = new char[size + 1];
@@ -392,12 +394,12 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val, size_t buffLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead)); OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
// re-allocate if too small // re-allocate if too small
if (buffLen < size + 1) { if (buffLen < size + 1) {
safeDelete(*val); safeDelete(*val);
@@ -420,13 +422,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept { constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(CString, bool const pass) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(g, m_reader.tellg()); OX_REQUIRE(g, m_reader.tellg());
OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead)); OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
if (!pass) { if (!pass) {
OX_RETURN_ERROR(m_reader.seekg(g)); OX_RETURN_ERROR(m_reader.seekg(g));
} }
@@ -437,12 +439,12 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept { constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(CString) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, &bytesRead); auto len = mc::decodeInteger<StringLength>(m_reader, bytesRead);
OX_RETURN_ERROR(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur)); OX_RETURN_ERROR(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur));
return len; return len;
} }
@@ -452,15 +454,15 @@ constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(con
template<Reader_c Reader> template<Reader_c Reader>
template<typename I> template<typename I>
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I &val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
std::size_t bytesRead = 0; size_t bytesRead = 0;
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead); auto const result = mc::decodeInteger<I>(m_reader, bytesRead);
OX_RETURN_ERROR(result); OX_RETURN_ERROR(result);
*val = result.value; val = result.value;
} else { } else {
*val = 0; val = 0;
} }
} }
++m_field; ++m_field;
@@ -469,17 +471,17 @@ constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
template<Reader_c Reader> template<Reader_c Reader>
template<typename T, typename CB> template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(CString, CB cb) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length // read the length
std::size_t bytesRead = 0; size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead)); OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
// read the list // read the list
auto reader = child(""); auto reader = child("");
auto &handler = *reader.interface(); auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len))); OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (std::size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
T val; T val;
OX_RETURN_ERROR(handler.field("", &val)); OX_RETURN_ERROR(handler.field("", &val));
OX_RETURN_ERROR(cb(i, &val)); OX_RETURN_ERROR(cb(i, &val));
@@ -493,7 +495,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexc
template<Reader_c Reader> template<Reader_c Reader>
template<typename T> template<typename T>
constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo( constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
const char*, int, const Vector<String>&, std::size_t fields) noexcept { CString, int, const Vector<String>&, size_t const fields) noexcept {
m_fields = fields; m_fields = fields;
// Warning: narrow-conv // Warning: narrow-conv
return m_reader.seekg( return m_reader.seekg(
@@ -503,24 +505,24 @@ constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
template<Reader_c Reader> template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child( constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
const char*, CString,
ox::Optional<int> unionIdx) noexcept { Optional<int> const unionIdx) noexcept {
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx); return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(const char*) const noexcept { constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(CString) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value; return m_fieldPresence.get(static_cast<size_t>(m_field)).value;
} }
template<Reader_c Reader> template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept { constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int const fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value; return m_fieldPresence.get(static_cast<size_t>(fieldNo)).value;
} }
template<Reader_c Reader> template<Reader_c Reader>
[[nodiscard]] [[nodiscard]]
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept { constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(CString, ModelUnion const &u) const noexcept {
FieldBitmapReader<Reader> p(m_reader); FieldBitmapReader<Reader> p(m_reader);
for (auto i = 0u; i < u.fieldCount(); ++i) { for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) { if (p.get(i)) {
@@ -538,11 +540,10 @@ constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>; using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
template<typename T> template<typename T>
Error readMC(ox::BufferView buff, T &val) noexcept { Error readMC(ox::BufferView const buff, T &val) noexcept {
BufferReader br(buff); BufferReader br(buff);
MetalClawReader reader(br); MetalClawReader reader(br);
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader); return model(reader.interface(), &val);
return model(&handler, &val);
} }
template<typename T> template<typename T>
+401
View File
@@ -0,0 +1,401 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/optional.hpp>
#include <ox/std/string.hpp>
#include <ox/std/types.hpp>
#include <ox/std/units.hpp>
#include "intops.hpp"
#include "err.hpp"
#include "presenceindicator.hpp"
#include "types.hpp"
namespace ox {
template<Writer_c Writer>
class MetalClawWriter: public ModelHandlerBase<MetalClawWriter<Writer>, OpType::Write> {
private:
Vector<char, 16> m_presenceMapBuff{};
FieldBitmapWriter m_fieldPresence{m_presenceMapBuff};
int m_field{};
Optional<int> m_unionIdx;
size_t m_writerBeginP{};
Writer &m_writer;
public:
constexpr explicit MetalClawWriter(Writer &writer, Optional<int> const &unionIdx = {}) noexcept;
constexpr ~MetalClawWriter() noexcept = default;
constexpr Error field(CString, int8_t const *val) noexcept;
constexpr Error field(CString, int16_t const *val) noexcept;
constexpr Error field(CString, int32_t const *val) noexcept;
constexpr Error field(CString, int64_t const *val) noexcept;
constexpr Error field(CString, uint8_t const *val) noexcept;
constexpr Error field(CString, uint16_t const *val) noexcept;
constexpr Error field(CString, uint32_t const *val) noexcept;
constexpr Error field(CString, uint64_t const *val) noexcept;
constexpr Error field(CString, bool const *val) noexcept;
template<typename T>
constexpr Error field(CString, T const *val, size_t len) noexcept;
template<typename T>
constexpr Error field(CString name, HashMap<String, T> const *val) noexcept;
template<size_t SmallStringSize>
constexpr Error field(CString, BasicString<SmallStringSize> const *val) noexcept;
template<size_t L>
constexpr Error field(CString, IString<L> const *val) noexcept;
constexpr Error fieldCString(CString name, CString const*val, size_t buffLen) noexcept;
constexpr Error fieldCString(CString name, CString *val) noexcept;
constexpr Error fieldCString(CString name, CString const*val) noexcept;
constexpr Error fieldCString(CString name, CString val, size_t strLen) noexcept;
template<typename T>
constexpr Error field(CString, T const *val) noexcept;
template<typename U, bool force = false>
constexpr Error field(CString, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t>
constexpr Error setTypeInfo(
CString name = T::TypeName,
int version = T::TypeVersion,
Vector<String> const& = {},
size_t fields = ModelFieldCount_v<T>) noexcept;
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto stringLength(CString) noexcept {
return 0;
}
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto arrayLength(CString, bool = true) noexcept {
return 0;
}
constexpr Error finalize() noexcept;
private:
constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(mi.data.data()), mi.length));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
};
extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
template<Writer_c Writer>
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, Optional<int> const &unionIdx) noexcept:
m_unionIdx(unionIdx),
m_writerBeginP(writer.tellp()),
m_writer(writer) {
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int8_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int16_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int32_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int64_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint8_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint16_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint32_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint64_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, bool const *val) noexcept {
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), *val));
}
++m_field;
return {};
}
template<Writer_c Writer>
template<size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(CString, BasicString<SmallStringSize> const *val) noexcept {
bool fieldSet = false;
if (val->size() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const strLen = mc::encodeInteger(val->size());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLen.data.data()), strLen.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<size_t>(val->size())));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<size_t L>
constexpr Error MetalClawWriter<Writer>::field(CString name, IString<L> const *val) noexcept {
return fieldCString(name, val->data(), val->size());
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const *val, size_t) noexcept {
bool fieldSet = false;
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
// this strlen is tolerated because sometimes 0 gets passed to
// the size param, which is a lie
// this code should be cleaned up at some point...
auto const strLen = *val ? ox::strlen(*val) : 0;
OX_ALLOW_UNSAFE_BUFFERS_END
// write the length
auto const strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
// write the string
OX_RETURN_ERROR(m_writer.write(*val, static_cast<size_t>(strLen)));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString *val) noexcept {
return fieldCString(name, val, {});
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString const *val) noexcept {
return fieldCString(name, val, {});
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const val, size_t const strLen) noexcept {
bool fieldSet = false;
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val, static_cast<size_t>(strLen)));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(nullptr, val->data(), val->size());
} else {
bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer);
OX_RETURN_ERROR(model(writer.interface(), val));
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
}
template<Writer_c Writer>
template<typename U, bool force>
constexpr Error MetalClawWriter<Writer>::field(CString, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer, Optional<int>(in_place, val.idx()));
OX_RETURN_ERROR(model(writer.interface(), val.get()));
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val, size_t const len) noexcept {
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer);
OX_RETURN_ERROR(writer.interface()->template setTypeInfo<T>("List", 0, {}, static_cast<size_t>(len)));
// write the array
for (size_t i{}; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(writer.interface()->field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, HashMap<String, T> const *val) noexcept {
auto const &keys = val->keys();
auto const len = keys.size();
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
// write map
MetalClawWriter writer(m_writer);
// double len for both key and value
OX_RETURN_ERROR(writer.interface()->setTypeInfo("Map", 0, {}, len * 2));
// this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto const &key, auto const &val) -> Error {
auto const keyLen = key.size();
auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1);
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));
OX_REQUIRE_M(value, val.at(key));
return handler.field("", value);
};
// write the array
for (size_t i{}; i < len; ++i) {
auto const &key = keys[i];
OX_RETURN_ERROR(loopBody(*writer.interface(), key, *val));
}
OX_RETURN_ERROR(writer.finalize());
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::setTypeInfo(
CString,
int,
Vector<String> const&,
size_t const fields) noexcept {
auto const fieldPresenceLen = (fields - 1) / 8 + 1;
OX_RETURN_ERROR(m_writer.write(nullptr, fieldPresenceLen));
m_presenceMapBuff.resize(fieldPresenceLen);
m_fieldPresence.setBuffer(m_presenceMapBuff);
return m_fieldPresence.setFields(static_cast<int>(fields));
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::finalize() noexcept {
auto const end = m_writer.tellp();
OX_RETURN_ERROR(m_writer.seekp(m_writerBeginP));
OX_RETURN_ERROR(m_writer.write(
m_presenceMapBuff.data(),
m_presenceMapBuff.size()));
OX_RETURN_ERROR(m_writer.seekp(end));
return {};
}
Result<Buffer> writeMC(Writer_c auto &writer, auto const &val) noexcept {
MetalClawWriter mcWriter(writer);
OX_RETURN_ERROR(model(mcWriter.interface(), &val));
OX_RETURN_ERROR(mcWriter.finalize());
return {};
}
Result<Buffer> writeMC(auto const &val, size_t const buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0);
OX_RETURN_ERROR(writeMC(bw, val));
buff.resize(bw.tellp());
return buff;
}
Error writeMC(char *buff, size_t const buffLen, auto const &val, size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw{{buff, buffLen}};
OX_RETURN_ERROR(writeMC(bw, val));
if (sizeOut) {
*sizeOut = bw.tellp();
}
return {};
}
}
+1 -1
View File
@@ -10,7 +10,7 @@
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include <ox/std/reader.hpp> #include <ox/std/reader.hpp>
#include "read.hpp" #include <ox/mc/read.hpp>
namespace ox { namespace ox {
@@ -11,7 +11,7 @@
#include <ox/std/memops.hpp> #include <ox/std/memops.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include "write.hpp" #include <ox/mc/write.hpp>
namespace ox { namespace ox {
@@ -157,8 +157,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch"); oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch"); oxAssert(testIn.String == testOut.String, "String value mismatch");
oxDebugf("{}", testOut.IString.size()); ox::expect(testIn.IString, testOut.IString);
oxExpect(testIn.IString, testOut.IString);
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch"); oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch"); oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
+45
View File
@@ -0,0 +1,45 @@
add_library(
OxModel
src/desctypes.cpp
src/descwrite.cpp
src/modelvalue.cpp
)
if(NOT MSVC)
target_compile_options(OxModel PRIVATE -Wconversion)
target_compile_options(OxModel PRIVATE -Wsign-conversion)
endif()
target_link_libraries(
OxModel PUBLIC
OxStd
)
if(NOT OX_BARE_METAL)
set_property(
TARGET
OxModel
PROPERTY
POSITION_INDEPENDENT_CODE ON
)
endif()
target_link_libraries(
OxModel PUBLIC
OxStd
)
target_include_directories(
OxModel PUBLIC
include
)
install(
TARGETS OxModel
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
add_subdirectory(test)
endif()
@@ -0,0 +1,7 @@
<Type> : <TypeName><FieldList>
<FieldList> : <FieldList> | <FieldList><Field>
<Field> : <FieldType><TypeID><FieldName>
<TypeID> : <TypeName> | <TypeName><Type>
<TypeName> : <string>
<FieldType> : <0: single> | <1: list>
<FieldName> : <string>
@@ -51,7 +51,7 @@ constexpr auto buildSubscriptStack(const T**, SubscriptStack *s) noexcept {
} }
template<typename T> template<typename T>
constexpr auto buildSubscriptStack(const UniquePtr<T>*, SubscriptStack *s) noexcept { constexpr auto buildSubscriptStack(const UPtr<T>*, SubscriptStack *s) noexcept {
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr}); s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
} }
@@ -187,7 +187,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
PrimitiveType pt; PrimitiveType pt;
if constexpr(is_union_v<T>) { if constexpr(is_union_v<T>) {
pt = PrimitiveType::Union; pt = PrimitiveType::Union;
} else if constexpr(isBasicString_v<T> || isBString_v<T>) { } else if constexpr(isBasicString_v<T> || isIString_v<T>) {
pt = PrimitiveType::String; pt = PrimitiveType::String;
} else { } else {
pt = PrimitiveType::Struct; pt = PrimitiveType::Struct;
@@ -357,7 +357,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
template<std::size_t sz> template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept { constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String; constexpr auto PT = PrimitiveType::String;
return getType(types::BString, 0, PT, 0); return getType(types::IString, 0, PT, 0);
} }
constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typeVersion, PrimitiveType pt, int b, constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typeVersion, PrimitiveType pt, int b,
@@ -380,7 +380,7 @@ constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typ
template<typename T> template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
TypeDescWriter writer(&typeStore); TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer); ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
std::allocator<T> a; std::allocator<T> a;
T *t = a.allocate(1); T *t = a.allocate(1);
@@ -396,7 +396,7 @@ constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
template<typename T> template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept {
TypeDescWriter writer(&typeStore); TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer); ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
OX_RETURN_ERROR(model(&handler, &val)); OX_RETURN_ERROR(model(&handler, &val));
return writer.definition(); return writer.definition();
} }
@@ -0,0 +1,243 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/utility.hpp>
#include "modelvalue.hpp"
namespace ox {
template<typename Handler, OpType opType_v = Handler::opType()>
class ModelHandlerInterface {
private:
Handler &m_handler;
public:
constexpr explicit ModelHandlerInterface(Handler &handler) noexcept: m_handler(handler) {
}
template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo(
CString name = T::TypeName,
int version = T::TypeVersion,
Vector<String> const &typeParams = {}) noexcept {
return m_handler.template setTypeInfo<T>(name, version, typeParams, ModelFieldCount_v<T>);
}
template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo(
CString name,
int version,
Vector<String> const &typeParams,
size_t fields) noexcept {
return m_handler.template setTypeInfo<T>(name, version, typeParams, fields);
}
template<size_t len>
constexpr Error fieldCString(CString name, char val[len]) noexcept {
return m_handler.fieldCString(name, &val[0], len);
}
template<size_t len>
constexpr Error fieldCString(CString name, char const val[len]) noexcept requires(opType_v != OpType::Read) {
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, &val[0], len);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char **val) noexcept {
return m_handler.fieldCString(name, val);
}
constexpr Error fieldCString(CString name, char const *const*val) noexcept requires(opType_v != OpType::Read) {
// this check looks pointless, but it's to address a Clang bug
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, val);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char const **val) noexcept requires(opType_v != OpType::Read) {
// this check looks pointless, but it's to address a Clang bug
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, val);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char **val, size_t buffLen) noexcept {
return m_handler.fieldCString(name, val, buffLen);
}
constexpr Error fieldCString(CString name, char const **val, size_t buffLen) noexcept requires(opType_v != OpType::Read) {
// this check looks pointless, but it's to address a Clang bug
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, val, buffLen);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char *val, size_t buffLen) noexcept {
return m_handler.fieldCString(name, val, buffLen);
}
constexpr Error fieldModelValue(char const *name, CommonPtrWith<ModelValue> auto *v) noexcept {
switch (v->type()) {
case ModelValue::Type::Undefined:
break;
case ModelValue::Type::Bool:
return m_handler.field(name, &v->template get<bool>());
case ModelValue::Type::UnsignedInteger8:
return m_handler.field(name, &v->template get<uint8_t>());
case ModelValue::Type::UnsignedInteger16:
return m_handler.field(name, &v->template get<uint16_t>());
case ModelValue::Type::UnsignedInteger32:
return m_handler.field(name, &v->template get<uint32_t>());
case ModelValue::Type::UnsignedInteger64:
return m_handler.field(name, &v->template get<uint64_t>());
case ModelValue::Type::SignedInteger8:
return m_handler.field(name, &v->template get<int8_t>());
case ModelValue::Type::SignedInteger16:
return m_handler.field(name, &v->template get<int16_t>());
case ModelValue::Type::SignedInteger32:
return m_handler.field(name, &v->template get<int32_t>());
case ModelValue::Type::SignedInteger64:
return m_handler.field(name, &v->template get<int64_t>());
case ModelValue::Type::String:
return m_handler.field(name, &v->template get<String>());
case ModelValue::Type::Object:
return m_handler.field(name, &v->template get<ModelObject>());
case ModelValue::Type::Union:
{
auto &u = v->template get<ModelUnion>();
if constexpr(opType_v == OpType::Read) {
u.setActiveField(whichFieldPresent(m_handler, name, u));
return m_handler.field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
} else {
return m_handler.field(name, UnionView<ModelUnion const, true>(&u, u.unionIdx()));
}
}
case ModelValue::Type::Vector:
return m_handler.field(name, &v->template get<ModelValueVector>());
case ModelValue::Type::InlineArray:
return m_handler.field(name, &v->template get<ModelValueArray>());
}
oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type()));
ox::panic("invalid type");
return ox::Error(1, "invalid type");
}
// array handler, with callback to allow handling individual elements
template<typename T, typename Callback>
constexpr Error field(CString name, Callback cb) noexcept {
return m_handler.template field<T, Callback>(name, cb);
}
template<typename T>
constexpr Error field(CString name, const T *v) noexcept {
if constexpr(ox::is_same_v<T, ModelValue>) {
return fieldModelValue(name, v);
} else {
return m_handler.field(name, v);
}
}
template<typename T>
constexpr Error field(CString name, T *v) noexcept {
if constexpr(ox::is_same_v<T, ModelValue>) {
return fieldModelValue(name, v);
} else {
return m_handler.field(name, v);
}
}
template<typename U, bool force = false>
constexpr Error field(CString name, UnionView<U, force> val) noexcept {
return m_handler.field(name, val);
}
constexpr Error field(CString name, auto *val, size_t len) noexcept {
return m_handler.field(name, val, len);
}
/**
* Reads an array length from the current location in the buffer.
* @param name
* @param pass indicates that the parsing should iterate past the array length
*/
[[nodiscard]]
constexpr auto arrayLength(CString name, bool pass = true) noexcept {
return m_handler.arrayLength(name, pass);
}
/**
* Reads an string length from the current location in the buffer.
*/
[[nodiscard]]
constexpr auto stringLength(CString name) noexcept {
return m_handler.stringLength(name);
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return Handler::opType();
}
[[nodiscard]]
constexpr auto handler() noexcept {
return m_handler;
}
private:
template<typename H>
static constexpr int whichFieldPresent(H &h, CString name, ModelUnion const &u) noexcept
requires(H::opType() == OpType::Read) {
return h.whichFieldPresent(name, u);
}
template<typename H>
static constexpr int whichFieldPresent(H&, CString, ModelUnion const&) noexcept
requires(H::opType() != OpType::Read) {
return 0;
}
};
template<typename Handler, OpType opType_v = Handler::opType()>
class ModelHandlerBase {
private:
ModelHandlerInterface<Handler, opType_v> m_interface{*static_cast<Handler*>(this)};
public:
[[nodiscard]]
constexpr auto interface() noexcept {
return &m_interface;
}
[[nodiscard]]
static constexpr OpType opType() noexcept {
return opType_v;
}
};
constexpr ox::Error resizeVector(auto &vec, size_t sz) {
if constexpr(ox::is_same_v<decltype(vec.resize(0)), ox::Error>) {
return vec.resize(sz);
} else {
vec.resize(sz);
return {};
}
}
}
@@ -100,7 +100,7 @@ class ModelValue {
return Type::Union; return Type::Union;
} else if constexpr(is_same_v<U, ModelObject>) { } else if constexpr(is_same_v<U, ModelObject>) {
return Type::Object; return Type::Object;
} else if constexpr(isBasicString_v<U> || isBString_v<U>) { } else if constexpr(isBasicString_v<U> || isIString_v<U>) {
return Type::String; return Type::String;
} else if constexpr(is_same_v<U, ModelValueVector>) { } else if constexpr(is_same_v<U, ModelValueVector>) {
return Type::Vector; return Type::Vector;
@@ -168,7 +168,7 @@ class ModelValue {
constexpr const auto &get() const noexcept { constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
oxPanic(ox::Error(1), "invalid cast"); ox::panic("invalid cast");
} }
return getValue<type>(*this); return getValue<type>(*this);
} }
@@ -178,7 +178,7 @@ class ModelValue {
constexpr auto &get() noexcept { constexpr auto &get() noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
oxPanic(ox::Error(1), "invalid cast"); ox::panic("invalid cast");
} }
return getValue<type>(*this); return getValue<type>(*this);
} }
@@ -200,8 +200,6 @@ class ModelValue {
template<typename T> template<typename T>
constexpr Error set(T &&v) noexcept; constexpr Error set(T &&v) noexcept;
constexpr ModelValue &operator=(ModelValue &val) noexcept;
constexpr ModelValue &operator=(const ModelValue &val) noexcept; constexpr ModelValue &operator=(const ModelValue &val) noexcept;
constexpr ModelValue &operator=(ModelValue &&val) noexcept; constexpr ModelValue &operator=(ModelValue &&val) noexcept;
@@ -521,7 +519,7 @@ class ModelObject {
protected: protected:
OX_MODEL_FRIEND(ModelObject); OX_MODEL_FRIEND(ModelObject);
friend ModelValue; friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder; Vector<UPtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields; HashMap<String, ModelValue*> m_fields;
const DescriptorType *m_type = nullptr; const DescriptorType *m_type = nullptr;
@@ -694,7 +692,7 @@ class ModelUnion {
}; };
friend constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept; friend constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept;
friend ModelValue; friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder; Vector<UPtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields; HashMap<String, Field*> m_fields;
const DescriptorType *m_type = nullptr; const DescriptorType *m_type = nullptr;
int m_unionIdx = -1; int m_unionIdx = -1;
@@ -720,14 +718,14 @@ class ModelUnion {
m_unionIdx = other.m_unionIdx; m_unionIdx = other.m_unionIdx;
} }
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept { static constexpr Result<UPtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UniquePtr<ModelUnion> out(new ModelUnion); UPtr<ModelUnion> out(new ModelUnion);
OX_RETURN_ERROR(out->setType(type)); OX_RETURN_ERROR(out->setType(type));
return out; return out;
} }
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept { static constexpr Result<UPtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UniquePtr<ModelUnion>(new ModelUnion(other)); return UPtr<ModelUnion>(new ModelUnion(other));
} }
constexpr ox::Result<ModelValue*> at(StringView const&k) noexcept { constexpr ox::Result<ModelValue*> at(StringView const&k) noexcept {
@@ -1098,7 +1096,7 @@ constexpr Error ModelValue::setType(
} else if (type->typeName == types::Bool) { } else if (type->typeName == types::Bool) {
m_type = Type::Bool; m_type = Type::Bool;
} else if (type->typeName == types::BasicString || } else if (type->typeName == types::BasicString ||
type->typeName == types::BString || type->typeName == types::IString ||
type->typeName == types::String) { type->typeName == types::String) {
m_type = Type::String; m_type = Type::String;
m_data.str = new String; m_data.str = new String;
@@ -1176,7 +1174,7 @@ template<typename T>
constexpr Error ModelValue::set(const T &v) noexcept { constexpr Error ModelValue::set(const T &v) noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
return ox::Error(1, "type mismatch"); return Error(1, "type mismatch");
} }
auto &value = getValue<type>(*this); auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object || if constexpr(type == Type::Vector || type == Type::Object ||
@@ -1202,10 +1200,6 @@ constexpr Error ModelValue::set(T &&v) noexcept {
return {}; return {};
} }
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
return this->operator=(const_cast<const ModelValue&>(other));
}
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept { constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
if (this == &other) [[unlikely]] { if (this == &other) [[unlikely]] {
return *this; return *this;
@@ -17,76 +17,34 @@
namespace ox { namespace ox {
struct TypeNameCatcher {
const char *name = "";
int version = 0;
constexpr TypeNameCatcher() noexcept = default;
template<typename T>
constexpr ox::Error setTypeInfo(
const char *n = T::TypeName,
int v = T::TypeVersion,
const Vector<String>& = {},
std::size_t = ModelFieldCount_v<T>) noexcept {
this->name = n;
this->version = v;
return {};
}
template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept {
return {};
}
template<typename T>
constexpr Error field(const char*, T) noexcept {
return {};
}
template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept {
return {};
}
static constexpr auto opType() noexcept {
return OpType::Reflect;
}
};
struct TypeInfoCatcher { struct TypeInfoCatcher {
const char *name = ""; CString name = "";
int version = 0; int version = 0;
constexpr TypeInfoCatcher() noexcept = default;
template<typename T = std::nullptr_t> template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo( constexpr Error setTypeInfo(
const char *n = T::TypeName, CString const n = T::TypeName,
int v = T::TypeVersion, int const v = T::TypeVersion,
const Vector<String>& = {}, Vector<String> const& = {},
std::size_t = 0) noexcept { size_t = 0) noexcept {
this->name = n; this->name = n;
this->version = v; this->version = v;
return {}; return {};
} }
template<typename T> template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept { constexpr Error field(CString, T*, size_t) noexcept {
return {}; return {};
} }
template<typename T> template<typename T>
constexpr Error field(const char*, T) noexcept { constexpr Error field(CString, T const&) noexcept {
return {}; return {};
} }
template<typename T> template<typename T>
constexpr Error fieldCString(const char*, T) noexcept { constexpr Error fieldCString(CString, T const&) noexcept {
return {}; return {};
} }
@@ -125,14 +83,14 @@ consteval int requireModelTypeVersion() noexcept {
template<typename T, typename Str = const char*> template<typename T, typename Str = const char*>
[[nodiscard]] [[nodiscard]]
constexpr Str getModelTypeName(T *val) noexcept { constexpr Str getModelTypeName(T *val) noexcept {
TypeNameCatcher nc; TypeInfoCatcher nc;
std::ignore = model(&nc, val); std::ignore = model(&nc, val);
return nc.name; return nc.name;
} }
template<typename T, typename Str = const char*> template<typename T, typename Str = const char*>
[[nodiscard]] [[nodiscard]]
constexpr Str getModelTypeName() noexcept { consteval Str getModelTypeName() noexcept {
std::allocator<T> a; std::allocator<T> a;
auto t = a.allocate(1); auto t = a.allocate(1);
auto out = getModelTypeName(t); auto out = getModelTypeName(t);
@@ -140,15 +98,15 @@ constexpr Str getModelTypeName() noexcept {
return out; return out;
} }
template<typename T, typename Str = const char*> template<typename T, typename Str = StringLiteral>
[[nodiscard]] [[nodiscard]]
consteval auto requireModelTypeName() noexcept { consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T, Str>(); constexpr auto name = getModelTypeName<T, Str>();
static_assert(ox::StringView{name}.size(), "Type lacks required TypeName"); static_assert(StringView{name}.size(), "Type lacks required TypeName");
return name; return name;
} }
template<typename T, typename Str = const char*> template<typename T, typename Str = StringLiteral>
constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>(); constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
template<typename T, typename Str = const char*> template<typename T, typename Str = const char*>
@@ -156,10 +114,10 @@ constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
template<typename T> template<typename T>
constexpr auto ModelTypeId_v = [] { constexpr auto ModelTypeId_v = [] {
constexpr auto name = ModelTypeName_v<T, ox::StringView>; constexpr auto name = ModelTypeName_v<T, StringView>;
constexpr auto version = ModelTypeVersion_v<T>; constexpr auto version = ModelTypeVersion_v<T>;
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version); constexpr auto versionStr = ox::sfmt<IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr); return ox::sfmt<IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
}(); }();
} }
@@ -31,18 +31,18 @@
namespace ox { namespace ox {
namespace types { namespace types {
constexpr StringView BasicString = "net.drinkingtea.ox.BasicString"; constexpr StringLiteral BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringView BString = "net.drinkingtea.ox.BString"; constexpr StringLiteral IString = "net.drinkingtea.ox.IString";
constexpr StringView String = "B.string"; constexpr StringLiteral String = "B.string";
constexpr StringView Bool = "B.bool"; constexpr StringLiteral Bool = "B.bool";
constexpr StringView Uint8 = "B.uint8"; constexpr StringLiteral Uint8 = "B.uint8";
constexpr StringView Uint16 = "B.uint16"; constexpr StringLiteral Uint16 = "B.uint16";
constexpr StringView Uint32 = "B.uint32"; constexpr StringLiteral Uint32 = "B.uint32";
constexpr StringView Uint64 = "B.uint64"; constexpr StringLiteral Uint64 = "B.uint64";
constexpr StringView Int8 = "B.int8"; constexpr StringLiteral Int8 = "B.int8";
constexpr StringView Int16 = "B.int16"; constexpr StringLiteral Int16 = "B.int16";
constexpr StringView Int32 = "B.int32"; constexpr StringLiteral Int32 = "B.int32";
constexpr StringView Int64 = "B.int64"; constexpr StringLiteral Int64 = "B.int64";
} }
template<typename T> template<typename T>
@@ -63,17 +63,17 @@ static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>); static_assert(isBasicString_v<ox::String>);
template<typename T> template<typename T>
consteval bool isBString(const T*) noexcept { consteval bool isIString(const T*) noexcept {
return false; return false;
} }
template<std::size_t SmallVecSize> template<std::size_t SmallVecSize>
consteval bool isBString(const BasicString<SmallVecSize>*) noexcept { consteval bool isIString(const BasicString<SmallVecSize>*) noexcept {
return true; return true;
} }
template<typename T> template<typename T>
constexpr bool isBString_v = isBasicString(static_cast<const T*>(nullptr)); constexpr bool isIString_v = isIString(static_cast<const T*>(nullptr));
static_assert(isBasicString_v<ox::BasicString<0ul>>); static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>); static_assert(isBasicString_v<ox::BasicString<8ul>>);
@@ -161,7 +161,7 @@ template<typename T>
constexpr bool isSmartPtr_v = false; constexpr bool isSmartPtr_v = false;
template<typename T> template<typename T>
constexpr bool isSmartPtr_v<::ox::UniquePtr<T>> = true; constexpr bool isSmartPtr_v<::ox::UPtr<T>> = true;
#if __has_include(<array>) #if __has_include(<array>)
template<typename T> template<typename T>
@@ -169,12 +169,12 @@ constexpr bool isSmartPtr_v<::std::unique_ptr<T>> = true;
#endif #endif
template<typename Union, bool force = false> template<typename Union, bool force = false> requires(force || is_union_v<Union>)
class UnionView { class UnionView {
protected: protected:
int m_idx = -1; int m_idx = -1;
typename enable_if<is_union_v<Union> || force, Union>::type *m_union = nullptr; Union *m_union = nullptr;
public: public:
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) { constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
@@ -21,7 +21,7 @@ namespace ox {
class TypeStore { class TypeStore {
private: private:
HashMap<String, UniquePtr<DescriptorType>> m_cache; HashMap<String, UPtr<DescriptorType>> m_cache;
public: public:
constexpr TypeStore() noexcept = default; constexpr TypeStore() noexcept = default;
@@ -86,12 +86,12 @@ class TypeStore {
return getLoad(typeName, typeVersion); return getLoad(typeName, typeVersion);
} }
constexpr void set(const auto &typeId, UniquePtr<DescriptorType> dt) noexcept { constexpr void set(const auto &typeId, UPtr<DescriptorType> dt) noexcept {
m_cache[typeId] = std::move(dt); m_cache[typeId] = std::move(dt);
} }
constexpr void set(const auto &typeId, DescriptorType *dt) noexcept { constexpr void set(const auto &typeId, DescriptorType *dt) noexcept {
m_cache[typeId] = UniquePtr<DescriptorType>(dt); m_cache[typeId] = UPtr<DescriptorType>(dt);
} }
[[nodiscard]] [[nodiscard]]
@@ -105,11 +105,11 @@ class TypeStore {
} }
protected: protected:
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept { virtual Result<UPtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
return ox::Error(1); return ox::Error(1);
} }
Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringViewCR name, int version, Result<UPtr<DescriptorType>> loadDescriptor(ox::StringViewCR name, int version,
const ox::TypeParamPack &typeParams) noexcept { const ox::TypeParamPack &typeParams) noexcept {
const auto typeId = buildTypeId(name, version, typeParams); const auto typeId = buildTypeId(name, version, typeParams);
return loadDescriptor(typeId); return loadDescriptor(typeId);
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "desctypes.hpp" #include <ox/model/desctypes.hpp>
namespace ox { namespace ox {
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "descwrite.hpp" #include <ox/model/descwrite.hpp>
namespace ox { namespace ox {

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