Compare commits

...

50 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
243 changed files with 2907 additions and 2794 deletions
+14 -1
View File
@@ -1,7 +1,7 @@
BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore
BUILDCORE_PATH=deps/ox/deps/buildcore
include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin)
@@ -13,6 +13,19 @@ else
endif
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
pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
-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/*-debug
build/*-release
.current_build
tags
compile_commands.json
conanbuildinfo.cmake
conanbuildinfo.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)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
include(address_sanitizer)
include(deps/buildcore/base.cmake)
if(NOT DEFINED OX_RUN_TESTS)
set(OX_RUN_TESTS ON)
@@ -78,6 +78,13 @@ include_directories(src)
install(FILES OxConfig.cmake DESTINATION lib/cmake/ox)
install(
DIRECTORY
include/ox
DESTINATION
include
)
if(OX_USE_STDLIB)
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
add_subdirectory(deps/jsoncpp)
+15 -65
View File
@@ -1,68 +1,18 @@
OS=$(shell uname | tr [:upper:] [:lower:])
HOST_ENV=${OS}-$(shell uname -m)
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
DEVENV_IMAGE=wombatant/devenv
ifneq ($(shell which docker 2>&1),)
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
BC_VAR_PROJECT_NAME=ox
BC_VAR_PROJECT_NAME_CAP=Ox
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk
all:
${ENV_RUN} ./scripts/run-make build
preinstall:
${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
.PHONY: git-setup-buildcore-remote
git-setup-buildcore-remote:
git remote add -f buildcore-master git@git.drinkingtea.net:drinkingtea/buildcore.git
devenv:
docker pull ${DEVENV_IMAGE}
docker run -d -v $(shell pwd):/usr/src/project \
-e LOCAL_USER_ID=$(shell id -u ${USER}) \
--name ${DEVENV} -t ${DEVENV_IMAGE} bash
devenv-destroy:
docker rm -f ${DEVENV}
devenv-shell:
${ENV_RUN} bash
.PHONY: git-pull-buildcore
git-pull-buildcore:
git fetch buildcore-master master
git subtree pull --prefix deps/buildcore buildcore-master master --squash
configure-release:
${ENV_RUN} rm -rf build/${HOST_ENV}-release
${ENV_RUN} ./scripts/setup_build ${HOST_ENV}
${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
.PHONY: git-push-buildcore
git-push-buildcore:
git subtree push --prefix=deps/buildcore buildcore-master master
-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)
-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(
OxClArgs
clargs.cpp
src/clargs.cpp
)
set_property(
@@ -27,11 +27,16 @@ target_link_libraries(
OxStd
)
target_include_directories(
OxClArgs PUBLIC
include
)
install(
FILES
clargs.hpp
DIRECTORY
include/ox
DESTINATION
include/ox/clargs
include
)
install(
@@ -7,7 +7,7 @@
*/
#include <ox/std/string.hpp>
#include "clargs.hpp"
#include <ox/clargs/clargs.hpp>
namespace ox {
@@ -1,8 +1,8 @@
add_library(
OxClaw
read.cpp
write.cpp
src/read.cpp
src/write.cpp
)
if(NOT MSVC)
@@ -27,9 +27,22 @@ target_link_libraries(
# )
#endif()
install(TARGETS OxClaw
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
target_include_directories(
OxClaw PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxClaw
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
@@ -52,8 +52,7 @@ Error readClaw(ox::BufferView buff, T &val) {
{
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader);
return model(&handler, &val);
return model(reader.interface(), &val);
}
case ClawFormat::Organic:
{
@@ -8,11 +8,11 @@
#include <ox/std/buffer.hpp>
#include "read.hpp"
#include <ox/claw/read.hpp>
namespace ox {
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
Result<StringView> readClawTypeId(BufferView const buff) noexcept {
auto buffRaw = buff.data();
auto buffLen = buff.size();
size_t outSz{};
@@ -43,7 +43,7 @@ ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
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 buffLen = buff.size();
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
@@ -87,7 +87,7 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
return hdr;
}
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
Result<BufferView> stripClawHeader(BufferView const buff) noexcept {
OX_REQUIRE(header, readClawHeader(buff));
return {{header.data, header.dataSize}};
}
@@ -106,15 +106,14 @@ Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
{
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader);
OX_RETURN_ERROR(model(&handler, &obj));
OX_RETURN_ERROR(model(reader.interface(), &obj));
return obj;
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(&reader);
ModelHandlerInterface handler(reader);
OX_RETURN_ERROR(model(&handler, &obj));
return obj;
#else
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "write.hpp"
#include <ox/claw/write.hpp>
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 expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
oxExpect(actual, expected);
ox::expect(actual, expected);
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:
~Signal() noexcept;
@@ -303,7 +303,7 @@ class Signal<Error(Args...)> {
}
};
mutable Vector<UniquePtr<BaseSlot>> m_slots;
mutable Vector<UPtr<BaseSlot>> m_slots;
public:
~Signal() noexcept;
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "signal.hpp"
#include <ox/event/signal.hpp>
namespace ox {
@@ -5,14 +5,12 @@ endif()
add_library(
OxFS
ptrarith/nodebuffer.hpp
ptrarith/ptr.hpp
filestore/filestoretemplate.cpp
filesystem/filelocation.cpp
filesystem/pathiterator.cpp
filesystem/directory.cpp
filesystem/filesystem.cpp
filesystem/passthroughfs.cpp
src/filestore/filestoretemplate.cpp
src/filesystem/filelocation.cpp
src/filesystem/pathiterator.cpp
src/filesystem/directory.cpp
src/filesystem/filesystem.cpp
src/filesystem/passthroughfs.cpp
)
if(NOT MSVC)
@@ -33,10 +31,22 @@ target_link_libraries(
OxMetalClaw
)
target_include_directories(
OxFS PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
if(NOT OX_BARE_METAL)
add_executable(
oxfs-tool
tool.cpp
src/tool.cpp
)
target_link_libraries(
@@ -52,29 +62,6 @@ if(NOT OX_BARE_METAL)
)
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(
TARGETS
OxFS
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "filestoretemplate.hpp"
#include <ox/fs/filestore/filestoretemplate.hpp>
namespace ox {
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "directory.hpp"
#include <ox/fs/filesystem/directory.hpp>
namespace ox {
@@ -8,7 +8,7 @@
#include <ox/model/modelops.hpp>
#include "filelocation.hpp"
#include <ox/fs/filesystem/filelocation.hpp>
namespace ox {
@@ -9,7 +9,7 @@
#include <ox/std/error.hpp>
#include <ox/std/utility.hpp>
#include "filesystem.hpp"
#include <ox/fs/filesystem/filesystem.hpp>
namespace ox {
@@ -8,7 +8,7 @@
#include <ox/std/error.hpp>
#include "passthroughfs.hpp"
#include <ox/fs/filesystem/passthroughfs.hpp>
#if defined(OX_HAS_PASSTHROUGHFS)
@@ -9,7 +9,7 @@
#include <ox/std/memops.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/trace.hpp>
#include "pathiterator.hpp"
#include <ox/fs/filesystem/pathiterator.hpp>
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));
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::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "usr");
ox::expect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "share");
ox::expect(buff, "share");
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);
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
ox::FileStore32 fileStore(list, buffLen);
oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed.");
oxAssert(fileStore.write(4, str1, str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, str2, str2Len, 1), "FileStore::write 2 failed.");
char str1Read[str1Len];
size_t str1ReadSize = 0;
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
add_library(
OxLogConn
logconn.cpp
src/logconn.cpp
)
set_property(
@@ -24,12 +24,16 @@ target_link_libraries(
$<$<BOOL:${OX_OS_WINDOWS}>:ws2_32>
)
target_include_directories(
OxLogConn PUBLIC
include
)
install(
FILES
circularbuff.hpp
logconn.hpp
DIRECTORY
include/ox
DESTINATION
include/ox/logconn
include
)
install(
@@ -23,7 +23,7 @@
#endif
#include "logconn.hpp"
#include <ox/logconn/logconn.hpp>
namespace ox {
@@ -1,8 +1,7 @@
add_library(
OxMetalClaw
presenceindicator.cpp
read.cpp
write.cpp
src/read.cpp
src/write.cpp
)
if(NOT MSVC)
@@ -25,22 +24,22 @@ if(NOT OX_BARE_METAL)
)
endif()
install(
FILES
intops.hpp
err.hpp
mc.hpp
presenceindicator.hpp
read.hpp
types.hpp
write.hpp
DESTINATION
include/ox/mc
target_include_directories(
OxMetalClaw PUBLIC
include
)
install(TARGETS OxMetalClaw
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxMetalClaw
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
@@ -18,25 +18,25 @@
namespace ox::mc {
template<typename T>
template<Integer_c T>
static constexpr auto Bits = sizeof(T) << 3;
/**
* Returns highest bit other than possible signed bit.
* Bit numbering starts at 0.
*/
template<typename I>
template<Integer_c I>
[[nodiscard]]
constexpr std::size_t highestBit(I val) noexcept {
constexpr size_t highestBit(I const val) noexcept {
unsigned shiftStart = sizeof(I) * 8 - 1;
// find most significant non-sign indicator bit
std::size_t highestBit = 0;
// find the most significant non-sign indicator bit
size_t highestBit = 0;
// start at one bit lower if signed
if constexpr(is_signed_v<I>) {
--shiftStart;
}
for (auto i = shiftStart; i > 0; --i) {
const auto bitValue = (val >> i) & 1;
auto const bitValue = (val >> i) & 1;
if (bitValue) {
highestBit = i;
break;
@@ -45,7 +45,7 @@ constexpr std::size_t highestBit(I val) noexcept {
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>(-2)) == 0);
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(4) == 2);
static_assert(highestBit(8) == 3);
static_assert(highestBit(uint64_t(1) << 31) == 31);
static_assert(highestBit(uint64_t(1) << 63) == 63);
static_assert(highestBit(static_cast<uint64_t>(1) << 31) == 31);
static_assert(highestBit(static_cast<uint64_t>(1) << 63) == 63);
struct McInt {
ox::Array<uint8_t, 9> data{};
Array<uint8_t, 9> data{};
// length of integer in bytes
std::size_t length = 0;
size_t length = 0;
};
template<typename I>
template<Integer_c I>
[[nodiscard]]
constexpr McInt encodeInteger(I pInput) noexcept {
auto const input = ox::ResizedInt_t<I, 64>{pInput};
constexpr McInt encodeInteger(I const pInput) noexcept {
auto const input = ResizedInt_t<I, 64>{pInput};
McInt out;
const auto inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid
auto const inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation and to avoid
// overflow concerns
uint64_t val = 0;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&val, &input, sizeof(input));
OX_ALLOW_UNSAFE_BUFFERS_END
auto const val = std::bit_cast<uint64_t>(input);
if (val) {
// bits needed to represent number factoring in space possibly
// needed for signed bit
const auto highBit = inputNegative ? highestBit(~val) : highestBit(val);
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
auto const highBit = inputNegative ? highestBit(~val) : highestBit(val);
auto const bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
// bytes needed to store value
std::size_t bytes = bits / 8 + (bits % 8 != 0);
const auto bitsAvailable = bytes * 8; // bits available to integer value
const auto bitsNeeded = bits + bytes;
size_t bytes = bits / 8 + (bits % 8 != 0);
auto const bitsAvailable = bytes * 8; // bits available to integer value
auto const bitsNeeded = bits + bytes;
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
// bits for integer + bits needed to represent bytes > bits available
if (bitsNeeded > bitsAvailable && bytes != 9) {
++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
LittleEndian<uint64_t> leVal = val;
if (inputNegative) {
@@ -103,9 +100,9 @@ constexpr McInt encodeInteger(I pInput) noexcept {
out.data[1] |= 0b1000'0000;
}
} else {
const auto valBits = bytes * 8;
uint64_t negBit = inputNegative ? 1 : 0;
auto intermediate =
auto const valBits = bytes * 8;
uint64_t const negBit = inputNegative ? 1 : 0;
auto const intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
@@ -122,8 +119,8 @@ constexpr McInt encodeInteger(I pInput) noexcept {
* length integer.
*/
[[nodiscard]]
constexpr std::size_t countBytes(unsigned b) noexcept {
std::size_t i = 0;
constexpr size_t countBytes(unsigned const b) noexcept {
size_t i = 0;
while ((b >> i) & 1) ++i;
return i + 1;
}
@@ -138,39 +135,39 @@ static_assert(countBytes(0b0011'1111) == 7);
static_assert(countBytes(0b0111'1111) == 8);
static_assert(countBytes(0b1111'1111) == 9);
template<typename I>
constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept {
template<Integer_c I>
constexpr Result<I> decodeInteger(Reader_c auto &rdr, size_t &bytesRead) noexcept {
uint8_t firstByte = 0;
OX_RETURN_ERROR(rdr.read(&firstByte, 1));
OX_RETURN_ERROR(rdr.seekg(-1, ox::ios_base::cur));
const auto bytes = countBytes(firstByte);
auto const bytes = countBytes(firstByte);
if (bytes == 9) {
*bytesRead = bytes;
bytesRead = bytes;
I out = 0;
OX_RETURN_ERROR(rdr.seekg(1, ox::ios_base::cur));
OX_RETURN_ERROR(rdr.read(&out, sizeof(I)));
return fromLittleEndian<I>(out);
}
*bytesRead = bytes;
bytesRead = bytes;
uint64_t decoded = 0;
OX_RETURN_ERROR(rdr.read(&decoded, bytes));
decoded >>= bytes;
// move sign bit
if constexpr(is_signed_v<I>) {
const auto negBit = bytes * 8 - bytes - 1;
auto const negBit = bytes * 8 - bytes - 1;
// move sign
const auto negative = (decoded >> negBit) == 1;
auto const negative = (decoded >> negBit) == 1;
if (negative) {
// 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
ox::Array<uint32_t, 2> d = {};
Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&d[0], &decoded, sizeof(decoded));
OX_ALLOW_UNSAFE_BUFFERS_END
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;
}
bit -= 32;
@@ -179,7 +176,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
}
I out = 0;
if constexpr(ox::defines::BigEndian) {
const auto d0Tmp = d[0];
auto const d0Tmp = d[0];
d[0] = d[1];
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);
}
template<typename I>
Result<I> decodeInteger(McInt m) noexcept {
std::size_t bytesRead{};
template<Integer_c I>
Result<I> decodeInteger(McInt const &m) noexcept {
size_t bytesRead{};
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:
FieldBitmapReader<Reader> m_fieldPresence;
std::size_t m_fields = 0;
std::size_t m_field = 0;
ox::Optional<int> m_unionIdx;
size_t m_fields{};
size_t m_field{};
Optional<int> const m_unionIdx{};
Reader &m_reader;
public:
explicit constexpr MetalClawReaderTemplate(
Reader &reader,
ox::Optional<int> const&unionIdx = {}) noexcept;
Optional<int> const &unionIdx = {}) noexcept;
constexpr ~MetalClawReaderTemplate() noexcept;
constexpr Error field(const char*, int8_t *val) noexcept;
constexpr Error field(const char*, int16_t *val) noexcept;
constexpr Error field(const char*, int32_t *val) noexcept;
constexpr Error field(const char*, int64_t *val) noexcept;
constexpr Error field(CString, int8_t *val) noexcept;
constexpr Error field(CString, int16_t *val) noexcept;
constexpr Error field(CString, int32_t *val) noexcept;
constexpr Error field(CString, int64_t *val) noexcept;
constexpr Error field(const char*, uint8_t *val) noexcept;
constexpr Error field(const char*, uint16_t *val) noexcept;
constexpr Error field(const char*, uint32_t *val) noexcept;
constexpr Error field(const char*, uint64_t *val) noexcept;
constexpr Error field(CString, uint8_t *val) noexcept;
constexpr Error field(CString, uint16_t *val) noexcept;
constexpr Error field(CString, uint32_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
constexpr Error field(const char*, auto *val, std::size_t len) noexcept;
constexpr Error field(CString, auto *val, size_t valLen) noexcept;
// map handler
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
template<typename T, typename CB>
constexpr Error field(const char*, CB cb) noexcept;
constexpr Error field(CString, CB cb) noexcept;
template<typename T>
constexpr Error field(const char*, T *val) noexcept;
constexpr Error field(CString, T *val) noexcept;
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>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<size_t SmallStringSize>
constexpr Error field(CString, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, IString<L> *val) noexcept;
template<size_t L>
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.
@@ -101,13 +101,13 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
const char *name = T::TypeName,
int version = T::TypeVersion,
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.
*/
[[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.
@@ -122,20 +122,20 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
constexpr bool fieldPresent(int fieldNo) const noexcept;
[[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;
private:
template<typename I>
constexpr Error readInteger(I *val) noexcept;
constexpr Error readInteger(I &val) noexcept;
};
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
Reader &reader,
ox::Optional<int> const&unionIdx) noexcept:
Optional<int> const &unionIdx) noexcept:
m_fieldPresence(reader),
m_unionIdx(unionIdx),
m_reader(reader) {
@@ -149,50 +149,50 @@ constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int8_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int16_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int32_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int64_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint8_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint16_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint32_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint64_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<size_t>(m_field));
*val = result.value;
OX_RETURN_ERROR(result);
}
@@ -202,18 +202,19 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) n
// array handler
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(
const char *name, auto *val, size_t const valLen) noexcept {
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
std::size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
// read the list
if (valLen >= len) {
auto reader = child({});
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
@@ -230,18 +231,18 @@ OX_ALLOW_UNSAFE_BUFFERS_END
template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, HashMap<String, T> *val) noexcept {
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
OX_REQUIRE(g, m_reader.tellg());
std::size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
OX_RETURN_ERROR(m_reader.seekg(g));
// read the list
auto reader = child("");
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
constexpr auto loopBody = [](auto &handler, auto &val) {
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));
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));
}
}
@@ -263,9 +264,9 @@ template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
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
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_RETURN_ERROR(ox::resizeVector(*val, len));
return field(name, val->data(), val->size());
@@ -275,9 +276,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
++m_field;
return {};
} 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
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));
if (len > val->size()) {
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;
return {};
} else {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
auto reader = child("");
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<typename U, bool force>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
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<std::size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
template<size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, BasicString<SmallStringSize> *val) noexcept {
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
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
const auto cap = size;
*val = BasicString<SmallStringSize>(cap);
auto data = val->data();
@@ -334,13 +335,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
}
template<Reader_c Reader>
template<std::size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
template<size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, IString<L> *val) noexcept {
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
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
*val = IString<L>();
OX_RETURN_ERROR(val->resize(size));
auto const data = val->data();
@@ -355,11 +356,12 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(
CString, char *val, size_t const buffLen) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
if (size > buffLen) {
return ox::Error(McOutputBuffEnded);
}
@@ -374,11 +376,11 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
@@ -392,12 +394,12 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val, size_t buffLen) noexcept {
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
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
// re-allocate if too small
if (buffLen < size + 1) {
safeDelete(*val);
@@ -420,13 +422,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
}
template<Reader_c Reader>
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(CString, bool const pass) noexcept {
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
std::size_t bytesRead = 0;
size_t bytesRead = 0;
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) {
OX_RETURN_ERROR(m_reader.seekg(g));
}
@@ -437,12 +439,12 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const
}
template<Reader_c Reader>
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(CString) noexcept {
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
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, &bytesRead);
size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, bytesRead);
OX_RETURN_ERROR(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur));
return len;
}
@@ -452,15 +454,15 @@ constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(con
template<Reader_c Reader>
template<typename I>
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
std::size_t bytesRead = 0;
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I &val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
size_t bytesRead = 0;
auto const result = mc::decodeInteger<I>(m_reader, bytesRead);
OX_RETURN_ERROR(result);
*val = result.value;
val = result.value;
} else {
*val = 0;
val = 0;
}
}
++m_field;
@@ -469,17 +471,17 @@ constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
template<Reader_c Reader>
template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, CB cb) noexcept {
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
std::size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
// read the list
auto reader = child("");
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (size_t i = 0; i < len; ++i) {
T val;
OX_RETURN_ERROR(handler.field("", &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<typename T>
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;
// Warning: narrow-conv
return m_reader.seekg(
@@ -503,24 +505,24 @@ constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
const char*,
ox::Optional<int> unionIdx) noexcept {
CString,
Optional<int> const unionIdx) noexcept {
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
}
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(CString) const noexcept {
return m_fieldPresence.get(static_cast<size_t>(m_field)).value;
}
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int const fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<size_t>(fieldNo)).value;
}
template<Reader_c Reader>
[[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);
for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) {
@@ -538,11 +540,10 @@ constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
template<typename T>
Error readMC(ox::BufferView buff, T &val) noexcept {
Error readMC(ox::BufferView const buff, T &val) noexcept {
BufferReader br(buff);
MetalClawReader reader(br);
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
return model(&handler, &val);
return model(reader.interface(), &val);
}
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/reader.hpp>
#include "read.hpp"
#include <ox/mc/read.hpp>
namespace ox {
@@ -11,7 +11,7 @@
#include <ox/std/memops.hpp>
#include <ox/std/trace.hpp>
#include "write.hpp"
#include <ox/mc/write.hpp>
namespace ox {
@@ -157,7 +157,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch");
oxExpect(testIn.IString, testOut.IString);
ox::expect(testIn.IString, testOut.IString);
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[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>
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});
}
@@ -187,7 +187,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
PrimitiveType pt;
if constexpr(is_union_v<T>) {
pt = PrimitiveType::Union;
} else if constexpr(isBasicString_v<T> || isBString_v<T>) {
} else if constexpr(isBasicString_v<T> || isIString_v<T>) {
pt = PrimitiveType::String;
} else {
pt = PrimitiveType::Struct;
@@ -357,7 +357,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
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,
@@ -380,7 +380,7 @@ constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typ
template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
if (std::is_constant_evaluated()) {
std::allocator<T> a;
T *t = a.allocate(1);
@@ -396,7 +396,7 @@ constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept {
TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
OX_RETURN_ERROR(model(&handler, &val));
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;
} else if constexpr(is_same_v<U, ModelObject>) {
return Type::Object;
} else if constexpr(isBasicString_v<U> || isBString_v<U>) {
} else if constexpr(isBasicString_v<U> || isIString_v<U>) {
return Type::String;
} else if constexpr(is_same_v<U, ModelValueVector>) {
return Type::Vector;
@@ -168,7 +168,7 @@ class ModelValue {
constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(ox::Error(1), "invalid cast");
ox::panic("invalid cast");
}
return getValue<type>(*this);
}
@@ -178,7 +178,7 @@ class ModelValue {
constexpr auto &get() noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(ox::Error(1), "invalid cast");
ox::panic("invalid cast");
}
return getValue<type>(*this);
}
@@ -187,7 +187,7 @@ class ModelValue {
constexpr Type type() const noexcept;
constexpr Error setType(
DescriptorType const*type,
DescriptorType const *type,
SubscriptStack const& = {},
int subscriptLevels = 0) noexcept;
@@ -200,8 +200,6 @@ class ModelValue {
template<typename T>
constexpr Error set(T &&v) noexcept;
constexpr ModelValue &operator=(ModelValue &val) noexcept;
constexpr ModelValue &operator=(const ModelValue &val) noexcept;
constexpr ModelValue &operator=(ModelValue &&val) noexcept;
@@ -275,7 +273,7 @@ class ModelValueArray {
}
constexpr Error setType(
DescriptorType const*type,
DescriptorType const *type,
SubscriptStack subscriptStack,
int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
@@ -418,7 +416,7 @@ class ModelValueVector {
}
constexpr Error setType(
DescriptorType const*type,
DescriptorType const *type,
SubscriptStack subscriptStack,
int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
@@ -521,7 +519,7 @@ class ModelObject {
protected:
OX_MODEL_FRIEND(ModelObject);
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
Vector<UPtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields;
const DescriptorType *m_type = nullptr;
@@ -694,7 +692,7 @@ class ModelUnion {
};
friend constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept;
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
Vector<UPtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields;
const DescriptorType *m_type = nullptr;
int m_unionIdx = -1;
@@ -720,14 +718,14 @@ class ModelUnion {
m_unionIdx = other.m_unionIdx;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UniquePtr<ModelUnion> out(new ModelUnion);
static constexpr Result<UPtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UPtr<ModelUnion> out(new ModelUnion);
OX_RETURN_ERROR(out->setType(type));
return out;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UniquePtr<ModelUnion>(new ModelUnion(other));
static constexpr Result<UPtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UPtr<ModelUnion>(new ModelUnion(other));
}
constexpr ox::Result<ModelValue*> at(StringView const&k) noexcept {
@@ -821,7 +819,7 @@ class ModelUnion {
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(ModelValueArray const*v) noexcept {
constexpr std::size_t sizeOf(ModelValueArray const *v) noexcept {
return sizeOf<PlatSpec>(&(*v)[0]) * v->size();
}
@@ -1098,7 +1096,7 @@ constexpr Error ModelValue::setType(
} else if (type->typeName == types::Bool) {
m_type = Type::Bool;
} else if (type->typeName == types::BasicString ||
type->typeName == types::BString ||
type->typeName == types::IString ||
type->typeName == types::String) {
m_type = Type::String;
m_data.str = new String;
@@ -1176,7 +1174,7 @@ template<typename T>
constexpr Error ModelValue::set(const T &v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return ox::Error(1, "type mismatch");
return Error(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
@@ -1202,10 +1200,6 @@ constexpr Error ModelValue::set(T &&v) noexcept {
return {};
}
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
return this->operator=(const_cast<const ModelValue&>(other));
}
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
if (this == &other) [[unlikely]] {
return *this;
@@ -17,76 +17,34 @@
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 {
const char *name = "";
CString name = "";
int version = 0;
constexpr TypeInfoCatcher() noexcept = default;
template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo(
const char *n = T::TypeName,
int v = T::TypeVersion,
const Vector<String>& = {},
std::size_t = 0) noexcept {
constexpr Error setTypeInfo(
CString const n = T::TypeName,
int const v = T::TypeVersion,
Vector<String> const& = {},
size_t = 0) noexcept {
this->name = n;
this->version = v;
return {};
}
template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept {
constexpr Error field(CString, T*, size_t) noexcept {
return {};
}
template<typename T>
constexpr Error field(const char*, T) noexcept {
constexpr Error field(CString, T const&) noexcept {
return {};
}
template<typename T>
constexpr Error fieldCString(const char*, T) noexcept {
constexpr Error fieldCString(CString, T const&) noexcept {
return {};
}
@@ -125,14 +83,14 @@ consteval int requireModelTypeVersion() noexcept {
template<typename T, typename Str = const char*>
[[nodiscard]]
constexpr Str getModelTypeName(T *val) noexcept {
TypeNameCatcher nc;
TypeInfoCatcher nc;
std::ignore = model(&nc, val);
return nc.name;
}
template<typename T, typename Str = const char*>
[[nodiscard]]
constexpr Str getModelTypeName() noexcept {
consteval Str getModelTypeName() noexcept {
std::allocator<T> a;
auto t = a.allocate(1);
auto out = getModelTypeName(t);
@@ -140,15 +98,15 @@ constexpr Str getModelTypeName() noexcept {
return out;
}
template<typename T, typename Str = const char*>
template<typename T, typename Str = StringLiteral>
[[nodiscard]]
consteval auto requireModelTypeName() noexcept {
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;
}
template<typename T, typename Str = const char*>
template<typename T, typename Str = StringLiteral>
constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
template<typename T, typename Str = const char*>
@@ -156,10 +114,10 @@ constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
template<typename T>
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 versionStr = ox::sfmt<ox::IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
constexpr auto versionStr = ox::sfmt<IString<19>>("{}", version);
return ox::sfmt<IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
}();
}
@@ -31,18 +31,18 @@
namespace ox {
namespace types {
constexpr StringView BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringView BString = "net.drinkingtea.ox.BString";
constexpr StringView String = "B.string";
constexpr StringView Bool = "B.bool";
constexpr StringView Uint8 = "B.uint8";
constexpr StringView Uint16 = "B.uint16";
constexpr StringView Uint32 = "B.uint32";
constexpr StringView Uint64 = "B.uint64";
constexpr StringView Int8 = "B.int8";
constexpr StringView Int16 = "B.int16";
constexpr StringView Int32 = "B.int32";
constexpr StringView Int64 = "B.int64";
constexpr StringLiteral BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringLiteral IString = "net.drinkingtea.ox.IString";
constexpr StringLiteral String = "B.string";
constexpr StringLiteral Bool = "B.bool";
constexpr StringLiteral Uint8 = "B.uint8";
constexpr StringLiteral Uint16 = "B.uint16";
constexpr StringLiteral Uint32 = "B.uint32";
constexpr StringLiteral Uint64 = "B.uint64";
constexpr StringLiteral Int8 = "B.int8";
constexpr StringLiteral Int16 = "B.int16";
constexpr StringLiteral Int32 = "B.int32";
constexpr StringLiteral Int64 = "B.int64";
}
template<typename T>
@@ -63,17 +63,17 @@ static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>);
template<typename T>
consteval bool isBString(const T*) noexcept {
consteval bool isIString(const T*) noexcept {
return false;
}
template<std::size_t SmallVecSize>
consteval bool isBString(const BasicString<SmallVecSize>*) noexcept {
consteval bool isIString(const BasicString<SmallVecSize>*) noexcept {
return true;
}
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<8ul>>);
@@ -161,7 +161,7 @@ template<typename T>
constexpr bool isSmartPtr_v = false;
template<typename T>
constexpr bool isSmartPtr_v<::ox::UniquePtr<T>> = true;
constexpr bool isSmartPtr_v<::ox::UPtr<T>> = true;
#if __has_include(<array>)
template<typename T>
@@ -169,12 +169,12 @@ constexpr bool isSmartPtr_v<::std::unique_ptr<T>> = true;
#endif
template<typename Union, bool force = false>
template<typename Union, bool force = false> requires(force || is_union_v<Union>)
class UnionView {
protected:
int m_idx = -1;
typename enable_if<is_union_v<Union> || force, Union>::type *m_union = nullptr;
Union *m_union = nullptr;
public:
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
@@ -21,7 +21,7 @@ namespace ox {
class TypeStore {
private:
HashMap<String, UniquePtr<DescriptorType>> m_cache;
HashMap<String, UPtr<DescriptorType>> m_cache;
public:
constexpr TypeStore() noexcept = default;
@@ -86,12 +86,12 @@ class TypeStore {
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);
}
constexpr void set(const auto &typeId, DescriptorType *dt) noexcept {
m_cache[typeId] = UniquePtr<DescriptorType>(dt);
m_cache[typeId] = UPtr<DescriptorType>(dt);
}
[[nodiscard]]
@@ -105,11 +105,11 @@ class TypeStore {
}
protected:
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
virtual Result<UPtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
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 auto typeId = buildTypeId(name, version, typeParams);
return loadDescriptor(typeId);
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "desctypes.hpp"
#include <ox/model/desctypes.hpp>
namespace ox {
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "descwrite.hpp"
#include <ox/model/descwrite.hpp>
namespace ox {
@@ -6,18 +6,23 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "modelvalue.hpp"
#include <ox/std/hashmap.hpp>
#include <ox/model/modelvalue.hpp>
namespace ox {
static_assert([]() -> ox::Error {
ox::ModelValue v;
static_assert([]() -> Error {
ModelValue v;
OX_RETURN_ERROR(v.setType<int32_t>());
if (v.type() != ModelValue::Type::SignedInteger32) {
return ox::Error(1, "type is wrong");
return Error(1, "type is wrong");
}
//oxReturnError(v.set<int32_t>(5));
return {};
}() == ox::Error{});
}() == Error{});
// a dummy function to prevent linker errors in a library that has no other symbols
void modelDummyFunc() noexcept {}
}

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