Compare commits
1 Commits
release-d2
...
hello_worl
| Author | SHA1 | Date | |
|---|---|---|---|
| c20aa2e0b9 |
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"log_functions": [
|
||||
{
|
||||
"function": "oxTraceHook",
|
||||
"ignore_frames": 3,
|
||||
"file_var": "file",
|
||||
"line_var": "line",
|
||||
"channel_var": "ch",
|
||||
"msg_var": "msg"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -1,15 +1,5 @@
|
||||
.current_build
|
||||
compile_commands.json
|
||||
build
|
||||
conanbuild
|
||||
dist
|
||||
build/current
|
||||
build/gba
|
||||
build/*-release
|
||||
build/*-debug
|
||||
tags
|
||||
nostalgia.gba
|
||||
nostalgia.sav
|
||||
nostalgia_media.oxfs
|
||||
media_header.txt
|
||||
studio_state.json
|
||||
CMakeLists.txt.user
|
||||
Session.vim
|
||||
ROM.oxfs
|
||||
graph_info.json
|
||||
|
||||
5
.liccor
Normal file
5
.liccor
Normal file
@@ -0,0 +1,5 @@
|
||||
Copyright 2016-2017 gtalent2@gmail.com
|
||||
|
||||
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 http://mozilla.org/MPL/2.0/.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
source:
|
||||
- src
|
||||
copyright_notice: |-
|
||||
Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
|
||||
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 http://mozilla.org/MPL/2.0/.
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"version": "0.2.1",
|
||||
"defaults": {},
|
||||
"configurations": [
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia.exe (Install)",
|
||||
"name": "nostalgia.exe (Install)",
|
||||
"args": [
|
||||
"${projectDir}/sample_project"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia.exe",
|
||||
"name": "nostalgia.exe",
|
||||
"args": [
|
||||
"${projectDir}/sample_project"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia-studio.exe (Install)",
|
||||
"name": "nostalgia-studio.exe (Install)",
|
||||
"args": [
|
||||
"-profile",
|
||||
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "nostalgia-studio.exe",
|
||||
"name": "nostalgia-studio.exe",
|
||||
"args": [
|
||||
"-profile",
|
||||
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
135
CMakeLists.txt
135
CMakeLists.txt
@@ -1,126 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_minimum_required(VERSION 2.8.8)
|
||||
|
||||
project(nostalgia)
|
||||
project(wombat)
|
||||
|
||||
set(NOSTALGIA_BUILD_TYPE "Native" CACHE STRING "The type of build to produce(Native/GBA)")
|
||||
set(NOSTALGIA_IDE_BUILD ON CACHE STRING "Build for IDE's to run")
|
||||
set(NOSTALGIA_QT_PATH "" CACHE STRING "Path to Qt Libraries")
|
||||
set(NOSTALGIA_BUILD_STUDIO ON CACHE BOOL "Build Studio")
|
||||
set(WOMBAT_BUILD_TYPE "Native" CACHE STRING "The type of build to produce(Native/GBA)")
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
set(NOSTALGIA_BUILD_STUDIO OFF)
|
||||
set(OX_BARE_METAL ON)
|
||||
set(OX_USE_STDLIB OFF)
|
||||
else()
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${NOSTALGIA_QT_PATH})
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
include(GenerateExportHeader)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||
include(address_sanitizer)
|
||||
|
||||
set(NOSTALGIA_CONAN_PATHS ${CMAKE_SOURCE_DIR}/conanbuild/conan_paths.cmake)
|
||||
if(NOT NOSTALGIA_BUILD_TYPE STREQUAL "GBA" AND EXISTS ${NOSTALGIA_CONAN_PATHS})
|
||||
include(${NOSTALGIA_CONAN_PATHS})
|
||||
if (WOMBAT_BUILD_TYPE STREQUAL "GBA")
|
||||
include(GBA)
|
||||
endif()
|
||||
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/dist/${NOSTALGIA_BUILD_CONFIG}")
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
add_definitions(
|
||||
-std=c++11
|
||||
-Wall
|
||||
-Wsign-compare
|
||||
-nostdlib
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
#-g
|
||||
#-fcolor-diagnostics
|
||||
#--analyze
|
||||
#-Os # GCC size optimization flag
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
if(NOT OX_BARE_METAL)
|
||||
add_definitions(-DOX_USE_STDLIB)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DDEBUG)
|
||||
else()
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
# forces colored output when using ninja
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
|
||||
|
||||
# enable warnings
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-align")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-variable")
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
include(GBA)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=arm7tdmi")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm7tdmi")
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOSTALGIA_IDE_BUILD)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(CMAKE_INSTALL_NAME_DIR "@executable_path/../Library/nostalgia")
|
||||
set(NOSTALGIA_DIST_BIN nostalgia-studio.app/Contents/MacOS)
|
||||
set(NOSTALGIA_DIST_LIB nostalgia-studio.app/Contents/Library)
|
||||
set(NOSTALGIA_DIST_PLUGIN nostalgia-studio.app/Contents/Plugins)
|
||||
set(NOSTALGIA_DIST_RESOURCES nostalgia-studio.app/Contents/Resources)
|
||||
set(NOSTALGIA_DIST_MAC_APP_CONTENTS nostalgia-studio.app/Contents)
|
||||
else()
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN" "$ORIGIN/../lib/nostalgia" "$ORIGIN/../")
|
||||
if(NOT ${NOSTALGIA_QT_PATH} STREQUAL "")
|
||||
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${NOSTALGIA_QT_PATH}/lib")
|
||||
endif()
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set(NOSTALGIA_DIST_BIN bin)
|
||||
set(NOSTALGIA_DIST_LIB lib)
|
||||
set(NOSTALGIA_DIST_PLUGIN lib/nostalgia/plugins)
|
||||
set(NOSTALGIA_DIST_RESOURCES share)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
add_definitions(
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
add_subdirectory(deps/gbastartup)
|
||||
endif()
|
||||
|
||||
add_subdirectory(deps/ox)
|
||||
include_directories(deps/ox/src)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
86
Dockerfile
86
Dockerfile
@@ -1,61 +1,33 @@
|
||||
FROM fedora:30
|
||||
FROM wombatant/devenv
|
||||
|
||||
RUN dnf update -y
|
||||
ENV DEVKITPRO /opt/devkitPro
|
||||
ENV DEVKITARM ${DEVKITPRO}/devkitARM
|
||||
|
||||
###############################################################################
|
||||
# Install gosu
|
||||
# Install Ox
|
||||
|
||||
RUN dnf install -y curl gnupg
|
||||
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
|
||||
RUN curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64" && \
|
||||
curl -o /usr/local/bin/gosu.asc -SL "https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64.asc" && \
|
||||
gpg --verify /usr/local/bin/gosu.asc && \
|
||||
rm /usr/local/bin/gosu.asc && \
|
||||
chmod +x /usr/local/bin/gosu
|
||||
|
||||
###############################################################################
|
||||
# Install dev tools
|
||||
|
||||
RUN dnf install -y clang
|
||||
RUN dnf install -y llvm
|
||||
RUN dnf install -y libasan
|
||||
RUN dnf install -y mingw64-gcc-c++
|
||||
RUN dnf install -y cmake
|
||||
RUN dnf install -y make
|
||||
RUN dnf install -y git
|
||||
RUN dnf install -y vim
|
||||
RUN dnf install -y sudo
|
||||
RUN dnf install -y fuse-devel
|
||||
RUN dnf install -y qt5-devel
|
||||
RUN dnf install -y findutils
|
||||
RUN dnf install -y ninja-build
|
||||
RUN dnf install -y libcxx-devel libcxxabi-devel
|
||||
|
||||
###############################################################################
|
||||
# Install devkitARM
|
||||
|
||||
#RUN dnf install -y lbzip2
|
||||
#RUN curl -o /tmp/devkitArm.tar.bz2 -SL https://phoenixnap.dl.sourceforge.net/project/devkitpro/devkitARM/devkitARM_r47/devkitARM_r47-x86_64-linux.tar.bz2
|
||||
#WORKDIR /opt
|
||||
#RUN tar xf /tmp/devkitArm.tar.bz2
|
||||
#ENV DEVKITARM /opt/devkitARM
|
||||
|
||||
###############################################################################
|
||||
# Setup sudoers
|
||||
|
||||
ADD devenv/sudoers /etc/sudoers
|
||||
|
||||
###############################################################################
|
||||
# Setup working directory
|
||||
|
||||
RUN mkdir /usr/src/project
|
||||
WORKDIR /usr/src/project
|
||||
|
||||
###############################################################################
|
||||
# Setup entrypoint
|
||||
|
||||
ADD devenv/entrypoint.sh /
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
ENV CC clang
|
||||
ENV CXX clang++
|
||||
RUN git clone -b release-0.1 https://github.com/wombatant/ox.git /usr/local/src/ox && \
|
||||
cd /usr/local/src/ox && \
|
||||
# setup build dirs
|
||||
mkdir -p \
|
||||
/usr/local/src/ox/build/release \
|
||||
/usr/local/src/ox/build/windows \
|
||||
/usr/local/src/ox/build/gba; \
|
||||
# install Ox for native environment
|
||||
cd /usr/local/src/ox/build/release && \
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../ && \
|
||||
make -j install; \
|
||||
# install Ox for GBA
|
||||
cd /usr/local/src/ox/build/gba && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/GBA.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/devkitPro/devkitARM \
|
||||
-DOX_USE_STDLIB=OFF ../../ && \
|
||||
make -j install; \
|
||||
# install Ox for Windows
|
||||
cd /usr/local/src/ox/build/windows && \
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/Mingw.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/x86_64-w64-mingw32 \
|
||||
-DOX_BUILD_EXEC=OFF ../../ && \
|
||||
make -j install
|
||||
|
||||
17
Jenkinsfile
vendored
17
Jenkinsfile
vendored
@@ -1,17 +0,0 @@
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'make conan'
|
||||
sh 'make configure-debug configure-release'
|
||||
sh 'make'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'make test'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Makefile
132
Makefile
@@ -2,113 +2,83 @@ OS=$(shell uname | tr [:upper:] [:lower:])
|
||||
HOST_ENV=${OS}-$(shell uname -m)
|
||||
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
|
||||
DEVENV_IMAGE=nostalgia-devenv
|
||||
CURRENT_BUILD=$(file < .current_build)
|
||||
ifneq ($(shell which docker 2> /dev/null),)
|
||||
ifneq ($(shell which docker),)
|
||||
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
|
||||
|
||||
ifeq ($(OS),windows)
|
||||
RM_RF=Remove-Item -ErrorAction Ignore -Path -Recurse
|
||||
else
|
||||
RM_RF=rm -rf
|
||||
endif
|
||||
|
||||
ifeq ($(OS),darwin)
|
||||
NOSTALGIA_STUDIO=./dist/${CURRENT_BUILD}/nostalgia-studio.app/Contents/MacOS/nostalgia-studio
|
||||
NOSTALGIA_STUDIO_PROFILE=dist/${CURRENT_BUILD}/nostalgia-studio.app/Contents/Resources/nostalgia-studio.json
|
||||
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
|
||||
else
|
||||
NOSTALGIA_STUDIO=./dist/${CURRENT_BUILD}/bin/nostalgia-studio
|
||||
NOSTALGIA_STUDIO_PROFILE=dist/${CURRENT_BUILD}/share/nostalgia-studio.json
|
||||
MGBA=mgba-qt
|
||||
endif
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target;)
|
||||
.PHONY: pkg-gba
|
||||
pkg-gba:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target install;)
|
||||
${ENV_RUN} ./scripts/gba-pkg
|
||||
.PHONY: install
|
||||
make:
|
||||
${ENV_RUN} make -j -C build HOST_ENV=${HOST_ENV}
|
||||
preinstall:
|
||||
${ENV_RUN} make -j -C build ARGS="preinstall" HOST_ENV=${HOST_ENV}
|
||||
install:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target install;)
|
||||
.PHONY: clean
|
||||
${ENV_RUN} make -j -C build ARGS="install" HOST_ENV=${HOST_ENV}
|
||||
clean:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target clean;)
|
||||
.PHONY: purge
|
||||
${ENV_RUN} make -j -C build ARGS="clean" HOST_ENV=${HOST_ENV}
|
||||
purge:
|
||||
${ENV_RUN} ${RM_RF} build .current_build
|
||||
.PHONY: test
|
||||
${ENV_RUN} rm -rf $$(find build -mindepth 1 -maxdepth 1 -type d)
|
||||
test:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target test;)
|
||||
${ENV_RUN} make -j -C build ARGS="test" HOST_ENV=${HOST_ENV}
|
||||
|
||||
.PHONY: run
|
||||
run: install
|
||||
${ENV_RUN} ./dist/${CURRENT_BUILD}/bin/nostalgia sample_project
|
||||
.PHONY: run-studio
|
||||
run-studio: install
|
||||
${ENV_RUN} ${NOSTALGIA_STUDIO} -profile ${NOSTALGIA_STUDIO_PROFILE}
|
||||
.PHONY: gba-run
|
||||
gba-run: pkg-gba
|
||||
${MGBA} nostalgia.gba
|
||||
.PHONY: gdb
|
||||
gdb: install
|
||||
${ENV_RUN} gdb --args ./dist/${CURRENT_BUILD}/bin/nostalgia sample_project
|
||||
.PHONY: gdb-studio
|
||||
gdb-studio: install
|
||||
${ENV_RUN} gdb --args ${NOSTALGIA_STUDIO} -profile ${NOSTALGIA_STUDIO_PROFILE}
|
||||
run: make
|
||||
./build/current/src/player/nostalgia -debug
|
||||
gba-run: make
|
||||
${ENV_RUN} mgba-qt build/current/src/player/nostalgia.bin
|
||||
gdb: make
|
||||
gdb ./build/current/src/wombat/wombat
|
||||
|
||||
.PHONY: devenv-image
|
||||
devenv-image:
|
||||
docker build . -t ${DEVENV_IMAGE}
|
||||
.PHONY: devenv-create
|
||||
devenv-create:
|
||||
docker run -d \
|
||||
devenv-build:
|
||||
docker build --no-cache . -t ${DEVENV_IMAGE}
|
||||
devenv:
|
||||
docker run -d -v $(shell pwd):/usr/src/project \
|
||||
-e LOCAL_USER_ID=$(shell id -u ${USER}) \
|
||||
-e DISPLAY=$(DISPLAY) \
|
||||
-e QT_AUTO_SCREEN_SCALE_FACTOR=1 \
|
||||
-v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||
-v /run/dbus/:/run/dbus/ \
|
||||
-v $(shell pwd):/usr/src/project \
|
||||
-v /dev/shm:/dev/shm \
|
||||
--restart=always \
|
||||
--name ${DEVENV} \
|
||||
-t ${DEVENV_IMAGE} bash
|
||||
.PHONY: devenv-destroy
|
||||
devenv-destroy:
|
||||
docker rm -f ${DEVENV}
|
||||
.PHONY: devenv-shell
|
||||
devenv-shell:
|
||||
|
||||
shell:
|
||||
${ENV_RUN} bash
|
||||
|
||||
.PHONY: conan
|
||||
conan:
|
||||
@mkdir -p conanbuild && cd conanbuild && conan install --build missing ../
|
||||
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
|
||||
|
||||
.PHONY: configure-release
|
||||
configure-release:
|
||||
${ENV_RUN} ${RM_RF} build/${HOST_ENV}-release
|
||||
${ENV_RUN} ./scripts/setup-build ${HOST_ENV} release
|
||||
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
|
||||
|
||||
.PHONY: configure-debug
|
||||
configure-debug:
|
||||
${ENV_RUN} ${RM_RF} build/${HOST_ENV}-debug
|
||||
${ENV_RUN} ./scripts/setup-build ${HOST_ENV} debug
|
||||
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
|
||||
|
||||
.PHONY: configure-asan
|
||||
configure-asan:
|
||||
${ENV_RUN} ${RM_RF} build/${HOST_ENV}-asan
|
||||
${ENV_RUN} ./scripts/setup-build ${HOST_ENV} asan
|
||||
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
|
||||
|
||||
.PHONY: configure-gba
|
||||
configure-gba:
|
||||
${ENV_RUN} ${RM_RF} build/gba-release
|
||||
${ENV_RUN} ./scripts/setup-build gba release
|
||||
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: configure-gba-debug
|
||||
configure-gba-debug:
|
||||
${ENV_RUN} ${RM_RF} build/gba-debug
|
||||
${ENV_RUN} ./scripts/setup-build gba debug
|
||||
gba-debug:
|
||||
${ENV_RUN} rm -rf build/gba-debug
|
||||
${ENV_RUN} ./scripts/setup_build gba debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s gba-debug build/current
|
||||
|
||||
@@ -1,9 +1 @@
|
||||
# Nostalgia
|
||||
|
||||
## Setup
|
||||
|
||||
### macOS
|
||||
|
||||
Run something along the lines of the following to let CMake know where Qt is installed. You may need to adjust this location.
|
||||
|
||||
export NOSTALGIA_QT_PATH=/usr/local/Cellar/qt5/5.8.0_2/
|
||||
|
||||
33
build/Makefile
Normal file
33
build/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
all: gba_build gba_debug_build native_build native_debug_build windows_release windows_debug
|
||||
|
||||
MAKE=make -j
|
||||
|
||||
gba_build:
|
||||
@if [ -d gba-release ]; then \
|
||||
${MAKE} -C gba-release ${ARGS}; \
|
||||
fi
|
||||
|
||||
gba_debug_build:
|
||||
@if [ -d gba-debug ]; then \
|
||||
${MAKE} -C gba-debug ${ARGS}; \
|
||||
fi
|
||||
|
||||
native_build:
|
||||
@if [ -d ${HOST_ENV}-release ]; then \
|
||||
${MAKE} -C ${HOST_ENV}-release ${ARGS}; \
|
||||
fi
|
||||
|
||||
native_debug_build:
|
||||
@if [ -d ${HOST_ENV}-debug ]; then \
|
||||
${MAKE} -C ${HOST_ENV}-debug ${ARGS}; \
|
||||
fi
|
||||
|
||||
windows_release:
|
||||
@if [ -d windows-release ]; then \
|
||||
${MAKE} -C windows-release ${ARGS}; \
|
||||
fi
|
||||
|
||||
windows_debug:
|
||||
@if [ -d windows-debug ]; then \
|
||||
${MAKE} -C windows-debug ${ARGS}; \
|
||||
fi
|
||||
10
build_rom.sh
Executable file
10
build_rom.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
padbin 32 build/gba-release/src/player/nostalgia.bin
|
||||
echo NOSTALGIA_MEDIA_HEADER_________ > media_header.txt
|
||||
oxfs format 32 1m nostalgia_media.oxfs
|
||||
./build/current/src/tools/nost-pack -fs nostalgia_media.oxfs -img charset.png -inode 1 -c
|
||||
cat build/gba-release/src/player/nostalgia.bin media_header.txt nostalgia_media.oxfs > nostalgia.gba
|
||||
gbafix nostalgia.gba
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
49
cmake/Modules/FindJansson.cmake
Normal file
49
cmake/Modules/FindJansson.cmake
Normal file
@@ -0,0 +1,49 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
# - Try to find Jansson
|
||||
# Once done this will define
|
||||
# JANSSON_FOUND - System has Jansson
|
||||
# JANSSON_INCLUDE_DIRS - The Jansson include directories
|
||||
# JANSSON_LIBRARIES - The libraries needed to use Jansson
|
||||
# JANSSON_DEFINITIONS - Compiler switches required for using Jansson
|
||||
|
||||
find_path(JANSSON_INCLUDE_DIR jansson.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(JANSSON_LIBRARY
|
||||
NAMES
|
||||
jansson
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
set(JANSSON_LIBRARIES ${JANSSON_LIBRARY})
|
||||
set(JANSSON_INCLUDE_DIRS ${JANSSON_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set JANSSON_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(Jansson DEFAULT_MSG
|
||||
JANSSON_LIBRARY JANSSON_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(JANSSON_INCLUDE_DIR JANSSON_LIBRARY)
|
||||
@@ -1,5 +1,10 @@
|
||||
set(CMAKE_SYSTEM_NAME "Generic")
|
||||
set(DEVKITARM $ENV{DEVKITARM})
|
||||
set(DEVKITPRO $ENV{DEVKITPRO})
|
||||
|
||||
if(NOT DEVKITPRO)
|
||||
message(FATAL_ERROR "DEVKITPRO environment variable not set")
|
||||
endif()
|
||||
|
||||
if(NOT DEVKITARM)
|
||||
message(FATAL_ERROR "DEVKITARM environment variable not set")
|
||||
@@ -19,10 +24,18 @@ set(CMAKE_FIND_LIBRARY_PREFIXES lib)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
|
||||
set(LINKER_FLAGS "-specs=gba.specs")
|
||||
add_definitions(-DARM7)
|
||||
add_definitions (
|
||||
-DARM7
|
||||
)
|
||||
|
||||
function(BuildStaticLib LIBNAME SRCFILES)
|
||||
add_library(${LIBNAME} OBJECT ${SRCFILES})
|
||||
set(OBJS ${OBJS} $<TARGET_OBJECTS:${LIBNAME}>)
|
||||
endfunction()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
|
||||
macro(OBJCOPY_FILE EXE_NAME)
|
||||
set(FO ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.bin)
|
||||
set(FI ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME})
|
||||
4
cmake/Modules/Native.cmake
Normal file
4
cmake/Modules/Native.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
function(BuildStaticLib libName srcFiles)
|
||||
endfunction()
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
from conans import ConanFile, CMake
|
||||
|
||||
class NostalgiaConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
requires = "jsoncpp/1.9.0@theirix/stable", "sdl2/2.0.10@bincrafters/stable"#, "qt/5.14.0@bincrafters/stable" # comma-separated list of requirements
|
||||
generators = "cmake", "cmake_find_package", "cmake_paths"
|
||||
|
||||
def requirements(self):
|
||||
pass
|
||||
10
deps/gbastartup/CMakeLists.txt
vendored
10
deps/gbastartup/CMakeLists.txt
vendored
@@ -1,10 +0,0 @@
|
||||
enable_language(C ASM)
|
||||
add_library(
|
||||
GbaStartup
|
||||
gba_crt0.s
|
||||
cstartup.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
GbaStartup
|
||||
)
|
||||
47
deps/gbastartup/cstartup.cpp
vendored
47
deps/gbastartup/cstartup.cpp
vendored
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
extern void (*__preinit_array_start[]) (void);
|
||||
extern void (*__preinit_array_end[]) (void);
|
||||
extern void (*__init_array_start[]) (void);
|
||||
extern void (*__init_array_end[]) (void);
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
void initHeap();
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
void __libc_init_array() {
|
||||
auto preInits = __preinit_array_end - __preinit_array_start;
|
||||
for (decltype(preInits) i = 0; i < preInits; i++) {
|
||||
__preinit_array_start[i]();
|
||||
}
|
||||
auto inits = __init_array_end - __init_array_start;
|
||||
for (decltype(inits) i = 0; i < inits; i++) {
|
||||
__preinit_array_start[i]();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv);
|
||||
|
||||
int c_start() {
|
||||
const char *args[2] = {"", "rom.oxfs"};
|
||||
nostalgia::core::initHeap();
|
||||
return main(2, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
258
deps/gbastartup/gba_crt0.s
vendored
258
deps/gbastartup/gba_crt0.s
vendored
@@ -1,258 +0,0 @@
|
||||
/*--------------------------------------------------------------------------------
|
||||
Copyright devkitPro Project
|
||||
https://github.com/devkitPro/devkitarm-crtls/blob/master/gba_crt0.s
|
||||
|
||||
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/.
|
||||
--------------------------------------------------------------------------------*/
|
||||
|
||||
.section ".crt0","ax"
|
||||
.global _start
|
||||
.align
|
||||
|
||||
.arm
|
||||
.cpu arm7tdmi
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
_start:
|
||||
@---------------------------------------------------------------------------------
|
||||
b rom_header_end
|
||||
|
||||
.fill 156,1,0 @ Nintendo Logo Character Data (8000004h)
|
||||
.fill 16,1,0 @ Game Title
|
||||
.byte 0x30,0x31 @ Maker Code (80000B0h)
|
||||
.byte 0x96 @ Fixed Value (80000B2h)
|
||||
.byte 0x00 @ Main Unit Code (80000B3h)
|
||||
.byte 0x00 @ Device Type (80000B4h)
|
||||
.fill 7,1,0 @ unused
|
||||
.byte 0x00 @ Software Version No (80000BCh)
|
||||
.byte 0xf0 @ Complement Check (80000BDh)
|
||||
.byte 0x00,0x00 @ Checksum (80000BEh)
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
rom_header_end:
|
||||
@---------------------------------------------------------------------------------
|
||||
b start_vector @ This branch must be here for proper
|
||||
@ positioning of the following header.
|
||||
|
||||
.GLOBAL __boot_method, __slave_number
|
||||
@---------------------------------------------------------------------------------
|
||||
__boot_method:
|
||||
@---------------------------------------------------------------------------------
|
||||
.byte 0 @ boot method (0=ROM boot, 3=Multiplay boot)
|
||||
@---------------------------------------------------------------------------------
|
||||
__slave_number:
|
||||
@---------------------------------------------------------------------------------
|
||||
.byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3)
|
||||
|
||||
.byte 0 @ reserved
|
||||
.byte 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
.word 0 @ reserved
|
||||
|
||||
.global start_vector
|
||||
.align
|
||||
@---------------------------------------------------------------------------------
|
||||
start_vector:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r0, #0x4000000 @ REG_BASE
|
||||
str r0, [r0, #0x208]
|
||||
|
||||
mov r0, #0x12 @ Switch to IRQ Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__sp_irq @ Set IRQ stack
|
||||
mov r0, #0x1f @ Switch to System Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =__sp_usr @ Set user stack
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Enter Thumb mode
|
||||
@---------------------------------------------------------------------------------
|
||||
add r0, pc, #1
|
||||
bx r0
|
||||
|
||||
.thumb
|
||||
|
||||
ldr r0, =__text_start
|
||||
lsl r0, #5 @ Was code compiled at 0x08000000 or higher?
|
||||
bcs DoEWRAMClear @ yes, you can not run it in external WRAM
|
||||
|
||||
mov r0, pc
|
||||
lsl r0, #5 @ Are we running from ROM (0x8000000 or higher) ?
|
||||
bcc SkipEWRAMClear @ No, so no need to do a copy.
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ We were started in ROM, silly emulators. :P
|
||||
@ So we need to copy to ExWRAM.
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r2, #2
|
||||
lsl r2, r2, #24 @ r2= 0x02000000
|
||||
ldr r3, =__end__ @ last ewram address
|
||||
sub r3, r2 @ r3= actual binary size
|
||||
mov r6, r2 @ r6= 0x02000000
|
||||
lsl r1, r2, #2 @ r1= 0x08000000
|
||||
|
||||
bl CopyMem
|
||||
|
||||
bx r6 @ Jump to the code to execute
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
DoEWRAMClear: @ Clear External WRAM to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r1, #0x40
|
||||
lsl r1, #12 @ r1 = 0x40000
|
||||
lsl r0, r1, #7 @ r0 = 0x2000000
|
||||
bl ClearMem
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
SkipEWRAMClear: @ Clear Internal WRAM to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Clear BSS section to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r0, =__bss_start__
|
||||
ldr r1, =__bss_end__
|
||||
sub r1, r0
|
||||
bl ClearMem
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Clear SBSS section to 0x00
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r0, =__sbss_start__
|
||||
ldr r1, =__sbss_end__
|
||||
sub r1, r0
|
||||
bl ClearMem
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy initialized data (data section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r1, =__data_lma
|
||||
ldr r2, =__data_start__
|
||||
ldr r4, =__data_end__
|
||||
bl CopyMemChk
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r1,= __iwram_lma
|
||||
ldr r2,= __iwram_start__
|
||||
ldr r4,= __iwram_end__
|
||||
bl CopyMemChk
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r2,= __load_stop_iwram0
|
||||
ldr r1,= __load_start_iwram0
|
||||
sub r3, r2, r1 @ Is there any data to copy?
|
||||
beq CIW0Skip @ no
|
||||
|
||||
ldr r2,= __iwram_overlay_start
|
||||
bl CopyMem
|
||||
@---------------------------------------------------------------------------------
|
||||
CIW0Skip:
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM)
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r1, =__ewram_lma
|
||||
ldr r2, =__ewram_start
|
||||
ldr r4, =__ewram_end
|
||||
bl CopyMemChk
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
CEW0Skip:
|
||||
@---------------------------------------------------------------------------------
|
||||
@ set heap end
|
||||
@---------------------------------------------------------------------------------
|
||||
// fake_heap_end does not appear to exist,
|
||||
// and Nostalgia has its own heap allocator anyway
|
||||
//ldr r1, =fake_heap_end
|
||||
//ldr r0, =__eheap_end
|
||||
//str r0, [r1]
|
||||
@---------------------------------------------------------------------------------
|
||||
@ global constructors
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r3, =__libc_init_array
|
||||
bl _blx_r3_stub
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Jump to user code
|
||||
@---------------------------------------------------------------------------------
|
||||
ldr r3, =c_start
|
||||
bl _blx_r3_stub
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Clear memory to 0x00 if length != 0
|
||||
@---------------------------------------------------------------------------------
|
||||
@ r0 = Start Address
|
||||
@ r1 = Length
|
||||
@---------------------------------------------------------------------------------
|
||||
ClearMem:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r2,#3 @ These commands are used in cases where
|
||||
add r1,r2 @ the length is not a multiple of 4,
|
||||
bic r1,r2 @ even though it should be.
|
||||
|
||||
beq ClearMX @ Length is zero so exit
|
||||
|
||||
mov r2,#0
|
||||
@---------------------------------------------------------------------------------
|
||||
ClrLoop:
|
||||
@---------------------------------------------------------------------------------
|
||||
stmia r0!, {r2}
|
||||
sub r1,#4
|
||||
bne ClrLoop
|
||||
@---------------------------------------------------------------------------------
|
||||
ClearMX:
|
||||
@---------------------------------------------------------------------------------
|
||||
bx lr
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
_blx_r3_stub:
|
||||
@---------------------------------------------------------------------------------
|
||||
bx r3
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy memory if length != 0
|
||||
@---------------------------------------------------------------------------------
|
||||
@ r1 = Source Address
|
||||
@ r2 = Dest Address
|
||||
@ r4 = Dest Address + Length
|
||||
@---------------------------------------------------------------------------------
|
||||
CopyMemChk:
|
||||
@---------------------------------------------------------------------------------
|
||||
sub r3, r4, r2 @ Is there any data to copy?
|
||||
@---------------------------------------------------------------------------------
|
||||
@ Copy memory
|
||||
@---------------------------------------------------------------------------------
|
||||
@ r1 = Source Address
|
||||
@ r2 = Dest Address
|
||||
@ r3 = Length
|
||||
@---------------------------------------------------------------------------------
|
||||
CopyMem:
|
||||
@---------------------------------------------------------------------------------
|
||||
mov r0, #3 @ These commands are used in cases where
|
||||
add r3, r0 @ the length is not a multiple of 4,
|
||||
bic r3, r0 @ even though it should be.
|
||||
beq CIDExit @ Length is zero so exit
|
||||
|
||||
@---------------------------------------------------------------------------------
|
||||
CIDLoop:
|
||||
@---------------------------------------------------------------------------------
|
||||
ldmia r1!, {r0}
|
||||
stmia r2!, {r0}
|
||||
sub r3, #4
|
||||
bne CIDLoop
|
||||
@---------------------------------------------------------------------------------
|
||||
CIDExit:
|
||||
@---------------------------------------------------------------------------------
|
||||
bx lr
|
||||
|
||||
.align
|
||||
.pool
|
||||
.end
|
||||
|
||||
12
deps/ox/.gdblogger.json
vendored
12
deps/ox/.gdblogger.json
vendored
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
deps/ox/.gitignore
vendored
10
deps/ox/.gitignore
vendored
@@ -1,10 +0,0 @@
|
||||
build/current
|
||||
build/gba
|
||||
build/*-asan
|
||||
build/*-debug
|
||||
build/*-release
|
||||
tags
|
||||
conanbuildinfo.cmake
|
||||
conanbuildinfo.txt
|
||||
conaninfo.txt
|
||||
graph_info.json
|
||||
9
deps/ox/.liccor.yml
vendored
9
deps/ox/.liccor.yml
vendored
@@ -1,9 +0,0 @@
|
||||
---
|
||||
source:
|
||||
- src
|
||||
copyright_notice: |-
|
||||
Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
|
||||
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 http://mozilla.org/MPL/2.0/.
|
||||
11
deps/ox/.travis.yml
vendored
11
deps/ox/.travis.yml
vendored
@@ -1,11 +0,0 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
dist: trusty
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cmake
|
||||
script: ./scripts/cibuild
|
||||
76
deps/ox/CMakeLists.txt
vendored
76
deps/ox/CMakeLists.txt
vendored
@@ -1,76 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(Ox)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
include(address_sanitizer)
|
||||
|
||||
if(NOT DEFINED OX_RUN_TESTS)
|
||||
set(OX_RUN_TESTS ON)
|
||||
endif()
|
||||
if(NOT DEFINED OX_BUILD_EXEC)
|
||||
set(OX_BUILD_EXEC ON)
|
||||
endif()
|
||||
if(NOT DEFINED OX_USE_STDLIB)
|
||||
set(OX_USE_STDLIB ON)
|
||||
endif()
|
||||
if(NOT DEFINED OX_BARE_METAL)
|
||||
set(OX_BARE_METAL OFF)
|
||||
endif()
|
||||
|
||||
set(OX_RUN_TESTS ${OX_RUN_TESTS} CACHE BOOL "Run tests (ON/OFF)")
|
||||
set(OX_BUILD_EXEC ${OX_BUILD_EXEC} CACHE BOOL "Build executables (ON/OFF)")
|
||||
set(OX_USE_STDLIB ${OX_USE_STDLIB} CACHE BOOL "Build libraries that need the std lib (ON/OFF)")
|
||||
set(OX_BARE_METAL ${OX_BARE_METAL} CACHE BOOL "Bare metal build (TRUE/FALSE)")
|
||||
|
||||
# can't run tests without building them
|
||||
if(NOT OX_BUILD_EXEC OR NOT OX_USE_STDLIB)
|
||||
set(OX_BUILD_EXEC OFF)
|
||||
set(OX_RUN_TESTS OFF)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
add_definitions(-DNDEBUG)
|
||||
else()
|
||||
add_definitions(-DDEBUG)
|
||||
endif()
|
||||
|
||||
if(NOT OX_USE_STDLIB)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-align")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdouble-promotion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare")
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-variable")
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
endif()
|
||||
# forces colored output when using ninja
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
include_directories("src")
|
||||
|
||||
install(FILES OxConfig.cmake DESTINATION lib/ox)
|
||||
|
||||
add_subdirectory(src)
|
||||
373
deps/ox/LICENSE
vendored
373
deps/ox/LICENSE
vendored
@@ -1,373 +0,0 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
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 http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
68
deps/ox/Makefile
vendored
68
deps/ox/Makefile
vendored
@@ -1,68 +0,0 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
15
deps/ox/OxConfig.cmake
vendored
15
deps/ox/OxConfig.cmake
vendored
@@ -1,15 +0,0 @@
|
||||
if("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
|
||||
set(Ox_INCLUDE_DIRS /usr/local/include/)
|
||||
set(OxStd_LIBRARY /usr/local/lib/ox/libOxStd.a)
|
||||
set(OxFS_LIBRARY /usr/local/lib/ox/libOxFS.a)
|
||||
set(OxClArgs_LIBRARY /usr/local/lib/ox/libOxClArgs.a)
|
||||
set(OxMetalClaw_LIBRARY /usr/local/lib/ox/libOxMetalClaw.a)
|
||||
set(OxModel_LIBRARY /usr/local/lib/ox/libOxModelClaw.a)
|
||||
else("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
|
||||
set(Ox_INCLUDE_DIRS ${CMAKE_FIND_ROOT_PATH}/include/)
|
||||
set(OxStd_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxStd.a)
|
||||
set(OxFS_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxFS.a)
|
||||
set(OxClArgs_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxClArgs.a)
|
||||
set(OxMetalClaw_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxMetalClaw.a)
|
||||
set(OxModel_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxModel.a)
|
||||
endif("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
|
||||
24
deps/ox/cmake/modules/GBA.cmake
vendored
24
deps/ox/cmake/modules/GBA.cmake
vendored
@@ -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
deps/ox/cmake/modules/Mingw.cmake
vendored
18
deps/ox/cmake/modules/Mingw.cmake
vendored
@@ -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
deps/ox/cmake/modules/address_sanitizer.cmake
vendored
52
deps/ox/cmake/modules/address_sanitizer.cmake
vendored
@@ -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
deps/ox/scripts/cibuild
vendored
8
deps/ox/scripts/cibuild
vendored
@@ -1,8 +0,0 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
make -j release
|
||||
make -j debug
|
||||
make -j
|
||||
make -j test
|
||||
8
deps/ox/scripts/run-make
vendored
8
deps/ox/scripts/run-make
vendored
@@ -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
|
||||
3
deps/ox/src/CMakeLists.txt
vendored
3
deps/ox/src/CMakeLists.txt
vendored
@@ -1,3 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
add_subdirectory(ox)
|
||||
8
deps/ox/src/ox/CMakeLists.txt
vendored
8
deps/ox/src/ox/CMakeLists.txt
vendored
@@ -1,8 +0,0 @@
|
||||
if(${OX_USE_STDLIB})
|
||||
add_subdirectory(clargs)
|
||||
endif()
|
||||
add_subdirectory(fs)
|
||||
add_subdirectory(mc)
|
||||
add_subdirectory(ptrarith)
|
||||
add_subdirectory(model)
|
||||
add_subdirectory(std)
|
||||
29
deps/ox/src/ox/clargs/CMakeLists.txt
vendored
29
deps/ox/src/ox/clargs/CMakeLists.txt
vendored
@@ -1,29 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
add_library(
|
||||
OxClArgs
|
||||
clargs.cpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
OxClArgs
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
target_link_libraries(OxClArgs OxStd)
|
||||
|
||||
install(
|
||||
FILES
|
||||
clargs.hpp
|
||||
DESTINATION
|
||||
include/ox/clargs
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
OxClArgs
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
53
deps/ox/src/ox/clargs/clargs.cpp
vendored
53
deps/ox/src/ox/clargs/clargs.cpp
vendored
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/strops.hpp>
|
||||
#include "clargs.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
using namespace ::std;
|
||||
|
||||
ClArgs::ClArgs(int argc, const char **args) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
string arg = args[i];
|
||||
if (arg[0] == '-') {
|
||||
while (arg[0] == '-' && arg.size()) {
|
||||
arg = arg.substr(1);
|
||||
}
|
||||
m_bools[arg] = true;
|
||||
|
||||
// parse additional arguments
|
||||
if (i < argc && args[i + 1]) {
|
||||
string val = args[i + 1];
|
||||
if (val.size() && val[i] != '-') {
|
||||
if (val == "false") {
|
||||
m_bools[arg] = false;
|
||||
}
|
||||
m_strings[arg] = val;
|
||||
m_ints[arg] = ox_atoi(val.c_str());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ClArgs::getBool(const char *arg) {
|
||||
return m_bools[arg];
|
||||
}
|
||||
|
||||
string ClArgs::getString(const char *arg) {
|
||||
return m_strings[arg];
|
||||
}
|
||||
|
||||
int ClArgs::getInt(const char *arg) {
|
||||
return m_ints[arg];
|
||||
}
|
||||
|
||||
}
|
||||
32
deps/ox/src/ox/clargs/clargs.hpp
vendored
32
deps/ox/src/ox/clargs/clargs.hpp
vendored
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class ClArgs {
|
||||
private:
|
||||
::std::map<::std::string, bool> m_bools;
|
||||
::std::map<::std::string, ::std::string> m_strings;
|
||||
::std::map<::std::string, int> m_ints;
|
||||
|
||||
public:
|
||||
ClArgs(int argc, const char **args);
|
||||
|
||||
bool getBool(const char *arg);
|
||||
|
||||
::std::string getString(const char *arg);
|
||||
|
||||
int getInt(const char *arg);
|
||||
};
|
||||
|
||||
}
|
||||
70
deps/ox/src/ox/fs/CMakeLists.txt
vendored
70
deps/ox/src/ox/fs/CMakeLists.txt
vendored
@@ -1,70 +0,0 @@
|
||||
|
||||
add_library(
|
||||
OxFS
|
||||
filestore/filestoretemplate.cpp
|
||||
filesystem/filelocation.cpp
|
||||
filesystem/pathiterator.cpp
|
||||
filesystem/directory.cpp
|
||||
filesystem/filesystem.cpp
|
||||
filesystem/passthroughfs.cpp
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
target_link_libraries(
|
||||
OxFS PUBLIC
|
||||
$<$<CXX_COMPILER_ID:Clang>:c++fs>
|
||||
$<$<CXX_COMPILER_ID:GNU>:stdc++fs>
|
||||
)
|
||||
set_property(
|
||||
TARGET
|
||||
OxFS
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
OxFS PUBLIC
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
if(OX_BUILD_EXEC STREQUAL "ON")
|
||||
#add_executable(
|
||||
# oxfstool
|
||||
# toollib.cpp
|
||||
# oxfstool.cpp
|
||||
#)
|
||||
#set_target_properties(oxfstool PROPERTIES OUTPUT_NAME oxfs)
|
||||
#target_link_libraries(
|
||||
# oxfstool
|
||||
# OxFS
|
||||
# OxMetalClaw
|
||||
# OxStd
|
||||
#)
|
||||
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(
|
||||
TARGETS
|
||||
OxFS
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "filestoretemplate.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template class FileStoreTemplate<uint16_t>;
|
||||
template class FileStoreTemplate<uint32_t>;
|
||||
|
||||
}
|
||||
777
deps/ox/src/ox/fs/filestore/filestoretemplate.hpp
vendored
777
deps/ox/src/ox/fs/filestore/filestoretemplate.hpp
vendored
@@ -1,777 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
using InodeId_t = uint64_t;
|
||||
using FsSize_t = std::size_t;
|
||||
|
||||
struct StatInfo {
|
||||
InodeId_t inode = 0;
|
||||
InodeId_t links = 0;
|
||||
FsSize_t size = 0;
|
||||
uint8_t fileType = 0;
|
||||
};
|
||||
|
||||
template<typename size_t>
|
||||
struct OX_PACKED FileStoreItem: public ptrarith::Item<size_t> {
|
||||
ox::LittleEndian<size_t> id = 0;
|
||||
ox::LittleEndian<uint8_t> fileType = 0;
|
||||
ox::LittleEndian<size_t> links = 0;
|
||||
ox::LittleEndian<size_t> left = 0;
|
||||
ox::LittleEndian<size_t> right = 0;
|
||||
|
||||
FileStoreItem() = default;
|
||||
|
||||
explicit FileStoreItem(size_t size) {
|
||||
this->setSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the data + the size of the Item type
|
||||
*/
|
||||
size_t fullSize() const {
|
||||
return sizeof(*this) + this->size();
|
||||
}
|
||||
|
||||
ptrarith::Ptr<uint8_t, std::size_t> data() {
|
||||
return ptrarith::Ptr<uint8_t, std::size_t>(this, this->fullSize(), sizeof(*this), this->size());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename size_t>
|
||||
class FileStoreTemplate {
|
||||
|
||||
public:
|
||||
using InodeId_t = size_t;
|
||||
|
||||
private:
|
||||
using Item = FileStoreItem<size_t>;
|
||||
using ItemPtr = typename ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>::ItemPtr;
|
||||
using Buffer = ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>;
|
||||
|
||||
static constexpr InodeId_t ReservedInodeEnd = 100;
|
||||
static constexpr auto MaxInode = MaxValue<size_t> / 2;
|
||||
|
||||
struct OX_PACKED FileStoreData {
|
||||
ox::LittleEndian<size_t> rootNode = 0;
|
||||
ox::Random random;
|
||||
};
|
||||
|
||||
size_t m_buffSize = 0;
|
||||
mutable Buffer *m_buffer = nullptr;
|
||||
|
||||
public:
|
||||
FileStoreTemplate() = default;
|
||||
|
||||
FileStoreTemplate(void *buff, size_t buffSize);
|
||||
|
||||
[[nodiscard]] static Error format(void *buffer, size_t bufferSize);
|
||||
|
||||
[[nodiscard]] Error setSize(InodeId_t buffSize);
|
||||
|
||||
[[nodiscard]] Error incLinks(InodeId_t id);
|
||||
|
||||
[[nodiscard]] Error decLinks(InodeId_t id);
|
||||
|
||||
[[nodiscard]] Error write(InodeId_t id, void *data, FsSize_t dataLen, uint8_t fileType = 0);
|
||||
|
||||
[[nodiscard]] Error remove(InodeId_t id);
|
||||
|
||||
[[nodiscard]] Error read(InodeId_t id, void *data, FsSize_t dataSize, FsSize_t *size = nullptr) const;
|
||||
|
||||
[[nodiscard]] Error read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size = nullptr) const;
|
||||
|
||||
const ptrarith::Ptr<uint8_t, std::size_t> read(InodeId_t id) const;
|
||||
|
||||
/**
|
||||
* Reads the "file" at the given id. You are responsible for freeing
|
||||
* the data when done with it.
|
||||
* @param id id of the "file"
|
||||
* @param readStart where in the data to start reading
|
||||
* @param readSize how much data to read
|
||||
* @param data pointer to the pointer where the data is stored
|
||||
* @param size pointer to a value that will be assigned the size of data
|
||||
* @return 0 if read is a success
|
||||
*/
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::Error read(InodeId_t id, FsSize_t readStart,
|
||||
FsSize_t readSize, T *data,
|
||||
FsSize_t *size) const;
|
||||
|
||||
[[nodiscard]] ValErr<StatInfo> stat(InodeId_t id);
|
||||
|
||||
[[nodiscard]] ox::Error resize();
|
||||
|
||||
[[nodiscard]] ox::Error resize(std::size_t size, void *newBuff = nullptr);
|
||||
|
||||
[[nodiscard]] InodeId_t spaceNeeded(FsSize_t size);
|
||||
|
||||
[[nodiscard]] InodeId_t size() const;
|
||||
|
||||
[[nodiscard]] InodeId_t available();
|
||||
|
||||
[[nodiscard]] char *buff();
|
||||
|
||||
[[nodiscard]] Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t));
|
||||
|
||||
[[nodiscard]] ValErr<InodeId_t> generateInodeId();
|
||||
|
||||
bool valid() const;
|
||||
|
||||
[[nodiscard]] ox::Error compact();
|
||||
|
||||
private:
|
||||
FileStoreData *fileStoreData() const;
|
||||
|
||||
/**
|
||||
* Places the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error placeItem(ItemPtr item);
|
||||
|
||||
/**
|
||||
* Places the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error placeItem(ItemPtr root, ItemPtr item, int depth = 0);
|
||||
|
||||
/**
|
||||
* Removes the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error unplaceItem(ItemPtr item);
|
||||
|
||||
/**
|
||||
* Removes the given Item at the given ID. If it already exists, the
|
||||
* existing value will be overwritten.
|
||||
*/
|
||||
Error unplaceItem(ItemPtr root, ItemPtr item, int depth = 0);
|
||||
|
||||
Error remove(ItemPtr item);
|
||||
|
||||
/**
|
||||
* Finds the parent an inode by its ID.
|
||||
*/
|
||||
ItemPtr findParent(ItemPtr ptr, size_t id, size_t oldAddr) const;
|
||||
|
||||
/**
|
||||
* Finds an inode by its ID.
|
||||
*/
|
||||
ItemPtr find(ItemPtr item, InodeId_t id, int depth = 0) const;
|
||||
|
||||
/**
|
||||
* Finds an inode by its ID.
|
||||
*/
|
||||
ItemPtr find(InodeId_t id) const;
|
||||
|
||||
/**
|
||||
* Gets the root inode.
|
||||
*/
|
||||
ItemPtr rootInode();
|
||||
|
||||
bool canWrite(ItemPtr existing, size_t size);
|
||||
|
||||
};
|
||||
|
||||
template<typename size_t>
|
||||
FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, size_t buffSize) {
|
||||
m_buffSize = buffSize;
|
||||
m_buffer = reinterpret_cast<ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>*>(buff);
|
||||
if (!m_buffer->valid(buffSize)) {
|
||||
m_buffSize = 0;
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::format(void *buffer, size_t bufferSize) {
|
||||
auto nb = new (buffer) Buffer(bufferSize);
|
||||
auto fsData = nb->malloc(sizeof(FileStoreData));
|
||||
if (fsData.valid()) {
|
||||
auto data = nb->template dataOf<FileStoreData>(fsData);
|
||||
if (data.valid()) {
|
||||
new (data) FileStoreData;
|
||||
return OxError(0);
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::format::fail") << "Could not read data section of FileStoreData";
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::setSize(InodeId_t size) {
|
||||
if (m_buffSize >= size) {
|
||||
return m_buffer->setSize(size);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
item->links++;
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
item->links--;
|
||||
if (item->links == 0) {
|
||||
remove(item);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::write(InodeId_t id, void *data, FsSize_t dataSize, uint8_t fileType) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Attempting to write to inode" << id;
|
||||
auto existing = find(id);
|
||||
if (!canWrite(existing, dataSize)) {
|
||||
oxReturnError(compact());
|
||||
existing = find(id);
|
||||
}
|
||||
|
||||
if (canWrite(existing, dataSize)) {
|
||||
// delete the old node if it exists
|
||||
if (existing.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Freeing old version of inode found at offset:" << existing.offset();
|
||||
auto err = m_buffer->free(existing);
|
||||
if (err) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write::fail") << "Free of old version of inode failed";
|
||||
return err;
|
||||
}
|
||||
existing = nullptr;
|
||||
}
|
||||
|
||||
// write the given data
|
||||
auto dest = m_buffer->malloc(dataSize);
|
||||
// if first malloc failed, compact and try again
|
||||
if (!dest.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Allocation failed, compacting";
|
||||
oxReturnError(compact());
|
||||
dest = m_buffer->malloc(dataSize);
|
||||
}
|
||||
if (dest.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Memory allocated";
|
||||
dest->id = id;
|
||||
dest->fileType = fileType;
|
||||
auto destData = m_buffer->template dataOf<uint8_t>(dest);
|
||||
if (destData.valid()) {
|
||||
oxAssert(destData.size() == dataSize, "Allocation size does not match data.");
|
||||
// write data if any was provided
|
||||
if (data != nullptr) {
|
||||
ox_memcpy(destData, data, dest->size());
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Data written";
|
||||
}
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Searching for root node at" << fsData->rootNode;
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Placing" << dest->id << "on" << root->id << "at" << destData.offset();
|
||||
return placeItem(dest);
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Initializing root inode:" << dest->id << "( offset:" << dest.offset()
|
||||
<< ", data size:" << destData.size() << ")";
|
||||
fsData->rootNode = dest.offset();
|
||||
oxTrace("ox::fs::FileStoreTemplate::write") << "Root inode:" << dest->id;
|
||||
return OxError(0);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::write::fail") << "Could not place item due to absence of FileStore header.";
|
||||
}
|
||||
}
|
||||
}
|
||||
oxReturnError(m_buffer->free(dest));
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::remove(InodeId_t id) {
|
||||
return remove(find(id));
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::read(InodeId_t id, void *out, FsSize_t outSize, FsSize_t *size) const {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read") << "Attempting to read from inode" << id;
|
||||
|
||||
auto src = find(id);
|
||||
|
||||
// error check
|
||||
if (!src.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not find requested item:" << id;
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
auto srcData = m_buffer->template dataOf<uint8_t>(src);
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::found") << id << "found at"<< src.offset()
|
||||
<< "with data section at" << srcData.offset();
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::outSize") << srcData.offset() << srcData.size() << outSize;
|
||||
|
||||
// error check
|
||||
if (!(srcData.valid() && srcData.size() <= outSize)) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail")
|
||||
<< "Could not read data section of item:" << id;
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail").del("")
|
||||
<< "Item data section size: " << srcData.size()
|
||||
<< ", Expected size: " << outSize;
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ox_memcpy(out, srcData, srcData.size());
|
||||
if (size) {
|
||||
*size = src.size();
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size) const {
|
||||
auto src = find(id);
|
||||
if (src.valid()) {
|
||||
auto srcData = src->data();
|
||||
if (srcData.valid()) {
|
||||
auto sub = srcData.template subPtr<uint8_t>(readStart, readSize);
|
||||
if (sub.valid()) {
|
||||
ox_memcpy(data, sub, sub.size());
|
||||
if (size) {
|
||||
*size = sub.size();
|
||||
}
|
||||
return OxError(0);
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not read requested data sub-section of item:" << id;
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not read data section of item:" << id;
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::read::fail") << "Could not find requested item:" << id;
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
template<typename T>
|
||||
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart,
|
||||
FsSize_t readSize, T *data, FsSize_t *size) const {
|
||||
auto src = find(id);
|
||||
if (src.valid()) {
|
||||
auto srcData = src->data();
|
||||
if (srcData.valid()) {
|
||||
auto sub = srcData.template subPtr<uint8_t>(readStart, readSize);
|
||||
if (sub.valid() && sub.size() % sizeof(T)) {
|
||||
for (FsSize_t i = 0; i < sub.size() / sizeof(T); i++) {
|
||||
// do byte-by-byte copy to ensure alignment is right when
|
||||
// copying to final destination
|
||||
T tmp;
|
||||
for (size_t ii = 0; ii < sizeof(T); ii++) {
|
||||
reinterpret_cast<uint8_t*>(&tmp)[ii] = *(sub.get() + ii);
|
||||
}
|
||||
*(data + i) = tmp;
|
||||
}
|
||||
if (size) {
|
||||
*size = sub.size();
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
const ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(InodeId_t id) const {
|
||||
auto item = find(id);
|
||||
if (item.valid()) {
|
||||
return item->data();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ox::Error FileStoreTemplate<size_t>::resize() {
|
||||
oxReturnError(compact());
|
||||
const auto newSize = size() - available();
|
||||
oxTrace("ox::fs::FileStoreTemplate::resize") << "resize to:" << newSize;
|
||||
oxReturnError(m_buffer->setSize(newSize));
|
||||
oxTrace("ox::fs::FileStoreTemplate::resize") << "resized to:" << m_buffer->size();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
|
||||
if (m_buffer->size() > size) {
|
||||
return OxError(1);
|
||||
}
|
||||
m_buffSize = size;
|
||||
if (newBuff) {
|
||||
m_buffer = reinterpret_cast<Buffer*>(newBuff);
|
||||
oxReturnError(m_buffer->setSize(size));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ValErr<StatInfo> FileStoreTemplate<size_t>::stat(InodeId_t id) {
|
||||
auto inode = find(id);
|
||||
if (inode.valid()) {
|
||||
return ValErr<StatInfo>({
|
||||
id,
|
||||
inode->links,
|
||||
inode->size(),
|
||||
inode->fileType,
|
||||
});
|
||||
}
|
||||
return ValErr<StatInfo>({}, OxError(0));
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::InodeId_t FileStoreTemplate<size_t>::spaceNeeded(FsSize_t size) {
|
||||
return m_buffer->spaceNeeded(size);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::InodeId_t FileStoreTemplate<size_t>::size() const {
|
||||
return m_buffer->size();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::InodeId_t FileStoreTemplate<size_t>::available() {
|
||||
return m_buffer->available();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
char *FileStoreTemplate<size_t>::buff() {
|
||||
return reinterpret_cast<char*>(m_buffer);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) {
|
||||
for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
|
||||
oxReturnError(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ValErr<typename FileStoreTemplate<size_t>::InodeId_t> FileStoreTemplate<size_t>::generateInodeId() {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
for (auto i = 0; i < 100; i++) {
|
||||
auto inode = fsData->random.gen() % MaxValue<InodeId_t>;
|
||||
if (inode > ReservedInodeEnd && !find(inode).valid()) {
|
||||
return inode;
|
||||
}
|
||||
}
|
||||
return {0, OxError(2)};
|
||||
}
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
ox::Error FileStoreTemplate<size_t>::compact() {
|
||||
auto isFirstItem = true;
|
||||
return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> ox::Error {
|
||||
if (isFirstItem) {
|
||||
isFirstItem = false;
|
||||
return OxError(0);
|
||||
}
|
||||
if (!item.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
oxTrace("ox::FileStoreTemplate::compact::moveItem")
|
||||
<< "Moving Item:" << item->id
|
||||
<< "from" << oldAddr
|
||||
<< "to" << item.offset();
|
||||
// update rootInode if this is it
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData && oldAddr == fsData->rootNode) {
|
||||
fsData->rootNode = item.offset();
|
||||
}
|
||||
auto parent = findParent(rootInode(), item->id, oldAddr);
|
||||
oxAssert(parent.valid() || rootInode() == item.offset(),
|
||||
"Parent inode not found for item that should have parent.");
|
||||
if (parent.valid()) {
|
||||
if (parent->left == oldAddr) {
|
||||
parent->left = item;
|
||||
} else if (parent->right == oldAddr) {
|
||||
parent->right = item;
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::FileStoreData *FileStoreTemplate<size_t>::fileStoreData() const {
|
||||
auto first = m_buffer->firstItem();
|
||||
if (first.valid()) {
|
||||
auto data = first->data();
|
||||
if (data.valid()) {
|
||||
return reinterpret_cast<FileStoreData*>(data.get());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
if (root->id == item->id) {
|
||||
fsData->rootNode = item;
|
||||
item->left = root->left;
|
||||
item->right = root->right;
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Overwrote Root Item:" << item->id;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return placeItem(root, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth) {
|
||||
if (depth < 5000) {
|
||||
if (item->id > root->id) {
|
||||
auto right = m_buffer->ptr(root->right);
|
||||
if (!right.valid() || right->id == item->id) {
|
||||
root->right = item.offset();
|
||||
if (right.valid()) {
|
||||
item->left = right->left;
|
||||
item->right = right->right;
|
||||
}
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Placed Item:" << item->id;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return placeItem(right, item, depth + 1);
|
||||
}
|
||||
} else if (item->id < root->id) {
|
||||
auto left = m_buffer->ptr(root->left);
|
||||
if (!left.valid() || left->id == item->id) {
|
||||
root->left = item.offset();
|
||||
if (left.valid()) {
|
||||
item->left = left->left;
|
||||
item->right = left->right;
|
||||
}
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem") << "Placed Item:" << item->id;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return placeItem(left, item, depth + 1);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem::fail") << "Cannot insert an item on itself.";
|
||||
return OxError(1);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::placeItem::fail") << "Excessive recursion depth, stopping before stack overflow.";
|
||||
return OxError(2);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
if (root->id == item->id) {
|
||||
item->left = root->left;
|
||||
item->right = root->right;
|
||||
auto left = m_buffer->ptr(item->left);
|
||||
auto right = m_buffer->ptr(item->right);
|
||||
if (right.valid()) {
|
||||
auto oldRoot = fsData->rootNode;
|
||||
fsData->rootNode = item->right;
|
||||
if (left.valid()) {
|
||||
auto err = placeItem(left);
|
||||
// undo if unable to place the left side of the tree
|
||||
if (err) {
|
||||
fsData->rootNode = oldRoot;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else if (left.valid()) {
|
||||
fsData->rootNode = item->left;
|
||||
} else {
|
||||
fsData->rootNode = 0;
|
||||
}
|
||||
return OxError(0);
|
||||
} else {
|
||||
return unplaceItem(root, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int depth) {
|
||||
if (depth >= 5000) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::unplaceItem::fail") << "Excessive recursion depth, stopping before stack overflow.";
|
||||
return OxError(1);
|
||||
}
|
||||
if (item->id > root->id) {
|
||||
auto right = m_buffer->ptr(root->right);
|
||||
if (right->id == item->id) {
|
||||
root->right = 0;
|
||||
oxTrace("ox::fs::FileStoreTemplate::unplaceItem") << "Unplaced Item:" << item->id;
|
||||
} else {
|
||||
return unplaceItem(right, item, depth + 1);
|
||||
}
|
||||
} else if (item->id < root->id) {
|
||||
auto left = m_buffer->ptr(root->left);
|
||||
if (left->id == item->id) {
|
||||
root->left = 0;
|
||||
oxTrace("ox::fs::FileStoreTemplate::unplaceItem") << "Unplaced Item:" << item->id;
|
||||
} else {
|
||||
return unplaceItem(left, item, depth + 1);
|
||||
}
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
if (item->right) {
|
||||
oxReturnError(placeItem(m_buffer->ptr(item->right)));
|
||||
}
|
||||
if (item->left) {
|
||||
oxReturnError(placeItem(m_buffer->ptr(item->left)));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
|
||||
if (item.valid()) {
|
||||
oxReturnError(unplaceItem(item));
|
||||
oxReturnError(m_buffer->free(item));
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::findParent(ItemPtr item, size_t id, size_t oldAddr) const {
|
||||
// This is a little bit confusing. findParent uses the inode ID to find
|
||||
// where the target ID should be, but the actual address of that item is
|
||||
// currently invalid, so we check it against what is known to be the old
|
||||
// address of the item to confirm that we have the right item.
|
||||
if (item.valid()) {
|
||||
if (id > item->id) {
|
||||
if (item->right == oldAddr) {
|
||||
return item;
|
||||
} else {
|
||||
auto right = m_buffer->ptr(item->right);
|
||||
return findParent(right, id, oldAddr);
|
||||
}
|
||||
} else if (id < item->id) {
|
||||
if (item->left == oldAddr) {
|
||||
return item;
|
||||
} else {
|
||||
auto left = m_buffer->ptr(item->left);
|
||||
return findParent(left, id, oldAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(ItemPtr item, InodeId_t id, int depth) const {
|
||||
if (depth > 5000) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "Excessive recursion depth, stopping before stack overflow. Search for:" << id;
|
||||
return nullptr;
|
||||
}
|
||||
if (!item.valid()) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "item invalid";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (id > item->id) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Not a match, searching on" << item->right;
|
||||
return find(m_buffer->ptr(item->right), id, depth + 1);
|
||||
} else if (id < item->id) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Not a match, searching on" << item->left;
|
||||
return find(m_buffer->ptr(item->left), id, depth + 1);
|
||||
} else if (id == item->id) {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Found" << id << "at" << item;
|
||||
return item;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(InodeId_t id) const {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find") << "Searching for inode:" << id;
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
auto root = m_buffer->ptr(fsData->rootNode);
|
||||
if (root.valid()) {
|
||||
auto item = find(root, id);
|
||||
return item;
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "No root node";
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::FileStoreTemplate::find::fail") << "No FileStore Data";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root inode.
|
||||
*/
|
||||
template<typename size_t>
|
||||
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::rootInode() {
|
||||
auto fsData = fileStoreData();
|
||||
if (fsData) {
|
||||
return m_buffer->ptr(fsData->rootNode);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
bool FileStoreTemplate<size_t>::canWrite(ItemPtr existing, size_t size) {
|
||||
return existing.size() >= size || m_buffer->spaceNeeded(size) <= m_buffer->available();
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
bool FileStoreTemplate<size_t>::valid() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
extern template class FileStoreTemplate<uint16_t>;
|
||||
extern template class FileStoreTemplate<uint32_t>;
|
||||
|
||||
using FileStore16 = FileStoreTemplate<uint16_t>;
|
||||
using FileStore32 = FileStoreTemplate<uint32_t>;
|
||||
|
||||
}
|
||||
19
deps/ox/src/ox/fs/filesystem/directory.cpp
vendored
19
deps/ox/src/ox/fs/filesystem/directory.cpp
vendored
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "directory.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template class Directory<FileStore16, uint16_t>;
|
||||
template class Directory<FileStore32, uint32_t>;
|
||||
|
||||
template struct DirectoryEntry<uint16_t>;
|
||||
template struct DirectoryEntry<uint32_t>;
|
||||
|
||||
}
|
||||
371
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
371
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/fs/filesystem/pathiterator.hpp>
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename InodeId_t>
|
||||
struct OX_PACKED DirectoryEntry {
|
||||
|
||||
public:
|
||||
struct OX_PACKED DirectoryEntryData {
|
||||
// DirectoryEntry fields
|
||||
LittleEndian<InodeId_t> inode = 0;
|
||||
char name[MaxFileNameLength];
|
||||
|
||||
static constexpr std::size_t spaceNeeded(std::size_t chars) {
|
||||
return offsetof(DirectoryEntryData, name) + chars;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// NodeBuffer fields
|
||||
LittleEndian<InodeId_t> prev = 0;
|
||||
LittleEndian<InodeId_t> next = 0;
|
||||
|
||||
|
||||
private:
|
||||
LittleEndian<InodeId_t> m_bufferSize = sizeof(DirectoryEntry);
|
||||
|
||||
public:
|
||||
DirectoryEntry() = default;
|
||||
|
||||
[[nodiscard]] ox::Error init(InodeId_t inode, const char *name, InodeId_t bufferSize) {
|
||||
m_bufferSize = bufferSize;
|
||||
auto d = data();
|
||||
if (d.valid()) {
|
||||
d->inode = inode;
|
||||
ox_strncpy(d->name, name, ox::min(bufferSize, static_cast<InodeId_t>(MaxFileNameLength)));
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ptrarith::Ptr<DirectoryEntryData, InodeId_t> data() {
|
||||
oxTrace("ox::fs::DirectoryEntry::data") << this->fullSize() << sizeof(*this) << this->size();
|
||||
return ptrarith::Ptr<DirectoryEntryData, InodeId_t>(this, this->fullSize(), sizeof(*this), this->size(), this->size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of the data + the size of the Item type
|
||||
*/
|
||||
InodeId_t fullSize() const {
|
||||
return m_bufferSize;
|
||||
}
|
||||
|
||||
InodeId_t size() const {
|
||||
return fullSize() - sizeof(*this);
|
||||
}
|
||||
|
||||
void setSize(InodeId_t) {
|
||||
// ignore set value
|
||||
}
|
||||
|
||||
static constexpr std::size_t spaceNeeded(std::size_t chars) {
|
||||
return sizeof(DirectoryEntry) + offsetof(DirectoryEntryData, name) + chars;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
class Directory {
|
||||
|
||||
private:
|
||||
using Buffer = ptrarith::NodeBuffer<InodeId_t, DirectoryEntry<InodeId_t>>;
|
||||
|
||||
InodeId_t m_inodeId = 0;
|
||||
std::size_t m_size = 0;
|
||||
FileStore m_fs;
|
||||
|
||||
public:
|
||||
Directory() = default;
|
||||
|
||||
Directory(FileStore fs, InodeId_t inode);
|
||||
|
||||
/**
|
||||
* Initializes Directory.
|
||||
*/
|
||||
[[nodiscard]] ox::Error init() noexcept;
|
||||
|
||||
[[nodiscard]] ox::Error mkdir(PathIterator path, bool parents, FileName *nameBuff = nullptr);
|
||||
|
||||
/**
|
||||
* @param parents indicates the operation should create non-existent directories in the path, like mkdir -p
|
||||
*/
|
||||
[[nodiscard]] ox::Error write(PathIterator it, InodeId_t inode, FileName *nameBuff = nullptr) noexcept;
|
||||
|
||||
[[nodiscard]] ox::Error remove(PathIterator it, FileName *nameBuff = nullptr) noexcept;
|
||||
|
||||
template<typename F>
|
||||
[[nodiscard]] ox::Error ls(F cb) noexcept;
|
||||
|
||||
[[nodiscard]] ValErr<typename FileStore::InodeId_t> findEntry(const FileName &name) const noexcept;
|
||||
|
||||
[[nodiscard]] ValErr<typename FileStore::InodeId_t> find(PathIterator name, FileName *nameBuff = nullptr) const noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
Directory<FileStore, InodeId_t>::Directory(FileStore fs, InodeId_t inodeId) {
|
||||
m_fs = fs;
|
||||
m_inodeId = inodeId;
|
||||
auto buff = m_fs.read(inodeId).template to<Buffer>();
|
||||
if (buff.valid()) {
|
||||
m_size = buff.size();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::init() noexcept {
|
||||
constexpr auto Size = sizeof(Buffer);
|
||||
oxTrace("ox::fs::Directory::init") << "Initializing Directory with Inode ID:" << m_inodeId;
|
||||
oxReturnError(m_fs.write(m_inodeId, nullptr, Size));
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
m_size = 0;
|
||||
return OxError(1);
|
||||
}
|
||||
new (buff) Buffer(Size);
|
||||
m_size = Size;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, FileName *nameBuff) {
|
||||
if (path.valid()) {
|
||||
oxTrace("ox::fs::Directory::mkdir") << path.fullPath();
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
|
||||
// determine if already exists
|
||||
auto name = nameBuff;
|
||||
path.get(name);
|
||||
auto childInode = find(name->c_str());
|
||||
if (!childInode.ok()) {
|
||||
// if this is not the last item in the path and parents is disabled,
|
||||
// return an error
|
||||
if (!parents && path.hasNext()) {
|
||||
return OxError(1);
|
||||
}
|
||||
childInode = m_fs.generateInodeId();
|
||||
oxTrace("ox::fs::Directory::mkdir") << "Generated Inode ID:" << childInode.value;
|
||||
oxLogError(childInode.error);
|
||||
oxReturnError(childInode.error);
|
||||
|
||||
// initialize the directory
|
||||
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
|
||||
oxReturnError(child.init());
|
||||
|
||||
auto err = write(name->c_str(), childInode.value);
|
||||
if (err) {
|
||||
oxLogError(err);
|
||||
// could not index the directory, delete it
|
||||
oxLogError(m_fs.remove(childInode.value));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
|
||||
if (path.hasNext()) {
|
||||
oxReturnError(child.mkdir(path.next(), parents, nameBuff));
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode, FileName *nameBuff) noexcept {
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
auto name = nameBuff;
|
||||
|
||||
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
|
||||
oxReturnError(path.get(name));
|
||||
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write to next sub-Directory: "
|
||||
<< name->c_str() << " of " << path.fullPath();
|
||||
|
||||
auto [nextChild, err] = findEntry(*name);
|
||||
oxReturnError(err);
|
||||
|
||||
oxTrace("ox::fs::Directory::write") << name->c_str() << ": " << nextChild;
|
||||
|
||||
if (nextChild) {
|
||||
// reuse name because it is a rather large variable and will not be used again
|
||||
// be attentive that this remains true
|
||||
name = nullptr;
|
||||
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::write") << name->c_str()
|
||||
<< "not found and not allowed to create it.";
|
||||
return OxError(1);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::write") << path.fullPath();
|
||||
// insert the new entry on this directory
|
||||
|
||||
// get the name
|
||||
path.next(name);
|
||||
|
||||
// find existing version of directory
|
||||
oxTrace("ox::fs::Directory::write") << "Searching for directory inode" << m_inodeId;
|
||||
auto oldStat = m_fs.stat(m_inodeId);
|
||||
oxReturnError(oldStat);
|
||||
oxTrace("ox::fs::Directory::write") << "Found existing directory of size" << oldStat.value.size;
|
||||
auto old = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!old.valid()) {
|
||||
oxTrace("ox::fs::Directory::write::fail") << "Could not read existing version of Directory";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
const auto pathSize = name->len() + 1;
|
||||
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
|
||||
const auto newSize = oldStat.value.size + Buffer::spaceNeeded(entryDataSize);
|
||||
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.value.size);
|
||||
if (cpy == nullptr) {
|
||||
oxTrace("ox::fs::Directory::write::fail") << "Could not allocate memory for copy of Directory";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
// TODO: look for old version of this entry and delete it
|
||||
oxReturnError(cpy->setSize(newSize));
|
||||
auto val = cpy->malloc(entryDataSize);
|
||||
if (!val.valid()) {
|
||||
oxTrace("ox::fs::Directory::write::fail") << "Could not allocate memory for new directory entry";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write Directory entry:" << name->data();
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write Directory to FileStore";
|
||||
oxReturnError(val->init(inode, name->data(), val.size()));
|
||||
return m_fs.write(m_inodeId, cpy, cpy->size());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameBuff) noexcept {
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
auto &name = *nameBuff;
|
||||
oxReturnError(path.get(&name));
|
||||
|
||||
oxTrace("ox::fs::Directory::remove") << name.c_str();
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (buff.valid()) {
|
||||
oxTrace("ox::fs::Directory::remove") << "Found directory buffer.";
|
||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||
auto data = i->data();
|
||||
if (data.valid()) {
|
||||
if (ox_strncmp(data->name, name.c_str(), name.len()) == 0) {
|
||||
oxReturnError(buff->free(i));
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::remove") << "INVALID DIRECTORY ENTRY";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::remove::fail") << "Could not find directory buffer";
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
template<typename F>
|
||||
ox::Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
|
||||
oxTrace("ox::fs::Directory::ls");
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
oxTrace("ox::fs::Directory::ls::fail") << "Could not directory buffer";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
oxTrace("ox::fs::Directory::ls") << "Found directory buffer.";
|
||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||
auto data = i->data();
|
||||
if (data.valid()) {
|
||||
oxReturnError(cb(data->name, data->inode));
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::ls") << "INVALID DIRECTORY ENTRY";
|
||||
}
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ValErr<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept {
|
||||
oxTrace("ox::fs::Directory::findEntry") << name.c_str();
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
oxTrace("ox::fs::Directory::findEntry::fail") << "Could not findEntry directory buffer";
|
||||
return {0, OxError(2)};
|
||||
}
|
||||
oxTrace("ox::fs::Directory::findEntry") << "Found directory buffer, size:" << buff.size();
|
||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||
auto data = i->data();
|
||||
if (data.valid()) {
|
||||
oxTrace("ox::fs::Directory::findEntry").del("") << "Comparing \"" << name.c_str() << "\" to \"" << data->name << "\"";
|
||||
if (ox_strncmp(data->name, name.c_str(), MaxFileNameLength) == 0) {
|
||||
oxTrace("ox::fs::Directory::findEntry").del("") << "\"" << name.c_str() << "\" match found.";
|
||||
return static_cast<InodeId_t>(data->inode);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::fs::Directory::findEntry") << "INVALID DIRECTORY ENTRY";
|
||||
}
|
||||
}
|
||||
oxTrace("ox::fs::Directory::findEntry::fail") << "Entry not present";
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename InodeId_t>
|
||||
ValErr<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(PathIterator path, FileName *nameBuff) const noexcept {
|
||||
// reuse nameBuff if it has already been allocated, as it is a rather large variable
|
||||
if (nameBuff == nullptr) {
|
||||
nameBuff = reinterpret_cast<FileName*>(ox_alloca(sizeof(FileName)));
|
||||
}
|
||||
|
||||
// determine if already exists
|
||||
auto name = nameBuff;
|
||||
oxReturnError(path.get(name));
|
||||
|
||||
auto v = findEntry(name->c_str());
|
||||
oxReturnError(v);
|
||||
// recurse if not at end of path
|
||||
if (auto p = path.next(); p.valid()) {
|
||||
Directory dir(m_fs, v.value);
|
||||
name = nullptr;
|
||||
return dir.find(p, nameBuff);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
extern template class Directory<FileStore16, uint16_t>;
|
||||
extern template class Directory<FileStore32, uint32_t>;
|
||||
|
||||
extern template struct DirectoryEntry<uint16_t>;
|
||||
extern template struct DirectoryEntry<uint32_t>;
|
||||
|
||||
using Directory16 = Directory<FileStore16, uint16_t>;
|
||||
using Directory32 = Directory<FileStore32, uint32_t>;
|
||||
|
||||
}
|
||||
69
deps/ox/src/ox/fs/filesystem/filelocation.cpp
vendored
69
deps/ox/src/ox/fs/filesystem/filelocation.cpp
vendored
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "filelocation.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
FileAddress::FileAddress() {
|
||||
m_data.inode = 0;
|
||||
m_type = FileAddressType::Inode;
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(const FileAddress &other) {
|
||||
operator=(other);
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(std::nullptr_t) {
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(uint64_t inode) {
|
||||
m_data.inode = inode;
|
||||
m_type = FileAddressType::Inode;
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(char *path) {
|
||||
auto pathSize = ox_strlen(path) + 1;
|
||||
m_data.path = new char[pathSize];
|
||||
memcpy(m_data.path, path, pathSize);
|
||||
m_type = FileAddressType::Path;
|
||||
}
|
||||
|
||||
FileAddress::FileAddress(const char *path) {
|
||||
m_data.constPath = path;
|
||||
m_type = FileAddressType::ConstPath;
|
||||
}
|
||||
|
||||
FileAddress::~FileAddress() {
|
||||
if (m_type == FileAddressType::Path) {
|
||||
delete[] m_data.path;
|
||||
m_data.path = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const FileAddress &FileAddress::operator=(const FileAddress &other) {
|
||||
m_type = other.m_type;
|
||||
switch (m_type) {
|
||||
case FileAddressType::Path:
|
||||
{
|
||||
auto strSize = ox_strlen(other.m_data.path) + 1;
|
||||
m_data.path = new char[strSize];
|
||||
ox_memcpy(m_data.path, other.m_data.path, strSize);
|
||||
break;
|
||||
}
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Inode:
|
||||
m_data = other.m_data;
|
||||
break;
|
||||
case FileAddressType::None:
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
148
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
148
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/std.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum class FileAddressType: int8_t {
|
||||
None = -1,
|
||||
Path,
|
||||
ConstPath,
|
||||
Inode,
|
||||
};
|
||||
|
||||
class FileAddress {
|
||||
|
||||
template<typename T>
|
||||
friend ox::Error modelRead(T*, FileAddress*);
|
||||
|
||||
template<typename T>
|
||||
friend ox::Error modelWrite(T*, FileAddress*);
|
||||
|
||||
public:
|
||||
static constexpr auto Fields = 2;
|
||||
|
||||
protected:
|
||||
FileAddressType m_type = FileAddressType::None;
|
||||
union {
|
||||
char *path;
|
||||
const char *constPath;
|
||||
uint64_t inode;
|
||||
} m_data;
|
||||
|
||||
public:
|
||||
FileAddress();
|
||||
|
||||
FileAddress(const FileAddress &other);
|
||||
|
||||
FileAddress(std::nullptr_t);
|
||||
|
||||
FileAddress(uint64_t inode);
|
||||
|
||||
FileAddress(char *path);
|
||||
|
||||
FileAddress(const char *path);
|
||||
|
||||
~FileAddress();
|
||||
|
||||
const FileAddress &operator=(const FileAddress &other);
|
||||
|
||||
[[nodiscard]] constexpr FileAddressType type() const noexcept {
|
||||
switch (m_type) {
|
||||
case FileAddressType::Path:
|
||||
case FileAddressType::ConstPath:
|
||||
return FileAddressType::Path;
|
||||
default:
|
||||
return m_type;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ValErr<uint64_t> getInode() const noexcept {
|
||||
switch (m_type) {
|
||||
case FileAddressType::Inode:
|
||||
return m_data.inode;
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ValErr<const char*> getPath() const noexcept {
|
||||
switch (m_type) {
|
||||
case FileAddressType::Path:
|
||||
return m_data.path;
|
||||
case FileAddressType::ConstPath:
|
||||
return m_data.constPath;
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return m_type != FileAddressType::None;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelRead(T *io, FileAddress *fa) {
|
||||
io->setTypeInfo("ox::FileAddress", FileAddress::Fields);
|
||||
decltype(fa->m_data.inode) inode = 0;
|
||||
const auto strSize = io->stringLength() + 1;
|
||||
auto path = new char[strSize];
|
||||
oxReturnError(io->field("path", SerStr(path, strSize - 1)));
|
||||
oxReturnError(io->field("inode", &inode));
|
||||
if (strSize) {
|
||||
fa->m_data.path = path;
|
||||
fa->m_type = FileAddressType::Path;
|
||||
} else {
|
||||
fa->m_data.inode = inode;
|
||||
fa->m_type = FileAddressType::Inode;
|
||||
delete[] path;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelWrite(T *io, FileAddress *fa) {
|
||||
io->setTypeInfo("ox::FileAddress", FileAddress::Fields);
|
||||
switch (fa->m_type) {
|
||||
case FileAddressType::Path:
|
||||
case FileAddressType::ConstPath:
|
||||
{
|
||||
decltype(fa->m_data.inode) blank = 0;
|
||||
const auto strSize = ox_strlen(fa->m_data.constPath) + 1;
|
||||
auto path = ox_malloca(strSize, char, 0);
|
||||
memcpy(path.get(), fa->m_data.constPath, strSize);
|
||||
oxReturnError(io->field("path", SerStr(path.get(), strSize - 1)));
|
||||
oxReturnError(io->field("inode", &blank));
|
||||
break;
|
||||
}
|
||||
case FileAddressType::Inode:
|
||||
{
|
||||
char blankPath[1] = "";
|
||||
oxReturnError(io->field("path", SerStr(blankPath, 0)));
|
||||
oxReturnError(io->field("inode", &fa->m_data.inode));
|
||||
break;
|
||||
}
|
||||
case FileAddressType::None:
|
||||
{
|
||||
char blankPath[1] = "";
|
||||
decltype(fa->m_data.inode) blankInode = 0;
|
||||
oxReturnError(io->field("path", SerStr(blankPath, 0)));
|
||||
oxReturnError(io->field("inode", &blankInode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
}
|
||||
88
deps/ox/src/ox/fs/filesystem/filesystem.cpp
vendored
88
deps/ox/src/ox/fs/filesystem/filesystem.cpp
vendored
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> FileSystem::read(FileAddress addr) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return read(addr.getInode().value);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return read(addr.getPath().value);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ox::Error FileSystem::read(FileAddress addr, void *buffer, std::size_t size) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return read(addr.getInode().value, buffer, size);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return read(addr.getPath().value, buffer, size);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ox::Error FileSystem::read(FileAddress addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return read(addr.getInode().value, readStart, readSize, buffer, size);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return read(addr.getPath().value, readStart, readSize, buffer, size);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] ox::Error FileSystem::remove(FileAddress addr, bool recursive) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return remove(addr.getInode().value, recursive);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return remove(addr.getPath().value, recursive);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error FileSystem::write(FileAddress addr, void *buffer, uint64_t size, uint8_t fileType) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return write(addr.getInode().value, buffer, size, fileType);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return write(addr.getPath().value, buffer, size, fileType);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
ox::ValErr<FileStat> FileSystem::stat(FileAddress addr) {
|
||||
switch (addr.type()) {
|
||||
case FileAddressType::Inode:
|
||||
return stat(addr.getInode().value);
|
||||
case FileAddressType::ConstPath:
|
||||
case FileAddressType::Path:
|
||||
return stat(addr.getPath().value);
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
template class FileSystemTemplate<FileStore16, Directory16>;
|
||||
template class FileSystemTemplate<FileStore32, Directory32>;
|
||||
|
||||
}
|
||||
423
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
423
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
@@ -1,423 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/fs/filesystem/filelocation.hpp>
|
||||
#include <ox/fs/filesystem/types.hpp>
|
||||
|
||||
#include "directory.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
class FileSystem {
|
||||
|
||||
public:
|
||||
virtual ~FileSystem() = default;
|
||||
|
||||
[[nodiscard]] virtual ox::Error mkdir(const char *path, bool recursive = false) = 0;
|
||||
|
||||
/**
|
||||
* Moves an entry from one directory to another.
|
||||
* @param src the path to the file
|
||||
* @param dest the path of the destination directory
|
||||
*/
|
||||
[[nodiscard]] virtual ox::Error move(const char *src, const char *dest) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error read(const char *path, void *buffer, std::size_t buffSize) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<uint8_t*> read(const char *path) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error read(uint64_t inode, void *buffer, std::size_t size) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<uint8_t*> read(uint64_t inode) = 0;
|
||||
|
||||
[[nodiscard]] ox::Error read(FileAddress addr, void *buffer, std::size_t size);
|
||||
|
||||
[[nodiscard]] ox::Error read(FileAddress addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size);
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> read(FileAddress addr);
|
||||
|
||||
[[nodiscard]] virtual ox::Error remove(const char *path, bool recursive = false) = 0;
|
||||
|
||||
[[nodiscard]] ox::Error remove(FileAddress addr, bool recursive = false);
|
||||
|
||||
[[nodiscard]] virtual ox::Error resize(uint64_t size, void *buffer = nullptr) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0;
|
||||
|
||||
[[nodiscard]] ox::Error write(FileAddress addr, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile);
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<FileStat> stat(uint64_t inode) = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::ValErr<FileStat> stat(const char *path) = 0;
|
||||
|
||||
[[nodiscard]] ox::ValErr<FileStat> stat(FileAddress addr);
|
||||
|
||||
[[nodiscard]] virtual uint64_t spaceNeeded(uint64_t size) = 0;
|
||||
|
||||
[[nodiscard]] virtual uint64_t available() = 0;
|
||||
|
||||
[[nodiscard]] virtual uint64_t size() const = 0;
|
||||
|
||||
[[nodiscard]] virtual char *buff() = 0;
|
||||
|
||||
[[nodiscard]] virtual ox::Error walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) = 0;
|
||||
|
||||
[[nodiscard]] virtual bool valid() const = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* FileSystemTemplate used to create file system that wraps around a FileStore,
|
||||
* taking an inode size and a directory type as parameters.
|
||||
*
|
||||
* Note: Directory parameter must have a default constructor.
|
||||
*/
|
||||
template<typename FileStore, typename Directory>
|
||||
class FileSystemTemplate: public FileSystem {
|
||||
private:
|
||||
static constexpr auto InodeFsData = 2;
|
||||
|
||||
struct OX_PACKED FileSystemData {
|
||||
LittleEndian<typename FileStore::InodeId_t> rootDirInode;
|
||||
};
|
||||
|
||||
FileStore m_fs;
|
||||
void(*m_freeBuffer)(char*) = nullptr;
|
||||
|
||||
public:
|
||||
FileSystemTemplate() = default;
|
||||
|
||||
FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*) = [] (char *buff) { delete buff; });
|
||||
|
||||
FileSystemTemplate(FileStore fs);
|
||||
|
||||
~FileSystemTemplate();
|
||||
|
||||
[[nodiscard]] static ox::Error format(void *buff, uint64_t buffSize);
|
||||
|
||||
[[nodiscard]] ox::Error mkdir(const char *path, bool recursive = false) override;
|
||||
|
||||
[[nodiscard]] ox::Error move(const char *src, const char *dest) override;
|
||||
|
||||
[[nodiscard]] ox::Error read(const char *path, void *buffer, std::size_t buffSize) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> read(const char*) override;
|
||||
|
||||
[[nodiscard]] ox::Error read(uint64_t inode, void *buffer, std::size_t size) override;
|
||||
|
||||
[[nodiscard]] ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> read(uint64_t) override;
|
||||
|
||||
template<typename F>
|
||||
[[nodiscard]] ox::Error ls(const char *dir, F cb);
|
||||
|
||||
[[nodiscard]] ox::Error remove(const char *path, bool recursive = false) override;
|
||||
|
||||
/**
|
||||
* Resizes FileSystem to minimum possible size.
|
||||
*/
|
||||
[[nodiscard]] ox::Error resize();
|
||||
|
||||
[[nodiscard]] ox::Error resize(uint64_t size, void *buffer = nullptr) override;
|
||||
|
||||
[[nodiscard]] ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
[[nodiscard]] ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<FileStat> stat(uint64_t inode) override;
|
||||
|
||||
[[nodiscard]] ox::ValErr<FileStat> stat(const char *path) override;
|
||||
|
||||
uint64_t spaceNeeded(uint64_t size) override;
|
||||
|
||||
uint64_t available() override;
|
||||
|
||||
uint64_t size() const override;
|
||||
|
||||
char *buff() override;
|
||||
|
||||
[[nodiscard]] ox::Error walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) override;
|
||||
|
||||
bool valid() const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] ValErr<FileSystemData> fileSystemData() const noexcept;
|
||||
|
||||
/**
|
||||
* Finds the inode ID at the given path.
|
||||
*/
|
||||
[[nodiscard]] ValErr<uint64_t> find(const char *path) const noexcept;
|
||||
|
||||
[[nodiscard]] ValErr<Directory> rootDir() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(FileStore fs) {
|
||||
m_fs = fs;
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*)):
|
||||
m_fs(buffer, bufferSize),
|
||||
m_freeBuffer(freeBuffer) {
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
FileSystemTemplate<FileStore, Directory>::~FileSystemTemplate() {
|
||||
if (m_freeBuffer && m_fs.buff()) {
|
||||
m_freeBuffer(m_fs.buff());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buffSize) {
|
||||
oxReturnError(FileStore::format(buff, buffSize));
|
||||
FileStore fs(buff, buffSize);
|
||||
|
||||
constexpr auto rootDirInode = MaxValue<typename FileStore::InodeId_t> / 2;
|
||||
Directory rootDir(fs, rootDirInode);
|
||||
oxReturnError(rootDir.init());
|
||||
|
||||
FileSystemData fd;
|
||||
fd.rootDirInode = rootDirInode;
|
||||
oxTrace("ox::fs::FileSystemTemplate::format") << "rootDirInode:" << fd.rootDirInode;
|
||||
oxReturnError(fs.write(InodeFsData, &fd, sizeof(fd)));
|
||||
|
||||
if (!fs.read(fd.rootDirInode).valid()) {
|
||||
oxTrace("ox::fs::FileSystemTemplate::format::error") << "FileSystemTemplate::format did not correctly create root directory";
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::mkdir(const char *path, bool recursive) {
|
||||
oxTrace("ox::fs::FileSystemTemplate::mkdir") << "path:" << path << "recursive:" << recursive;
|
||||
auto rootDir = this->rootDir();
|
||||
oxReturnError(rootDir.error);
|
||||
return rootDir.value.mkdir(path, recursive);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char *dest) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto [inode, err] = rootDir.find(src);
|
||||
oxReturnError(err);
|
||||
oxReturnError(rootDir.write(dest, inode));
|
||||
oxReturnError(rootDir.remove(src));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buffer, std::size_t buffSize) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto [inode, err] = rootDir.find(path);
|
||||
oxReturnError(err);
|
||||
return read(inode, buffer, buffSize);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> FileSystemTemplate<FileStore, Directory>::read(const char *path) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto [inode, err] = rootDir.find(path);
|
||||
oxReturnError(err);
|
||||
return read(inode);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, void *buffer, std::size_t buffSize) {
|
||||
return m_fs.read(inode, buffer, buffSize);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) {
|
||||
return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
[[nodiscard]] ox::ValErr<uint8_t*> FileSystemTemplate<FileStore, Directory>::read(uint64_t inode) {
|
||||
auto data = m_fs.read(inode);
|
||||
if (!data.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
return data.get();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
template<typename F>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::ls(const char *path, F cb) {
|
||||
oxTrace("ox::FileSystemTemplate::ls") << "path:" << path;
|
||||
auto [s, err] = stat(path);
|
||||
oxReturnError(err);
|
||||
Directory dir(m_fs, s.inode);
|
||||
return dir.ls(cb);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool recursive) {
|
||||
auto fd = fileSystemData();
|
||||
oxReturnError(fd.error);
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto inode = rootDir.find(path);
|
||||
oxReturnError(inode.error);
|
||||
auto st = stat(inode.value);
|
||||
oxReturnError(st.error);
|
||||
if (st.value.fileType == FileType_NormalFile || recursive) {
|
||||
if (auto err = rootDir.remove(path)) {
|
||||
// removal failed, try putting the index back
|
||||
oxLogError(rootDir.write(path, inode.value));
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
oxTrace("FileSystemTemplate::remove::fail") << "Tried to remove directory without recursive setting.";
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::resize() {
|
||||
return m_fs.resize();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) {
|
||||
oxReturnError(m_fs.resize(size, buffer));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
|
||||
auto [inode, err] = find(path);
|
||||
if (err) {
|
||||
auto generated = m_fs.generateInodeId();
|
||||
oxReturnError(generated.error);
|
||||
inode = generated.value;
|
||||
}
|
||||
auto rootDir = this->rootDir();
|
||||
oxReturnError(rootDir.error);
|
||||
oxReturnError(rootDir.value.write(path, inode));
|
||||
oxReturnError(write(inode, buffer, size, fileType));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType) {
|
||||
return m_fs.write(inode, buffer, size, fileType);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode) {
|
||||
auto s = m_fs.stat(inode);
|
||||
FileStat out;
|
||||
out.inode = s.value.inode;
|
||||
out.links = s.value.links;
|
||||
out.size = s.value.size;
|
||||
out.fileType = s.value.fileType;
|
||||
return {out, s.error};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<FileStat> FileSystemTemplate<FileStore, Directory>::stat(const char *path) {
|
||||
auto inode = find(path);
|
||||
if (inode.error) {
|
||||
return {{}, inode.error};
|
||||
}
|
||||
return stat(inode.value);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
uint64_t FileSystemTemplate<FileStore, Directory>::spaceNeeded(uint64_t size) {
|
||||
return m_fs.spaceNeeded(size);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
uint64_t FileSystemTemplate<FileStore, Directory>::available() {
|
||||
return m_fs.available();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
uint64_t FileSystemTemplate<FileStore, Directory>::size() const {
|
||||
return m_fs.size();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
char *FileSystemTemplate<FileStore, Directory>::buff() {
|
||||
return m_fs.buff();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ox::Error FileSystemTemplate<FileStore, Directory>::walk(ox::Error(*cb)(uint8_t, uint64_t, uint64_t)) {
|
||||
return m_fs.walk(cb);
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
bool FileSystemTemplate<FileStore, Directory>::valid() const {
|
||||
return m_fs.valid();
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSystemTemplate<FileStore, Directory>::fileSystemData() const noexcept {
|
||||
FileSystemData fd;
|
||||
auto err = m_fs.read(InodeFsData, &fd, sizeof(fd));
|
||||
if (err != 0) {
|
||||
return {fd, err};
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<uint64_t> FileSystemTemplate<FileStore, Directory>::find(const char *path) const noexcept {
|
||||
auto fd = fileSystemData();
|
||||
if (fd.error) {
|
||||
return {0, fd.error};
|
||||
}
|
||||
// return root as a special case
|
||||
if (ox_strcmp(path, "/") == 0) {
|
||||
return static_cast<uint64_t>(fd.value.rootDirInode);
|
||||
}
|
||||
Directory rootDir(m_fs, fd.value.rootDirInode);
|
||||
auto inode = rootDir.find(path);
|
||||
if (inode.error) {
|
||||
return {0, inode.error};
|
||||
}
|
||||
return inode.value;
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
ValErr<Directory> FileSystemTemplate<FileStore, Directory>::rootDir() const noexcept {
|
||||
auto fd = fileSystemData();
|
||||
if (fd.error) {
|
||||
return {{}, fd.error};
|
||||
}
|
||||
return Directory(m_fs, fd.value.rootDirInode);
|
||||
}
|
||||
|
||||
extern template class FileSystemTemplate<FileStore16, Directory16>;
|
||||
extern template class FileSystemTemplate<FileStore32, Directory32>;
|
||||
|
||||
using FileSystem16 = FileSystemTemplate<FileStore16, Directory16>;
|
||||
using FileSystem32 = FileSystemTemplate<FileStore32, Directory32>;
|
||||
|
||||
}
|
||||
166
deps/ox/src/ox/fs/filesystem/passthroughfs.cpp
vendored
166
deps/ox/src/ox/fs/filesystem/passthroughfs.cpp
vendored
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "passthroughfs.hpp"
|
||||
|
||||
#if defined(OX_HAS_PASSTHROUGHFS)
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace ox {
|
||||
|
||||
PassThroughFS::PassThroughFS(const char *dirPath) {
|
||||
m_path = dirPath;
|
||||
}
|
||||
|
||||
PassThroughFS::~PassThroughFS() {
|
||||
}
|
||||
|
||||
std::string PassThroughFS::basePath() {
|
||||
return m_path.string();
|
||||
}
|
||||
|
||||
Error PassThroughFS::mkdir(const char *path, bool recursive) {
|
||||
bool success = false;
|
||||
const auto p = m_path / stripSlash(path);
|
||||
const auto u8p = p.u8string();
|
||||
oxTrace("ox::fs::PassThroughFS::mkdir") << u8p.c_str();
|
||||
if (recursive) {
|
||||
success = std::filesystem::create_directories(p);
|
||||
} else {
|
||||
success = std::filesystem::create_directory(p);
|
||||
}
|
||||
return OxError(success ? 0 : 1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::move(const char *src, const char *dest) {
|
||||
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize) {
|
||||
try {
|
||||
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
|
||||
const std::size_t size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
if (size > buffSize) {
|
||||
oxTrace("ox::fs::PassThroughFS::read::error") << "Read failed: Buffer too small:" << path;
|
||||
return OxError(1);
|
||||
}
|
||||
file.read(static_cast<char*>(buffer), buffSize);
|
||||
} catch (const std::fstream::failure&) {
|
||||
oxTrace("ox::fs::PassThroughFS::read::error") << "Read failed:" << path;
|
||||
throw OxError(2);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
ValErr<uint8_t*> PassThroughFS::read(const char*) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::read(uint64_t, void*, std::size_t) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ValErr<uint8_t*> PassThroughFS::read(uint64_t) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::remove(const char *path, bool recursive) {
|
||||
if (recursive) {
|
||||
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
|
||||
} else {
|
||||
return OxError(std::filesystem::remove(m_path / stripSlash(path)) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error PassThroughFS::resize(uint64_t, void*) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
Error PassThroughFS::write(const char *path, void *buffer, uint64_t size, uint8_t) {
|
||||
auto p = (m_path / stripSlash(path));
|
||||
try {
|
||||
std::ofstream f(p, std::ios::binary);
|
||||
f.write(static_cast<char*>(buffer), size);
|
||||
} catch (const std::fstream::failure&) {
|
||||
oxTrace("ox::fs::PassThroughFS::write::error") << "Write failed:" << path;
|
||||
throw OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error PassThroughFS::write(uint64_t, void*, uint64_t, uint8_t) {
|
||||
// unsupported
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ValErr<FileStat> PassThroughFS::stat(uint64_t) {
|
||||
// unsupported
|
||||
return {{}, OxError(1)};
|
||||
}
|
||||
|
||||
ValErr<FileStat> PassThroughFS::stat(const char *path) {
|
||||
std::error_code ec;
|
||||
const auto p = m_path / stripSlash(path);
|
||||
uint8_t type = std::filesystem::is_directory(p, ec) ?
|
||||
FileType_Directory : FileType_NormalFile;
|
||||
oxTrace("PassThroughFS::stat") << ec.message().c_str() << path;
|
||||
uint64_t size = type == FileType_Directory ? 0 : std::filesystem::file_size(p, ec);
|
||||
oxTrace("PassThroughFS::stat") << ec.message().c_str() << path;
|
||||
oxTrace("PassThroughFS::stat::size") << path << size;
|
||||
return {{0, 0, size, type}, OxError(ec.value())};
|
||||
}
|
||||
|
||||
uint64_t PassThroughFS::spaceNeeded(uint64_t size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
uint64_t PassThroughFS::available() {
|
||||
std::error_code ec;
|
||||
auto s = std::filesystem::space(m_path, ec);
|
||||
return s.available;
|
||||
}
|
||||
|
||||
uint64_t PassThroughFS::size() const {
|
||||
std::error_code ec;
|
||||
auto s = std::filesystem::space(m_path, ec);
|
||||
return s.capacity;
|
||||
}
|
||||
|
||||
char *PassThroughFS::buff() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Error PassThroughFS::walk(Error(*)(uint8_t, uint64_t, uint64_t)) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
bool PassThroughFS::valid() const {
|
||||
return std::filesystem::is_directory(m_path);
|
||||
}
|
||||
|
||||
const char *PassThroughFS::stripSlash(const char *path) {
|
||||
auto pathLen = ox_strlen(path);
|
||||
for (decltype(pathLen) i = 0; i < pathLen && path[0] == '/'; i++) {
|
||||
path++;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
100
deps/ox/src/ox/fs/filesystem/passthroughfs.hpp
vendored
100
deps/ox/src/ox/fs/filesystem/passthroughfs.hpp
vendored
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#define OX_HAS_PASSTHROUGHFS
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OX_HAS_PASSTHROUGHFS
|
||||
|
||||
#include "filesystem.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class PassThroughFS: public FileSystem {
|
||||
private:
|
||||
std::filesystem::path m_path;
|
||||
|
||||
public:
|
||||
PassThroughFS(const char *dirPath);
|
||||
|
||||
~PassThroughFS();
|
||||
|
||||
[[nodiscard]] std::string basePath();
|
||||
|
||||
ox::Error mkdir(const char *path, bool recursive = false) override;
|
||||
|
||||
ox::Error move(const char *src, const char *dest) override;
|
||||
|
||||
ox::Error read(const char *path, void *buffer, std::size_t buffSize) override;
|
||||
|
||||
ox::ValErr<uint8_t*> read(const char*) override;
|
||||
|
||||
ox::Error read(uint64_t inode, void *buffer, std::size_t size) override;
|
||||
|
||||
ox::Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) override;
|
||||
|
||||
ox::ValErr<uint8_t*> read(uint64_t) override;
|
||||
|
||||
template<typename F>
|
||||
ox::Error ls(const char *dir, F cb);
|
||||
|
||||
ox::Error remove(const char *path, bool recursive = false) override;
|
||||
|
||||
ox::Error resize(uint64_t size, void *buffer = nullptr) override;
|
||||
|
||||
ox::Error write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
ox::Error write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override;
|
||||
|
||||
ox::ValErr<FileStat> stat(uint64_t inode) override;
|
||||
|
||||
ox::ValErr<FileStat> stat(const char *path) override;
|
||||
|
||||
uint64_t spaceNeeded(uint64_t size) override;
|
||||
|
||||
uint64_t available() override;
|
||||
|
||||
uint64_t size() const override;
|
||||
|
||||
char *buff() override;
|
||||
|
||||
ox::Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) override;
|
||||
|
||||
bool valid() const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Strips the leading slashes from a string.
|
||||
*/
|
||||
const char *stripSlash(const char *path);
|
||||
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
ox::Error PassThroughFS::ls(const char *dir, F cb) {
|
||||
for (auto &p : std::filesystem::directory_iterator(m_path / stripSlash(dir))) {
|
||||
auto u8p = p.path().filename().u8string();
|
||||
oxReturnError(cb(u8p.c_str(), 0));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
214
deps/ox/src/ox/fs/filesystem/pathiterator.cpp
vendored
214
deps/ox/src/ox/fs/filesystem/pathiterator.cpp
vendored
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include "pathiterator.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t iterator) {
|
||||
m_path = path;
|
||||
m_maxSize = maxSize;
|
||||
m_iterator = iterator;
|
||||
}
|
||||
|
||||
PathIterator::PathIterator(const char *path): PathIterator(path, ox_strlen(path)) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::dirPath(char *out, std::size_t outSize) {
|
||||
int idx = ox_lastIndexOf(m_path, '/', m_maxSize);
|
||||
std::size_t size = idx + 1;
|
||||
if (idx >= 0 && size < outSize) {
|
||||
ox_memcpy(out, m_path, size);
|
||||
out[size] = 0;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::fileName(char *out, std::size_t outSize) {
|
||||
auto idx = ox_lastIndexOf(m_path, '/', m_maxSize);
|
||||
if (idx >= 0) {
|
||||
idx++; // pass up the preceding /
|
||||
std::size_t fileNameSize = ox_strlen(&m_path[idx]);
|
||||
if (fileNameSize < outSize) {
|
||||
ox_memcpy(out, &m_path[idx], fileNameSize);
|
||||
out[fileNameSize] = 0;
|
||||
return OxError(0);
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
} else {
|
||||
return OxError(2);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the get item in the path
|
||||
Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
|
||||
std::size_t size = 0;
|
||||
if (m_iterator >= m_maxSize) {
|
||||
oxTrace("ox::fs::PathIterator::get") << "m_iterator >= m_maxSize";
|
||||
return OxError(1);
|
||||
}
|
||||
if (!ox_strlen(&m_path[m_iterator])) {
|
||||
oxTrace("ox::fs::PathIterator::get") << "!ox_strlen(&m_path[m_iterator])";
|
||||
return OxError(1);
|
||||
}
|
||||
auto start = m_iterator;
|
||||
if (m_path[start] == '/') {
|
||||
start++;
|
||||
}
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
// cannot fit the output in the output parameter
|
||||
if (size >= pathOutSize || size == 0) {
|
||||
return OxError(1);
|
||||
}
|
||||
ox_memcpy(pathOut, &m_path[start], size);
|
||||
// truncate trailing /
|
||||
if (size && pathOut[size - 1] == '/') {
|
||||
size--;
|
||||
}
|
||||
pathOut[size] = 0; // end with null terminator
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
// Gets the get item in the path
|
||||
Error PathIterator::next(char *pathOut, std::size_t pathOutSize) {
|
||||
std::size_t size = 0;
|
||||
auto retval = OxError(1);
|
||||
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
|
||||
retval = OxError(0);
|
||||
if (m_path[m_iterator] == '/') {
|
||||
m_iterator++;
|
||||
}
|
||||
std::size_t start = m_iterator;
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
// cannot fit the output in the output parameter
|
||||
if (size >= pathOutSize) {
|
||||
return OxError(1);
|
||||
}
|
||||
ox_memcpy(pathOut, &m_path[start], size);
|
||||
}
|
||||
// truncate trailing /
|
||||
if (size && pathOut[size - 1] == '/') {
|
||||
size--;
|
||||
}
|
||||
pathOut[size] = 0; // end with null terminator
|
||||
m_iterator += size;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::get(BString<MaxFileNameLength> *fileName) {
|
||||
return get(fileName->data(), fileName->cap());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error PathIterator::next(BString<MaxFileNameLength> *fileName) {
|
||||
return next(fileName->data(), fileName->cap());
|
||||
}
|
||||
|
||||
ValErr<std::size_t> PathIterator::nextSize() const {
|
||||
std::size_t size = 0;
|
||||
auto retval = OxError(1);
|
||||
auto it = m_iterator;
|
||||
if (it < m_maxSize && ox_strlen(&m_path[it])) {
|
||||
retval = OxError(0);
|
||||
if (m_path[it] == '/') {
|
||||
it++;
|
||||
}
|
||||
std::size_t start = it;
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
}
|
||||
it += size;
|
||||
return {size, retval};
|
||||
}
|
||||
|
||||
bool PathIterator::hasNext() const {
|
||||
std::size_t size = 0;
|
||||
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
|
||||
std::size_t start = m_iterator;
|
||||
if (m_path[start] == '/') {
|
||||
start++;
|
||||
}
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
bool PathIterator::valid() const {
|
||||
return m_iterator < m_maxSize && m_path[m_iterator] != 0;
|
||||
}
|
||||
|
||||
PathIterator PathIterator::next() const {
|
||||
std::size_t size = 0;
|
||||
auto iterator = m_iterator;
|
||||
if (iterator < m_maxSize && ox_strlen(&m_path[iterator])) {
|
||||
if (m_path[iterator] == '/') {
|
||||
iterator++;
|
||||
}
|
||||
std::size_t start = iterator;
|
||||
// end is at the next /
|
||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||
// correct end if it is invalid, which happens if there is no next /
|
||||
if (!substr) {
|
||||
substr = ox_strchr(&m_path[start], 0, m_maxSize - start);
|
||||
}
|
||||
std::size_t end = substr - m_path;
|
||||
size = end - start;
|
||||
}
|
||||
iterator += size;
|
||||
return PathIterator(m_path, m_maxSize, iterator + 1);
|
||||
}
|
||||
|
||||
const char *PathIterator::fullPath() const {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
}
|
||||
74
deps/ox/src/ox/fs/filesystem/pathiterator.hpp
vendored
74
deps/ox/src/ox/fs/filesystem/pathiterator.hpp
vendored
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
constexpr std::size_t MaxFileNameLength = 255;
|
||||
using FileName = BString<MaxFileNameLength>;
|
||||
|
||||
class PathIterator {
|
||||
private:
|
||||
const char *m_path = nullptr;
|
||||
std::size_t m_iterator = 0;
|
||||
std::size_t m_maxSize = 0;
|
||||
|
||||
public:
|
||||
PathIterator(const char *path, std::size_t maxSize, std::size_t iterator = 0);
|
||||
|
||||
PathIterator(const char *path);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error dirPath(char *pathOut, std::size_t pathOutSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error fileName(char *out, std::size_t outSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error next(char *pathOut, std::size_t pathOutSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error get(char *pathOut, std::size_t pathOutSize);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error next(FileName *fileName);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
Error get(FileName *fileName);
|
||||
|
||||
/**
|
||||
* @return 0 if no error
|
||||
*/
|
||||
ValErr<std::size_t> nextSize() const;
|
||||
|
||||
bool hasNext() const;
|
||||
|
||||
bool valid() const;
|
||||
|
||||
[[nodiscard]] PathIterator next() const;
|
||||
|
||||
const char *fullPath() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
44
deps/ox/src/ox/fs/filesystem/types.hpp
vendored
44
deps/ox/src/ox/fs/filesystem/types.hpp
vendored
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum FsType {
|
||||
OxFS_16 = 1,
|
||||
OxFS_32 = 2,
|
||||
OxFS_64 = 3
|
||||
};
|
||||
|
||||
enum FileType {
|
||||
FileType_NormalFile = 1,
|
||||
FileType_Directory = 2
|
||||
};
|
||||
|
||||
constexpr const char *toString(FileType t) {
|
||||
switch (t) {
|
||||
case FileType_NormalFile:
|
||||
return "Normal File";
|
||||
case FileType_Directory:
|
||||
return "Directory";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
struct FileStat {
|
||||
uint64_t inode = 0;
|
||||
uint64_t links = 0;
|
||||
uint64_t size = 0;
|
||||
uint8_t fileType = 0;
|
||||
};
|
||||
|
||||
}
|
||||
15
deps/ox/src/ox/fs/fs.hpp
vendored
15
deps/ox/src/ox/fs/fs.hpp
vendored
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filestore/filestoretemplate.hpp"
|
||||
#include "filesystem/filelocation.hpp"
|
||||
#include "filesystem/filesystem.hpp"
|
||||
#include "filesystem/passthroughfs.hpp"
|
||||
#include "filesystem/directory.hpp"
|
||||
27
deps/ox/src/ox/fs/test/CMakeLists.txt
vendored
27
deps/ox/src/ox/fs/test/CMakeLists.txt
vendored
@@ -1,27 +0,0 @@
|
||||
add_executable(
|
||||
FSTests
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
FSTests
|
||||
OxFS
|
||||
OxStd
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ PathIterator::next1" FSTests PathIterator::next1)
|
||||
add_test("Test\\ PathIterator::next2" FSTests PathIterator::next2)
|
||||
add_test("Test\\ PathIterator::next3" FSTests PathIterator::next3)
|
||||
add_test("Test\\ PathIterator::next4" FSTests PathIterator::next4)
|
||||
add_test("Test\\ PathIterator::next5" FSTests PathIterator::next5)
|
||||
add_test("Test\\ PathIterator::hasNext" FSTests PathIterator::hasNext)
|
||||
|
||||
add_test("Test\\ PathIterator::dirPath" FSTests PathIterator::dirPath)
|
||||
add_test("Test\\ PathIterator::fileName" FSTests PathIterator::fileName)
|
||||
|
||||
add_test("Test\\ NodeBuffer::insert" FSTests "NodeBuffer::insert")
|
||||
add_test("Test\\ FileStore::readWrite" FSTests "FileStore::readWrite")
|
||||
|
||||
add_test("Test\\ Directory" FSTests "Directory")
|
||||
add_test("Test\\ FileSystem" FSTests "FileSystem")
|
||||
231
deps/ox/src/ox/fs/test/tests.cpp
vendored
231
deps/ox/src/ox/fs/test/tests.cpp
vendored
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// make sure asserts are enabled for the test file
|
||||
#undef NDEBUG
|
||||
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/fs/filesystem/filesystem.hpp>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace ox;
|
||||
|
||||
map<string, int(*)(string)> tests = {
|
||||
{
|
||||
{
|
||||
"PathIterator::next1",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next2",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next3",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "\0") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next4",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::next5",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "usr/share/";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0);
|
||||
retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::dirPath",
|
||||
[] (string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.dirPath(buff, path.size()) == 0 && ox_strcmp(buff, "/usr/share/") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::fileName",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
string path = "/usr/share/charset.gbag";
|
||||
PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
retval |= !(it.fileName(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"PathIterator::hasNext",
|
||||
[](string) {
|
||||
int retval = 0;
|
||||
const auto path = "/file1";
|
||||
PathIterator it(path, ox_strlen(path));
|
||||
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
|
||||
oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
|
||||
return retval;
|
||||
}
|
||||
},
|
||||
{
|
||||
"Ptr::subPtr",
|
||||
[](string) {
|
||||
constexpr auto buffLen = 5000;
|
||||
ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
|
||||
oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid.");
|
||||
|
||||
auto subPtr = p.subPtr<uint64_t>(50);
|
||||
oxAssert(subPtr.valid(), "Ptr::subPtr: Ptr subPtr is invalid.");
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"NodeBuffer::insert",
|
||||
[](string) {
|
||||
int err = 0;
|
||||
constexpr auto buffLen = 5000;
|
||||
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
|
||||
oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 1 failed");
|
||||
oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 2 failed");
|
||||
auto first = list->firstItem();
|
||||
oxAssert(first.valid(), "NodeBuffer::insert: Could not access first item");
|
||||
oxAssert(first->size() == 50, "NodeBuffer::insert: First item size invalid");
|
||||
return err;
|
||||
}
|
||||
},
|
||||
{
|
||||
"FileStore::readWrite",
|
||||
[](string) {
|
||||
constexpr auto buffLen = 5000;
|
||||
constexpr auto str1 = "Hello, World!";
|
||||
constexpr auto str1Len = ox_strlen(str1) + 1;
|
||||
constexpr auto str2 = "Hello, Moon!";
|
||||
constexpr auto str2Len = ox_strlen(str2) + 1;
|
||||
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.");
|
||||
|
||||
char str1Read[str1Len];
|
||||
size_t str1ReadSize = 0;
|
||||
oxAssert(fileStore.read(4, reinterpret_cast<void*>(str1Read), str1Len, &str1ReadSize), "FileStore::read 1 failed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"Directory",
|
||||
[](string) {
|
||||
std::vector<uint8_t> fsBuff(5000);
|
||||
oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
|
||||
ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
|
||||
ox::Directory32 dir(fileStore, 105);
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "Init";
|
||||
oxAssert(dir.init(), "Init failed");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "write 1";
|
||||
oxAssert(dir.write("/file1", 1), "Directory write of file1 failed");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "find";
|
||||
oxAssert(dir.find("file1").error, "Could not find file1");
|
||||
oxAssert(dir.find("file1").value == 1, "Could not find file1");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "write 2";
|
||||
oxAssert(dir.write("/file3", 3), "Directory write of file3 failed");
|
||||
|
||||
oxTrace("ox::fs::test::Directory") << "write 3";
|
||||
oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"FileSystem",
|
||||
[](string) {
|
||||
std::vector<uint8_t> fsBuff(5000);
|
||||
oxTrace("ox::fs::test::FileSystem") << "format";
|
||||
oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
|
||||
ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size()));
|
||||
|
||||
oxTrace("ox::fs::test::FileSystem") << "mkdir";
|
||||
oxAssert(fs.mkdir("/dir", true), "mkdir failed");
|
||||
oxAssert(fs.stat("/dir").error, "mkdir failed");
|
||||
oxAssert(fs.mkdir("/l1d1/l2d1/l3d1", true), "mkdir failed");
|
||||
oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed");
|
||||
oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed");
|
||||
oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 1) {
|
||||
auto testName = args[1];
|
||||
string testArg = "";
|
||||
if (args[2]) {
|
||||
testArg = args[2];
|
||||
}
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName](testArg);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
43
deps/ox/src/ox/mc/CMakeLists.txt
vendored
43
deps/ox/src/ox/mc/CMakeLists.txt
vendored
@@ -1,43 +0,0 @@
|
||||
add_library(
|
||||
OxMetalClaw
|
||||
presenceindicator.cpp
|
||||
read.cpp
|
||||
write.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxMetalClaw PUBLIC
|
||||
OxModel
|
||||
OxStd
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxMetalClaw
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
intops.hpp
|
||||
err.hpp
|
||||
mc.hpp
|
||||
presenceindicator.hpp
|
||||
read.hpp
|
||||
types.hpp
|
||||
write.hpp
|
||||
DESTINATION
|
||||
include/ox/mc
|
||||
)
|
||||
|
||||
install(TARGETS OxMetalClaw
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS STREQUAL "ON")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
19
deps/ox/src/ox/mc/err.hpp
vendored
19
deps/ox/src/ox/mc/err.hpp
vendored
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum {
|
||||
MC_PRESENCEMASKOUTBOUNDS = 1,
|
||||
MC_BUFFENDED = 2,
|
||||
MC_OUTBUFFENDED = 4
|
||||
};
|
||||
|
||||
}
|
||||
159
deps/ox/src/ox/mc/intops.hpp
vendored
159
deps/ox/src/ox/mc/intops.hpp
vendored
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
|
||||
namespace ox::mc {
|
||||
|
||||
template<typename T>
|
||||
static constexpr auto Bits = sizeof(T) << 3;
|
||||
|
||||
/**
|
||||
* Returns highest bit other than possible signed bit.
|
||||
* Bit numbering starts at 0.
|
||||
*/
|
||||
template<typename I>
|
||||
[[nodiscard]] constexpr std::size_t highestBit(I val) noexcept {
|
||||
auto shiftStart = sizeof(I) * 8 - 1;
|
||||
// find most significant non-sign indicator bit
|
||||
std::size_t highestBit = 0;
|
||||
// start at one bit lower if signed
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
--shiftStart;
|
||||
}
|
||||
for (int i = shiftStart; i > -1; --i) {
|
||||
const auto bitValue = (val >> i) & 1;
|
||||
if (bitValue) {
|
||||
highestBit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return highestBit;
|
||||
}
|
||||
|
||||
static_assert(highestBit(int8_t(0b10000000)) == 0);
|
||||
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);
|
||||
|
||||
struct McInt {
|
||||
uint8_t data[9] = {0};
|
||||
// length of integer in bytes
|
||||
std::size_t length = 0;
|
||||
};
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] constexpr McInt encodeInteger(I input) noexcept {
|
||||
McInt out;
|
||||
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
||||
// overflow concerns
|
||||
uint64_t val = 0;
|
||||
ox_memcpy(&val, &input, sizeof(I));
|
||||
if (val) {
|
||||
// bits needed to represent number factoring in space possibly
|
||||
// needed for signed bit
|
||||
const auto bits = highestBit(val) + 1 + (ox::is_signed<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;
|
||||
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
|
||||
// bits for integer + bits neded to represent bytes > bits available
|
||||
if (bitsNeeded > bitsAvailable && bytes != 9) {
|
||||
++bytes;
|
||||
}
|
||||
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
|
||||
|
||||
// move sign bit
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
if (val < 0) {
|
||||
val ^= uint64_t(1) << (sizeof(I) * 8 - 1);
|
||||
val |= uint64_t(1) << (bitsAvailable - 1);
|
||||
}
|
||||
}
|
||||
// ensure we are copying from little endian represenstation
|
||||
LittleEndian<I> leVal = val;
|
||||
if (bytes == 9) {
|
||||
out.data[0] = bytesIndicator;
|
||||
ox_memcpy(&out.data[1], &leVal, sizeof(I));
|
||||
} else {
|
||||
auto intermediate =
|
||||
static_cast<uint64_t>(leVal.raw()) << bytes |
|
||||
static_cast<uint64_t>(bytesIndicator);
|
||||
ox_memcpy(out.data, &intermediate, sizeof(intermediate));
|
||||
}
|
||||
out.length = bytes;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes indicated by the bytes indicator of a variable
|
||||
* length integer.
|
||||
*/
|
||||
[[nodiscard]] static constexpr std::size_t countBytes(uint8_t b) noexcept {
|
||||
std::size_t i = 0;
|
||||
for (; (b >> i) & 1; i++);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static_assert(countBytes(0b00000000) == 1);
|
||||
static_assert(countBytes(0b00000001) == 2);
|
||||
static_assert(countBytes(0b00000011) == 3);
|
||||
static_assert(countBytes(0b00000111) == 4);
|
||||
static_assert(countBytes(0b00001111) == 5);
|
||||
static_assert(countBytes(0b00011111) == 6);
|
||||
static_assert(countBytes(0b00111111) == 7);
|
||||
static_assert(countBytes(0b01111111) == 8);
|
||||
static_assert(countBytes(0b11111111) == 9);
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] constexpr ValErr<I> decodeInteger(uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
|
||||
const auto bytes = countBytes(buff[0]);
|
||||
if (bytes == 9) {
|
||||
*bytesRead = bytes;
|
||||
I out = 0;
|
||||
memcpy(&out, &buff[1], sizeof(I));
|
||||
return {LittleEndian<I>(out), OxError(0)};
|
||||
} else if (buffLen >= bytes) {
|
||||
*bytesRead = bytes;
|
||||
uint64_t decoded = 0;
|
||||
memcpy(&decoded, &buff[0], bytes);
|
||||
decoded >>= bytes;
|
||||
auto out = static_cast<I>(decoded);
|
||||
// move sign bit
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
const auto valBits = bytes << 3;
|
||||
// get sign
|
||||
uint64_t sign = decoded >> (valBits - 1);
|
||||
// remove sign
|
||||
decoded &= uint64_t(~0) ^ (uint64_t(1) << valBits);
|
||||
// set sign
|
||||
decoded |= sign << (Bits<I> - 1);
|
||||
memcpy(&out, &decoded, sizeof(out));
|
||||
}
|
||||
return {out, OxError(0)};
|
||||
}
|
||||
return {0, OxError(1)};
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
[[nodiscard]] ValErr<I> decodeInteger(McInt m) noexcept {
|
||||
std::size_t bytesRead;
|
||||
return decodeInteger<I>(m.data, 9, &bytesRead);
|
||||
}
|
||||
|
||||
}
|
||||
15
deps/ox/src/ox/mc/mc.hpp
vendored
15
deps/ox/src/ox/mc/mc.hpp
vendored
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "intops.hpp"
|
||||
#include "read.hpp"
|
||||
#include "types.hpp"
|
||||
#include "walk.hpp"
|
||||
#include "write.hpp"
|
||||
57
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
57
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include "err.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
FieldPresenceIndicator::FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen) {
|
||||
m_mask = mask;
|
||||
m_maskLen = maxLen;
|
||||
}
|
||||
|
||||
ValErr<bool> FieldPresenceIndicator::get(std::size_t i) const {
|
||||
if (i / 8 < m_maskLen) {
|
||||
return (m_mask[i / 8] >> (i % 8)) & 1;
|
||||
} else {
|
||||
return {false, OxError(MC_PRESENCEMASKOUTBOUNDS)};
|
||||
}
|
||||
}
|
||||
|
||||
Error FieldPresenceIndicator::set(std::size_t i, bool on) {
|
||||
if (i / 8 < m_maskLen) {
|
||||
if (on) {
|
||||
m_mask[i / 8] |= 1 << (i % 8);
|
||||
} else {
|
||||
m_mask[i / 8] &= ~(1 << (i % 8));
|
||||
}
|
||||
return OxError(0);
|
||||
} else {
|
||||
return OxError(MC_PRESENCEMASKOUTBOUNDS);
|
||||
}
|
||||
}
|
||||
|
||||
void FieldPresenceIndicator::setFields(int fields) noexcept {
|
||||
m_fields = fields;
|
||||
}
|
||||
|
||||
int FieldPresenceIndicator::getFields() const noexcept {
|
||||
return m_fields;
|
||||
}
|
||||
|
||||
void FieldPresenceIndicator::setMaxLen(int maxLen) noexcept {
|
||||
m_maskLen = maxLen;
|
||||
}
|
||||
|
||||
int FieldPresenceIndicator::getMaxLen() const noexcept {
|
||||
return m_maskLen;
|
||||
}
|
||||
|
||||
}
|
||||
39
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
39
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class FieldPresenceIndicator {
|
||||
private:
|
||||
uint8_t *m_mask = nullptr;
|
||||
std::size_t m_maskLen = 0;
|
||||
std::size_t m_fields = 0;
|
||||
|
||||
public:
|
||||
FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen);
|
||||
|
||||
ValErr<bool> get(std::size_t i) const;
|
||||
|
||||
Error set(std::size_t i, bool on);
|
||||
|
||||
void setFields(int) noexcept;
|
||||
|
||||
int getFields() const noexcept;
|
||||
|
||||
void setMaxLen(int) noexcept;
|
||||
|
||||
int getMaxLen() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
146
deps/ox/src/ox/mc/read.cpp
vendored
146
deps/ox/src/ox/mc/read.cpp
vendored
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
|
||||
#include "read.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent): m_fieldPresence(buff, buffLen) {
|
||||
m_buff = buff;
|
||||
m_buffLen = buffLen;
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
MetalClawReader::~MetalClawReader() {
|
||||
if (m_parent) {
|
||||
m_parent->m_buffIt += m_buffIt;
|
||||
}
|
||||
//oxAssert(m_field == m_fields, "MetalClawReader: incorrect fields number given");
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int8_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int16_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int32_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int64_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
|
||||
Error MetalClawReader::field(const char*, uint8_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, uint16_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, uint32_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, uint64_t *val) {
|
||||
return readInteger(val);
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, bool *val) {
|
||||
auto valErr = m_fieldPresence.get(m_field++);
|
||||
*val = valErr.value;
|
||||
return valErr.error;
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, SerStr val) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(err);
|
||||
|
||||
// read the string
|
||||
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
|
||||
if (m_buffIt + size <= m_buffLen) {
|
||||
ox_memcpy(val.data(), &m_buff[m_buffIt], size);
|
||||
m_buffIt += size;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
} else {
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
} else {
|
||||
val.data()[0] = 0;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(bool pass) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
|
||||
if (pass) {
|
||||
m_buffIt += bytesRead;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
[[nodiscard]] StringLength MetalClawReader::stringLength() {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
return len.value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MetalClawReader::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_fieldPresence.setMaxLen(m_buffIt);
|
||||
}
|
||||
|
||||
MetalClawReader MetalClawReader::child() {
|
||||
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, this);
|
||||
}
|
||||
|
||||
bool MetalClawReader::fieldPresent() const {
|
||||
return m_fieldPresence.get(m_field).value;
|
||||
}
|
||||
|
||||
bool MetalClawReader::fieldPresent(int fieldNo) const {
|
||||
return m_fieldPresence.get(fieldNo).value;
|
||||
}
|
||||
|
||||
void MetalClawReader::nextField() noexcept {
|
||||
++m_field;
|
||||
}
|
||||
|
||||
}
|
||||
217
deps/ox/src/ox/mc/read.hpp
vendored
217
deps/ox/src/ox/mc/read.hpp
vendored
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "err.hpp"
|
||||
#include "intops.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
class MetalClawReader {
|
||||
|
||||
private:
|
||||
FieldPresenceIndicator m_fieldPresence;
|
||||
int m_fields = 0;
|
||||
int m_field = 0;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
uint8_t *m_buff = nullptr;
|
||||
MetalClawReader *m_parent = nullptr;
|
||||
|
||||
public:
|
||||
MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent = nullptr);
|
||||
|
||||
~MetalClawReader();
|
||||
|
||||
Error field(const char*, int8_t *val);
|
||||
Error field(const char*, int16_t *val);
|
||||
Error field(const char*, int32_t *val);
|
||||
Error field(const char*, int64_t *val);
|
||||
|
||||
Error field(const char*, uint8_t *val);
|
||||
Error field(const char*, uint16_t *val);
|
||||
Error field(const char*, uint32_t *val);
|
||||
Error field(const char*, uint64_t *val);
|
||||
|
||||
Error field(const char*, bool *val);
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename Handler>
|
||||
Error field(const char*, Handler handler);
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename Handler>
|
||||
Error field(const char*, Handler handler, ArrayLength len);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, ox::Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, T *val);
|
||||
|
||||
template<std::size_t L>
|
||||
Error field(const char*, ox::BString<L> *val);
|
||||
|
||||
Error field(const char*, SerStr val);
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
* @param pass indicates that the parsing should iterate past the array length
|
||||
*/
|
||||
[[nodiscard]] ValErr<ArrayLength> arrayLength(bool pass = true);
|
||||
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]] StringLength stringLength();
|
||||
|
||||
void setTypeInfo(const char *name, int fields);
|
||||
|
||||
/**
|
||||
* Returns a MetalClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]] MetalClawReader child();
|
||||
|
||||
/**
|
||||
* Indicates whether or not the next field to be read is present.
|
||||
*/
|
||||
bool fieldPresent() const;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the given field is present.
|
||||
*/
|
||||
bool fieldPresent(int fieldNo) const;
|
||||
|
||||
void nextField() noexcept;
|
||||
|
||||
static constexpr OpType opType() {
|
||||
return OpType::Read;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
Error readInteger(I *val);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char*, T *val) {
|
||||
if (val && m_fieldPresence.get(m_field++)) {
|
||||
auto reader = child();
|
||||
oxReturnError(model(&reader, val));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<std::size_t L>
|
||||
Error MetalClawReader::field(const char *name, ox::BString<L> *val) {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawReader::readInteger(I *val) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
std::size_t bytesRead = 0;
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(valErr.error);
|
||||
*val = valErr.value;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
if (valLen >= len.value) {
|
||||
auto reader = child();
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
oxReturnError(reader.field("", &val[i]));
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T, typename Handler>
|
||||
Error MetalClawReader::field(const char*, Handler handler) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
auto reader = child();
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
T val;
|
||||
oxReturnError(reader.field("", &val));
|
||||
oxReturnError(handler(i, &val));
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char* name, ox::Vector<T> *val) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
const auto [len, err] = arrayLength(false);
|
||||
oxReturnError(err);
|
||||
val->resize(len);
|
||||
return field(name, val->data(), val->size());
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error readMC(uint8_t *buff, std::size_t buffLen, T *val) {
|
||||
MetalClawReader reader(buff, buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
|
||||
}
|
||||
15
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
15
deps/ox/src/ox/mc/test/CMakeLists.txt
vendored
@@ -1,15 +0,0 @@
|
||||
add_executable(
|
||||
McTest
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
McTest
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ McTest\\ Writer" McTest MetalClawWriter)
|
||||
add_test("Test\\ McTest\\ Reader" McTest MetalClawReader)
|
||||
add_test("Test\\ McTest\\ MetalClawDef" McTest MetalClawDef)
|
||||
add_test("Test\\ McTest\\ encodeInteger" McTest encodeInteger)
|
||||
add_test("Test\\ McTest\\ decodeInteger" McTest decodeInteger)
|
||||
366
deps/ox/src/ox/mc/test/tests.cpp
vendored
366
deps/ox/src/ox/mc/test/tests.cpp
vendored
@@ -1,366 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
struct TestStructNest {
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
int32_t Int2 = 0;
|
||||
int32_t Int3 = 0;
|
||||
int32_t Int4 = 0;
|
||||
int32_t Int5 = 0;
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0 , 0};
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("TestStructNest", 3);
|
||||
err |= io->field("Bool", &obj->Bool);
|
||||
err |= io->field("Int", &obj->Int);
|
||||
err |= io->field("String", &obj->String);
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("TestStruct", 14);
|
||||
err |= io->field("Bool", &obj->Bool);
|
||||
err |= io->field("Int", &obj->Int);
|
||||
err |= io->field("Int1", &obj->Int1);
|
||||
err |= io->field("Int2", &obj->Int2);
|
||||
err |= io->field("Int3", &obj->Int3);
|
||||
err |= io->field("Int4", &obj->Int4);
|
||||
err |= io->field("Int5", &obj->Int5);
|
||||
err |= io->field("Int6", &obj->Int6);
|
||||
err |= io->field("Int7", &obj->Int7);
|
||||
err |= io->field("Int8", &obj->Int8);
|
||||
err |= io->field("String", &obj->String);
|
||||
err |= io->field("List", obj->List, 4);
|
||||
err |= io->field("EmptyStruct", &obj->EmptyStruct);
|
||||
err |= io->field("Struct", &obj->Struct);
|
||||
return err;
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
{
|
||||
"MetalClawWriter",
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
constexpr size_t buffLen = 1024;
|
||||
uint8_t buff[buffLen];
|
||||
auto err = ox::Error(0);
|
||||
TestStruct ts;
|
||||
|
||||
err |= ox::writeMC(buff, buffLen, &ts);
|
||||
|
||||
return err;
|
||||
}
|
||||
},
|
||||
{
|
||||
"MetalClawReader",
|
||||
[] {
|
||||
constexpr size_t buffLen = 1024;
|
||||
uint8_t buff[buffLen];
|
||||
TestStruct testIn, testOut;
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
|
||||
oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed");
|
||||
std::cout << testIn.Int << " " << testOut.Int << '\n';
|
||||
|
||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");
|
||||
oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch");
|
||||
oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch");
|
||||
oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch");
|
||||
oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch");
|
||||
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
|
||||
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"encodeInteger",
|
||||
[] {
|
||||
using ox::MaxValue;
|
||||
using ox::mc::McInt;
|
||||
using ox::mc::encodeInteger;
|
||||
|
||||
constexpr auto check = [](McInt val, std::vector<uint8_t> &&expected) {
|
||||
if (val.length != expected.size()) {
|
||||
std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
for (std::size_t i = 0; i < expected.size(); i++) {
|
||||
if (expected[i] != val.data[i]) {
|
||||
std::cout << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
};
|
||||
constexpr auto check64 = [](McInt val, auto expected) {
|
||||
if (val.length != 9) {
|
||||
std::cout << "val.length: " << val.length << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
ox::LittleEndian<decltype(expected)> decoded = *reinterpret_cast<decltype(expected)*>(&val.data[1]);
|
||||
if (expected != decoded) {
|
||||
std::cout << "decoded: " << decoded << ", expected: " << expected << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(0);
|
||||
};
|
||||
|
||||
oxAssert(check(encodeInteger(int64_t(1)), {0b00000010}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(2)), {0b00000100}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(3)), {0b00000110}), "Encode 3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(4)), {0b00001000}), "Encode 4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(128)), {0b00000001, 0b10}), "Encode 128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(129)), {0b00000101, 0b10}), "Encode 129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(130)), {0b00001001, 0b10}), "Encode 130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(131)), {0b00001101, 0b10}), "Encode 131 fail");
|
||||
|
||||
oxAssert(check(encodeInteger(int64_t(-1)), {255, 255, 255, 255, 255, 255, 255, 255, 255}), "Encode -1 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-2)), {255, 254, 255, 255, 255, 255, 255, 255, 255}), "Encode -2 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-3)), {255, 253, 255, 255, 255, 255, 255, 255, 255}), "Encode -3 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-4)), {255, 252, 255, 255, 255, 255, 255, 255, 255}), "Encode -4 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-128)), {255, 128, 255, 255, 255, 255, 255, 255, 255}), "Encode -128 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-129)), {255, 127, 255, 255, 255, 255, 255, 255, 255}), "Encode -129 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-130)), {255, 126, 255, 255, 255, 255, 255, 255, 255}), "Encode -130 fail");
|
||||
oxAssert(check(encodeInteger(int64_t(-131)), {255, 125, 255, 255, 255, 255, 255, 255, 255}), "Encode -131 fail");
|
||||
|
||||
oxAssert(check(encodeInteger(uint32_t(0xffffffff)), {0b11101111, 255, 255, 255, 0b00011111}), "Encode 0xffffffff fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(1)), {0b0010}), "Encode 1 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(4)), {0b1000}), "Encode 4 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(128)), {0b0001, 0b10}), "Encode 128 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(129)), {0b0101, 0b10}), "Encode 129 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(130)), {0b1001, 0b10}), "Encode 130 fail");
|
||||
oxAssert(check(encodeInteger(uint64_t(131)), {0b1101, 0b10}), "Encode 131 fail");
|
||||
|
||||
// Signed check needs lambda templates to run correctly without
|
||||
// code deduplication
|
||||
//oxAssert(check64(encodeInteger(MaxValue<int64_t>), MaxValue<int64_t>), "Encode MaxValue<int64_t> fail");
|
||||
oxAssert(check64(encodeInteger(MaxValue<uint64_t>), MaxValue<uint64_t>), "Encode MaxValue<uint64_t> fail");
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"decodeInteger",
|
||||
[] {
|
||||
using ox::MaxValue;
|
||||
using ox::mc::McInt;
|
||||
using ox::mc::encodeInteger;
|
||||
using ox::mc::decodeInteger;
|
||||
|
||||
constexpr auto check = [](auto val) {
|
||||
auto result = decodeInteger<decltype(val)>(encodeInteger(val));
|
||||
oxReturnError(result.error);
|
||||
if (result.value != val) {
|
||||
std::cout << "Bad value: " << result.value << ", expected: " << val << '\n';
|
||||
}
|
||||
return OxError(result.value != val);
|
||||
};
|
||||
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
|
||||
oxAssert(check(int64_t(1)), "Decode of 1 failed.");
|
||||
oxAssert(check(int64_t(2)), "Decode of 2 failed.");
|
||||
oxAssert(check(int64_t(42)), "Decode of 42 failed.");
|
||||
oxAssert(check(int64_t(130)), "Decode of 130 failed.");
|
||||
oxAssert(check(int64_t(131)), "Decode of 131 failed.");
|
||||
oxAssert(check(uint64_t(1)), "Decode of 1 failed.");
|
||||
oxAssert(check(uint64_t(2)), "Decode of 2 failed.");
|
||||
oxAssert(check(uint64_t(42)), "Decode of 42 failed.");
|
||||
oxAssert(check(uint64_t(130)), "Decode of 130 failed.");
|
||||
oxAssert(check(uint64_t(131)), "Decode of 131 failed.");
|
||||
oxAssert(check(0xffffffff), "Decode of 0xffffffff failed.");
|
||||
oxAssert(check(0xffffffffffff), "Decode of 0xffffffffffff failed.");
|
||||
oxAssert(check(0xffffffffffffffff), "Decode of U64 max failed.");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"MetalClawDef",
|
||||
[] {
|
||||
auto err = OxError(0);
|
||||
//constexpr size_t descBuffLen = 1024;
|
||||
//uint8_t descBuff[descBuffLen];
|
||||
constexpr size_t dataBuffLen = 1024;
|
||||
uint8_t dataBuff[dataBuffLen];
|
||||
TestStruct testIn, testOut;
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
|
||||
auto type = ox::buildMCDef(&testIn);
|
||||
oxAssert(type.error, "Descriptor write failed");
|
||||
ox::walkMC<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
|
||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
|
||||
//std::cout << f.fieldName.c_str() << '\n';
|
||||
auto fieldName = f.fieldName.c_str();
|
||||
switch (f.type->primitiveType) {
|
||||
case ox::PrimitiveType::UnsignedInteger:
|
||||
std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
uint8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
uint16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
uint64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::SignedInteger:
|
||||
std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
int8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::Bool: {
|
||||
bool i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::String: {
|
||||
ox::Vector<char> v(rdr->stringLength());
|
||||
//std::cout << rdr->stringLength() << '\n';
|
||||
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "string: " << v.data() << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::Struct:
|
||||
break;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
);
|
||||
delete type.value;
|
||||
|
||||
return err;
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 0) {
|
||||
auto testName = args[1];
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName]();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
22
deps/ox/src/ox/mc/walk.hpp
vendored
22
deps/ox/src/ox/mc/walk.hpp
vendored
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/model/walk.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename Reader, typename Handler>
|
||||
ox::Error walkMC(DescriptorType *type, uint8_t *data, std::size_t dataLen, Handler handler) {
|
||||
DataWalker<Reader, Handler> walker(type, handler);
|
||||
Reader rdr(data, dataLen);
|
||||
return model(&rdr, &walker);
|
||||
}
|
||||
|
||||
}
|
||||
97
deps/ox/src/ox/mc/write.cpp
vendored
97
deps/ox/src/ox/mc/write.cpp
vendored
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
|
||||
#include "write.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen): m_fieldPresence(buff, buffLen) {
|
||||
m_buff = buff;
|
||||
m_buffLen = buffLen;
|
||||
}
|
||||
|
||||
MetalClawWriter::~MetalClawWriter() noexcept {
|
||||
oxAssert(m_field == m_fields, "MetalClawWriter: incorrect fields number given");
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int8_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int16_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int32_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int64_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint8_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint16_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint32_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint64_t *val) {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, bool *val) {
|
||||
return m_fieldPresence.set(m_field++, *val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, SerStr val) {
|
||||
auto err = OxError(0);
|
||||
bool fieldSet = false;
|
||||
if (val.cap()) {
|
||||
// write the length
|
||||
const auto strLen = mc::encodeInteger(val.bytes());
|
||||
if (m_buffIt + strLen.length + val.bytes() < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
|
||||
m_buffIt += strLen.length;
|
||||
|
||||
// write the string
|
||||
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.bytes());
|
||||
m_buffIt += val.bytes();
|
||||
fieldSet = true;
|
||||
} else {
|
||||
err = OxError(MC_BUFFENDED);
|
||||
}
|
||||
}
|
||||
err |= m_fieldPresence.set(m_field, fieldSet);
|
||||
m_field++;
|
||||
return err;
|
||||
}
|
||||
|
||||
void MetalClawWriter::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_fieldPresence.setMaxLen(m_buffIt);
|
||||
}
|
||||
|
||||
std::size_t MetalClawWriter::size() {
|
||||
return m_buffIt;
|
||||
}
|
||||
|
||||
}
|
||||
167
deps/ox/src/ox/mc/write.hpp
vendored
167
deps/ox/src/ox/mc/write.hpp
vendored
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "intops.hpp"
|
||||
#include "err.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
class MetalClawWriter {
|
||||
|
||||
private:
|
||||
FieldPresenceIndicator m_fieldPresence;
|
||||
int m_fields = 0;
|
||||
int m_field = 0;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
uint8_t *m_buff = nullptr;
|
||||
|
||||
public:
|
||||
MetalClawWriter(uint8_t *buff, std::size_t buffLen);
|
||||
|
||||
~MetalClawWriter() noexcept;
|
||||
|
||||
Error field(const char*, int8_t *val);
|
||||
Error field(const char*, int16_t *val);
|
||||
Error field(const char*, int32_t *val);
|
||||
Error field(const char*, int64_t *val);
|
||||
|
||||
Error field(const char*, uint8_t *val);
|
||||
Error field(const char*, uint16_t *val);
|
||||
Error field(const char*, uint32_t *val);
|
||||
Error field(const char*, uint64_t *val);
|
||||
|
||||
Error field(const char*, bool *val);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, ox::Vector<T> *val);
|
||||
|
||||
template<std::size_t L>
|
||||
Error field(const char*, ox::BString<L> *val);
|
||||
|
||||
Error field(const char*, SerStr val);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, T *val);
|
||||
|
||||
void setTypeInfo(const char *name, int fields);
|
||||
|
||||
std::size_t size();
|
||||
|
||||
static constexpr OpType opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
Error appendInteger(I val);
|
||||
};
|
||||
|
||||
template<std::size_t L>
|
||||
Error MetalClawWriter::field(const char *name, ox::BString<L> *val) {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, T *val) {
|
||||
bool fieldSet = false;
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
if (val) {
|
||||
oxReturnError(model(&writer, val));
|
||||
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, T *val, std::size_t len) {
|
||||
auto err = OxError(0);
|
||||
bool fieldSet = false;
|
||||
|
||||
if (len) {
|
||||
// write the length
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
if (m_buffIt + arrLen.length < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
|
||||
m_buffIt += arrLen.length;
|
||||
} else {
|
||||
err = OxError(MC_BUFFENDED);
|
||||
}
|
||||
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
writer.setTypeInfo("List", len);
|
||||
|
||||
// write the array
|
||||
for (std::size_t i = 0; i < len; i++) {
|
||||
err |= writer.field("", &val[i]);
|
||||
}
|
||||
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, ox::Vector<T> *val) {
|
||||
return field(nullptr, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawWriter::appendInteger(I val) {
|
||||
auto err = OxError(0);
|
||||
bool fieldSet = false;
|
||||
if (val) {
|
||||
auto mi = mc::encodeInteger(val);
|
||||
if (mi.length < m_buffLen) {
|
||||
fieldSet = true;
|
||||
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
|
||||
m_buffIt += mi.length;
|
||||
} else {
|
||||
err |= OxError(MC_BUFFENDED);
|
||||
}
|
||||
}
|
||||
err |= m_fieldPresence.set(m_field, fieldSet);
|
||||
m_field++;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error writeMC(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
|
||||
MetalClawWriter writer(buff, buffLen);
|
||||
auto err = model(&writer, val);
|
||||
if (sizeOut) {
|
||||
*sizeOut = writer.size();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
37
deps/ox/src/ox/model/CMakeLists.txt
vendored
37
deps/ox/src/ox/model/CMakeLists.txt
vendored
@@ -1,37 +0,0 @@
|
||||
add_library(
|
||||
OxModel
|
||||
desctypes.cpp
|
||||
descwrite.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxModel PUBLIC
|
||||
OxStd
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxModel
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
descread.hpp
|
||||
desctypes.hpp
|
||||
descwrite.hpp
|
||||
optype.hpp
|
||||
model.hpp
|
||||
types.hpp
|
||||
walk.hpp
|
||||
DESTINATION
|
||||
include/ox/model
|
||||
)
|
||||
|
||||
install(TARGETS OxModel
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
7
deps/ox/src/ox/model/definition-language.txt
vendored
7
deps/ox/src/ox/model/definition-language.txt
vendored
@@ -1,7 +0,0 @@
|
||||
<Type> : <TypeName><FieldList>
|
||||
<FieldList> : <FieldList> | <FieldList><Field>
|
||||
<Field> : <FieldType><TypeID><FieldName>
|
||||
<TypeID> : <TypeName> | <TypeName><Type>
|
||||
<TypeName> : <string>
|
||||
<FieldType> : <0: single> | <1: list>
|
||||
<FieldName> : <string>
|
||||
42
deps/ox/src/ox/model/descread.hpp
vendored
42
deps/ox/src/ox/model/descread.hpp
vendored
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "desctypes.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename ReaderBase>
|
||||
class TypeDescReader: public ReaderBase {
|
||||
private:
|
||||
TypeStore m_typeStore;
|
||||
|
||||
public:
|
||||
TypeDescReader(uint8_t *buff, std::size_t buffLen);
|
||||
|
||||
const TypeStore &typeStore() const;
|
||||
|
||||
};
|
||||
|
||||
template<typename ReaderBase>
|
||||
TypeDescReader<ReaderBase>::TypeDescReader(uint8_t *buff, std::size_t buffLen): ReaderBase(buff, buffLen) {
|
||||
}
|
||||
|
||||
template<typename ReaderBase>
|
||||
const TypeStore &TypeDescReader<ReaderBase>::typeStore() const {
|
||||
return m_typeStore;
|
||||
}
|
||||
|
||||
template<typename ReaderBase, typename T>
|
||||
int readMCDef(uint8_t *buff, std::size_t buffLen, T *val) {
|
||||
TypeDescReader<ReaderBase> reader(buff, buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
|
||||
}
|
||||
19
deps/ox/src/ox/model/desctypes.cpp
vendored
19
deps/ox/src/ox/model/desctypes.cpp
vendored
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "desctypes.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
DescriptorField::~DescriptorField() {
|
||||
if (ownsType) {
|
||||
delete type;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
175
deps/ox/src/ox/model/desctypes.hpp
vendored
175
deps/ox/src/ox/model/desctypes.hpp
vendored
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
using ModelString = BString<100>;
|
||||
using FieldName = ModelString;
|
||||
using TypeName = ModelString;
|
||||
|
||||
enum class PrimitiveType: uint8_t {
|
||||
UnsignedInteger = 0,
|
||||
SignedInteger = 1,
|
||||
Bool = 2,
|
||||
// Float = 3, reserved, but not implemented
|
||||
String = 4,
|
||||
Struct = 5,
|
||||
};
|
||||
|
||||
struct DescriptorField {
|
||||
// order of fields matters
|
||||
|
||||
// only serialize type name if type has already been serialized
|
||||
const struct DescriptorType *type = nullptr;
|
||||
FieldName fieldName;
|
||||
int subscriptLevels = 0;
|
||||
|
||||
// do not serialize the following
|
||||
TypeName typeName; // gives reference to type for lookup if type is null
|
||||
bool ownsType = false;
|
||||
|
||||
constexpr DescriptorField() noexcept = default;
|
||||
|
||||
/**
|
||||
* Allow for explicit copying.
|
||||
*/
|
||||
constexpr explicit DescriptorField(const DescriptorField &other) noexcept {
|
||||
type = other.type;
|
||||
fieldName = other.fieldName;
|
||||
subscriptLevels = other.subscriptLevels;
|
||||
typeName = other.typeName;
|
||||
ownsType = false; // is copy, only owns type if move
|
||||
}
|
||||
|
||||
constexpr DescriptorField(const DescriptorType *type, const FieldName &fieldName, int subscriptLevels, const TypeName &typeName, bool ownsType) noexcept {
|
||||
this->type = type;
|
||||
this->fieldName = fieldName;
|
||||
this->subscriptLevels = subscriptLevels;
|
||||
this->typeName = typeName;
|
||||
this->ownsType = ownsType;
|
||||
}
|
||||
|
||||
constexpr DescriptorField(DescriptorField &&other) noexcept {
|
||||
type = other.type;
|
||||
fieldName = other.fieldName;
|
||||
subscriptLevels = other.subscriptLevels;
|
||||
typeName = other.typeName;
|
||||
ownsType = other.ownsType;
|
||||
|
||||
other.type = {};
|
||||
other.fieldName = "";
|
||||
other.subscriptLevels = {};
|
||||
other.typeName = "";
|
||||
other.ownsType = {};
|
||||
}
|
||||
|
||||
~DescriptorField();
|
||||
|
||||
const DescriptorField &operator=(DescriptorField &&other) noexcept {
|
||||
type = other.type;
|
||||
fieldName = other.fieldName;
|
||||
subscriptLevels = other.subscriptLevels;
|
||||
typeName = other.typeName;
|
||||
ownsType = other.ownsType;
|
||||
|
||||
other.type = {};
|
||||
other.fieldName = "";
|
||||
other.subscriptLevels = {};
|
||||
other.typeName = "";
|
||||
other.ownsType = {};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using FieldList = Vector<DescriptorField>;
|
||||
|
||||
struct DescriptorType {
|
||||
TypeName typeName;
|
||||
PrimitiveType primitiveType;
|
||||
// fieldList only applies to structs
|
||||
FieldList fieldList;
|
||||
// - number of bytes for integer and float types
|
||||
// - number of fields for structs and lists
|
||||
int64_t length = 0;
|
||||
|
||||
DescriptorType() = default;
|
||||
|
||||
DescriptorType(TypeName tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) {
|
||||
}
|
||||
|
||||
DescriptorType(TypeName tn, PrimitiveType t, FieldList fl): typeName(tn), primitiveType(t), fieldList(fl) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
Error model(T *io, DescriptorType *type) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("ox::DescriptorType", 4);
|
||||
err |= io->field("typeName", &type->typeName);
|
||||
err |= io->field("primitiveType", &type->primitiveType);
|
||||
err |= io->field("fieldList", &type->fieldList);
|
||||
err |= io->field("length", &type->length);
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error modelWrite(T *io, DescriptorField *field) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("ox::DescriptorField", 4);
|
||||
if (field->ownsType) {
|
||||
err |= io->field("typeName", "");
|
||||
err |= io->field("type", field->type);
|
||||
} else {
|
||||
err |= io->field("typeName", &field->type->typeName);
|
||||
err |= io->field("type", static_cast<decltype(field->type)>(nullptr));
|
||||
}
|
||||
err |= io->field("fieldName", &field->fieldName);
|
||||
// defaultValue is unused now, but leave placeholder for backwards compatibility
|
||||
const int DefaultValue = 0;
|
||||
err |= io->field("defaultValue", &DefaultValue);
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error modelRead(T *io, DescriptorField *field) {
|
||||
auto err = OxError(0);
|
||||
auto &typeStore = io->typeStore();
|
||||
io->setTypeInfo("ox::DescriptorField", 4);
|
||||
err |= io->field("typeName", &field->typeName);
|
||||
if (field->typeName == "") {
|
||||
field->ownsType = true;
|
||||
if (field->type == nullptr) {
|
||||
field->type = new DescriptorType;
|
||||
}
|
||||
err |= io->field("type", field->type);
|
||||
typeStore[field->type->typeName] = field->type;
|
||||
} else {
|
||||
// should be empty, so discard
|
||||
DescriptorType t;
|
||||
err |= io->field("type", &t);
|
||||
field->type = typeStore[field->typeName];
|
||||
}
|
||||
err |= io->field("fieldName", &field->fieldName);
|
||||
// defaultValue is unused now, but placeholder for backwards compatibility
|
||||
err |= io->field("defaultValue", nullptr);
|
||||
return err;
|
||||
}
|
||||
|
||||
using TypeStore = ox::HashMap<ModelString, DescriptorType*>;
|
||||
|
||||
}
|
||||
147
deps/ox/src/ox/model/descwrite.cpp
vendored
147
deps/ox/src/ox/model/descwrite.cpp
vendored
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2019 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/typeinfo.hpp>
|
||||
|
||||
#include "descwrite.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
static_assert([] {
|
||||
int i = 0;
|
||||
return indirectionLevels(i) == 0;
|
||||
}(), "indirectionLevels broken: indirectionLevels(int)");
|
||||
|
||||
static_assert([] {
|
||||
int i = 0;
|
||||
return indirectionLevels(&i) == 1;
|
||||
}(), "indirectionLevels broken: indirectionLevels(int*)");
|
||||
|
||||
static_assert([] {
|
||||
int i[2] = {};
|
||||
return indirectionLevels(i) == 1;
|
||||
}(), "indirectionLevels broken: indirectionLevels(int[])");
|
||||
|
||||
TypeDescWriter::TypeDescWriter(TypeStore *typeStore) {
|
||||
if (!typeStore) {
|
||||
m_typeStoreOwnerRef = new TypeStore;
|
||||
typeStore = m_typeStoreOwnerRef;
|
||||
}
|
||||
m_typeStore = typeStore;
|
||||
}
|
||||
|
||||
TypeDescWriter::~TypeDescWriter() {
|
||||
// does not own it's elements
|
||||
delete m_typeStoreOwnerRef;
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int8_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int8_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 1;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int16_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int16_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 2;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int32_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int32_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 4;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(int64_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:int64_t";
|
||||
constexpr auto PT = PrimitiveType::SignedInteger;
|
||||
constexpr auto Bytes = 8;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint8_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint8_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 1;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint16_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint16_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 2;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint32_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint32_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 4;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(uint64_t*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:uint64_t";
|
||||
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
||||
constexpr auto Bytes = 8;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(const char*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(SerStr, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:bool";
|
||||
constexpr auto PT = PrimitiveType::Bool;
|
||||
constexpr auto Bytes = 0;
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
void TypeDescWriter::setTypeInfo(const char *name, int) {
|
||||
auto &t = m_typeStore->at(name);
|
||||
if (!t) {
|
||||
t = new DescriptorType;
|
||||
}
|
||||
m_type = t;
|
||||
m_type->typeName = name;
|
||||
m_type->primitiveType = PrimitiveType::Struct;
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::getType(TypeName tn, PrimitiveType pt, int b, bool *alreadyExisted) {
|
||||
if (m_typeStore->contains(tn)) {
|
||||
*alreadyExisted = true;
|
||||
auto type = m_typeStore->at(tn);
|
||||
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
|
||||
return type;
|
||||
} else {
|
||||
*alreadyExisted = false;
|
||||
auto &t = m_typeStore->at(tn);
|
||||
if (!t) {
|
||||
t = new DescriptorType;
|
||||
}
|
||||
t->typeName = tn;
|
||||
t->primitiveType = pt;
|
||||
t->length = b;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
183
deps/ox/src/ox/model/descwrite.hpp
vendored
183
deps/ox/src/ox/model/descwrite.hpp
vendored
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2019 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "desctypes.hpp"
|
||||
#include "optype.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
static constexpr int indirectionLevels(T) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr int indirectionLevels(T *t) {
|
||||
return 1 + indirectionLevels(*t);
|
||||
}
|
||||
|
||||
class TypeDescWriter {
|
||||
|
||||
private:
|
||||
struct NameCatcher {
|
||||
|
||||
TypeName name;
|
||||
|
||||
constexpr void setTypeInfo(const char *n, int) noexcept {
|
||||
this->name = n;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr ox::Error field(const char*, T*, std::size_t) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr ox::Error field(const char*, T*) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TypeStore *m_typeStoreOwnerRef = nullptr;
|
||||
TypeStore *m_typeStore = nullptr;
|
||||
DescriptorType *m_type = nullptr;
|
||||
|
||||
public:
|
||||
explicit TypeDescWriter(TypeStore *typeStore = nullptr);
|
||||
|
||||
~TypeDescWriter();
|
||||
|
||||
template<typename T>
|
||||
ox::Error field(const char *name, T *val, std::size_t valLen);
|
||||
|
||||
template<typename T>
|
||||
ox::Error field(const char *name, ox::Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
ox::Error field(const char *name, T *val);
|
||||
|
||||
void setTypeInfo(const char *name, int fields);
|
||||
|
||||
[[nodiscard]] DescriptorType *definition() noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
static constexpr OpType opType() {
|
||||
return OpType::WriteDefinition;
|
||||
}
|
||||
|
||||
private:
|
||||
DescriptorType *type(int8_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(int16_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(int32_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(int64_t *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(uint8_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(uint16_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(uint32_t *val, bool *alreadyExisted);
|
||||
DescriptorType *type(uint64_t *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(bool *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(const char *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(SerStr val, bool *alreadyExisted);
|
||||
|
||||
template<std::size_t sz>
|
||||
DescriptorType *type(BString<sz> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(T *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *getType(TypeName tn, PrimitiveType t, int b, bool *alreadyExisted);
|
||||
};
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, T *val, std::size_t) {
|
||||
if (m_type) {
|
||||
constexpr typename ox::remove_pointer<decltype(val)>::type *p = nullptr;
|
||||
bool alreadyExisted = false;
|
||||
const auto t = type(p, &alreadyExisted);
|
||||
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
|
||||
if (t == nullptr) {
|
||||
type(p, &alreadyExisted);
|
||||
}
|
||||
m_type->fieldList.emplace_back(t, name, indirectionLevels(val), alreadyExisted ? t->typeName : "", !alreadyExisted);
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, ox::Vector<T> *val) {
|
||||
return field(name, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, T *val) {
|
||||
if (m_type) {
|
||||
bool alreadyExisted = false;
|
||||
const auto t = type(val, &alreadyExisted);
|
||||
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
|
||||
m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted);
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<std::size_t sz>
|
||||
DescriptorType *TypeDescWriter::type(BString<sz> *val, bool *alreadyExisted) {
|
||||
return type(SerStr(val), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
|
||||
NameCatcher nc;
|
||||
model(&nc, val);
|
||||
if (m_typeStore->contains(nc.name)) {
|
||||
*alreadyExisted = true;
|
||||
return m_typeStore->at(nc.name);
|
||||
} else {
|
||||
TypeDescWriter dw(m_typeStore);
|
||||
oxLogError(model(&dw, val));
|
||||
*alreadyExisted = false;
|
||||
return dw.m_type;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ValErr<DescriptorType*> buildMCDef(T *val) {
|
||||
TypeDescWriter writer;
|
||||
Error err = model(&writer, val);
|
||||
return {writer.definition(), err};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error writeMCDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
|
||||
auto def = buildMCDef(val);
|
||||
auto err = def.error;
|
||||
if (!err) {
|
||||
err |= writeMC(buff, buffLen, def.value, sizeOut);
|
||||
}
|
||||
delete def.value;
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
15
deps/ox/src/ox/model/model.hpp
vendored
15
deps/ox/src/ox/model/model.hpp
vendored
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2019 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "descread.hpp"
|
||||
#include "desctypes.hpp"
|
||||
#include "descwrite.hpp"
|
||||
#include "types.hpp"
|
||||
#include "walk.hpp"
|
||||
50
deps/ox/src/ox/model/optype.hpp
vendored
50
deps/ox/src/ox/model/optype.hpp
vendored
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/error.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum class OpType {
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
WriteDefinition = 3,
|
||||
};
|
||||
|
||||
// empty default implementations of model functions
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error modelRead(T*, O*) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error modelWrite(T*, O*) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error modelWriteDefinition(T*, O*) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error model(T *io, O *obj) {
|
||||
if constexpr(T::opType() == ox::OpType::Read) {
|
||||
return modelRead(io, obj);
|
||||
} else if constexpr(T::opType() == ox::OpType::Write) {
|
||||
return modelWrite(io, obj);
|
||||
} else if constexpr(T::opType() == ox::OpType::WriteDefinition) {
|
||||
return modelWriteDefinition(io, obj);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
}
|
||||
58
deps/ox/src/ox/model/types.hpp
vendored
58
deps/ox/src/ox/model/types.hpp
vendored
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class SerStr {
|
||||
|
||||
protected:
|
||||
int m_cap = 0;
|
||||
char *m_str = nullptr;
|
||||
|
||||
public:
|
||||
template<std::size_t sz>
|
||||
constexpr SerStr(BString<sz> *str) noexcept {
|
||||
m_str = str->data();
|
||||
m_cap = str->cap();
|
||||
}
|
||||
|
||||
constexpr SerStr(char *str, int cap) noexcept {
|
||||
m_str = str;
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
constexpr const char *c_str() noexcept {
|
||||
return m_str;
|
||||
}
|
||||
|
||||
constexpr char *data() noexcept {
|
||||
// do not return a non-const pointer to the const_casted m_str
|
||||
return m_str;
|
||||
}
|
||||
|
||||
constexpr int len() noexcept {
|
||||
return ox_strlen(m_str);
|
||||
}
|
||||
|
||||
constexpr int bytes() noexcept {
|
||||
return ox_strlen(m_str) + 1; // adds 1 for \0
|
||||
}
|
||||
|
||||
constexpr int cap() noexcept {
|
||||
return m_cap;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
147
deps/ox/src/ox/model/walk.hpp
vendored
147
deps/ox/src/ox/model/walk.hpp
vendored
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/error.hpp>
|
||||
|
||||
#include "desctypes.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename Reader, typename T>
|
||||
class DataWalker {
|
||||
template<typename ReaderBase, typename FH>
|
||||
friend ox::Error parseField(const DescriptorField &field, ReaderBase *rdr, DataWalker<ReaderBase, FH> *walker);
|
||||
|
||||
private:
|
||||
Vector<const DescriptorType*> m_typeStack;
|
||||
T m_fieldHandler;
|
||||
Vector<FieldName> m_path;
|
||||
Vector<TypeName> m_typePath;
|
||||
|
||||
public:
|
||||
DataWalker(DescriptorType *type, T fieldHandler);
|
||||
|
||||
[[nodiscard]] const DescriptorType *type() const noexcept;
|
||||
|
||||
ox::Error read(const DescriptorField&, Reader *rdr);
|
||||
|
||||
protected:
|
||||
void pushNamePath(FieldName fn);
|
||||
|
||||
void popNamePath();
|
||||
|
||||
void pushType(const DescriptorType *type);
|
||||
|
||||
void popType();
|
||||
|
||||
};
|
||||
|
||||
template<typename Reader, typename T>
|
||||
DataWalker<Reader, T>::DataWalker(DescriptorType *type, T fieldHandler): m_fieldHandler(fieldHandler) {
|
||||
m_typeStack.push_back(type);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
const DescriptorType *DataWalker<Reader, T>::type() const noexcept {
|
||||
return m_typeStack.back();
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
ox::Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rdr) {
|
||||
// get const ref of paths
|
||||
const auto &pathCr = m_path;
|
||||
const auto &typePathCr = m_typePath;
|
||||
return m_fieldHandler(pathCr, typePathCr, f, rdr);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::pushNamePath(FieldName fn) {
|
||||
m_path.push_back(fn);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::popNamePath() {
|
||||
m_path.pop_back();
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::pushType(const DescriptorType *type) {
|
||||
m_typeStack.push_back(type);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void DataWalker<Reader, T>::popType() {
|
||||
m_typeStack.pop_back();
|
||||
}
|
||||
|
||||
template<typename Reader, typename FH>
|
||||
static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalker<Reader, FH> *walker) {
|
||||
walker->pushNamePath(field.fieldName);
|
||||
if (field.subscriptLevels) {
|
||||
// add array handling
|
||||
const auto [arrayLen, err] = rdr->arrayLength(true);
|
||||
oxReturnError(err);
|
||||
auto child = rdr->child();
|
||||
child.setTypeInfo(field.fieldName.c_str(), arrayLen);
|
||||
DescriptorField f(field); // create mutable copy
|
||||
--f.subscriptLevels;
|
||||
BString<100> subscript;
|
||||
for (ArrayLength i = 0; i < arrayLen; i++) {
|
||||
subscript = "[";
|
||||
subscript += i;
|
||||
subscript += "]";
|
||||
walker->pushNamePath(subscript);
|
||||
oxReturnError(parseField(f, &child, walker));
|
||||
walker->popNamePath();
|
||||
}
|
||||
rdr->nextField();
|
||||
} else {
|
||||
switch (field.type->primitiveType) {
|
||||
case PrimitiveType::UnsignedInteger:
|
||||
case PrimitiveType::SignedInteger:
|
||||
case PrimitiveType::Bool:
|
||||
case PrimitiveType::String:
|
||||
oxReturnError(walker->read(field, rdr));
|
||||
break;
|
||||
case PrimitiveType::Struct:
|
||||
if (rdr->fieldPresent()) {
|
||||
auto child = rdr->child();
|
||||
walker->pushType(field.type);
|
||||
oxReturnError(model(&child, walker));
|
||||
walker->popType();
|
||||
rdr->nextField();
|
||||
} else {
|
||||
// skip and discard absent field
|
||||
int discard;
|
||||
oxReturnError(rdr->field("", &discard));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
walker->popNamePath();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename Reader, typename FH>
|
||||
ox::Error model(Reader *rdr, DataWalker<Reader, FH> *walker) {
|
||||
auto type = walker->type();
|
||||
if (!type) {
|
||||
return OxError(1);
|
||||
}
|
||||
auto typeName = type->typeName.c_str();
|
||||
auto &fields = type->fieldList;
|
||||
rdr->setTypeInfo(typeName, fields.size());
|
||||
for (std::size_t i = 0; i < fields.size(); i++) {
|
||||
oxReturnError(parseField(fields[i], rdr, walker));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
}
|
||||
11
deps/ox/src/ox/ptrarith/CMakeLists.txt
vendored
11
deps/ox/src/ox/ptrarith/CMakeLists.txt
vendored
@@ -1,11 +0,0 @@
|
||||
install(
|
||||
FILES
|
||||
nodebuffer.hpp
|
||||
ptr.hpp
|
||||
DESTINATION
|
||||
include/ox/ptrarith
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
455
deps/ox/src/ox/ptrarith/nodebuffer.hpp
vendored
455
deps/ox/src/ox/ptrarith/nodebuffer.hpp
vendored
@@ -1,455 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/stddef.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
|
||||
#include "ptr.hpp"
|
||||
|
||||
namespace ox::ptrarith {
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
class OX_PACKED NodeBuffer {
|
||||
|
||||
public:
|
||||
struct OX_PACKED Header {
|
||||
ox::LittleEndian<size_t> size = sizeof(Header); // capacity
|
||||
ox::LittleEndian<size_t> bytesUsed = sizeof(Header);
|
||||
ox::LittleEndian<size_t> firstItem = 0;
|
||||
};
|
||||
|
||||
using ItemPtr = Ptr<Item, size_t, sizeof(Header)>;
|
||||
|
||||
class Iterator {
|
||||
private:
|
||||
NodeBuffer *m_buffer = nullptr;
|
||||
ItemPtr m_current;
|
||||
size_t m_it = 0;
|
||||
|
||||
public:
|
||||
Iterator(NodeBuffer *buffer, ItemPtr current) {
|
||||
m_buffer = buffer;
|
||||
m_current = current;
|
||||
oxTrace("ox::ptrarith::Iterator::start") << current.offset();
|
||||
}
|
||||
|
||||
operator const Item*() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
ItemPtr ptr() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
Item *get() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator ItemPtr() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator Item*() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
const Item *operator->() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
Item *operator->() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const noexcept {
|
||||
return m_current.valid();
|
||||
}
|
||||
|
||||
bool hasNext() {
|
||||
if (m_current.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::Iterator::hasNext::current") << m_current.offset();
|
||||
auto next = m_buffer->next(m_current);
|
||||
return next.valid() && m_buffer->firstItem() != next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void next() {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::Iterator::next") << m_it++;
|
||||
if (hasNext()) {
|
||||
m_current = m_buffer->next(m_current);
|
||||
} else {
|
||||
m_current = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Header m_header;
|
||||
|
||||
public:
|
||||
NodeBuffer();
|
||||
|
||||
NodeBuffer(const NodeBuffer &other, size_t size);
|
||||
|
||||
explicit NodeBuffer(size_t size);
|
||||
|
||||
const Iterator iterator() const;
|
||||
|
||||
Iterator iterator();
|
||||
|
||||
ItemPtr firstItem();
|
||||
|
||||
ItemPtr lastItem();
|
||||
|
||||
/**
|
||||
* @return the data section of the given item
|
||||
*/
|
||||
template<typename T>
|
||||
Ptr<T, size_t, sizeof(Item)> dataOf(ItemPtr);
|
||||
|
||||
[[nodiscard]] ItemPtr prev(Item *item);
|
||||
|
||||
[[nodiscard]] ItemPtr next(Item *item);
|
||||
|
||||
/**
|
||||
* Like pointer but omits checks that assume the memory at the offset has
|
||||
* already been initialed as an Item.
|
||||
*/
|
||||
[[nodiscard]] ItemPtr uninitializedPtr(size_t offset);
|
||||
|
||||
[[nodiscard]] ItemPtr ptr(size_t offset);
|
||||
|
||||
[[nodiscard]] ItemPtr ptr(void *item);
|
||||
|
||||
[[nodiscard]] ItemPtr malloc(size_t size);
|
||||
|
||||
[[nodiscard]] ox::Error free(ItemPtr item);
|
||||
|
||||
[[nodiscard]] bool valid(size_t maxSize);
|
||||
|
||||
/**
|
||||
* Set size, capacity.
|
||||
*/
|
||||
[[nodiscard]] ox::Error setSize(size_t size);
|
||||
|
||||
/**
|
||||
* Get size, capacity.
|
||||
* @return capacity
|
||||
*/
|
||||
size_t size();
|
||||
|
||||
/**
|
||||
* @return the bytes still available in this NodeBuffer
|
||||
*/
|
||||
size_t available();
|
||||
|
||||
/**
|
||||
* @return the actual number a bytes need to store the given number of
|
||||
* bytes
|
||||
*/
|
||||
static size_t spaceNeeded(size_t size);
|
||||
|
||||
template<typename F>
|
||||
[[nodiscard]] ox::Error compact(F cb = [](uint64_t, ItemPtr) {});
|
||||
|
||||
void truncate();
|
||||
|
||||
private:
|
||||
uint8_t *data();
|
||||
|
||||
};
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
NodeBuffer<size_t, Item>::NodeBuffer(size_t size) {
|
||||
m_header.size = size;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + sizeof(*this);
|
||||
ox_memset(data, 0, size - sizeof(*this));
|
||||
oxTrace("ox::NodeBuffer::constructor") << m_header.firstItem;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
NodeBuffer<size_t, Item>::NodeBuffer(const NodeBuffer &other, size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::copy") << "other.m_header.firstItem:" << other.m_header.firstItem;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + sizeof(*this);
|
||||
ox_memset(data, 0, size - sizeof(*this));
|
||||
ox_memcpy(this, &other, size);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
const typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() const {
|
||||
return Iterator(this, firstItem());
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::iterator::size") << m_header.size;
|
||||
return Iterator(this, firstItem());
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::firstItem() {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::firstItem") << m_header.firstItem;
|
||||
return ptr(m_header.firstItem);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::lastItem() {
|
||||
auto first = ptr(m_header.firstItem);
|
||||
if (first.valid()) {
|
||||
return prev(first);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
template<typename T>
|
||||
Ptr<T, size_t, sizeof(Item)> NodeBuffer<size_t, Item>::dataOf(ItemPtr ip) {
|
||||
auto out = ip.template subPtr<T>(sizeof(Item));
|
||||
oxAssert(out.size() == ip.size() - sizeof(Item), "Sub Ptr has invalid size.");
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::prev(Item *item) {
|
||||
return ptr(item->prev);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::next(Item *item) {
|
||||
return ptr(item->next);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::uninitializedPtr(size_t itemOffset) {
|
||||
// make sure this can be read as an Item, and then use Item::size for the size
|
||||
std::size_t itemSpace = m_header.size - itemOffset;
|
||||
if (itemOffset >= sizeof(Header) &&
|
||||
itemOffset + itemSpace <= size() &&
|
||||
itemSpace >= sizeof(Item)) {
|
||||
return ItemPtr(this, m_header.size, itemOffset, itemSpace);
|
||||
} else {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset:" << itemOffset;
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset >= sizeof(Header):" << (itemOffset >= sizeof(Header));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= sizeof(Item):" << (itemSpace >= sizeof(Item));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= item->fullSize():" << (itemSpace >= item->fullSize());
|
||||
return ItemPtr(this, m_header.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::ptr(size_t itemOffset) {
|
||||
// make sure this can be read as an Item, and then use Item::size for the size
|
||||
std::size_t itemSpace = m_header.size - itemOffset;
|
||||
auto item = reinterpret_cast<Item*>(reinterpret_cast<uint8_t*>(this) + itemOffset);
|
||||
if (itemOffset >= sizeof(Header) &&
|
||||
itemOffset + itemSpace <= size() &&
|
||||
itemSpace >= sizeof(Item) &&
|
||||
itemSpace >= item->fullSize()) {
|
||||
return ItemPtr(this, m_header.size, itemOffset, item->fullSize());
|
||||
} else {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset:" << itemOffset;
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset >= sizeof(Header):" << (itemOffset >= sizeof(Header));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= sizeof(Item):" << (itemSpace >= sizeof(Item));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= item->fullSize():" << (itemSpace >= item->fullSize());
|
||||
return ItemPtr(this, m_header.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::malloc(size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "Size:" << size;
|
||||
size_t fullSize = size + sizeof(Item);
|
||||
if (m_header.size - m_header.bytesUsed >= fullSize) {
|
||||
auto last = lastItem();
|
||||
size_t addr = 0;
|
||||
if (last.valid()) {
|
||||
addr = last.offset() + last.size();
|
||||
} else {
|
||||
// there is no first item, so this must be the first item
|
||||
if (!m_header.firstItem) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "No first item, initializing.";
|
||||
m_header.firstItem = sizeof(m_header);
|
||||
addr = m_header.firstItem;
|
||||
} else {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer is in invalid state.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "buffer size:" << m_header.size
|
||||
<< ";addr:" << addr
|
||||
<< ";fullSize:" << fullSize;
|
||||
auto out = ItemPtr(this, m_header.size, addr, fullSize);
|
||||
if (!out.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "Unknown";
|
||||
return nullptr;
|
||||
}
|
||||
ox_memset(out, 0, fullSize);
|
||||
new (out) Item;
|
||||
out->setSize(size);
|
||||
|
||||
auto first = firstItem();
|
||||
auto oldLast = last;
|
||||
out->next = first.offset();
|
||||
if (first.valid()) {
|
||||
first->prev = out.offset();
|
||||
} else {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer malloc failed due to invalid first element pointer.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (oldLast.valid()) {
|
||||
out->prev = oldLast.offset();
|
||||
oldLast->next = out.offset();
|
||||
} else { // check to see if this is the first allocation
|
||||
if (out.offset() != first.offset()) {
|
||||
// if this is not the first allocation, there should be an oldLast
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer malloc failed due to invalid last element pointer.";
|
||||
return nullptr;
|
||||
}
|
||||
out->prev = out.offset();
|
||||
}
|
||||
m_header.bytesUsed += out.size();
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "Offset:" << out.offset();
|
||||
return out;
|
||||
}
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "Insufficient space:" << fullSize << "needed," << available() << "available";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
Error NodeBuffer<size_t, Item>::free(ItemPtr item) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free") << "offset:" << item.offset();
|
||||
auto prev = this->prev(item);
|
||||
auto next = this->next(item);
|
||||
if (prev.valid() && next.valid()) {
|
||||
if (next != item) {
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
if (item.offset() == m_header.firstItem) {
|
||||
m_header.firstItem = next;
|
||||
}
|
||||
} else {
|
||||
// only one item, null out first
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free") << "Nulling out firstItem.";
|
||||
m_header.firstItem = 0;
|
||||
}
|
||||
} else {
|
||||
if (!prev.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free::fail") << "NodeBuffer free failed due to invalid prev element pointer:" << prev.offset();
|
||||
return OxError(1);
|
||||
}
|
||||
if (!next.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free::fail") << "NodeBuffer free failed due to invalid next element pointer:" << next.offset();
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
m_header.bytesUsed -= item.size();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
Error NodeBuffer<size_t, Item>::setSize(size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::setSize") << m_header.size << "to" << size;
|
||||
auto last = lastItem();
|
||||
auto end = last.valid() ? last.end() : sizeof(m_header);
|
||||
oxTrace("ox::ptrarith::NodeBuffer::setSize") << "end:" << end;
|
||||
if (end > size) {
|
||||
// resizing to less than buffer size
|
||||
return OxError(1);
|
||||
} else {
|
||||
m_header.size = size;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + end;
|
||||
ox_memset(data, 0, size - end);
|
||||
return OxError(0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::size() {
|
||||
return m_header.size;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
bool NodeBuffer<size_t, Item>::valid(size_t maxSize) {
|
||||
return m_header.size <= maxSize;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::available() {
|
||||
return m_header.size - m_header.bytesUsed;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::spaceNeeded(size_t size) {
|
||||
return sizeof(Item) + size;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
template<typename F>
|
||||
ox::Error NodeBuffer<size_t, Item>::compact(F cb) {
|
||||
auto src = firstItem();
|
||||
auto dest = ptr(sizeof(*this));
|
||||
while (dest.offset() <= src.offset()) {
|
||||
if (!src.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
if (!dest.valid()) {
|
||||
return OxError(2);
|
||||
}
|
||||
// move node
|
||||
ox_memcpy(dest, src, src->fullSize());
|
||||
oxReturnError(cb(src, dest));
|
||||
// update surrounding nodes
|
||||
auto prev = ptr(dest->prev);
|
||||
if (prev.valid()) {
|
||||
prev->next = dest;
|
||||
}
|
||||
auto next = ptr(dest->next);
|
||||
if (next.valid()) {
|
||||
next->prev = dest;
|
||||
}
|
||||
// update iterators
|
||||
src = ptr(dest->next);
|
||||
dest = uninitializedPtr(dest.offset() + dest->fullSize());
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
void NodeBuffer<size_t, Item>::truncate() {
|
||||
m_header.size = m_header.bytesUsed;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
uint8_t *NodeBuffer<size_t, Item>::data() {
|
||||
return reinterpret_cast<uint8_t*>(ptr(sizeof(*this)).get());
|
||||
}
|
||||
|
||||
|
||||
template<typename size_t>
|
||||
struct OX_PACKED Item {
|
||||
public:
|
||||
ox::LittleEndian<size_t> prev = 0;
|
||||
ox::LittleEndian<size_t> next = 0;
|
||||
|
||||
private:
|
||||
ox::LittleEndian<size_t> m_size = sizeof(Item);
|
||||
|
||||
public:
|
||||
size_t size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void setSize(size_t size) {
|
||||
m_size = size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
230
deps/ox/src/ox/ptrarith/ptr.hpp
vendored
230
deps/ox/src/ox/ptrarith/ptr.hpp
vendored
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
namespace ox::ptrarith {
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset = 1>
|
||||
class Ptr {
|
||||
|
||||
private:
|
||||
uint8_t *m_dataStart = nullptr;
|
||||
size_t m_dataSize = 0;
|
||||
size_t m_itemOffset = 0;
|
||||
size_t m_itemSize = 0;
|
||||
// this should be removed later on, but the excessive validation is
|
||||
// desirable during during heavy development
|
||||
mutable uint8_t m_validated = false;
|
||||
|
||||
public:
|
||||
inline Ptr() = default;
|
||||
|
||||
inline Ptr(std::nullptr_t);
|
||||
|
||||
inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T), size_t itemTypeSize = sizeof(T));
|
||||
|
||||
[[nodiscard]] inline bool valid() const;
|
||||
|
||||
inline size_t size() const;
|
||||
|
||||
inline size_t offset() const;
|
||||
|
||||
inline size_t end();
|
||||
|
||||
inline const T *get() const;
|
||||
|
||||
inline T *get();
|
||||
|
||||
inline const T *operator->() const;
|
||||
|
||||
inline T *operator->();
|
||||
|
||||
inline operator const T*() const;
|
||||
|
||||
inline operator T*();
|
||||
|
||||
inline const T &operator*() const;
|
||||
|
||||
inline T &operator*();
|
||||
|
||||
inline operator size_t() const;
|
||||
|
||||
inline bool operator==(const Ptr<T, size_t, minOffset> &other) const;
|
||||
|
||||
inline bool operator!=(const Ptr<T, size_t, minOffset> &other) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset, size_t size) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset, size_t size);
|
||||
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset);
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, minOffset> to() const;
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(std::nullptr_t) {
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize, size_t itemTypeSize) {
|
||||
// do some sanity checks before assuming this is valid
|
||||
if (itemSize >= itemTypeSize &&
|
||||
dataStart &&
|
||||
itemStart >= minOffset &&
|
||||
itemStart + itemSize <= dataSize) {
|
||||
m_dataStart = reinterpret_cast<uint8_t*>(dataStart);
|
||||
m_dataSize = dataSize;
|
||||
m_itemOffset = itemStart;
|
||||
m_itemSize = itemSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::valid() const {
|
||||
m_validated = m_dataStart != nullptr;
|
||||
return m_validated;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::size() const {
|
||||
return m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::offset() const {
|
||||
return m_itemOffset;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::end() {
|
||||
return m_itemOffset + m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T *Ptr<T, size_t, minOffset>::get() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T *Ptr<T, size_t, minOffset>::get() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T *Ptr<T, size_t, minOffset>::operator->() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T *Ptr<T, size_t, minOffset>::operator->() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator const T*() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator const T*())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator const T*())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator T*() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator T*())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator T*())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T &Ptr<T, size_t, minOffset>::operator*() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
oxAssert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
return *reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T &Ptr<T, size_t, minOffset>::operator*() {
|
||||
oxAssert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
oxAssert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
return *reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator size_t() const {
|
||||
if (m_dataStart && m_itemOffset) {
|
||||
return m_itemOffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::operator==(const Ptr<T, size_t, minOffset> &other) const {
|
||||
return m_dataStart == other.m_dataStart &&
|
||||
m_itemOffset == other.m_itemOffset &&
|
||||
m_itemSize == other.m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::operator!=(const Ptr<T, size_t, minOffset> &other) const {
|
||||
return m_dataStart != other.m_dataStart ||
|
||||
m_itemOffset != other.m_itemOffset ||
|
||||
m_itemSize != other.m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset, size_t size) const {
|
||||
return Ptr<SubT, size_t, sizeof(T)>(get(), this->size(), offset, size);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const {
|
||||
oxTrace("ox::fs::Ptr::subPtr") << m_itemOffset << this->size() << offset << m_itemSize << (m_itemSize - offset);
|
||||
return subPtr<SubT>(offset, m_itemSize - offset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset, size_t size) {
|
||||
return Ptr<SubT, size_t, sizeof(T)>(get(), this->size(), offset, size);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) {
|
||||
oxTrace("ox::fs::Ptr::subPtr") << m_itemOffset << this->size() << offset << m_itemSize << (m_itemSize - offset);
|
||||
return subPtr<SubT>(offset, m_itemSize - offset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, minOffset> Ptr<T, size_t, minOffset>::to() const {
|
||||
return Ptr<SubT, size_t, minOffset>(m_dataStart, m_dataSize, m_itemOffset, m_itemSize);
|
||||
}
|
||||
|
||||
}
|
||||
11
deps/ox/src/ox/ptrarith/test/CMakeLists.txt
vendored
11
deps/ox/src/ox/ptrarith/test/CMakeLists.txt
vendored
@@ -1,11 +0,0 @@
|
||||
add_executable(
|
||||
PtrArithTests
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
PtrArithTests
|
||||
OxStd
|
||||
)
|
||||
|
||||
add_test("Test\\ PtrArith::setSize" PtrArithTests PtrArith::setSize)
|
||||
77
deps/ox/src/ox/ptrarith/test/tests.cpp
vendored
77
deps/ox/src/ox/ptrarith/test/tests.cpp
vendored
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// make sure asserts are enabled for the test file
|
||||
#undef NDEBUG
|
||||
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/fs/filesystem/filesystem.hpp>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace ox;
|
||||
|
||||
template<typename T>
|
||||
struct OX_PACKED NodeType: public ox::ptrarith::Item<T> {
|
||||
public:
|
||||
size_t fullSize() const {
|
||||
return this->size() + sizeof(*this);
|
||||
}
|
||||
};
|
||||
|
||||
map<string, int(*)(string)> tests = {
|
||||
{
|
||||
{
|
||||
"PtrArith::setSize",
|
||||
[](string) {
|
||||
using BuffPtr_t = uint32_t;
|
||||
std::vector<char> buff(5 * ox::units::MB);
|
||||
auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
|
||||
using String = BString<6>;
|
||||
auto a1 = buffer->malloc(sizeof(String));
|
||||
auto a2 = buffer->malloc(sizeof(String));
|
||||
oxAssert(a1.valid(), "Allocation 1 failed.");
|
||||
oxAssert(a2.valid(), "Allocation 2 failed.");
|
||||
auto &s1 = *new (buffer->dataOf<String>(a1)) String("asdf");
|
||||
auto &s2 = *new (buffer->dataOf<String>(a2)) String("aoeu");
|
||||
oxTrace("test") << "s1: " << s1.c_str();
|
||||
oxTrace("test") << "s2: " << s2.c_str();
|
||||
oxAssert(s1 == "asdf", "Allocation 1 not as expected.");
|
||||
oxAssert(s2 == "aoeu", "Allocation 2 not as expected.");
|
||||
oxAssert(buffer->free(a1), "Free failed.");
|
||||
oxAssert(buffer->free(a2), "Free failed.");
|
||||
oxAssert(buffer->setSize(buffer->size() - buffer->available()), "Resize failed.");
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 1) {
|
||||
auto testName = args[1];
|
||||
string testArg = "";
|
||||
if (args[2]) {
|
||||
testArg = args[2];
|
||||
}
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName](testArg);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
74
deps/ox/src/ox/std/CMakeLists.txt
vendored
74
deps/ox/src/ox/std/CMakeLists.txt
vendored
@@ -1,74 +0,0 @@
|
||||
add_library(
|
||||
OxStd
|
||||
assert.cpp
|
||||
buildinfo.cpp
|
||||
byteswap.cpp
|
||||
memops.cpp
|
||||
new.cpp
|
||||
random.cpp
|
||||
substitutes.cpp
|
||||
stacktrace.cpp
|
||||
string.cpp
|
||||
strops.cpp
|
||||
trace.cpp
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxStd
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${OX_USE_STDLIB})
|
||||
target_compile_definitions(
|
||||
OxStd PUBLIC
|
||||
OX_USE_STDLIB
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
OxStd PUBLIC
|
||||
$<$<CXX_COMPILER_ID:GNU>:gcc>
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
assert.hpp
|
||||
bit.hpp
|
||||
bstring.hpp
|
||||
buildinfo.hpp
|
||||
byteswap.hpp
|
||||
defines.hpp
|
||||
error.hpp
|
||||
hardware.hpp
|
||||
hashmap.hpp
|
||||
math.hpp
|
||||
memops.hpp
|
||||
new.hpp
|
||||
random.hpp
|
||||
stacktrace.hpp
|
||||
string.hpp
|
||||
strongint.hpp
|
||||
strops.hpp
|
||||
std.hpp
|
||||
stddef.hpp
|
||||
trace.hpp
|
||||
types.hpp
|
||||
typetraits.hpp
|
||||
units.hpp
|
||||
vector.hpp
|
||||
DESTINATION
|
||||
include/ox/std
|
||||
)
|
||||
|
||||
install(TARGETS OxStd
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS STREQUAL "ON")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
54
deps/ox/src/ox/std/assert.cpp
vendored
54
deps/ox/src/ox/std/assert.cpp
vendored
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#if defined(OX_USE_STDLIB)
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "stacktrace.hpp"
|
||||
#include "trace.hpp"
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<>
|
||||
void assertFunc<bool>([[maybe_unused]]const char *file, [[maybe_unused]]int line, [[maybe_unused]]bool pass, [[maybe_unused]]const char *msg) {
|
||||
#if defined(OX_USE_STDLIB)
|
||||
if (!pass) {
|
||||
std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << msg << std::endl;
|
||||
printStackTrace(2);
|
||||
oxTrace("assert").del("") << "Failed assert: " << msg << " (" << file << ":" << line << ")";
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<>
|
||||
void assertFunc<Error>(const char *file, int line, Error err, const char *msg) {
|
||||
if (err) {
|
||||
panic(file, line, msg, err);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OX_USE_STDLIB)
|
||||
void panic(const char *file, int line, const char *msg, Error err) {
|
||||
std::cerr << "\033[31;1;1mPANIC:\033[0m (" << file << ':' << line << "): " << msg << '\n';
|
||||
std::cerr << "\tError Code:\t" << err << '\n';
|
||||
if (err.file != nullptr) {
|
||||
std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
|
||||
}
|
||||
printStackTrace(2);
|
||||
oxTrace("assert").del("") << "Failed assert: " << msg << " (" << file << ":" << line << ")";
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
36
deps/ox/src/ox/std/assert.hpp
vendored
36
deps/ox/src/ox/std/assert.hpp
vendored
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
void assertFunc(const char*, int, T, const char*) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void assertFunc<bool>(const char *file, int line, bool pass, const char *msg);
|
||||
|
||||
template<>
|
||||
void assertFunc<Error>(const char *file, int line, Error err, const char*);
|
||||
|
||||
void panic([[maybe_unused]]const char *file, [[maybe_unused]]int line, [[maybe_unused]]const char *msg, [[maybe_unused]]Error err = OxError(0));
|
||||
|
||||
}
|
||||
|
||||
#define oxPanic(pass, msg) ox::panic(__FILE__, __LINE__, msg, pass)
|
||||
#ifndef NDEBUG
|
||||
#define oxAssert(pass, msg) ox::assertFunc<decltype(pass)>(__FILE__, __LINE__, pass, msg)
|
||||
#else
|
||||
inline void oxAssert(bool, const char*) {}
|
||||
inline void oxAssert(ox::Error, const char*) {}
|
||||
#endif
|
||||
47
deps/ox/src/ox/std/bit.hpp
vendored
47
deps/ox/src/ox/std/bit.hpp
vendored
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "memops.hpp"
|
||||
#include "types.hpp"
|
||||
#include "typetraits.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename To, typename From>
|
||||
typename enable_if<sizeof(To) == sizeof(From), To>::type bit_cast(From src) noexcept {
|
||||
To dst = {};
|
||||
memcpy(&dst, &src, sizeof(src));
|
||||
return dst;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T rotl(T i, int shift) noexcept {
|
||||
constexpr auto bits = sizeof(i) * 8;
|
||||
return (i << shift) | (i >> (bits - shift));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T onMask(int bits = sizeof(T) << 3 /* *8 */) noexcept {
|
||||
T out = T(0);
|
||||
for (auto i = 0; i < bits; i++) {
|
||||
out |= static_cast<T>(1) << i;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr auto MaxValue = onMask<T>();
|
||||
|
||||
static_assert(onMask<int>(1) == 1);
|
||||
static_assert(onMask<int>(2) == 3);
|
||||
static_assert(onMask<int>(3) == 7);
|
||||
static_assert(onMask<int>(4) == 15);
|
||||
|
||||
}
|
||||
197
deps/ox/src/ox/std/bstring.hpp
vendored
197
deps/ox/src/ox/std/bstring.hpp
vendored
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "memops.hpp"
|
||||
#include "strops.hpp"
|
||||
#include "typetraits.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
// Bounded String
|
||||
template<std::size_t buffLen>
|
||||
class BString {
|
||||
private:
|
||||
char m_buff[buffLen + 1];
|
||||
|
||||
public:
|
||||
constexpr BString() noexcept;
|
||||
|
||||
constexpr BString(const char *str) noexcept;
|
||||
|
||||
constexpr const BString &operator=(const char *str) noexcept;
|
||||
|
||||
constexpr const BString &operator=(char *str) noexcept;
|
||||
|
||||
constexpr const BString &operator=(int64_t i) noexcept;
|
||||
|
||||
constexpr const BString &operator+=(const char *str) noexcept;
|
||||
|
||||
constexpr const BString &operator+=(char *str) noexcept;
|
||||
|
||||
constexpr const BString &operator+=(int64_t i) noexcept;
|
||||
|
||||
constexpr bool operator==(const BString &other) noexcept;
|
||||
|
||||
constexpr bool operator!=(const BString &other) noexcept;
|
||||
|
||||
constexpr char operator[](std::size_t i) const noexcept;
|
||||
|
||||
constexpr char &operator[](std::size_t i) noexcept;
|
||||
|
||||
constexpr char *data() noexcept;
|
||||
|
||||
constexpr const char *c_str() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the number of characters in this string.
|
||||
*/
|
||||
constexpr std::size_t len() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the number of bytes used for this string.
|
||||
*/
|
||||
constexpr std::size_t bytes() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the capacity of bytes for this string.
|
||||
*/
|
||||
constexpr std::size_t cap() const noexcept;
|
||||
};
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr BString<size>::BString() noexcept {
|
||||
m_buff[0] = 0;
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr BString<size>::BString(const char *str) noexcept {
|
||||
*this = str;
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr const BString<size> &BString<size>::operator=(int64_t i) noexcept {
|
||||
char str[65] = {};
|
||||
ox_itoa(i, str);
|
||||
return this->operator=(str);
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr const BString<size> &BString<size>::operator=(const char *str) noexcept {
|
||||
std::size_t strLen = ox_strlen(str) + 1;
|
||||
if (cap() < strLen) {
|
||||
strLen = cap();
|
||||
}
|
||||
ox_memcpy(m_buff, str, strLen);
|
||||
// make sure last element is a null terminator
|
||||
m_buff[cap() - 1] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr const BString<size> &BString<size>::operator=(char *str) noexcept {
|
||||
return *this = static_cast<const char*>(str);
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr const BString<size> &BString<size>::operator+=(const char *str) noexcept {
|
||||
std::size_t strLen = ox_strlen(str) + 1;
|
||||
auto currentLen = len();
|
||||
if (cap() < currentLen + strLen) {
|
||||
strLen = cap() - currentLen;
|
||||
}
|
||||
ox_memcpy(m_buff + currentLen, str, strLen);
|
||||
// make sure last element is a null terminator
|
||||
m_buff[currentLen + strLen] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr const BString<size> &BString<size>::operator+=(char *str) noexcept {
|
||||
return *this += static_cast<const char*>(str);
|
||||
}
|
||||
|
||||
template<std::size_t size>
|
||||
constexpr const BString<size> &BString<size>::operator+=(int64_t i) noexcept {
|
||||
char str[65] = {};
|
||||
ox_itoa(i, str);
|
||||
return this->operator+=(str);
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr bool BString<buffLen>::operator==(const BString<buffLen> &other) noexcept {
|
||||
bool retval = true;
|
||||
std::size_t i = 0;
|
||||
while (i < buffLen && (m_buff[i] || other.m_buff[i])) {
|
||||
if (m_buff[i] != other.m_buff[i]) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr bool BString<buffLen>::operator!=(const BString<buffLen> &other) noexcept {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr char BString<buffLen>::operator[](std::size_t i) const noexcept {
|
||||
return m_buff[i];
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
|
||||
return m_buff[i];
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr char *BString<buffLen>::data() noexcept {
|
||||
return static_cast<char*>(m_buff);
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr const char *BString<buffLen>::c_str() const noexcept {
|
||||
return static_cast<const char*>(m_buff);
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr std::size_t BString<buffLen>::len() const noexcept {
|
||||
std::size_t length = 0;
|
||||
for (std::size_t i = 0; i < buffLen; i++) {
|
||||
uint8_t b = static_cast<uint8_t>(m_buff[i]);
|
||||
if (b) {
|
||||
if ((b & 128) == 0) { // normal ASCII character
|
||||
length++;
|
||||
} else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character
|
||||
length++;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr std::size_t BString<buffLen>::bytes() const noexcept {
|
||||
std::size_t i = 0;
|
||||
for (i = 0; i < buffLen && m_buff[i]; i++);
|
||||
return i + 1; // add one for null terminator
|
||||
}
|
||||
|
||||
template<std::size_t buffLen>
|
||||
constexpr std::size_t BString<buffLen>::cap() const noexcept {
|
||||
return buffLen;
|
||||
}
|
||||
|
||||
}
|
||||
46
deps/ox/src/ox/std/buildinfo.cpp
vendored
46
deps/ox/src/ox/std/buildinfo.cpp
vendored
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace ox::buildinfo {
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-const-variable"
|
||||
#endif
|
||||
|
||||
#if defined(OX_USE_STDLIB)
|
||||
const bool UseStdLib = true;
|
||||
#else
|
||||
const bool UseStdLib = false;
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
const bool Debug = true;
|
||||
#else
|
||||
const bool Debug = false;
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG)
|
||||
const bool NDebug = true;
|
||||
#else
|
||||
const bool NDebug = false;
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
const bool BigEndian = true;
|
||||
const bool LittleEndian = false;
|
||||
#else
|
||||
const bool BigEndian = false;
|
||||
const bool LittleEndian = true;
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
}
|
||||
17
deps/ox/src/ox/std/buildinfo.hpp
vendored
17
deps/ox/src/ox/std/buildinfo.hpp
vendored
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace ox::buildinfo {
|
||||
|
||||
extern const bool UseStdLib;
|
||||
extern const bool Debug;
|
||||
extern const bool NDebug;
|
||||
extern const bool BigEndian;
|
||||
extern const bool LittleEndian;
|
||||
|
||||
}
|
||||
58
deps/ox/src/ox/std/byteswap.cpp
vendored
58
deps/ox/src/ox/std/byteswap.cpp
vendored
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "byteswap.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
static constexpr bool testLittleEndian(T i) {
|
||||
return LittleEndian<T>(i) == i;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr bool testBigEndian(T i) {
|
||||
return BigEndian<T>(i) == i;
|
||||
}
|
||||
|
||||
static_assert(testLittleEndian<uint16_t>(0x00ff), "Test LittleEndian 0x00ff");
|
||||
static_assert(testLittleEndian<uint16_t>(0xff00), "Test LittleEndian 0xff00");
|
||||
|
||||
static_assert(testLittleEndian<uint32_t>(0x000000ff), "Test LittleEndian 0x000000ff");
|
||||
static_assert(testLittleEndian<uint32_t>(0x0000ff00), "Test LittleEndian 0x0000ff00");
|
||||
static_assert(testLittleEndian<uint32_t>(0x00ff0000), "Test LittleEndian 0x00ff0000");
|
||||
static_assert(testLittleEndian<uint32_t>(0xff000000), "Test LittleEndian 0xff000000");
|
||||
|
||||
static_assert(testLittleEndian<uint64_t>(0x00000000000000ff), "Test LittleEndian 0x00000000000000ff");
|
||||
static_assert(testLittleEndian<uint64_t>(0x000000000000ff00), "Test LittleEndian 0x000000000000ff00");
|
||||
static_assert(testLittleEndian<uint64_t>(0x0000000000ff0000), "Test LittleEndian 0x0000000000ff0000");
|
||||
static_assert(testLittleEndian<uint64_t>(0x00000000ff000000), "Test LittleEndian 0x00000000ff000000");
|
||||
static_assert(testLittleEndian<uint64_t>(0x000000ff00000000), "Test LittleEndian 0x000000ff00000000");
|
||||
static_assert(testLittleEndian<uint64_t>(0x0000ff0000000000), "Test LittleEndian 0x0000ff0000000000");
|
||||
static_assert(testLittleEndian<uint64_t>(0x00ff000000000000), "Test LittleEndian 0x00ff000000000000");
|
||||
static_assert(testLittleEndian<uint64_t>(0xff00000000000000), "Test LittleEndian 0xff00000000000000");
|
||||
|
||||
|
||||
static_assert(testBigEndian<uint16_t>(0x00ff), "Test BigEndian 0x00ff");
|
||||
static_assert(testBigEndian<uint16_t>(0xff00), "Test BigEndian 0xff00");
|
||||
|
||||
static_assert(testBigEndian<uint32_t>(0x000000ff), "Test BigEndian 0x000000ff");
|
||||
static_assert(testBigEndian<uint32_t>(0x0000ff00), "Test BigEndian 0x0000ff00");
|
||||
static_assert(testBigEndian<uint32_t>(0x00ff0000), "Test BigEndian 0x00ff0000");
|
||||
static_assert(testBigEndian<uint32_t>(0xff000000), "Test BigEndian 0xff000000");
|
||||
|
||||
static_assert(testBigEndian<uint64_t>(0x00000000000000ff), "Test BigEndian 0x00000000000000ff");
|
||||
static_assert(testBigEndian<uint64_t>(0x000000000000ff00), "Test BigEndian 0x000000000000ff00");
|
||||
static_assert(testBigEndian<uint64_t>(0x0000000000ff0000), "Test BigEndian 0x0000000000ff0000");
|
||||
static_assert(testBigEndian<uint64_t>(0x00000000ff000000), "Test BigEndian 0x00000000ff000000");
|
||||
static_assert(testBigEndian<uint64_t>(0x000000ff00000000), "Test BigEndian 0x000000ff00000000");
|
||||
static_assert(testBigEndian<uint64_t>(0x0000ff0000000000), "Test BigEndian 0x0000ff0000000000");
|
||||
static_assert(testBigEndian<uint64_t>(0x00ff000000000000), "Test BigEndian 0x00ff000000000000");
|
||||
static_assert(testBigEndian<uint64_t>(0xff00000000000000), "Test BigEndian 0xff00000000000000");
|
||||
|
||||
}
|
||||
195
deps/ox/src/ox/std/byteswap.hpp
vendored
195
deps/ox/src/ox/std/byteswap.hpp
vendored
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "stddef.hpp"
|
||||
#include "types.hpp"
|
||||
#include "typetraits.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr inline T byteSwap(typename enable_if<sizeof(T) == 1, T>::type i) noexcept {
|
||||
return i;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr inline T byteSwap(typename enable_if<sizeof(T) == 2, T>::type i) noexcept {
|
||||
return (i << 8) | (i >> 8);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr inline T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept {
|
||||
return ((i >> 24) & 0x000000ff) |
|
||||
((i >> 8) & 0x0000ff00) |
|
||||
((i << 8) & 0x00ff0000) |
|
||||
((i << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr inline T byteSwap(typename enable_if<sizeof(T) == 8, T>::type i) noexcept {
|
||||
return ((i >> 56) & 0x00000000000000ff) |
|
||||
((i >> 40) & 0x000000000000ff00) |
|
||||
((i >> 24) & 0x0000000000ff0000) |
|
||||
((i >> 8) & 0x00000000ff000000) |
|
||||
((i << 8) & 0x000000ff00000000) |
|
||||
((i << 24) & 0x0000ff0000000000) |
|
||||
((i << 40) & 0x00ff000000000000) |
|
||||
((i << 56) & 0xff00000000000000);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Takes an int and byte swaps if the platform is the given condition is true.
|
||||
*/
|
||||
template<typename T, bool byteSwap>
|
||||
[[nodiscard]] constexpr inline T conditionalByteSwap(T i) noexcept {
|
||||
if constexpr(byteSwap) {
|
||||
return ox::byteSwap<T>(i);
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, bool byteSwap>
|
||||
class OX_PACKED ByteSwapInteger {
|
||||
private:
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
constexpr inline ByteSwapInteger() noexcept = default;
|
||||
|
||||
constexpr inline ByteSwapInteger(const ByteSwapInteger &other) noexcept {
|
||||
m_value = other.m_value;
|
||||
}
|
||||
|
||||
constexpr inline ByteSwapInteger(T value) noexcept: m_value(ox::conditionalByteSwap<T, byteSwap>(value)) {
|
||||
}
|
||||
|
||||
constexpr inline const ByteSwapInteger &operator=(const ByteSwapInteger &other) noexcept {
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator=(I value) noexcept {
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr inline operator T() const noexcept {
|
||||
return ox::conditionalByteSwap<T, byteSwap>(m_value);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator+=(I other) noexcept {
|
||||
auto newVal = *this + other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator-=(I other) noexcept {
|
||||
auto newVal = *this - other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator*=(I other) noexcept {
|
||||
auto newVal = *this * other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator/=(I other) noexcept {
|
||||
auto newVal = *this / other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
// Prefix increment
|
||||
constexpr inline T operator++() noexcept {
|
||||
return operator+=(1);
|
||||
}
|
||||
|
||||
// Postfix increment
|
||||
constexpr inline T operator++(int) noexcept {
|
||||
auto old = *this;
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
// Prefix decrement
|
||||
constexpr inline T operator--() noexcept {
|
||||
return operator-=(1);
|
||||
}
|
||||
|
||||
// Postfix decrement
|
||||
constexpr inline T operator--(int) noexcept {
|
||||
auto old = *this;
|
||||
--*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator&=(I other) noexcept {
|
||||
auto newVal = *this & other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator|=(I other) noexcept {
|
||||
auto newVal = *this | other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator^=(I other) noexcept {
|
||||
auto newVal = *this ^ other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator>>=(I other) noexcept {
|
||||
auto newVal = *this >> other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
constexpr inline T operator<<=(I other) noexcept {
|
||||
auto newVal = *this << other;
|
||||
m_value = ox::conditionalByteSwap<T, byteSwap>(newVal);
|
||||
return newVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer as it is stored. If it is stored as little endian,
|
||||
* a little endian integer is returned regardless of the endianness of
|
||||
* the system.
|
||||
*/
|
||||
constexpr auto raw() noexcept -> T {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using LittleEndian = ByteSwapInteger<T, ox::defines::BigEndian>;
|
||||
|
||||
template<typename T>
|
||||
using BigEndian = ByteSwapInteger<T, ox::defines::LittleEndian>;
|
||||
|
||||
}
|
||||
39
deps/ox/src/ox/std/defines.hpp
vendored
39
deps/ox/src/ox/std/defines.hpp
vendored
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ox::defines {
|
||||
|
||||
#if defined(OX_USE_STDLIB)
|
||||
constexpr auto UseStdLib = true;
|
||||
#else
|
||||
constexpr auto UseStdLib = false;
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
constexpr auto Debug = true;
|
||||
#else
|
||||
constexpr auto Debug = false;
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG)
|
||||
constexpr auto NDebug = true;
|
||||
#else
|
||||
constexpr auto NDebug = false;
|
||||
#endif
|
||||
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
constexpr auto BigEndian = true;
|
||||
constexpr auto LittleEndian = false;
|
||||
#else
|
||||
constexpr auto BigEndian = false;
|
||||
constexpr auto LittleEndian = true;
|
||||
#endif
|
||||
|
||||
}
|
||||
97
deps/ox/src/ox/std/error.hpp
vendored
97
deps/ox/src/ox/std/error.hpp
vendored
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "strongint.hpp"
|
||||
#include "typetraits.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define OxError(x) ox::_error(__FILE__, __LINE__, static_cast<ox::Error>(x))
|
||||
#else
|
||||
#define OxError(x) static_cast<ox::Error>(x)
|
||||
#endif
|
||||
|
||||
namespace ox {
|
||||
|
||||
struct BaseError {
|
||||
const char *file = "";
|
||||
uint16_t line = 0;
|
||||
|
||||
BaseError() = default;
|
||||
|
||||
constexpr BaseError(const BaseError &o) noexcept {
|
||||
file = o.file;
|
||||
line = o.line;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using Error = Integer<uint64_t, BaseError>;
|
||||
|
||||
static constexpr Error _error(const char *file, uint32_t line, Error errCode) {
|
||||
Error err = errCode;
|
||||
err.file = file;
|
||||
err.line = line;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct ValErr {
|
||||
T value;
|
||||
Error error;
|
||||
|
||||
constexpr ValErr() noexcept: error(0) {
|
||||
}
|
||||
|
||||
constexpr ValErr(Error error) noexcept: value(ox::move(value)), error(error) {
|
||||
this->error = error;
|
||||
}
|
||||
|
||||
constexpr ValErr(T value, Error error = OxError(0)) noexcept: value(ox::move(value)), error(error) {
|
||||
}
|
||||
|
||||
explicit constexpr operator const T&() const noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
explicit constexpr operator T&() noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool ok() const noexcept {
|
||||
return error == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ox::Error get(T *val) noexcept {
|
||||
*val = value;
|
||||
return error;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace error {
|
||||
|
||||
[[nodiscard]] constexpr ox::Error toError(ox::Error e) noexcept {
|
||||
return e;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr ox::Error toError(ox::ValErr<T> ve) noexcept {
|
||||
return ve.error;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline void oxIgnoreError(ox::Error) {}
|
||||
#define oxReturnError(x) if (const auto _ox_error = ox::error::toError(x)) return _ox_error
|
||||
#define oxThrowError(x) if (const auto _ox_error = ox::error::toError(x)) throw _ox_error
|
||||
|
||||
38
deps/ox/src/ox/std/hardware.hpp
vendored
38
deps/ox/src/ox/std/hardware.hpp
vendored
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_AMD64)
|
||||
#define OX_ARCH_x86_64
|
||||
#elif defined(__i386__) || defined(_M_IX86)
|
||||
#define OX_ARCH_x86_32
|
||||
#elif defined(_M_AMD64)
|
||||
#define OX_ARCH_ARM64
|
||||
#elif defined(__arm__)
|
||||
#define OX_ARCH_ARM
|
||||
#endif
|
||||
|
||||
#if defined(OX_ARCH_ARM)
|
||||
|
||||
#if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__)
|
||||
#define OX_HW_DIV 1
|
||||
#else
|
||||
#define OX_HW_DIV 0
|
||||
#endif
|
||||
|
||||
#elif defined(OX_ARCH_x86_32) || defined(OX_ARCH_x86_64) || defined(OX_ARCH_ARM64)
|
||||
|
||||
#define OX_HW_DIV 1
|
||||
|
||||
#else
|
||||
|
||||
#error "Undefined hardware"
|
||||
|
||||
#endif
|
||||
|
||||
151
deps/ox/src/ox/std/hashmap.hpp
vendored
151
deps/ox/src/ox/std/hashmap.hpp
vendored
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "strops.hpp"
|
||||
#include "vector.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename K, typename T>
|
||||
class HashMap {
|
||||
|
||||
private:
|
||||
struct Pair {
|
||||
K key = {};
|
||||
T value = {};
|
||||
};
|
||||
Vector<K> m_keys;
|
||||
Vector<Pair*> m_pairs;
|
||||
|
||||
public:
|
||||
explicit HashMap(std::size_t size = 100);
|
||||
|
||||
HashMap(HashMap &other);
|
||||
|
||||
~HashMap();
|
||||
|
||||
HashMap &operator=(HashMap &other);
|
||||
|
||||
/**
|
||||
* K is assumed to be a null terminated string.
|
||||
*/
|
||||
T &operator[](K key);
|
||||
|
||||
/**
|
||||
* K is assumed to be a null terminated string.
|
||||
*/
|
||||
T &at(K key);
|
||||
|
||||
bool contains(K key);
|
||||
|
||||
std::size_t size() const noexcept;
|
||||
|
||||
private:
|
||||
void expand();
|
||||
|
||||
/**
|
||||
* K is assumed to be a null terminated string.
|
||||
*/
|
||||
static uint64_t hash(K, int len = 0xFFFF) noexcept;
|
||||
|
||||
/**
|
||||
* K is assumed to be a null terminated string.
|
||||
*/
|
||||
Pair *&access(Vector<Pair*> &pairs, K key);
|
||||
|
||||
};
|
||||
|
||||
template<typename K, typename T>
|
||||
HashMap<K, T>::HashMap(std::size_t size): m_pairs(size) {
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
HashMap<K, T>::HashMap(HashMap<K, T> &other) {
|
||||
m_pairs = other.m_pairs;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
HashMap<K, T>::~HashMap() {
|
||||
for (std::size_t i = 0; i < m_pairs.size(); i++) {
|
||||
delete m_pairs[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &other) {
|
||||
this->~HashMap<K, T>();
|
||||
m_keys = other.m_keys;
|
||||
m_pairs = other.m_pairs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
T &HashMap<K, T>::operator[](K k) {
|
||||
auto &p = access(m_pairs, k);
|
||||
if (p == nullptr) {
|
||||
if (m_pairs.size() * 0.7 < m_keys.size()) {
|
||||
expand();
|
||||
}
|
||||
p = new Pair;
|
||||
p->key = k;
|
||||
m_keys.push_back(k);
|
||||
}
|
||||
return p->value;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
T &HashMap<K, T>::at(K k) {
|
||||
return operator[](k);
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool HashMap<K, T>::contains(K k) {
|
||||
return access(m_pairs, k) != nullptr;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
std::size_t HashMap<K, T>::size() const noexcept {
|
||||
return m_keys.size();
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
void HashMap<K, T>::expand() {
|
||||
Vector<Pair*> r;
|
||||
for (std::size_t i = 0; i < m_keys.size(); i++) {
|
||||
auto k = m_keys[i];
|
||||
access(r, k) = access(m_pairs, k);
|
||||
}
|
||||
m_pairs = r;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
uint64_t HashMap<K, T>::hash(K k, int len) noexcept {
|
||||
uint64_t sum = 1;
|
||||
for (int i = 0; i < len && k[i]; i++) {
|
||||
sum += ((sum + k[i]) * 7) * sum;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, K k) {
|
||||
auto h = hash(k) % pairs.size();
|
||||
auto hashStr = reinterpret_cast<char*>(&h);
|
||||
while (1) {
|
||||
auto &p = pairs[h];
|
||||
if (p == nullptr || ox_strcmp(p->key, k) == 0) {
|
||||
return p;
|
||||
} else {
|
||||
h = hash(hashStr, 8) % pairs.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
34
deps/ox/src/ox/std/math.hpp
vendored
34
deps/ox/src/ox/std/math.hpp
vendored
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* 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 http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "typetraits.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr const T &min(const T &a, const T &b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr const T &max(const T &a, const T &b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
inline constexpr I pow(I v, int e) {
|
||||
I out = 1;
|
||||
for (I i = 0; i < e; i++) {
|
||||
out *= v;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user