Compare commits

..

20 Commits

Author SHA1 Message Date
3544392fa8 [nostalgia/core/studio] Cleanup, fix possible TileSheet fill tool failure
All checks were successful
Build / build (push) Successful in 3m21s
2025-01-17 21:43:46 -06:00
144d234d09 [nostalgia/studio] Change version to release-d2024.12
All checks were successful
Build / build (push) Successful in 3m20s
2025-01-12 21:03:34 -06:00
465fb06f76 [nostalgia/core] Fix TileSheet validation/repair to ensure pixels gets cleared if there are subsheets
Some checks failed
Build / build (push) Has been cancelled
2025-01-12 20:58:19 -06:00
db953dd0d1 [studio] Fix new project menu to return an appropriately sized string for name 2025-01-12 20:58:19 -06:00
daab4dc4f5 [nostalgia/core/studio] Fix SubSheet editor to return an appropriately sized string 2025-01-12 20:58:19 -06:00
83cbac5cca [nostalgia/studio] Update version to d2024.12.1
All checks were successful
Build / build (push) Successful in 3m19s
2025-01-11 17:22:02 -06:00
74e518fee0 [nostalgia/core/studio/tilesheeteditor] Fix select all not to go beyond end 2025-01-11 17:07:50 -06:00
6b0ce40c02 [nostalgia/core/studio] Fix crash that occurs when a non-leaf node subsheet is selected 2025-01-11 17:07:50 -06:00
4f55964dd9 [nostalgia/core/studio] Fix tile insert to correct input when inserting past the last tile 2025-01-11 17:07:50 -06:00
cb597cf92e [nostalgia/core/studio] Fix tile insert to work on last tile 2025-01-11 17:07:50 -06:00
6906c66ba7 [keel] Fix reloadAsset 2025-01-11 17:07:50 -06:00
ba00d10dfc [nostalgia] Update liccor file 2025-01-11 17:07:50 -06:00
cdfbfe48b7 [ox] Update liccor file 2025-01-11 17:07:50 -06:00
21ae2a14e9 [ox] Run liccor 2025-01-11 17:07:50 -06:00
81b120b1ce [nostalgia,olympic] Run liccor 2025-01-11 17:07:50 -06:00
40938958de [turbine/glfw] Ensure window opens with a standard mandatory refresh period 2025-01-11 17:07:50 -06:00
df190c05a0 [studio] Make first tab not draw before selected tab when window opens 2025-01-11 17:07:50 -06:00
3fe3b08eca [ox/std] Add hash.hpp to install 2025-01-11 17:07:50 -06:00
ecc5ae6b2f [studio] Make selection tracker not go below 0 2025-01-11 17:07:50 -06:00
a863bfc181 [nostalgia/studio] Update version to d2024.12.0
All checks were successful
Build / build (push) Successful in 3m20s
2024-12-21 19:27:00 -06:00
419 changed files with 7705 additions and 38202 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
sample_project text eol=lf

View File

@@ -4,7 +4,7 @@ on: [push]
jobs:
build:
runs-on: olympic
runs-on: nostalgia
steps:
- name: Check out repository code
uses: actions/checkout@v3
@@ -17,10 +17,3 @@ jobs:
- run: make purge configure-release
- run: make build
- run: make test
- run: make install
- run: mv dist/linux-x86_64-release nostalgia-linux-x86_64
- run: tar cf nostalgia-linux-x86_64.tar nostalgia-linux-x86_64
- uses: actions/upload-artifact@v3
with:
name: nostalgia-linux-x86_64
path: nostalgia-linux-x86_64.tar

4
.gitignore vendored
View File

@@ -6,14 +6,12 @@
.mypy_cache
.stfolder
.stignore
.vs
util/scripts/__pycache__
scripts/__pycache__
pyenv
CMakeLists.txt.user
ROM.oxfs
Session.vim
build
cmake-build-*
compile_commands.json
dist
graph_info.json

View File

@@ -1,4 +1,4 @@
FROM fedora:41
FROM fedora:36
RUN dnf update -y

View File

@@ -1,68 +1,35 @@
BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin)
PROJECT_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
else
PROJECT_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=mgba-qt
endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba
pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac
pkg-mac: install
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-dmg.py NostalgiaStudio
.PHONY: generate-studio-rsrc
generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: run
run: build-player
${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
run: build
./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: run-studio
run-studio: build-studio
${PROJECT_STUDIO}
run-studio: build
${NOSTALGIA_STUDIO}
.PHONY: gba-run
gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
${MGBA} ${BC_VAR_PROJECT_NAME}.gba
.PHONY: debug
debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: debug-studio
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}
.PHONY: configure-gba
configure-gba:
@@ -71,25 +38,3 @@ configure-gba:
.PHONY: configure-gba-debug
configure-gba-debug:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=debug --build_root=${BC_VAR_BUILD_PATH}
.PHONY: loc
loc:
${BC_PY3} util/scripts/loc.py \
--search-dirs \
src \
deps/ox/src \
deps/buildcore \
deps/gbabuildcore \
deps/glutils \
deps/teagba \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake \
--exclude-paths \
deps/teagba/src/gba_crt0.s \
src/olympic/studio/applib/src/font.cpp \
src/olympic/studio/applib/src/font.hpp \
src/nostalgia/studio/icondata.cpp

View File

@@ -93,7 +93,7 @@ purge:
${BC_CMD_RM_RF} compile_commands.json
.PHONY: test
test: build
${BC_CMD_ENVRUN} ${BC_CMD_PY3} -m mypy ${BC_VAR_SCRIPTS}
${BC_CMD_ENVRUN} mypy ${BC_VAR_SCRIPTS}
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test
.PHONY: test-verbose
test-verbose: build

View File

@@ -11,7 +11,6 @@
# "Python Busy Box" - adds cross-platform equivalents to Unix commands that
# don't translate well to that other operating system
import multiprocessing
import os
import platform
import shutil
@@ -58,11 +57,7 @@ def cmake_build(base_path: str, target: Optional[str]) -> int:
path = os.path.join(base_path, d)
if not os.path.isdir(path):
continue
args = ['cmake', '--build', path, f'-j{multiprocessing.cpu_count()}']
if path.endswith('release'):
args.append('--config=release')
elif path.endswith('debug'):
args.append('--config=debug')
args = ['cmake', '--build', path]
if target is not None:
args.extend(['--target', target])
err = subprocess.run(args).returncode

View File

@@ -35,6 +35,4 @@ def get_arch() -> str:
arch = platform.machine().lower()
if arch == 'amd64':
arch = 'x86_64'
elif arch == 'aarch64':
arch = 'arm64'
return arch

View File

@@ -1,8 +1,8 @@
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
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-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")

View File

@@ -1,11 +1,2 @@
add_library(glad src/glad.c)
target_include_directories(glad PUBLIC include)
install(
TARGETS
glad
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
add_library(glad OBJECT src/glad.c)
target_include_directories(glad PUBLIC include)

View File

@@ -89,7 +89,7 @@ struct GLObject: public Base {
return id;
}
constexpr operator GLuint const&() const noexcept {
constexpr operator const GLuint&() const noexcept {
return id;
}
@@ -135,7 +135,7 @@ struct FrameBuffer {
return fbo.id;
}
constexpr operator GLuint const&() const noexcept {
constexpr operator const GLuint&() const noexcept {
return fbo.id;
}
@@ -158,14 +158,14 @@ struct FrameBuffer {
class FrameBufferBind {
private:
static FrameBuffer const *s_activeFb;
FrameBuffer const *m_restoreFb = nullptr;
static const FrameBuffer *s_activeFb;
const FrameBuffer *m_restoreFb = nullptr;
public:
explicit FrameBufferBind(FrameBuffer const &fb) noexcept;
explicit FrameBufferBind(const FrameBuffer &fb) noexcept;
~FrameBufferBind() noexcept;
};
void bind(FrameBuffer const &fb) noexcept;
void bind(const FrameBuffer &fb) noexcept;
struct ShaderVarSet {
GLsizei len{};
@@ -176,7 +176,7 @@ struct ProgramSource {
ox::Vector<glutils::ShaderVarSet> const shaderParams;
GLsizei const rowLen = [this] {
GLsizei len{};
for (auto const &v : shaderParams) {
for (auto const&v : shaderParams) {
len += v.len;
}
return len;
@@ -187,23 +187,23 @@ struct ProgramSource {
ox::String const geomShader{};
};
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept;
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept;
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const &vert,
ox::CStringView const &frag,
ox::CStringView const &geo = "") noexcept;
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo = "") noexcept;
void setupShaderParams(
GLProgram const &shader,
ox::Vector<ShaderVarSet> const &vars,
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept;
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept;
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept;
GLVertexArray generateVertexArrayObject() noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept;
GLBuffer generateBuffer() noexcept;
glutils::GLBuffer generateBuffer() noexcept;
[[nodiscard]]
FrameBuffer generateFrameBuffer(int width, int height) noexcept;
@@ -215,20 +215,20 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
*/
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
struct BufferSet {
GLVertexArray vao;
GLBuffer vbo;
GLBuffer ebo;
GLTexture tex;
glutils::GLVertexArray vao;
glutils::GLBuffer vbo;
glutils::GLBuffer ebo;
glutils::GLTexture tex;
ox::Vector<float> vertices;
ox::Vector<GLuint> elements;
};
void sendVbo(BufferSet const &bs) noexcept;
void sendVbo(BufferSet const&bs) noexcept;
void sendEbo(BufferSet const &bs) noexcept;
void sendEbo(BufferSet const&bs) noexcept;
void clearScreen() noexcept;

View File

@@ -46,9 +46,9 @@ template struct GLObject<deleteVertexArray>;
template struct GLObject<deleteProgram>;
template struct GLObject<deleteShader>;
FrameBuffer const *FrameBufferBind::s_activeFb = nullptr;
const FrameBuffer *FrameBufferBind::s_activeFb = nullptr;
FrameBufferBind::FrameBufferBind(FrameBuffer const &fb) noexcept: m_restoreFb(s_activeFb) {
FrameBufferBind::FrameBufferBind(const FrameBuffer &fb) noexcept: m_restoreFb(s_activeFb) {
s_activeFb = &fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
@@ -64,15 +64,15 @@ FrameBufferBind::~FrameBufferBind() noexcept {
}
}
void bind(FrameBuffer const &fb) noexcept {
void bind(const FrameBuffer &fb) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
}
static ox::Result<GLShader> buildShader(
GLuint const shaderType,
GLchar const *src,
GLuint shaderType,
const GLchar *src,
ox::StringViewCR shaderName) noexcept {
GLShader shader(glCreateShader(shaderType));
glShaderSource(shader, 1, &src, nullptr);
@@ -88,7 +88,7 @@ static ox::Result<GLShader> buildShader(
return shader;
}
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
OX_REQUIRE_M(program, buildShaderProgram(
src.vertShader,
src.fragShader,
@@ -98,11 +98,11 @@ ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
}
void setupShaderParams(
GLProgram const &shader,
ox::Vector<ShaderVarSet> const &vars,
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept {
// setup vars
for (size_t lenWritten = 0; auto const &v : vars) {
for (size_t lenWritten = 0; auto const&v : vars) {
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
glEnableVertexAttribArray(attr);
glVertexAttribPointer(
@@ -113,19 +113,19 @@ void setupShaderParams(
}
}
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept {
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept {
// get row len
GLsizei vertexRowLen{};
for (auto const &v : vars) {
for (auto const&v : vars) {
vertexRowLen += v.len;
}
setupShaderParams(shader, vars, vertexRowLen);
}
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const &vert,
ox::CStringView const &frag,
ox::CStringView const &geo) noexcept {
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo) noexcept {
GLProgram prgm(glCreateProgram());
OX_REQUIRE(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad"));
glAttachShader(prgm, vs);
@@ -162,30 +162,16 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
// color texture
glGenTextures(1, &fb.color.id);
glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
nullptr);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
// depth texture
glGenRenderbuffers(1, &fb.depth.id);
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER,
fb.depth);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
// verify FBO
oxAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame Buffer is incomplete");
// restore primary FB
@@ -203,16 +189,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture
glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
nullptr);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// depth texture
@@ -224,7 +201,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) noexcept {
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
if (!fb) {
fb = generateFrameBuffer(width, height);
return;
@@ -232,18 +209,18 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) n
resizeFrameBuffer(fb, width, height);
}
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept {
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
resizeInitFrameBuffer(fb, sz.width, sz.height);
}
void sendVbo(BufferSet const &bs) noexcept {
auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
void sendVbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
}
void sendEbo(BufferSet const &bs) noexcept {
auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
void sendEbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);
}

View File

@@ -6,7 +6,7 @@ endif()
# DrinkingTea: end
add_library(
imgui
imgui OBJECT
imgui.cpp
imgui_demo.cpp
imgui_draw.cpp
@@ -19,12 +19,4 @@ add_library(
target_include_directories(
imgui SYSTEM PUBLIC
.
)
install(
TARGETS
imgui
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.19)
cmake_minimum_required(VERSION 3.5)
project(nativefiledialog-extended VERSION 1.1.1)
set(nfd_ROOT_PROJECT OFF)

View File

@@ -12,7 +12,7 @@
# CMake versions greater than the JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION policies will
# continue to generate policy warnings "CMake Warning (dev)...Policy CMP0XXX is not set:"
#
set(JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION "3.13.2")
set(JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION "3.8.0")
set(JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION "3.13.2")
cmake_minimum_required(VERSION ${JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION})
if("${CMAKE_VERSION}" VERSION_LESS "${JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION}")

217
deps/ox/ox-docs.md vendored
View File

@@ -28,7 +28,10 @@ All components have a platform indicator next to them:
Ox provides ```ox::Error``` to report errors.
```ox::Error``` is a struct that has overloaded operators to behave like an
integer error code, plus some extra fields to enhance debuggability.
```ox::Error```s will also include the file and line of the error.
If instantiated through the ```OxError(x)``` macro, it will also include the
file and line of the error.
The ```OxError(x)``` macro should only be used for the initial instantiation of
an ```ox::Error```.
In addition to ```ox::Error``` there is also the template ```ox::Result<T>```.
```ox::Result``` simply wraps the type T value in a struct that also includes
@@ -46,7 +49,7 @@ ox::Result<int> foo(int i) noexcept {
if (i < 10) {
return i + 1; // implicitly calls ox::Result<T>::Result(T)
}
return ox::Error(1); // implicitly calls ox::Result<T>::Result(ox::Error)
return OxError(1); // implicitly calls ox::Result<T>::Result(ox::Error)
}
int caller1() {
@@ -178,216 +181,6 @@ variant for creating a non-const value.
* ```OX_REQUIRE_M``` - OX_REQUIRE Mutable
### Ox String Types
Ox has six different major string types.
These types are divided into two categories: store types and view types.
String stores maintain a copy of the string data, whereas view types only
maintain a reference to the data.
Views should be used where you otherwise might use a const reference to a
string store type.
Having all of these different string types may sound like an interoperability
nightmare, but taking string view types extensively where applicable makes the
imagined interoperability issues virtually non-existent.
#### String Store Types
##### String / BasicString
```ox::String```, or really ```ox::BasicString```, is Ox's version of
```std::string```.
Like ```std::string```, ```String``` allocates to store the string data.
Also like ```std::string```, ```String``` allows for small string
optimization for strings under 8 bytes.
Unlike ```std::string```, the template that ```String``` is based on,
```BasicString```, takes a parameter that allows adjusting to different size
small string buffers.
```ox::String``` is an alias to ```ox::BasicString<8>```.
```cpp
// s can hold up to 100 bytes, plus one for a null terminator before allocating
ox::BasicString<100> s;
```
Also unlike ```std::string```, ```ox::String``` has an explicit C-string conversion
constructor.
This prevents accidental instantiations of ```String```.
Consider the following:
```cpp
void fStd(std::string const&);
void fOx(ox::String const&);
int main() {
// implicit and silent instantiation of std::string, which includes an
// allocation
fStd("123456789");
// Will fail to compile:
fOx("123456789");
// But explicit String instantiation will work:
fOx(ox::String{"123456789"});
}
```
##### IString
```IString```, or "inline string", is like ```BasicString```, but it will cut
off strings that exceed that limit.
```cpp
ox::IString<5> s; // s can hold up to 5 characters, plus a null terminator
s = "12345"; // valid
s = "123456"; // will compile and run, but will get cut off at '5'
```
This is useful for certain string categories that have fixed lengths, like UUID
strings or for numbers.
Ox makes use of ```IString``` in the following ways:
```cpp
using UUIDStr = ox::IString<36>;
// and
template<Integer_c Integer>
[[nodiscard]]
constexpr auto intToStr(Integer v) noexcept {
constexpr auto Cap = [] {
auto out = 0;
switch (sizeof(Integer)) {
case 1:
out = 3;
break;
case 2:
out = 5;
break;
case 4:
out = 10;
break;
case 8:
out = 21;
break;
}
return out + ox::is_signed_v<Integer>;
}();
ox::IString<Cap> out;
std::ignore = out.resize(out.cap());
ox::CharBuffWriter w{{out.data(), out.cap()}};
std::ignore = writeItoa(v, w);
std::ignore = out.resize(w.tellp());
return out;
}
```
##### StringParam
```StringParam``` is a weird type.
Because ```String::String(const char*)``` is explicit, it becomes a pain for
functions to take ```String```s.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::String p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // invalid - will not compile
Type t2{s}; // invalid - will not compile
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
```StringParam``` has implicit conversion constructors, and will appropriately
move from r-value ```String```s or create a ```String``` if not passed
ownership of an existing ```String```.
Think of ```StringParam``` as a way to opt-in to implicit instantiation with
strings.
```StringParam``` can access the string as a view through the ```view()```
function, and the ```String``` inside can be accessed by moving from the
```StringParam```.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::StringParam p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // valid
Type t2{s}; // valid
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
#### String View Types
##### StringView
```ox::StringView``` is Ox's version of ```std::string_view```.
```StringView``` contains a pointer to a string, along with its size.
This should be the normal type taken when a function needs a string that will
exist until it returns.
##### CStringView
```CStringView``` is like ```StringView```, but it comes with the promise that
the string ends with a null terminator.
Accordingly, it has a ```c_str()``` function in addition to the ```data()```
function that ```StringView``` has.
```CStringView``` should be used when wrapping a C API that only takes C
strings.
##### StringLiteral
```StringLiteral``` is a string view type, but it kind of straddles the line
between view and store types.
Creating a ```StringLiteral``` is a promise that you are passing a string
literal into the constructor.
This means you can treat it like a store, that can be safely used as a copy of
the data.
Functions that take ```StringLiteral```s are allowed to assume that the data
will have no lifetime concerns and hold onto it without any need to make a
copy.
It has a consteval constructor to enforce the promise that it is a compile time
string.
```cpp
void f(ox::StringLiteral const&);
int main() {
f("123456789"); // valid
f(ox::String{"123456789"}.c_str()); // invalid - will not compile
}
```
#### Other Variants
There are a few convenience aliases as well.
* StringCR = String const&
* StringViewCR = StringView const&
* CStringViewCR = CStringView const&
* CString = const char*
String views do not generally need const references, but it does make debugging
easier, as we can skip the constructor call if a string view already exists.
These kind of aliases probably should not exist for most types, but strings are
fundamental and ease of use is desirable.
### Logging and Output
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.

View File

@@ -15,21 +15,21 @@ ClArgs::ClArgs(int argc, const char **args) noexcept: ClArgs({args, static_cast<
ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
for (auto i = 0u; i < args.size(); ++i) {
auto arg = StringView{args[i]};
auto arg = StringView(args[i]);
if (arg[0] == '-') {
while (arg[0] == '-' && arg.size()) {
while (arg[0] == '-' && arg.len()) {
arg = substr(arg, 1);
}
m_bools[arg] = true;
// parse additional arguments
if (i < args.size() && args[i + 1]) {
auto const val = StringView{args[i + 1]};
if (val.size() && val[0] != '-') {
auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') {
if (val == "false") {
m_bools[arg] = false;
}
m_strings[arg] = val;
if (auto r = ox::strToInt(val); r.error == 0) {
if (auto r = ox::atoi(val.c_str()); r.error == 0) {
m_ints[arg] = r.value;
}
++i;
@@ -40,17 +40,17 @@ ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
}
bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept {
auto const [value, err] = m_ints.at(arg);
auto [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue;
}
String ClArgs::getString(ox::StringViewCR arg, ox::StringView defaultValue) const noexcept {
auto const [value, err] = m_strings.at(arg);
auto [value, err] = m_strings.at(arg);
return !err ? ox::String(*value) : ox::String(defaultValue);
}
int ClArgs::getInt(ox::StringViewCR arg, int defaultValue) const noexcept {
auto const [value, err] = m_ints.at(arg);
auto [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue;
}

View File

@@ -12,7 +12,7 @@
namespace ox {
Result<StringView> readClawTypeId(BufferView const buff) noexcept {
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
auto buffRaw = buff.data();
auto buffLen = buff.size();
size_t outSz{};
@@ -43,7 +43,7 @@ Result<StringView> readClawTypeId(BufferView const buff) noexcept {
return {{buff.data() + fmtSz, outSz - fmtSz - 1}};
}
Result<ClawHeader> readClawHeader(BufferView const buff) noexcept {
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
auto buffRaw = buff.data();
auto buffLen = buff.size();
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
@@ -81,13 +81,13 @@ Result<ClawHeader> readClawHeader(BufferView const buff) noexcept {
return ox::Error(4, "Claw format does not match any supported format/version combo");
}
hdr.typeName = typeName;
std::ignore = ox::strToInt(versionStr).copyTo(hdr.typeVersion);
std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
hdr.data = buffRaw;
hdr.dataSize = buffLen;
return hdr;
}
Result<BufferView> stripClawHeader(BufferView const buff) noexcept {
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
OX_REQUIRE(header, readClawHeader(buff));
return {{header.data, header.dataSize}};
}
@@ -106,14 +106,15 @@ Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
{
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
OX_RETURN_ERROR(model(reader.interface(), &obj));
ModelHandlerInterface handler(&reader);
OX_RETURN_ERROR(model(&handler, &obj));
return obj;
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(reader);
ModelHandlerInterface handler(&reader);
OX_RETURN_ERROR(model(&handler, &obj));
return obj;
#else

View File

@@ -52,7 +52,8 @@ Error readClaw(ox::BufferView buff, T &val) {
{
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
return model(reader.interface(), &val);
ModelHandlerInterface handler(&reader);
return model(&handler, &val);
}
case ClawFormat::Organic:
{

View File

@@ -109,7 +109,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader",
[] {
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
@@ -121,7 +121,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader2",
[] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
@@ -134,8 +134,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
[] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
ox::expect(actual, expected);
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.len() + 1}));
oxExpect(actual, expected);
return ox::Error{};
}
},

View File

@@ -39,7 +39,7 @@ struct TypeInfoCatcher {
}
constexpr Error field(...) noexcept {
return {};
return ox::Error(0);
}
static constexpr auto opType() {

View File

@@ -122,7 +122,7 @@ class Signal {
}
};
mutable Vector<UPtr<BaseSlot>> m_slots;
mutable Vector<UniquePtr<BaseSlot>> m_slots;
public:
~Signal() noexcept;
@@ -143,11 +143,6 @@ class Signal {
Error disconnectObject(const void *receiver) const noexcept;
[[nodiscard]]
size_t connectionCnt() const noexcept {
return m_slots.size();
}
void emit(Args... args) const;
Error emitCheckError(Args... args) const noexcept;
@@ -218,9 +213,9 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) {
f->call(args...);
}
return {};
return ox::Error(0);
} catch (const ox::Exception &ex) {
return ox::Error(ex.errCode, ex.msg, ex.src);
return ox::Error(ex.file, ex.line, ex.errCode, ex.msg);
}
}
@@ -303,7 +298,7 @@ class Signal<Error(Args...)> {
}
};
mutable Vector<UPtr<BaseSlot>> m_slots;
mutable Vector<UniquePtr<BaseSlot>> m_slots;
public:
~Signal() noexcept;
@@ -324,11 +319,6 @@ class Signal<Error(Args...)> {
Error disconnectObject(const void *receiver) const noexcept;
[[nodiscard]]
size_t connectionCnt() const noexcept {
return m_slots.size();
}
void emit(Args... args) const noexcept;
Error emitCheckError(Args... args) const noexcept;
@@ -410,7 +400,7 @@ Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) {
OX_RETURN_ERROR(f->call(ox::forward<Args>(args)...));
}
return {};
return ox::Error(0);
}
}

View File

@@ -230,7 +230,7 @@ template<typename size_t>
Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate());
++item->links;
return {};
return ox::Error(0);
}
template<typename size_t>
@@ -240,7 +240,7 @@ Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
if (item->links == 0) {
OX_RETURN_ERROR(remove(item));
}
return {};
return ox::Error(0);
}
template<typename size_t>
@@ -298,7 +298,7 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
dest->id.get(), dest.offset(), destData.size());
fsData->rootNode = dest.offset();
oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get());
return {};
return ox::Error(0);
}
} else {
oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header.");
@@ -427,20 +427,20 @@ Error FileStoreTemplate<size_t>::resize() {
oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize);
OX_RETURN_ERROR(m_buffer->setSize(newSize));
oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size());
return {};
return ox::Error(0);
}
template<typename size_t>
Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
if (m_buffer->size() > size) {
return ox::Error{1, "new buffer is too small for existing data"};
return ox::Error(1);
}
m_buffSize = static_cast<size_t>(size);
if (newBuff) {
m_buffer = static_cast<Buffer*>(newBuff);
m_buffer = reinterpret_cast<Buffer*>(newBuff);
OX_RETURN_ERROR(m_buffer->setSize(static_cast<size_t>(size)));
}
return {};
return ox::Error(0);
}
template<typename size_t>
@@ -479,7 +479,7 @@ Error FileStoreTemplate<size_t>::walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) {
for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
}
return {};
return ox::Error(0);
}
template<typename size_t>
@@ -503,7 +503,7 @@ Error FileStoreTemplate<size_t>::compact() {
return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> Error {
if (isFirstItem) {
isFirstItem = false;
return {};
return ox::Error(0);
}
if (!item.valid()) {
return ox::Error(1);
@@ -524,7 +524,7 @@ Error FileStoreTemplate<size_t>::compact() {
parent->right = item;
}
}
return {};
return ox::Error(0);
});
}
@@ -552,7 +552,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
item->left = root->left;
item->right = root->right;
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get());
return {};
return ox::Error(0);
} else {
return placeItem(root, item);
}
@@ -573,7 +573,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = right->right;
}
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return {};
return ox::Error(0);
} else {
return placeItem(right, item, depth + 1);
}
@@ -586,7 +586,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = left->right;
}
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return {};
return ox::Error(0);
} else {
return placeItem(left, item, depth + 1);
}
@@ -624,7 +624,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
} else {
fsData->rootNode = 0;
}
return {};
return ox::Error(0);
} else {
return unplaceItem(root, item);
}
@@ -661,7 +661,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
if (item->left) {
OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left)));
}
return {};
return ox::Error(0);
}
template<typename size_t>
@@ -669,7 +669,7 @@ Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
if (item.valid()) {
OX_RETURN_ERROR(unplaceItem(item));
OX_RETURN_ERROR(m_buffer->free(item));
return {};
return ox::Error(0);
}
return ox::Error(1);
}

View File

@@ -52,7 +52,7 @@ struct OX_PACKED DirectoryEntry {
if (d.valid()) {
d->inode = inode;
auto const maxStrSz = bufferSize - 1 - sizeof(*this);
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.size()));
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.len()));
return {};
}
return ox::Error(1);
@@ -219,7 +219,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory");
return ox::Error(1, "Could not read existing version of Directory");
}
const auto pathSize = name.size() + 1;
const auto pathSize = name.len() + 1;
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);

View File

@@ -31,10 +31,10 @@ FileAddress::FileAddress(uint64_t inode) noexcept {
FileAddress::FileAddress(ox::StringViewCR path) noexcept {
auto pathSize = path.bytes();
m_data.path = new char[pathSize + 1];
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(m_data.path, path.data(), pathSize);
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
m_data.path[pathSize] = 0;
OX_ALLOW_UNSAFE_BUFFERS_END
OX_CLANG_NOWARN_END
m_type = FileAddressType::Path;
}
@@ -48,11 +48,9 @@ FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
case FileAddressType::Path:
{
if (other.m_data.path) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
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);
OX_ALLOW_UNSAFE_BUFFERS_END
} else {
m_data.constPath = "";
m_type = FileAddressType::ConstPath;

View File

@@ -24,6 +24,9 @@ enum class FileAddressType: int8_t {
Inode,
};
template<typename T>
constexpr Error model(T *h, CommonPtrWith<class FileAddress> auto *fa) noexcept;
class FileAddress {
template<typename T>

View File

@@ -37,30 +37,6 @@ Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size)
}
}
Result<Buffer> FileSystem::read(FileAddress const &addr, size_t const size) noexcept {
Result<Buffer> out;
out.value.resize(size);
switch (addr.type()) {
case FileAddressType::Inode:
OX_RETURN_ERROR(readFileInode(addr.getInode().value, out.value.data(), size));
break;
case FileAddressType::ConstPath:
case FileAddressType::Path:
OX_RETURN_ERROR(readFilePath(StringView{addr.getPath().value}, out.value.data(), size));
break;
default:
return ox::Error{1};
}
return out;
}
Result<Buffer> FileSystem::read(StringViewCR path, size_t const size) noexcept {
Result<Buffer> out;
out.value.resize(size);
OX_RETURN_ERROR(readFilePath(path, out.value.data(), size));
return out;
}
Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
OX_REQUIRE(s, stat(addr));
Buffer buff(static_cast<std::size_t>(s.size));
@@ -75,31 +51,28 @@ Result<Buffer> FileSystem::read(StringViewCR path) noexcept {
return buff;
}
Error FileSystem::read(
FileAddress const &addr,
std::size_t const readStart,
std::size_t const readSize,
void *buffer,
std::size_t *size) noexcept {
Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
switch (addr.type()) {
case FileAddressType::Inode:
return readFileInodeRange(addr.getInode().value, readStart, readSize, buffer, size);
return read(addr.getInode().value, readStart, readSize, buffer, size);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return readFilePathRange(addr.getPath().value, readStart, readSize, buffer, size);
return ox::Error(2, "Unsupported for path lookups");
default:
return ox::Error(1);
}
}
Result<size_t> FileSystem::read(
StringViewCR path,
std::size_t const readStart,
std::size_t const readSize,
Span<char> buff) noexcept {
size_t szOut{buff.size()};
OX_RETURN_ERROR(readFilePathRange(path, readStart, readSize, buff.data(), &szOut));
return szOut;
Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
switch (addr.type()) {
case FileAddressType::Inode:
return remove(addr.getInode().value, recursive);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return remove(StringView(addr.getPath().value), recursive);
default:
return ox::Error(1);
}
}
Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept {

View File

@@ -20,7 +20,7 @@
namespace ox {
namespace detail {
inline void fsBuffFree(char *buff) noexcept {
static inline void fsBuffFree(char *buff) noexcept {
safeDelete(buff);
}
}
@@ -41,45 +41,25 @@ class FileSystem {
Error read(const FileAddress &addr, void *buffer, std::size_t size) noexcept;
Result<Buffer> read(FileAddress const &addr, size_t size) noexcept;
Result<Buffer> read(StringViewCR path, size_t size) noexcept;
Result<Buffer> read(const FileAddress &addr) noexcept;
Result<Buffer> read(StringViewCR path) noexcept;
Error read(StringViewCR path, void *buffer, std::size_t buffSize) noexcept {
inline Error read(StringViewCR path, void *buffer, std::size_t buffSize) noexcept {
return readFilePath(path, buffer, buffSize);
}
Error read(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
inline Error read(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
return readFileInode(inode, buffer, buffSize);
}
Error read(
FileAddress const &addr,
size_t readStart,
size_t readSize,
void *buffer,
size_t *size) noexcept;
/**
*
* @param path
* @param readStart
* @param readSize
* @param buff
* @return error or number of bytes read
*/
Result<size_t> read(
StringViewCR path, size_t readStart, size_t readSize, ox::Span<char> buff) noexcept;
Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept;
virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0;
Error remove(StringViewCR path, bool recursive = false) noexcept {
return removePath(path, recursive);
}
virtual Error remove(StringViewCR path, bool recursive) noexcept = 0;
Error remove(const FileAddress &addr, bool recursive = false) noexcept;
virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
@@ -87,7 +67,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile);
}
Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept {
Error write(StringViewCR path, ox::Span<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile);
}
@@ -95,42 +75,42 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile);
}
Error write(uint64_t inode, ox::SpanView<char> const&buff) noexcept {
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept {
return write(inode, buff.data(), buff.size(), FileType::NormalFile);
}
Error write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept;
Error write(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept {
inline Error write(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept {
return writeFilePath(path, buffer, size, fileType);
}
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
inline Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
return writeFileInode(inode, buffer, size, fileType);
}
Result<FileStat> stat(uint64_t inode) const noexcept {
inline Result<FileStat> stat(uint64_t inode) const noexcept {
return statInode(inode);
}
Result<FileStat> stat(StringViewCR path) const noexcept {
inline Result<FileStat> stat(StringViewCR path) const noexcept {
return statPath(path);
}
Result<FileStat> stat(const FileAddress &addr) const noexcept;
[[nodiscard]]
bool exists(uint64_t inode) const noexcept {
inline bool exists(uint64_t inode) const noexcept {
return statInode(inode).ok();
}
[[nodiscard]]
bool exists(ox::StringView path) const noexcept {
inline bool exists(ox::StringView path) const noexcept {
return statPath(path).ok();
}
[[nodiscard]]
bool exists(FileAddress const&addr) const noexcept {
inline bool exists(FileAddress const&addr) const noexcept {
return stat(addr).ok();
}
@@ -160,12 +140,7 @@ class FileSystem {
virtual Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
virtual Error readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept = 0;
virtual Error readFileInodeRange(uint64_t inode, size_t readStart, size_t readSize, void *buffer, size_t *size) noexcept = 0;
virtual Error removePath(StringViewCR path, bool recursive) noexcept = 0;
virtual Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0;
virtual Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
@@ -177,11 +152,11 @@ class MemFS: public FileSystem {
public:
Result<const char*> directAccess(const FileAddress &addr) const noexcept;
Result<const char*> directAccess(StringViewCR path) const noexcept {
inline Result<const char*> directAccess(StringViewCR path) const noexcept {
return directAccessPath(path);
}
Result<const char*> directAccess(uint64_t inode) const noexcept {
inline Result<const char*> directAccess(uint64_t inode) const noexcept {
return directAccessInode(inode);
}
@@ -234,11 +209,6 @@ class FileSystemTemplate: public MemFS {
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept override;
Error removePath(StringViewCR path, bool recursive) noexcept override;
Result<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(StringViewCR dir) const noexcept override;
@@ -246,6 +216,8 @@ class FileSystemTemplate: public MemFS {
template<typename F>
Error ls(StringViewCR path, F cb) const;
Error remove(StringViewCR path, bool recursive) noexcept override;
/**
* Resizes FileSystem to minimum possible size.
*/
@@ -329,7 +301,7 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
return ox::Error(1);
}
return {};
return ox::Error(0);
}
template<typename FileStore, typename Directory>
@@ -346,7 +318,7 @@ Error FileSystemTemplate<FileStore, Directory>::move(StringViewCR src, StringVie
OX_REQUIRE_M(inode, rootDir.find(src));
OX_RETURN_ERROR(rootDir.write(dest, inode));
OX_RETURN_ERROR(rootDir.remove(src));
return {};
return ox::Error(0);
}
template<typename FileStore, typename Directory>
@@ -385,14 +357,35 @@ Error FileSystemTemplate<FileStore, Directory>::readFileInodeRange(uint64_t inod
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept {
OX_REQUIRE(s, stat(path));
return readFileInodeRange(s.inode, readStart, readSize, buffer, buffSize);
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode);
if (!data.valid()) {
return ox::Error(1, "Data not valid");
}
return reinterpret_cast<char*>(data.get());
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::removePath(StringViewCR path, bool recursive) noexcept {
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path) const noexcept {
Vector<String> out;
OX_RETURN_ERROR(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) {
out.emplace_back(name);
return ox::Error(0);
}));
return out;
}
template<typename FileStore, typename Directory>
template<typename F>
Error FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path, F cb) const {
oxTracef("ox.fs.FileSystemTemplate.ls", "path: {}", path);
OX_REQUIRE(s, stat(path));
Directory dir(m_fs, s.inode);
return dir.ls(cb);
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::remove(StringViewCR path, bool recursive) noexcept {
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
OX_REQUIRE(inode, rootDir.find(path));
@@ -407,35 +400,7 @@ Error FileSystemTemplate<FileStore, Directory>::removePath(StringViewCR path, bo
oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return ox::Error(1);
}
return {};
}
template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode);
if (!data.valid()) {
return ox::Error(1, "Data not valid");
}
return reinterpret_cast<char*>(data.get());
}
template<typename FileStore, typename Directory>
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path) const noexcept {
Vector<String> out;
OX_RETURN_ERROR(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) {
out.emplace_back(name);
return ox::Error{};
}));
return out;
}
template<typename FileStore, typename Directory>
template<typename F>
Error FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path, F cb) const {
oxTracef("ox.fs.FileSystemTemplate.ls", "path: {}", path);
OX_REQUIRE(s, stat(path));
Directory dir(m_fs, s.inode);
return dir.ls(cb);
return ox::Error(0);
}
template<typename FileStore, typename Directory>
@@ -468,7 +433,7 @@ Error FileSystemTemplate<FileStore, Directory>::writeFilePath(
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
oxTrace("ox.fs.FileSystemTemplate.writeFileInode", ox::intToStr(inode));
oxTrace("ox.fs.FileSystemTemplate.writeFileInode", ox::itoa(inode));
return m_fs.write(inode, buffer, static_cast<size_t>(size), static_cast<uint8_t>(fileType));
}

View File

@@ -60,7 +60,7 @@ Error PassThroughFS::move(StringViewCR src, StringViewCR dest) noexcept {
if (ec.value()) {
return ox::Error(1);
}
return {};
return ox::Error(0);
}
Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
@@ -75,6 +75,14 @@ Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
return out;
}
Error PassThroughFS::remove(StringViewCR path, bool recursive) noexcept {
if (recursive) {
return ox::Error(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
} else {
return ox::Error(std::filesystem::remove(m_path / stripSlash(path)) != 0);
}
}
Error PassThroughFS::resize(uint64_t, void*) noexcept {
// unsupported
return ox::Error(1, "resize is not supported by PassThroughFS");
@@ -93,9 +101,7 @@ Result<FileStat> PassThroughFS::statPath(StringViewCR path) const noexcept {
oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec);
oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size);
if (auto err = ec.value()) {
return ox::Error{static_cast<ox::ErrorCode>(err), "PassThroughFS: stat failed"};
}
OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
return FileStat{0, 0, size, type};
}
@@ -148,7 +154,7 @@ Error PassThroughFS::readFilePath(StringViewCR path, void *buffer, std::size_t b
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return ox::Error(2);
}
return {};
return ox::Error(0);
}
Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept {
@@ -156,38 +162,11 @@ Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept {
return ox::Error(1, "readFileInode(uint64_t, void*, std::size_t) is not supported by PassThroughFS");
}
Error PassThroughFS::readFilePathRange(
StringViewCR path, size_t const readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept {
try {
std::ifstream file(m_path / stripSlash(path), std::ios::binary | std::ios::ate);
auto const size = static_cast<size_t>(file.tellg());
readSize = ox::min(readSize, size);
file.seekg(static_cast<off_t>(readStart), std::ios::beg);
if (readSize > *buffSize) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read failed: Buffer too small: {}", path);
return ox::Error{1};
}
file.read(static_cast<char*>(buffer), static_cast<std::streamsize>(readSize));
return {};
} catch (std::fstream::failure const &f) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return ox::Error{2};
}
}
Error PassThroughFS::readFileInodeRange(uint64_t, std::size_t, std::size_t, void*, std::size_t*) noexcept {
// unsupported
return ox::Error(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS");
}
Error PassThroughFS::removePath(StringViewCR path, bool const recursive) noexcept {
if (recursive) {
return ox::Error{std::filesystem::remove_all(m_path / stripSlash(path)) == 0};
} else {
return ox::Error{!std::filesystem::remove(m_path / stripSlash(path))};
}
}
Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType) noexcept {
const auto p = (m_path / stripSlash(path));
try {
@@ -197,7 +176,7 @@ Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64
oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return ox::Error(1);
}
return {};
return ox::Error(0);
}
Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept {
@@ -206,7 +185,8 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
}
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
for (auto i = 0u; i < path.size() && path[0] == '/'; i++) {
const auto pathLen = ox::strlen(path);
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
path = substr(path, 1);
}
return {path.data(), path.bytes()};

View File

@@ -45,6 +45,8 @@ class PassThroughFS: public FileSystem {
template<typename F>
Error ls(StringViewCR dir, F cb) const noexcept;
Error remove(StringViewCR path, bool recursive) noexcept override;
Error resize(uint64_t size, void *buffer) noexcept override;
Result<FileStat> statInode(uint64_t inode) const noexcept override;
@@ -71,13 +73,8 @@ class PassThroughFS: public FileSystem {
Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept override;
Error readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept override;
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error removePath(StringViewCR path, bool recursive) noexcept override;
Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;
@@ -99,7 +96,7 @@ Error PassThroughFS::ls(StringViewCR dir, F cb) const noexcept {
for (auto &p : di) {
OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0));
}
return {};
return ox::Error(0);
}
}

View File

@@ -36,7 +36,7 @@ Error PathIterator::dirPath(char *out, std::size_t outSize) {
if (idx >= 0 && size < outSize) {
ox::memcpy(out, m_path, size);
out[size] = 0;
return {};
return ox::Error(0);
} else {
return ox::Error(1);
}
@@ -74,7 +74,7 @@ Error PathIterator::get(StringView &fileName) {
if (size && fileName[size - 1] == '/') {
fileName = ox::substr(m_path, start, start + size - 1);
}
oxAssert(fileName[fileName.size()-1] != '/', "name ends in /");
oxAssert(fileName[fileName.len()-1] != '/', "name ends in /");
return {};
}
@@ -85,7 +85,7 @@ Error PathIterator::next(StringView &fileName) {
std::size_t size = 0;
auto retval = ox::Error(1);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = {};
retval = ox::Error(0);
if (m_path[m_iterator] == '/') {
m_iterator++;
}
@@ -104,11 +104,11 @@ Error PathIterator::next(StringView &fileName) {
}
fileName = ox::substr(m_path, start, start + size);
// truncate trailing /
while (fileName.size() && fileName[fileName.size() - 1] == '/') {
while (fileName.len() && fileName[fileName.len() - 1] == '/') {
fileName = ox::substr(m_path, start, start + size);
}
m_iterator += size;
oxAssert(fileName.size() == 0 || fileName[fileName.size()-1] != '/', "name ends in /");
oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /");
}
return retval;
}
@@ -118,7 +118,7 @@ Result<std::size_t> PathIterator::nextSize() const {
auto retval = ox::Error(1);
auto it = m_iterator;
if (it < m_maxSize && ox::strlen(&m_path[it])) {
retval = {};
retval = ox::Error(0);
if (m_path[it] == '/') {
it++;
}

View File

@@ -354,7 +354,7 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
}
}
m_header.bytesUsed -= item.size();
return {};
return ox::Error(0);
}
template<typename size_t, typename Item>
@@ -370,7 +370,7 @@ Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept {
m_header.size = static_cast<size_t>(size);
auto data = reinterpret_cast<uint8_t*>(this) + end;
ox::memset(data, 0, size - end);
return {};
return ox::Error(0);
}
}
@@ -422,7 +422,7 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
src = ptr(dest->next);
dest = uninitializedPtr(dest.offset() + dest->fullSize());
}
return {};
return ox::Error(0);
}
template<typename size_t, typename Item>

View File

@@ -59,7 +59,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next1",
[](ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.size());
ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -74,9 +74,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
ox::PathIterator it(path);
ox::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error");
ox::expect(buff, "usr");
oxExpect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error");
ox::expect(buff, "share");
oxExpect(buff, "share");
return ox::Error(0);
}
},
@@ -84,7 +84,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next3",
[](ox::StringView) {
auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.size());
ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return ox::Error(0);
@@ -106,7 +106,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next5",
[](ox::StringView) {
auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.size());
ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -117,11 +117,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::dirPath",
[] (ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.size());
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxAssert(it.dirPath(buff, path.size()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
OX_ALLOW_UNSAFE_BUFFERS_END
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
return ox::Error(0);
}
},
@@ -129,9 +127,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::hasNext",
[](ox::StringView) {
const auto path = "/file1";
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::PathIterator it(path, ox::strlen(path));
OX_ALLOW_UNSAFE_BUFFERS_END
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
return ox::Error(0);
@@ -167,16 +163,14 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
constexpr auto buffLen = 5000;
constexpr auto str1 = "Hello, World!";
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
constexpr auto str1Len = ox::strlen(str1) + 1;
constexpr auto str2 = "Hello, Moon!";
constexpr auto str2Len = ox::strlen(str2) + 1;
OX_ALLOW_UNSAFE_BUFFERS_END
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, str1, str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, str2, str2Len, 1), "FileStore::write 2 failed.");
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;

View File

@@ -34,7 +34,7 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
}
}
static ox::Result<ox::UPtr<ox::FileSystem>> loadFs(const char *path) noexcept {
static ox::Result<ox::UniquePtr<ox::FileSystem>> loadFs(const char *path) noexcept {
OX_REQUIRE(buff, loadFsBuff(path));
return {ox::make_unique<ox::FileSystem32>(buff.data, buff.size)};
}
@@ -48,7 +48,7 @@ static ox::Error runLs(ox::FileSystem *fs, ox::Span<const char*> args) noexcept
for (const auto &file : files) {
oxOutf("{}\n", file);
}
return {};
return ox::Error(0);
}
static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
@@ -57,10 +57,8 @@ static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcep
return ox::Error(1);
}
OX_REQUIRE(buff, fs->read(ox::StringView(args[1])));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
std::ignore = fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
OX_ALLOW_UNSAFE_BUFFERS_END
return {};
return ox::Error(0);
}
static ox::Error run(int argc, const char **argv) noexcept {

View File

@@ -14,7 +14,7 @@
{ \
const auto loggerErr = (loggerName).initConn(appName); \
if (loggerErr) { \
oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.src.file_name(), loggerErr.src.line()); \
oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.file, loggerErr.line); \
} else { \
ox::trace::setLogger(&(loggerName)); \
} \

View File

@@ -91,28 +91,23 @@ ox::Error LoggerConn::sendInit(const InitTraceMsg &msg) noexcept {
}
void LoggerConn::msgSend() noexcept {
try {
while (true) {
std::unique_lock lk(m_waitMut);
m_waitCond.wait(lk);
if (!m_running) {
break;
}
std::lock_guard const buffLk(m_buffMut);
while (true) {
std::unique_lock lk(m_waitMut);
m_waitCond.wait(lk);
if (!m_running) {
Array<char, units::KB> tmp;
const auto read = m_buff.read(tmp.data(), tmp.size());
if (!read) {
break;
}
std::lock_guard const buffLk(m_buffMut);
while (true) {
Array<char, units::KB> tmp;
const auto read = m_buff.read(tmp.data(), tmp.size());
if (!read) {
break;
}
oxAssert(read <= tmp.size(), "logger trying to read too much data");
//std::printf("LoggerConn: sending %lu bytes\n", read);
std::ignore = send(tmp.data(), read);
}
oxAssert(read <= tmp.size(), "logger trying to read too much data");
//std::printf("LoggerConn: sending %lu bytes\n", read);
std::ignore = send(tmp.data(), read);
}
} catch (std::exception const &e) {
oxErrf("Exception in logger thread: {}\n", e.what());
oxAssert(false, "logger thread exception");
}
}

View File

@@ -1,5 +1,6 @@
add_library(
OxMetalClaw
presenceindicator.cpp
read.cpp
write.cpp
)

View File

@@ -18,25 +18,25 @@
namespace ox::mc {
template<Integer_c T>
template<typename T>
static constexpr auto Bits = sizeof(T) << 3;
/**
* Returns highest bit other than possible signed bit.
* Bit numbering starts at 0.
*/
template<Integer_c I>
template<typename I>
[[nodiscard]]
constexpr size_t highestBit(I const val) noexcept {
constexpr std::size_t highestBit(I val) noexcept {
unsigned shiftStart = sizeof(I) * 8 - 1;
// find the most significant non-sign indicator bit
size_t highestBit = 0;
// find most significant non-sign indicator bit
std::size_t highestBit = 0;
// start at one bit lower if signed
if constexpr(is_signed_v<I>) {
--shiftStart;
}
for (auto i = shiftStart; i > 0; --i) {
auto const bitValue = (val >> i) & 1;
const auto bitValue = (val >> i) & 1;
if (bitValue) {
highestBit = i;
break;
@@ -45,7 +45,7 @@ constexpr size_t highestBit(I const val) noexcept {
return highestBit;
}
static_assert(highestBit(static_cast<int8_t>(0b10000000)) == 0);
static_assert(highestBit(int8_t(0b10000000)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-1)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-2)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-3)) == 1);
@@ -53,39 +53,40 @@ static_assert(highestBit(1) == 0);
static_assert(highestBit(2) == 1);
static_assert(highestBit(4) == 2);
static_assert(highestBit(8) == 3);
static_assert(highestBit(static_cast<uint64_t>(1) << 31) == 31);
static_assert(highestBit(static_cast<uint64_t>(1) << 63) == 63);
static_assert(highestBit(uint64_t(1) << 31) == 31);
static_assert(highestBit(uint64_t(1) << 63) == 63);
struct McInt {
Array<uint8_t, 9> data{};
ox::Array<uint8_t, 9> data{};
// length of integer in bytes
size_t length = 0;
std::size_t length = 0;
};
template<Integer_c I>
template<typename I>
[[nodiscard]]
constexpr McInt encodeInteger(I const pInput) noexcept {
auto const input = ResizedInt_t<I, 64>{pInput};
constexpr McInt encodeInteger(I pInput) noexcept {
auto const input = ox::ResizedInt_t<I, 64>{pInput};
McInt out;
auto const inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation and to avoid
const auto inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid
// overflow concerns
auto const val = std::bit_cast<uint64_t>(input);
uint64_t val = 0;
ox::memcpy(&val, &input, sizeof(input));
if (val) {
// bits needed to represent number factoring in space possibly
// needed for signed bit
auto const highBit = inputNegative ? highestBit(~val) : highestBit(val);
auto const bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
const auto highBit = inputNegative ? highestBit(~val) : highestBit(val);
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
// bytes needed to store value
size_t bytes = bits / 8 + (bits % 8 != 0);
auto const bitsAvailable = bytes * 8; // bits available to integer value
auto const bitsNeeded = bits + bytes;
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 needed to represent bytes > bits available
if (bitsNeeded > bitsAvailable && bytes != 9) {
++bytes;
}
auto const bytesIndicator = onMask<uint8_t>(bytes - 1);
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
// ensure we are copying from little endian representation
LittleEndian<uint64_t> leVal = val;
if (inputNegative) {
@@ -93,21 +94,17 @@ constexpr McInt encodeInteger(I const pInput) noexcept {
}
if (bytes == 9) {
out.data[0] = bytesIndicator;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out.data[1], &leVal, 8);
OX_ALLOW_UNSAFE_BUFFERS_END
if (inputNegative) {
out.data[1] |= 0b1000'0000;
}
} else {
auto const valBits = bytes * 8;
uint64_t const negBit = inputNegative ? 1 : 0;
auto const intermediate =
const auto valBits = bytes * 8;
uint64_t negBit = inputNegative ? 1 : 0;
auto intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out.data[0], &intermediate, sizeof(intermediate));
OX_ALLOW_UNSAFE_BUFFERS_END
}
out.length = bytes;
}
@@ -119,8 +116,8 @@ constexpr McInt encodeInteger(I const pInput) noexcept {
* length integer.
*/
[[nodiscard]]
constexpr size_t countBytes(unsigned const b) noexcept {
size_t i = 0;
constexpr std::size_t countBytes(unsigned b) noexcept {
std::size_t i = 0;
while ((b >> i) & 1) ++i;
return i + 1;
}
@@ -135,65 +132,61 @@ static_assert(countBytes(0b0011'1111) == 7);
static_assert(countBytes(0b0111'1111) == 8);
static_assert(countBytes(0b1111'1111) == 9);
template<Integer_c I>
constexpr Result<I> decodeInteger(Reader_c auto &rdr, size_t &bytesRead) noexcept {
template<typename I>
constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept {
uint8_t firstByte = 0;
OX_RETURN_ERROR(rdr.read(&firstByte, 1));
OX_RETURN_ERROR(rdr.seekg(-1, ox::ios_base::cur));
auto const bytes = countBytes(firstByte);
const auto bytes = countBytes(firstByte);
if (bytes == 9) {
bytesRead = bytes;
*bytesRead = bytes;
I out = 0;
OX_RETURN_ERROR(rdr.seekg(1, ox::ios_base::cur));
OX_RETURN_ERROR(rdr.read(&out, sizeof(I)));
return fromLittleEndian<I>(out);
}
bytesRead = bytes;
*bytesRead = bytes;
uint64_t decoded = 0;
OX_RETURN_ERROR(rdr.read(&decoded, bytes));
decoded >>= bytes;
// move sign bit
if constexpr(is_signed_v<I>) {
auto const negBit = bytes * 8 - bytes - 1;
// move sign
auto const negative = (decoded >> negBit) == 1;
if (negative) {
// fill in all bits between encoded sign and real sign with 1s
// split it up because the 32-bit ARM can't shift more than 32 bits
Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&d[0], &decoded, sizeof(decoded));
OX_ALLOW_UNSAFE_BUFFERS_END
auto bit = negBit;
for (; bit < ox::min<size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit;
}
bit -= 32;
for (; bit < Bits<I>; ++bit) {
d[1] |= 1 << bit;
}
I out = 0;
if constexpr(ox::defines::BigEndian) {
auto const d0Tmp = d[0];
d[0] = d[1];
d[1] = d0Tmp;
}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out, &d[0], sizeof(out));
OX_ALLOW_UNSAFE_BUFFERS_END
return out;
}
const auto negBit = bytes * 8 - bytes - 1;
// move sign
const auto negative = (decoded >> negBit) == 1;
if (negative) {
// fill in all bits between encoded sign and real sign with 1s
// split it up because the 32-bit ARM can't shift more than 32 bits
ox::Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
ox::memcpy(&d[0], &decoded, sizeof(decoded));
auto bit = negBit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit;
}
bit -= 32;
for (; bit < Bits<I>; ++bit) {
d[1] |= 1 << bit;
}
I out = 0;
if constexpr(ox::defines::BigEndian) {
const auto d0Tmp = d[0];
d[0] = d[1];
d[1] = d0Tmp;
}
ox::memcpy(&out, &d[0], sizeof(out));
return out;
}
}
return static_cast<I>(decoded);
}
template<Integer_c I>
Result<I> decodeInteger(McInt const &m) noexcept {
size_t bytesRead{};
template<typename I>
Result<I> decodeInteger(McInt m) noexcept {
std::size_t bytesRead{};
BufferReader br({reinterpret_cast<const char*>(m.data.data()), 9});
return decodeInteger<I>(br, bytesRead);
return decodeInteger<I>(br, &bytesRead);
}
}

17
deps/ox/src/ox/mc/presenceindicator.cpp vendored Normal file
View File

@@ -0,0 +1,17 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "err.hpp"
#include "presenceindicator.hpp"
namespace ox {
template class FieldBitmapWriterBase<uint8_t*>;
template class FieldBitmapWriterBase<const uint8_t*>;
}

View File

@@ -11,7 +11,6 @@
#include <ox/std/array.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/span.hpp>
#include <ox/std/types.hpp>
#include <ox/std/reader.hpp>
@@ -22,101 +21,143 @@ namespace ox {
template<Reader_c Reader>
class FieldBitmapReader {
protected:
mutable size_t m_mapBlockIdx = ~size_t{};
mutable uint64_t m_mapBlock{};
size_t m_mapStart{};
mutable std::size_t m_mapBlockIdx = ~std::size_t{0};
mutable uint64_t m_mapBlock = 0;
std::size_t m_mapStart = 0;
Reader &m_reader;
public:
explicit constexpr FieldBitmapReader(Reader &reader) noexcept:
m_mapStart(reader.tellg()),
m_reader(reader) {
}
explicit constexpr FieldBitmapReader(Reader &reader) noexcept;
constexpr Result<bool> get(size_t idx) const noexcept {
constexpr auto blockBits = sizeof(m_mapBlock);
auto const blockIdx = idx / blockBits;
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
OX_RETURN_ERROR(loadMapBlock(blockIdx));
}
idx %= blockBits;
return (m_mapBlock >> idx) & 1;
}
constexpr Result<bool> get(std::size_t i) const noexcept;
private:
constexpr Error loadMapBlock(size_t const idx) const noexcept {
OX_REQUIRE(g, m_reader.tellg());
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
Array<char, sizeof(m_mapBlock)> mapBlock{};
OX_RETURN_ERROR(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
// Warning: narrow-conv
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
m_mapBlock = 0;
for (uint64_t i{}; auto b : mapBlock) {
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
i += 8;
}
m_mapBlockIdx = idx;
return {};
}
constexpr ox::Error loadMapBlock(std::size_t id) const noexcept;
};
template<Reader_c Reader>
constexpr FieldBitmapReader<Reader>::FieldBitmapReader(Reader &reader) noexcept:
m_mapStart(reader.tellg()),
m_reader(reader) {
}
class FieldBitmapWriter {
template<Reader_c Reader>
constexpr Result<bool> FieldBitmapReader<Reader>::get(std::size_t idx) const noexcept {
constexpr auto blockBits = sizeof(m_mapBlock);
auto const blockIdx = idx / blockBits;
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
OX_RETURN_ERROR(loadMapBlock(blockIdx));
}
idx %= blockBits;
return (m_mapBlock >> idx) & 1;
}
template<Reader_c Reader>
constexpr ox::Error FieldBitmapReader<Reader>::loadMapBlock(std::size_t idx) const noexcept {
OX_REQUIRE(g, m_reader.tellg());
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
ox::Array<char, sizeof(m_mapBlock)> mapBlock{};
OX_RETURN_ERROR(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
// Warning: narrow-conv
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
m_mapBlock = 0;
for (auto i = 0ull; auto b : mapBlock) {
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
i += 8;
}
m_mapBlockIdx = idx;
return {};
}
template<typename T>
class FieldBitmapWriterBase {
protected:
Span<char> m_map;
size_t m_mapLen{};
T m_map = nullptr;
std::size_t m_mapLen = 0;
public:
explicit constexpr FieldBitmapWriter(Span<char> const &map) noexcept:
m_map(map),
m_mapLen(m_map.size()) {
}
constexpr FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept;
constexpr auto setBuffer(Span<char> const &map) noexcept {
m_map = map;
m_mapLen = map.size();
}
constexpr auto setBuffer(T map, std::size_t maxLen) noexcept;
constexpr Result<bool> get(size_t const i) const noexcept {
if (i / 8 < m_mapLen) {
return (std::bit_cast<uint8_t>(m_map[i / 8]) >> (i % 8)) & 1;
}
return Error{McPresenceMapOverflow};
}
constexpr Result<bool> get(std::size_t i) const noexcept;
constexpr Error setFields(int const fields) noexcept {
m_mapLen = static_cast<size_t>((fields / 8 + 1) - (fields % 8 == 0));
if (m_mapLen > m_map.size()) [[unlikely]] {
return Error{McPresenceMapOverflow};
}
return {};
}
constexpr void setFields(int) noexcept;
constexpr void setMaxLen(int const maxLen) noexcept {
m_mapLen = static_cast<size_t>(maxLen);
}
constexpr void setMaxLen(int) noexcept;
constexpr int64_t getMaxLen() const noexcept {
return static_cast<int64_t>(m_mapLen);
}
constexpr Error set(size_t const i, bool const on) noexcept {
if (i / 8 < m_mapLen) {
char &actual = m_map[i / 8];
uint8_t v = std::bit_cast<uint8_t>(actual);
if (on) {
v |= 1 << (i % 8);
} else {
v &= ~static_cast<uint8_t>(1 << (i % 8));
}
actual = std::bit_cast<char>(v);
return {};
}
return Error{McPresenceMapOverflow};
}
[[nodiscard]]
constexpr int64_t getMaxLen() const noexcept;
};
template<typename T>
constexpr FieldBitmapWriterBase<T>::FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept {
m_map = map;
m_mapLen = maxLen;
}
template<typename T>
constexpr auto FieldBitmapWriterBase<T>::setBuffer(T map, std::size_t maxLen) noexcept {
m_map = map;
m_mapLen = maxLen;
}
template<typename T>
constexpr Result<bool> FieldBitmapWriterBase<T>::get(std::size_t i) const noexcept {
if (i / 8 < m_mapLen) {
return (m_map[i / 8] >> (i % 8)) & 1;
} else {
return ox::Error(McPresenceMapOverflow);
}
}
template<typename T>
constexpr void FieldBitmapWriterBase<T>::setFields(int fields) noexcept {
m_mapLen = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
}
template<typename T>
constexpr void FieldBitmapWriterBase<T>::setMaxLen(int maxLen) noexcept {
m_mapLen = static_cast<std::size_t>(maxLen);
}
template<typename T>
constexpr int64_t FieldBitmapWriterBase<T>::getMaxLen() const noexcept {
return static_cast<int64_t>(m_mapLen);
}
extern template class FieldBitmapWriterBase<uint8_t*>;
extern template class FieldBitmapWriterBase<const uint8_t*>;
class FieldBitmap: public FieldBitmapWriterBase<uint8_t*> {
public:
constexpr FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept;
constexpr Error set(std::size_t i, bool on) noexcept;
};
constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept:
FieldBitmapWriterBase<uint8_t*>(map, maxLen) {
}
constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
if (i / 8 < m_mapLen) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
if (on) {
m_map[i / 8] |= 1 << (i % 8);
} else {
m_map[i / 8] &= ~static_cast<uint8_t>(1 << (i % 8));
}
OX_ALLOW_UNSAFE_BUFFERS_END
return {};
} else {
return ox::Error(McPresenceMapOverflow);
}
}
}

View File

@@ -32,58 +32,58 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
private:
FieldBitmapReader<Reader> m_fieldPresence;
size_t m_fields{};
size_t m_field{};
Optional<int> const m_unionIdx{};
std::size_t m_fields = 0;
std::size_t m_field = 0;
ox::Optional<int> m_unionIdx;
Reader &m_reader;
public:
explicit constexpr MetalClawReaderTemplate(
Reader &reader,
Optional<int> const &unionIdx = {}) noexcept;
ox::Optional<int> const&unionIdx = {}) noexcept;
constexpr ~MetalClawReaderTemplate() noexcept;
constexpr Error field(CString, int8_t *val) noexcept;
constexpr Error field(CString, int16_t *val) noexcept;
constexpr Error field(CString, int32_t *val) noexcept;
constexpr Error field(CString, int64_t *val) noexcept;
constexpr Error field(const char*, int8_t *val) noexcept;
constexpr Error field(const char*, int16_t *val) noexcept;
constexpr Error field(const char*, int32_t *val) noexcept;
constexpr Error field(const char*, int64_t *val) noexcept;
constexpr Error field(CString, uint8_t *val) noexcept;
constexpr Error field(CString, uint16_t *val) noexcept;
constexpr Error field(CString, uint32_t *val) noexcept;
constexpr Error field(CString, uint64_t *val) noexcept;
constexpr Error field(const char*, uint8_t *val) noexcept;
constexpr Error field(const char*, uint16_t *val) noexcept;
constexpr Error field(const char*, uint32_t *val) noexcept;
constexpr Error field(const char*, uint64_t *val) noexcept;
constexpr Error field(CString, bool *val) noexcept;
constexpr Error field(const char*, bool *val) noexcept;
// array handler
constexpr Error field(CString, auto *val, size_t valLen) noexcept;
constexpr Error field(const char*, auto *val, std::size_t len) noexcept;
// map handler
template<typename T>
constexpr Error field(CString, HashMap<String, T> *val) noexcept;
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
// array handler, with callback to allow handling individual elements
template<typename T, typename CB>
constexpr Error field(CString, CB cb) noexcept;
constexpr Error field(const char*, CB cb) noexcept;
template<typename T>
constexpr Error field(CString, T *val) noexcept;
constexpr Error field(const char*, T *val) noexcept;
template<typename U, bool force>
constexpr Error field(CString, UnionView<U, force> val) noexcept;
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<size_t SmallStringSize>
constexpr Error field(CString, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<size_t L>
constexpr Error field(CString, IString<L> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, IString<L> *val) noexcept;
constexpr Error fieldCString(CString, char *val, size_t buffLen) noexcept;
constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept;
constexpr Error fieldCString(CString, char **val) noexcept;
constexpr Error fieldCString(const char*, char **val) noexcept;
constexpr Error fieldCString(CString, char **val, size_t buffLen) noexcept;
constexpr Error fieldCString(const char*, char **val, std::size_t buffLen) noexcept;
/**
* Reads an array length from the current location in the buffer.
@@ -101,13 +101,13 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
const char *name = T::TypeName,
int version = T::TypeVersion,
const Vector<String>& = {},
size_t fields = ModelFieldCount_v<T>) noexcept;
std::size_t fields = ModelFieldCount_v<T>) noexcept;
/**
* Returns a MetalClawReader to parse a child object.
*/
[[nodiscard]]
constexpr MetalClawReaderTemplate<Reader> child(const char *name, Optional<int> unionIdx = {}) noexcept;
constexpr MetalClawReaderTemplate<Reader> child(const char *name, ox::Optional<int> unionIdx = {}) noexcept;
/**
* Indicates whether or not the next field to be read is present.
@@ -122,20 +122,20 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
constexpr bool fieldPresent(int fieldNo) const noexcept;
[[nodiscard]]
constexpr int whichFieldPresent(const char *name, ModelUnion const&) const noexcept;
constexpr int whichFieldPresent(const char *name, const ModelUnion&) const noexcept;
constexpr void nextField() noexcept;
private:
template<typename I>
constexpr Error readInteger(I &val) noexcept;
constexpr Error readInteger(I *val) noexcept;
};
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
Reader &reader,
Optional<int> const &unionIdx) noexcept:
ox::Optional<int> const&unionIdx) noexcept:
m_fieldPresence(reader),
m_unionIdx(unionIdx),
m_reader(reader) {
@@ -149,72 +149,71 @@ constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int8_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int16_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int32_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int64_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint8_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint16_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint32_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint64_t *val) noexcept {
return readInteger(*val);
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<size_t>(m_field));
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = result.value;
OX_RETURN_ERROR(result);
}
++m_field;
return {};
return ox::Error(0);
}
// array handler
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(
const char *name, auto *val, size_t const valLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
// read the list
if (valLen >= len) {
auto reader = child({});
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
@@ -231,18 +230,18 @@ OX_ALLOW_UNSAFE_BUFFERS_END
template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, HashMap<String, T> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
OX_REQUIRE(g, m_reader.tellg());
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
OX_RETURN_ERROR(m_reader.seekg(g));
// read the list
auto reader = child("");
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
// this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto &val) {
OX_REQUIRE(keyLen, handler.stringLength(nullptr));
@@ -251,22 +250,22 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(CString, HashMap<String,
OX_RETURN_ERROR(handler.fieldCString("", &wkeyPtr, keyLen + 1));
return handler.field("", &val[wkeyPtr]);
};
for (size_t i = 0; i < len; ++i) {
for (std::size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(loopBody(handler, *val));
}
}
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
if constexpr(isVector_v<T>) {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
// set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
OX_REQUIRE(len, arrayLength(name, false));
OX_RETURN_ERROR(ox::resizeVector(*val, len));
return field(name, val->data(), val->size());
@@ -276,9 +275,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
++m_field;
return {};
} else if constexpr(isArray_v<T>) {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
// set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
OX_REQUIRE(len, arrayLength(name, false));
if (len > val->size()) {
return ox::Error(1, "Input array is too long");
@@ -289,8 +288,8 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
++m_field;
return {};
} else {
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("");
OX_RETURN_ERROR(model(reader.interface(), val));
}
@@ -302,9 +301,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
template<Reader_c Reader>
template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
OX_RETURN_ERROR(model(reader.interface(), val.get()));
}
@@ -314,13 +313,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(CString, UnionView<U, for
}
template<Reader_c Reader>
template<size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, BasicString<SmallStringSize> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
template<std::size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
const auto cap = size;
*val = BasicString<SmallStringSize>(cap);
auto data = val->data();
@@ -331,17 +330,17 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(CString, BasicString<Smal
}
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
template<size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, IString<L> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
template<std::size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
*val = IString<L>();
OX_RETURN_ERROR(val->resize(size));
auto const data = val->data();
@@ -356,12 +355,11 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(CString, IString<L> *val)
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(
CString, char *val, size_t const buffLen) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
if (size > buffLen) {
return ox::Error(McOutputBuffEnded);
}
@@ -372,15 +370,15 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(
data[size] = 0;
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
@@ -390,16 +388,16 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **va
data[size] = 0;
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val, size_t buffLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
// re-allocate if too small
if (buffLen < size + 1) {
safeDelete(*val);
@@ -418,17 +416,17 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **va
}
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(CString, bool const pass) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
std::size_t bytesRead = 0;
OX_REQUIRE(g, m_reader.tellg());
OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
if (!pass) {
OX_RETURN_ERROR(m_reader.seekg(g));
}
@@ -439,12 +437,12 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(CStri
}
template<Reader_c Reader>
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(CString) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, bytesRead);
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, &bytesRead);
OX_RETURN_ERROR(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur));
return len;
}
@@ -454,34 +452,34 @@ constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(CSt
template<Reader_c Reader>
template<typename I>
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I &val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
size_t bytesRead = 0;
auto const result = mc::decodeInteger<I>(m_reader, bytesRead);
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
std::size_t bytesRead = 0;
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
OX_RETURN_ERROR(result);
val = result.value;
*val = result.value;
} else {
val = 0;
*val = 0;
}
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, CB cb) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
std::size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
// read the list
auto reader = child("");
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
T val;
OX_RETURN_ERROR(handler.field("", &val));
OX_RETURN_ERROR(cb(i, &val));
@@ -489,13 +487,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(CString, CB cb) noexcept
}
}
++m_field;
return {};
return ox::Error(0);
}
template<Reader_c Reader>
template<typename T>
constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
CString, int, const Vector<String>&, size_t const fields) noexcept {
const char*, int, const Vector<String>&, std::size_t fields) noexcept {
m_fields = fields;
// Warning: narrow-conv
return m_reader.seekg(
@@ -505,24 +503,24 @@ constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
CString,
Optional<int> const unionIdx) noexcept {
const char*,
ox::Optional<int> unionIdx) noexcept {
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
}
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(CString) const noexcept {
return m_fieldPresence.get(static_cast<size_t>(m_field)).value;
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
}
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int const fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<size_t>(fieldNo)).value;
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
}
template<Reader_c Reader>
[[nodiscard]]
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(CString, ModelUnion const &u) const noexcept {
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
FieldBitmapReader<Reader> p(m_reader);
for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) {
@@ -540,10 +538,11 @@ constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
template<typename T>
Error readMC(ox::BufferView const buff, T &val) noexcept {
Error readMC(ox::BufferView buff, T &val) noexcept {
BufferReader br(buff);
MetalClawReader reader(br);
return model(reader.interface(), &val);
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
return model(&handler, &val);
}
template<typename T>

View File

@@ -157,7 +157,8 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch");
ox::expect(testIn.IString, testOut.IString);
oxDebugf("{}", testOut.IString.len());
oxExpect(testIn.IString, testOut.IString);
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");

View File

@@ -29,71 +29,71 @@
namespace ox {
template<Writer_c Writer>
class MetalClawWriter: public ModelHandlerBase<MetalClawWriter<Writer>, OpType::Write> {
class MetalClawWriter {
private:
Vector<char, 16> m_presenceMapBuff{};
FieldBitmapWriter m_fieldPresence{m_presenceMapBuff};
int m_field{};
Optional<int> m_unionIdx;
size_t m_writerBeginP{};
ox::Vector<uint8_t, 16> m_presenceMapBuff{};
FieldBitmap m_fieldPresence;
int m_field = 0;
ox::Optional<int> m_unionIdx;
std::size_t m_writerBeginP{};
Writer &m_writer;
public:
constexpr explicit MetalClawWriter(Writer &writer, Optional<int> const &unionIdx = {}) noexcept;
constexpr explicit MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx = {}) noexcept;
constexpr ~MetalClawWriter() noexcept = default;
constexpr Error field(CString, int8_t const *val) noexcept;
constexpr Error field(CString, int16_t const *val) noexcept;
constexpr Error field(CString, int32_t const *val) noexcept;
constexpr Error field(CString, int64_t const *val) noexcept;
constexpr Error field(const char*, const int8_t *val) noexcept;
constexpr Error field(const char*, const int16_t *val) noexcept;
constexpr Error field(const char*, const int32_t *val) noexcept;
constexpr Error field(const char*, const int64_t *val) noexcept;
constexpr Error field(CString, uint8_t const *val) noexcept;
constexpr Error field(CString, uint16_t const *val) noexcept;
constexpr Error field(CString, uint32_t const *val) noexcept;
constexpr Error field(CString, uint64_t const *val) noexcept;
constexpr Error field(const char*, const uint8_t *val) noexcept;
constexpr Error field(const char*, const uint16_t *val) noexcept;
constexpr Error field(const char*, const uint32_t *val) noexcept;
constexpr Error field(const char*, const uint64_t *val) noexcept;
constexpr Error field(CString, bool const *val) noexcept;
constexpr Error field(const char*, const bool *val) noexcept;
template<typename T>
constexpr Error field(CString, T const *val, size_t len) noexcept;
constexpr Error field(const char*, const T *val, std::size_t len) noexcept;
template<typename T>
constexpr Error field(CString name, HashMap<String, T> const *val) noexcept;
constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept;
template<size_t SmallStringSize>
constexpr Error field(CString, BasicString<SmallStringSize> const *val) noexcept;
template<std::size_t SmallStringSize>
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<size_t L>
constexpr Error field(CString, IString<L> const *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, const IString<L> *val) noexcept;
constexpr Error fieldCString(CString name, CString const*val, size_t buffLen) noexcept;
constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept;
constexpr Error fieldCString(CString name, CString *val) noexcept;
constexpr Error fieldCString(const char *name, const char **val) noexcept;
constexpr Error fieldCString(CString name, CString const*val) noexcept;
constexpr Error fieldCString(const char *name, const char *const*val) noexcept;
constexpr Error fieldCString(CString name, CString val, size_t strLen) noexcept;
constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept;
template<typename T>
constexpr Error field(CString, T const *val) noexcept;
constexpr Error field(const char*, const T *val) noexcept;
template<typename U, bool force = false>
constexpr Error field(CString, UnionView<U, force> val) noexcept;
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t>
constexpr Error setTypeInfo(
CString name = T::TypeName,
constexpr ox::Error setTypeInfo(
const char *name = T::TypeName,
int version = T::TypeVersion,
Vector<String> const& = {},
size_t fields = ModelFieldCount_v<T>) noexcept;
const Vector<String>& = {},
std::size_t fields = ModelFieldCount_v<T>) noexcept;
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto stringLength(CString) noexcept {
constexpr auto stringLength(const char*) noexcept {
return 0;
}
@@ -101,23 +101,28 @@ class MetalClawWriter: public ModelHandlerBase<MetalClawWriter<Writer>, OpType::
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto arrayLength(CString, bool = true) noexcept {
constexpr auto arrayLength(const char*, bool = true) noexcept {
return 0;
}
constexpr Error finalize() noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Write;
}
ox::Error finalize() noexcept;
private:
constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(mi.data.data()), mi.length));
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(mi.data.data()), mi.length));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
return ox::Error(0);
}
};
@@ -126,147 +131,144 @@ extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
template<Writer_c Writer>
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, Optional<int> const &unionIdx) noexcept:
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx) noexcept:
m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()),
m_unionIdx(unionIdx),
m_writerBeginP(writer.tellp()),
m_writer(writer) {
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int8_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const int8_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int16_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const int16_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int32_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const int32_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int64_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const int64_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint8_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint8_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint16_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint16_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint32_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint32_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint64_t const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint64_t *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, bool const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noexcept {
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), *val));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
++m_field;
return {};
return ox::Error(0);
}
template<Writer_c Writer>
template<size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(CString, BasicString<SmallStringSize> const *val) noexcept {
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false;
if (val->size() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const strLen = mc::encodeInteger(val->size());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLen.data.data()), strLen.length));
const auto strLen = mc::encodeInteger(val->len());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<size_t>(val->size())));
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
return ox::Error(0);
}
template<Writer_c Writer>
template<size_t L>
constexpr Error MetalClawWriter<Writer>::field(CString name, IString<L> const *val) noexcept {
return fieldCString(name, val->data(), val->size());
template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->len());
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const *val, size_t) noexcept {
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
bool fieldSet = false;
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
// this strlen is tolerated because sometimes 0 gets passed to
// the size param, which is a lie
// this code should be cleaned up at some point...
auto const strLen = *val ? ox::strlen(*val) : 0;
OX_ALLOW_UNSAFE_BUFFERS_END
const auto strLen = *val ? ox::strlen(*val) : 0;
// write the length
auto const strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
const auto strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data.data()), strLenBuff.length));
// write the string
OX_RETURN_ERROR(m_writer.write(*val, static_cast<size_t>(strLen)));
OX_RETURN_ERROR(m_writer.write(*val, static_cast<std::size_t>(strLen)));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
return ox::Error(0);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString *val) noexcept {
constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const char **val) noexcept {
return fieldCString(name, val, {});
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const char *const*val) noexcept {
return fieldCString(name, val, {});
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const val, size_t const strLen) noexcept {
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
bool fieldSet = false;
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
const auto strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data.data()), strLenBuff.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val, static_cast<size_t>(strLen)));
OX_RETURN_ERROR(m_writer.write(val, static_cast<std::size_t>(strLen)));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
return ox::Error(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(nullptr, val->data(), val->size());
} else {
bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer);
OX_RETURN_ERROR(model(writer.interface(), val));
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
OX_RETURN_ERROR(model(&handler, val));
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
}
@@ -274,62 +276,65 @@ constexpr Error MetalClawWriter<Writer>::field(CString, T const *val) noexcept {
template<Writer_c Writer>
template<typename U, bool force>
constexpr Error MetalClawWriter<Writer>::field(CString, UnionView<U, force> val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer, Optional<int>(in_place, val.idx()));
OX_RETURN_ERROR(model(writer.interface(), val.get()));
MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx()));
ModelHandlerInterface handler{&writer};
OX_RETURN_ERROR(model(&handler, val.get()));
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val, size_t const len) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
const auto arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(arrLen.data.data()), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer);
OX_RETURN_ERROR(writer.interface()->template setTypeInfo<T>("List", 0, {}, static_cast<size_t>(len)));
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
OX_RETURN_ERROR(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
// write the array
for (size_t i{}; i < len; ++i) {
for (std::size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(writer.interface()->field("", &val[i]));
OX_RETURN_ERROR(handler.field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
return ox::Error(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, HashMap<String, T> const *val) noexcept {
auto const &keys = val->keys();
auto const len = keys.size();
constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String, T> *val) noexcept {
const auto &keys = val->keys();
const auto len = keys.size();
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
const auto arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(arrLen.data.data()), arrLen.length));
// write map
MetalClawWriter writer(m_writer);
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
// double len for both key and value
OX_RETURN_ERROR(writer.interface()->setTypeInfo("Map", 0, {}, len * 2));
OX_RETURN_ERROR(handler.setTypeInfo("Map", 0, {}, len * 2));
// this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto const &key, auto const &val) -> Error {
auto const keyLen = key.size();
constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto keyLen = key.len();
auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1);
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));
@@ -337,51 +342,53 @@ constexpr Error MetalClawWriter<Writer>::field(CString, HashMap<String, T> const
return handler.field("", value);
};
// write the array
for (size_t i{}; i < len; ++i) {
auto const &key = keys[i];
OX_RETURN_ERROR(loopBody(*writer.interface(), key, *val));
for (std::size_t i = 0; i < len; ++i) {
auto const&key = keys[i];
OX_RETURN_ERROR(loopBody(handler, key, *val));
}
OX_RETURN_ERROR(writer.finalize());
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
return ox::Error(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::setTypeInfo(
CString,
constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo(
const char*,
int,
Vector<String> const&,
size_t const fields) noexcept {
auto const fieldPresenceLen = (fields - 1) / 8 + 1;
const Vector<String>&,
std::size_t fields) noexcept {
const auto fieldPresenceLen = (fields - 1) / 8 + 1;
OX_RETURN_ERROR(m_writer.write(nullptr, fieldPresenceLen));
m_presenceMapBuff.resize(fieldPresenceLen);
m_fieldPresence.setBuffer(m_presenceMapBuff);
return m_fieldPresence.setFields(static_cast<int>(fields));
m_fieldPresence.setBuffer(m_presenceMapBuff.data(), m_presenceMapBuff.size());
m_fieldPresence.setFields(static_cast<int>(fields));
return {};
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::finalize() noexcept {
auto const end = m_writer.tellp();
ox::Error MetalClawWriter<Writer>::finalize() noexcept {
const auto end = m_writer.tellp();
OX_RETURN_ERROR(m_writer.seekp(m_writerBeginP));
OX_RETURN_ERROR(m_writer.write(
m_presenceMapBuff.data(),
m_presenceMapBuff.size()));
reinterpret_cast<const char*>(m_presenceMapBuff.data()),
m_presenceMapBuff.size()));
OX_RETURN_ERROR(m_writer.seekp(end));
return {};
}
Result<Buffer> writeMC(Writer_c auto &writer, auto const &val) noexcept {
Result<Buffer> writeMC(Writer_c auto &writer, const auto &val) noexcept {
MetalClawWriter mcWriter(writer);
OX_RETURN_ERROR(model(mcWriter.interface(), &val));
ModelHandlerInterface handler{&mcWriter};
OX_RETURN_ERROR(model(&handler, &val));
OX_RETURN_ERROR(mcWriter.finalize());
return {};
}
Result<Buffer> writeMC(auto const &val, size_t const buffReserveSz = 2 * units::KB) noexcept {
Result<Buffer> writeMC(auto const&val, std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0);
OX_RETURN_ERROR(writeMC(bw, val));
@@ -389,7 +396,7 @@ Result<Buffer> writeMC(auto const &val, size_t const buffReserveSz = 2 * units::
return buff;
}
Error writeMC(char *buff, size_t const buffLen, auto const &val, size_t *sizeOut = nullptr) noexcept {
Error writeMC(char *buff, std::size_t buffLen, auto const&val, std::size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw{{buff, buffLen}};
OX_RETURN_ERROR(writeMC(bw, val));
if (sizeOut) {

View File

@@ -13,7 +13,7 @@
// oxModelFwdDecl is necessary because Apple-Clang is broken...
#define OX_MODEL_FWD_DECL(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
#define OX_MODEL_BEGIN(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { OX_RETURN_ERROR(io->template setTypeInfo<modelName>());
#define OX_MODEL_END() return {}; }
#define OX_MODEL_END() return ox::Error(0); }
#define OX_MODEL_FIELD(fieldName) OX_RETURN_ERROR(io->field(#fieldName, &o->fieldName));
#define OX_MODEL_FIELD_RENAME(objFieldName, serFieldName) OX_RETURN_ERROR(io->field(#serFieldName, &o->objFieldName));
#define OX_MODEL_FRIEND(modelName) friend constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept

View File

@@ -43,7 +43,7 @@ static constexpr auto buildTypeId(
for (const auto &p : typeParams) {
tp += p + ",";
}
tp.resize(tp.size() - 1);
tp.resize(tp.len() - 1);
tp += "#";
}
return ox::sfmt("{}{};{}", name, tp, version);
@@ -244,7 +244,7 @@ constexpr Error model(TypeDescReader<T> *io, CommonPtrWith<DescriptorField> auto
// defaultValue is unused now, but placeholder for backwards compatibility
int defaultValue = 0;
oxReturnError(io->field("defaultValue", &defaultValue));
return {};
return ox::Error(0);
}
#endif

View File

@@ -51,7 +51,7 @@ constexpr auto buildSubscriptStack(const T**, SubscriptStack *s) noexcept {
}
template<typename T>
constexpr auto buildSubscriptStack(const UPtr<T>*, SubscriptStack *s) noexcept {
constexpr auto buildSubscriptStack(const UniquePtr<T>*, SubscriptStack *s) noexcept {
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
}
@@ -187,7 +187,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
PrimitiveType pt;
if constexpr(is_union_v<T>) {
pt = PrimitiveType::Union;
} else if constexpr(isBasicString_v<T> || isIString_v<T>) {
} else if constexpr(isBasicString_v<T> || isBString_v<T>) {
pt = PrimitiveType::String;
} else {
pt = PrimitiveType::Struct;
@@ -205,7 +205,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t,
const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
m_type->fieldList.emplace_back(t, String(name), detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t));
return {};
return ox::Error(0);
}
return ox::Error(1);
}
@@ -220,7 +220,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t)
auto const lvls = detail::indirectionLevels_v<T> + 1;
SubscriptStack subscriptStack{lvls};
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
return {};
return ox::Error(0);
}
return ox::Error(1);
}
@@ -231,7 +231,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val
const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return {};
return ox::Error(0);
}
return ox::Error(1);
}
@@ -357,7 +357,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::IString, 0, PT, 0);
return getType(types::BString, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typeVersion, PrimitiveType pt, int b,
@@ -380,7 +380,7 @@ constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typ
template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
if (std::is_constant_evaluated()) {
std::allocator<T> a;
T *t = a.allocate(1);
@@ -396,7 +396,7 @@ constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept {
TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
OX_RETURN_ERROR(model(&handler, &val));
return writer.definition();
}

View File

@@ -31,25 +31,25 @@ class FieldCounter {
template<typename U>
constexpr ox::Error field(StringViewCR, U) noexcept {
++fields;
return {};
return ox::Error(0);
}
template<typename U>
constexpr ox::Error field(StringViewCR, U, std::size_t) noexcept {
++fields;
return {};
return ox::Error(0);
}
template<typename U, typename Handler>
constexpr Error field(StringViewCR, Handler) {
++fields;
return {};
return ox::Error(0);
}
template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept {
++fields;
return {};
return ox::Error(0);
}
static constexpr auto opType() noexcept {

View File

@@ -17,177 +17,176 @@ namespace ox {
template<typename Handler, OpType opType_v = Handler::opType()>
class ModelHandlerInterface {
private:
Handler &m_handler;
Handler *m_handler = nullptr;
public:
constexpr explicit ModelHandlerInterface(Handler &handler) noexcept: m_handler(handler) {
constexpr explicit ModelHandlerInterface(Handler *handler) noexcept: m_handler(handler) {
}
template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo(
CString name = T::TypeName,
const char* name = T::TypeName,
int version = T::TypeVersion,
Vector<String> const &typeParams = {}) noexcept {
return m_handler.template setTypeInfo<T>(name, version, typeParams, ModelFieldCount_v<T>);
const Vector<String>& typeParams = {}) noexcept {
return m_handler->template setTypeInfo<T>(name, version, typeParams, ModelFieldCount_v<T>);
}
template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo(
CString name,
const char *name,
int version,
Vector<String> const &typeParams,
size_t fields) noexcept {
return m_handler.template setTypeInfo<T>(name, version, typeParams, fields);
const Vector<String>& typeParams,
std::size_t fields) noexcept {
return m_handler->template setTypeInfo<T>(name, version, typeParams, fields);
}
template<size_t len>
constexpr Error fieldCString(CString name, char val[len]) noexcept {
return m_handler.fieldCString(name, &val[0], len);
template<std::size_t len>
constexpr Error fieldCString(const char *name, char val[len]) noexcept {
return m_handler->fieldCString(name, &val[0], len);
}
template<size_t len>
constexpr Error fieldCString(CString name, char const val[len]) noexcept requires(opType_v != OpType::Read) {
template<std::size_t len>
constexpr Error fieldCString(const char *name, const char val[len]) noexcept requires(opType_v != OpType::Read) {
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, &val[0], len);
return m_handler->fieldCString(name, &val[0], len);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char **val) noexcept {
return m_handler.fieldCString(name, val);
constexpr Error fieldCString(const char *name, char **val) noexcept {
return m_handler->fieldCString(name, val);
}
constexpr Error fieldCString(CString name, char const *const*val) noexcept requires(opType_v != OpType::Read) {
constexpr Error fieldCString(const char *name, const char *const*val) noexcept requires(opType_v != OpType::Read) {
// this check looks pointless, but it's to address a Clang bug
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, val);
return m_handler->fieldCString(name, val);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char const **val) noexcept requires(opType_v != OpType::Read) {
constexpr Error fieldCString(const char *name, const char **val) noexcept requires(opType_v != OpType::Read) {
// this check looks pointless, but it's to address a Clang bug
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, val);
return m_handler->fieldCString(name, val);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char **val, size_t buffLen) noexcept {
return m_handler.fieldCString(name, val, buffLen);
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error fieldCString(CString name, char const **val, size_t buffLen) noexcept requires(opType_v != OpType::Read) {
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept requires(opType_v != OpType::Read) {
// this check looks pointless, but it's to address a Clang bug
if constexpr(opType_v != OpType::Read) {
return m_handler.fieldCString(name, val, buffLen);
return m_handler->fieldCString(name, val, buffLen);
} else {
return {};
}
}
constexpr Error fieldCString(CString name, char *val, size_t buffLen) noexcept {
return m_handler.fieldCString(name, val, buffLen);
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error fieldModelValue(char const *name, CommonPtrWith<ModelValue> auto *v) noexcept {
constexpr Error fieldModelValue(const char *name, CommonPtrWith<ModelValue> auto *v) noexcept {
switch (v->type()) {
case ModelValue::Type::Undefined:
break;
case ModelValue::Type::Bool:
return m_handler.field(name, &v->template get<bool>());
return m_handler->field(name, &v->template get<bool>());
case ModelValue::Type::UnsignedInteger8:
return m_handler.field(name, &v->template get<uint8_t>());
return m_handler->field(name, &v->template get<uint8_t>());
case ModelValue::Type::UnsignedInteger16:
return m_handler.field(name, &v->template get<uint16_t>());
return m_handler->field(name, &v->template get<uint16_t>());
case ModelValue::Type::UnsignedInteger32:
return m_handler.field(name, &v->template get<uint32_t>());
return m_handler->field(name, &v->template get<uint32_t>());
case ModelValue::Type::UnsignedInteger64:
return m_handler.field(name, &v->template get<uint64_t>());
return m_handler->field(name, &v->template get<uint64_t>());
case ModelValue::Type::SignedInteger8:
return m_handler.field(name, &v->template get<int8_t>());
return m_handler->field(name, &v->template get<int8_t>());
case ModelValue::Type::SignedInteger16:
return m_handler.field(name, &v->template get<int16_t>());
return m_handler->field(name, &v->template get<int16_t>());
case ModelValue::Type::SignedInteger32:
return m_handler.field(name, &v->template get<int32_t>());
return m_handler->field(name, &v->template get<int32_t>());
case ModelValue::Type::SignedInteger64:
return m_handler.field(name, &v->template get<int64_t>());
return m_handler->field(name, &v->template get<int64_t>());
case ModelValue::Type::String:
return m_handler.field(name, &v->template get<String>());
return m_handler->field(name, &v->template get<String>());
case ModelValue::Type::Object:
return m_handler.field(name, &v->template get<ModelObject>());
return m_handler->field(name, &v->template get<ModelObject>());
case ModelValue::Type::Union:
{
auto &u = v->template get<ModelUnion>();
if constexpr(opType_v == OpType::Read) {
u.setActiveField(whichFieldPresent(m_handler, name, u));
return m_handler.field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
u.setActiveField(m_handler->whichFieldPresent(name, u));
return m_handler->field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
} else {
return m_handler.field(name, UnionView<ModelUnion const, true>(&u, u.unionIdx()));
return m_handler->field(name, UnionView<const ModelUnion, true>(&u, u.unionIdx()));
}
}
case ModelValue::Type::Vector:
return m_handler.field(name, &v->template get<ModelValueVector>());
return m_handler->field(name, &v->template get<ModelValueVector>());
case ModelValue::Type::InlineArray:
return m_handler.field(name, &v->template get<ModelValueArray>());
return m_handler->field(name, &v->template get<ModelValueArray>());
}
oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type()));
ox::panic("invalid type");
oxPanic(ox::Error(1), "invalid type");
return ox::Error(1, "invalid type");
}
// array handler, with callback to allow handling individual elements
template<typename T, typename Callback>
constexpr Error field(CString name, Callback cb) noexcept {
return m_handler.template field<T, Callback>(name, cb);
constexpr Error field(const char *name, Callback cb) noexcept {
return m_handler->template field<T, Callback>(name, cb);
}
template<typename T>
constexpr Error field(CString name, const T *v) noexcept {
constexpr Error field(const char *name, const T *v) noexcept {
if constexpr(ox::is_same_v<T, ModelValue>) {
return fieldModelValue(name, v);
} else {
return m_handler.field(name, v);
return m_handler->field(name, v);
}
}
template<typename T>
constexpr Error field(CString name, T *v) noexcept {
constexpr Error field(const char *name, T *v) noexcept {
if constexpr(ox::is_same_v<T, ModelValue>) {
return fieldModelValue(name, v);
} else {
return m_handler.field(name, v);
return m_handler->field(name, v);
}
}
template<typename U, bool force = false>
constexpr Error field(CString name, UnionView<U, force> val) noexcept {
return m_handler.field(name, val);
constexpr Error field(const char *name, UnionView<U, force> val) noexcept {
return m_handler->field(name, val);
}
constexpr Error field(CString name, auto *val, size_t len) noexcept {
return m_handler.field(name, val, len);
constexpr Error field(const char *name, auto *val, std::size_t len) noexcept {
return m_handler->field(name, val, len);
}
/**
* Reads an array length from the current location in the buffer.
* @param name
* @param pass indicates that the parsing should iterate past the array length
*/
[[nodiscard]]
constexpr auto arrayLength(CString name, bool pass = true) noexcept {
return m_handler.arrayLength(name, pass);
constexpr auto arrayLength(const char *name, bool pass = true) noexcept {
return m_handler->arrayLength(name, pass);
}
/**
* Reads an string length from the current location in the buffer.
*/
[[nodiscard]]
constexpr auto stringLength(CString name) noexcept {
return m_handler.stringLength(name);
constexpr auto stringLength(const char *name) noexcept {
return m_handler->stringLength(name);
}
[[nodiscard]]
@@ -199,33 +198,22 @@ class ModelHandlerInterface {
constexpr auto handler() noexcept {
return m_handler;
}
private:
template<typename H>
static constexpr int whichFieldPresent(H &h, CString name, ModelUnion const &u) noexcept
requires(H::opType() == OpType::Read) {
return h.whichFieldPresent(name, u);
}
template<typename H>
static constexpr int whichFieldPresent(H&, CString, ModelUnion const&) noexcept
requires(H::opType() != OpType::Read) {
return 0;
}
};
template<typename Handler, OpType opType_v = Handler::opType()>
template<typename Handler, ox::OpType opType_v = Handler::opType()>
class ModelHandlerBase {
private:
ModelHandlerInterface<Handler, opType_v> m_interface{*static_cast<Handler*>(this)};
ModelHandlerInterface<Handler, opType_v> m_interface;
public:
constexpr ModelHandlerBase() noexcept: m_interface(static_cast<Handler*>(this)) {}
constexpr ModelHandlerBase(const ModelHandlerBase&) noexcept: m_interface(static_cast<Handler*>(this)) {}
constexpr ModelHandlerBase(ModelHandlerBase&&) noexcept: m_interface(static_cast<Handler*>(this)) {}
[[nodiscard]]
constexpr auto interface() noexcept {
return &m_interface;
}
[[nodiscard]]
static constexpr OpType opType() noexcept {
static constexpr ox::OpType opType() noexcept {
return opType_v;
}
};

View File

@@ -56,19 +56,19 @@ class MemberList {
template<typename T>
constexpr Error field(const char*, T *v) noexcept {
vars[m_i++] = static_cast<void*>(v);
return {};
return ox::Error(0);
}
template<typename T>
constexpr Error field(const char*, T *v, int) noexcept {
vars[m_i++] = static_cast<void*>(v);
return {};
return ox::Error(0);
}
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
vars[m_i++] = static_cast<void*>(u.get());
return {};
return ox::Error(0);
}
template<typename T>
@@ -107,7 +107,7 @@ class Copier {
auto &dst = *cbit_cast<FT*>(m_dst->vars[m_i]);
dst = src;
++m_i;
return {};
return ox::Error(0);
}
}
@@ -119,7 +119,7 @@ class Copier {
dst = src;
}
++m_i;
return {};
return ox::Error(0);
}
template<typename U, bool force = false>
@@ -128,7 +128,7 @@ class Copier {
auto &src = *u.get();
dst = src;
++m_i;
return {};
return ox::Error(0);
}
template<typename T = void>
@@ -168,7 +168,7 @@ class Mover {
dst = std::move(src);
src = FT{};
++m_i;
return {};
return ox::Error(0);
}
}
@@ -181,7 +181,7 @@ class Mover {
src = FT{};
}
++m_i;
return {};
return ox::Error(0);
}
template<typename U, bool force = false>
@@ -190,7 +190,7 @@ class Mover {
auto &src = *u.get();
dst = std::move(src);
++m_i;
return {};
return ox::Error(0);
}
template<typename T = void>
@@ -228,7 +228,7 @@ class Equals {
const auto &dst = std::bit_cast<FT>(*m_other->vars[m_i]);
++m_i;
if (dst == src) {
return {};
return ox::Error(0);
} else {
this->value = false;
return ox::Error(1);
@@ -246,7 +246,7 @@ class Equals {
}
}
++m_i;
return {};
return ox::Error(0);
}
template<typename U, bool force = false>
@@ -255,7 +255,7 @@ class Equals {
const auto &src = *u.get();
++m_i;
if (dst == src) {
return {};
return ox::Error(0);
} else {
this->value = false;
return ox::Error(1);

View File

@@ -6,23 +6,18 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/hashmap.hpp>
#include "modelvalue.hpp"
namespace ox {
static_assert([]() -> Error {
ModelValue v;
static_assert([]() -> ox::Error {
ox::ModelValue v;
OX_RETURN_ERROR(v.setType<int32_t>());
if (v.type() != ModelValue::Type::SignedInteger32) {
return Error(1, "type is wrong");
return ox::Error(1, "type is wrong");
}
//oxReturnError(v.set<int32_t>(5));
return {};
}() == Error{});
// a dummy function to prevent linker errors in a library that has no other symbols
void modelDummyFunc() noexcept {}
}() == ox::Error(0));
}

View File

@@ -100,7 +100,7 @@ class ModelValue {
return Type::Union;
} else if constexpr(is_same_v<U, ModelObject>) {
return Type::Object;
} else if constexpr(isBasicString_v<U> || isIString_v<U>) {
} else if constexpr(isBasicString_v<U> || isBString_v<U>) {
return Type::String;
} else if constexpr(is_same_v<U, ModelValueVector>) {
return Type::Vector;
@@ -168,7 +168,7 @@ class ModelValue {
constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
ox::panic("invalid cast");
oxPanic(ox::Error(1), "invalid cast");
}
return getValue<type>(*this);
}
@@ -178,7 +178,7 @@ class ModelValue {
constexpr auto &get() noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
ox::panic("invalid cast");
oxPanic(ox::Error(1), "invalid cast");
}
return getValue<type>(*this);
}
@@ -187,7 +187,7 @@ class ModelValue {
constexpr Type type() const noexcept;
constexpr Error setType(
DescriptorType const *type,
DescriptorType const*type,
SubscriptStack const& = {},
int subscriptLevels = 0) noexcept;
@@ -200,6 +200,8 @@ class ModelValue {
template<typename T>
constexpr Error set(T &&v) noexcept;
constexpr ModelValue &operator=(ModelValue &val) noexcept;
constexpr ModelValue &operator=(const ModelValue &val) noexcept;
constexpr ModelValue &operator=(ModelValue &&val) noexcept;
@@ -273,7 +275,7 @@ class ModelValueArray {
}
constexpr Error setType(
DescriptorType const *type,
DescriptorType const*type,
SubscriptStack subscriptStack,
int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
@@ -416,7 +418,7 @@ class ModelValueVector {
}
constexpr Error setType(
DescriptorType const *type,
DescriptorType const*type,
SubscriptStack subscriptStack,
int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
@@ -519,7 +521,7 @@ class ModelObject {
protected:
OX_MODEL_FRIEND(ModelObject);
friend ModelValue;
Vector<UPtr<Field>> m_fieldsOrder;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields;
const DescriptorType *m_type = nullptr;
@@ -692,7 +694,7 @@ class ModelUnion {
};
friend constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept;
friend ModelValue;
Vector<UPtr<Field>> m_fieldsOrder;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields;
const DescriptorType *m_type = nullptr;
int m_unionIdx = -1;
@@ -718,14 +720,14 @@ class ModelUnion {
m_unionIdx = other.m_unionIdx;
}
static constexpr Result<UPtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UPtr<ModelUnion> out(new ModelUnion);
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UniquePtr<ModelUnion> out(new ModelUnion);
OX_RETURN_ERROR(out->setType(type));
return out;
}
static constexpr Result<UPtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UPtr<ModelUnion>(new ModelUnion(other));
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UniquePtr<ModelUnion>(new ModelUnion(other));
}
constexpr ox::Result<ModelValue*> at(StringView const&k) noexcept {
@@ -819,7 +821,7 @@ class ModelUnion {
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(ModelValueArray const *v) noexcept {
constexpr std::size_t sizeOf(ModelValueArray const*v) noexcept {
return sizeOf<PlatSpec>(&(*v)[0]) * v->size();
}
@@ -970,7 +972,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
for (auto &f : obj->m_fieldsOrder) {
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
}
return {};
return ox::Error(0);
}
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
@@ -979,7 +981,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
for (auto &f : obj->m_fieldsOrder) {
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
}
return {};
return ox::Error(0);
}
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
@@ -995,7 +997,7 @@ constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
m_data = other.m_data;
ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
@@ -1028,8 +1030,8 @@ constexpr ModelValue::ModelValue(ModelValue &&other) noexcept {
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
m_data = other.m_data;
other.m_data.ui64 = 0;
ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
ox::memset(&other.m_data, 0, sizeof(m_data));
break;
case Type::String:
m_data.str = other.m_data.str;
@@ -1096,7 +1098,7 @@ constexpr Error ModelValue::setType(
} else if (type->typeName == types::Bool) {
m_type = Type::Bool;
} else if (type->typeName == types::BasicString ||
type->typeName == types::IString ||
type->typeName == types::BString ||
type->typeName == types::String) {
m_type = Type::String;
m_data.str = new String;
@@ -1127,7 +1129,7 @@ constexpr Error ModelValue::setType(
OX_RETURN_ERROR(m_data.uni->setType(type));
}
oxAssert(m_type != Type::Undefined, "No type set");
return {};
return ox::Error(0);
}
template<typename T>
@@ -1174,7 +1176,7 @@ template<typename T>
constexpr Error ModelValue::set(const T &v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return Error(1, "type mismatch");
return ox::Error(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
@@ -1182,7 +1184,7 @@ constexpr Error ModelValue::set(const T &v) noexcept {
safeDelete(&value);
}
value = v;
return {};
return ox::Error(0);
}
template<typename T>
@@ -1197,7 +1199,11 @@ constexpr Error ModelValue::set(T &&v) noexcept {
safeDelete(&value);
}
value = std::move(v);
return {};
return ox::Error(0);
}
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
return this->operator=(const_cast<const ModelValue&>(other));
}
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
@@ -1217,7 +1223,7 @@ constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
m_data = other.m_data;
ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
@@ -1255,8 +1261,8 @@ constexpr ModelValue &ModelValue::operator=(ModelValue &&other) noexcept {
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
m_data = other.m_data;
other.m_data = {};
ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
ox::memset(&other.m_data, 0, sizeof(m_data));
break;
case Type::String:
m_data.str = other.m_data.str;

View File

@@ -38,17 +38,17 @@ struct TypeNameCatcher {
template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept {
return {};
return ox::Error(0);
}
template<typename T>
constexpr Error field(const char*, T) noexcept {
return {};
return ox::Error(0);
}
template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept {
return {};
return ox::Error(0);
}
static constexpr auto opType() noexcept {
@@ -77,17 +77,17 @@ struct TypeInfoCatcher {
template<typename T>
constexpr Error field(const char*, T*, std::size_t) noexcept {
return {};
return ox::Error(0);
}
template<typename T>
constexpr Error field(const char*, T) noexcept {
return {};
return ox::Error(0);
}
template<typename T>
constexpr Error fieldCString(const char*, T) noexcept {
return {};
return ox::Error(0);
}
static constexpr auto opType() noexcept {
@@ -140,16 +140,16 @@ constexpr Str getModelTypeName() noexcept {
return out;
}
template<typename T, typename Str = const char*>
template<typename T>
[[nodiscard]]
consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T, Str>();
static_assert(ox::StringView{name}.size(), "Type lacks required TypeName");
constexpr auto name = getModelTypeName<T>();
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
return name;
}
template<typename T, typename Str = const char*>
constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
constexpr auto ModelTypeName_v = getModelTypeName<T, Str>();
template<typename T, typename Str = const char*>
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
@@ -159,7 +159,7 @@ constexpr auto ModelTypeId_v = [] {
constexpr auto name = ModelTypeName_v<T, ox::StringView>;
constexpr auto version = ModelTypeVersion_v<T>;
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
return ox::sfmt<ox::IString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr);
}();
}

View File

@@ -31,18 +31,18 @@
namespace ox {
namespace types {
constexpr StringLiteral BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringLiteral IString = "net.drinkingtea.ox.IString";
constexpr StringLiteral String = "B.string";
constexpr StringLiteral Bool = "B.bool";
constexpr StringLiteral Uint8 = "B.uint8";
constexpr StringLiteral Uint16 = "B.uint16";
constexpr StringLiteral Uint32 = "B.uint32";
constexpr StringLiteral Uint64 = "B.uint64";
constexpr StringLiteral Int8 = "B.int8";
constexpr StringLiteral Int16 = "B.int16";
constexpr StringLiteral Int32 = "B.int32";
constexpr StringLiteral Int64 = "B.int64";
constexpr StringView BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringView BString = "net.drinkingtea.ox.BString";
constexpr StringView String = "B.string";
constexpr StringView Bool = "B.bool";
constexpr StringView Uint8 = "B.uint8";
constexpr StringView Uint16 = "B.uint16";
constexpr StringView Uint32 = "B.uint32";
constexpr StringView Uint64 = "B.uint64";
constexpr StringView Int8 = "B.int8";
constexpr StringView Int16 = "B.int16";
constexpr StringView Int32 = "B.int32";
constexpr StringView Int64 = "B.int64";
}
template<typename T>
@@ -63,17 +63,17 @@ static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>);
template<typename T>
consteval bool isIString(const T*) noexcept {
consteval bool isBString(const T*) noexcept {
return false;
}
template<std::size_t SmallVecSize>
consteval bool isIString(const BasicString<SmallVecSize>*) noexcept {
consteval bool isBString(const BasicString<SmallVecSize>*) noexcept {
return true;
}
template<typename T>
constexpr bool isIString_v = isIString(static_cast<const T*>(nullptr));
constexpr bool isBString_v = isBasicString(static_cast<const T*>(nullptr));
static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>);
@@ -161,7 +161,7 @@ template<typename T>
constexpr bool isSmartPtr_v = false;
template<typename T>
constexpr bool isSmartPtr_v<::ox::UPtr<T>> = true;
constexpr bool isSmartPtr_v<::ox::UniquePtr<T>> = true;
#if __has_include(<array>)
template<typename T>
@@ -169,12 +169,12 @@ constexpr bool isSmartPtr_v<::std::unique_ptr<T>> = true;
#endif
template<typename Union, bool force = false> requires(force || is_union_v<Union>)
template<typename Union, bool force = false>
class UnionView {
protected:
int m_idx = -1;
Union *m_union = nullptr;
typename enable_if<is_union_v<Union> || force, Union>::type *m_union = nullptr;
public:
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {

View File

@@ -21,7 +21,7 @@ namespace ox {
class TypeStore {
private:
HashMap<String, UPtr<DescriptorType>> m_cache;
HashMap<String, UniquePtr<DescriptorType>> m_cache;
public:
constexpr TypeStore() noexcept = default;
@@ -58,11 +58,7 @@ class TypeStore {
if (!std::is_constant_evaluated()) {
OX_REQUIRE_M(dt, loadDescriptor(typeId));
for (auto &f : dt->fieldList) {
if (typeId == f.typeId) {
f.type = dt.get();
} else {
OX_RETURN_ERROR(this->getLoad(f.typeId).moveTo(f.type));
}
OX_RETURN_ERROR(this->getLoad(f.typeId).moveTo(f.type));
}
auto &out = m_cache[typeId];
out = std::move(dt);
@@ -86,12 +82,12 @@ class TypeStore {
return getLoad(typeName, typeVersion);
}
constexpr void set(const auto &typeId, UPtr<DescriptorType> dt) noexcept {
constexpr void set(const auto &typeId, UniquePtr<DescriptorType> dt) noexcept {
m_cache[typeId] = std::move(dt);
}
constexpr void set(const auto &typeId, DescriptorType *dt) noexcept {
m_cache[typeId] = UPtr<DescriptorType>(dt);
m_cache[typeId] = UniquePtr<DescriptorType>(dt);
}
[[nodiscard]]
@@ -105,11 +101,11 @@ class TypeStore {
}
protected:
virtual Result<UPtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
return ox::Error(1);
}
Result<UPtr<DescriptorType>> loadDescriptor(ox::StringViewCR name, int version,
Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringViewCR name, int version,
const ox::TypeParamPack &typeParams) noexcept {
const auto typeId = buildTypeId(name, version, typeParams);
return loadDescriptor(typeId);

View File

@@ -127,7 +127,7 @@ static constexpr Error parseField(const DescriptorField &field, Reader *rdr, Dat
}
}
walker->popNamePath();
return {};
return ox::Error(0);
}
template<typename Reader, typename FH>
@@ -141,7 +141,7 @@ constexpr Error model(Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
for (const auto &field : fields) {
OX_RETURN_ERROR(parseField(field, rdr, walker));
}
return {};
return ox::Error(0);
}
template<typename Reader, typename Handler>

View File

@@ -13,31 +13,31 @@
namespace ox {
OrganicClawReader::OrganicClawReader(const uint8_t *buff, size_t const buffSize) {
OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) {
auto json = reinterpret_cast<const char*>(buff);
auto jsonLen = ox::strnlen_s(json, buffSize);
auto jsonLen = ox::strnlen(json, buffSize);
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw Exception(1, "Could not parse JSON");
throw ox::Exception(1, "Could not parse JSON");
}
}
OrganicClawReader::OrganicClawReader(CString const json, size_t const jsonLen) {
OrganicClawReader::OrganicClawReader(const char *json, std::size_t jsonLen) {
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw Exception(1, "Could not parse JSON");
throw ox::Exception(1, "Could not parse JSON");
}
}
OrganicClawReader::OrganicClawReader(Json::Value json, int const unionIdx) noexcept:
OrganicClawReader::OrganicClawReader(Json::Value json, int unionIdx) noexcept:
m_json(std::move(json)),
m_unionIdx(unionIdx) {
}
Error OrganicClawReader::field(CString const key, bool *val) noexcept {
Error err{};
Error OrganicClawReader::field(const char *key, bool *val) noexcept {
auto err = ox::Error(0);
if (targetValid()) {
const auto &jv = value(key);
if (jv.empty()) {
@@ -45,16 +45,16 @@ Error OrganicClawReader::field(CString const key, bool *val) noexcept {
} else if (jv.isBool()) {
*val = jv.asBool();
} else {
err = Error(1, "Type mismatch");
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(CString const key, char *val, size_t const buffLen) noexcept {
Error err{};
CString begin = nullptr, end = nullptr;
Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept {
auto err = ox::Error(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (targetValid()) {
if (jv.empty()) {
@@ -64,25 +64,25 @@ Error OrganicClawReader::fieldCString(CString const key, char *val, size_t const
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<size_t>(end - begin);
const auto strSize = static_cast<std::size_t>(end - begin);
auto data = val;
if (strSize >= buffLen) {
err = Error(2, "String size exceeds capacity of destination");
err = ox::Error(2, "String size exceeds capacity of destination");
} else {
memcpy(data, begin, static_cast<size_t>(strSize));
ox::memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
}
} else {
err = Error(1, "Type mismatch");
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(CString const key, char **val) noexcept {
Error err{};
CString begin = nullptr, end = nullptr;
Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
auto err = ox::Error(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
auto &data = *val;
if (targetValid()) {
@@ -92,22 +92,22 @@ Error OrganicClawReader::fieldCString(CString const key, char **val) noexcept {
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<size_t>(end - begin);
const auto strSize = static_cast<std::size_t>(end - begin);
safeDelete(*val);
*val = new char[strSize + 1];
memcpy(data, begin, static_cast<size_t>(strSize));
ox::memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
} else {
err = Error(1, "Type mismatch");
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(CString const key, char **val, size_t const buffLen) noexcept {
Error err{};
CString begin = nullptr, end = nullptr;
Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept {
auto err = ox::Error(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (targetValid()) {
if (jv.empty()) {
@@ -117,29 +117,29 @@ Error OrganicClawReader::fieldCString(CString const key, char **val, size_t cons
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<size_t>(end - begin);
const auto strSize = static_cast<std::size_t>(end - begin);
auto data = val;
if (strSize >= buffLen) {
safeDelete(*val);
*val = new char[strSize + 1];
}
memcpy(data, begin, static_cast<size_t>(strSize));
ox::memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = nullptr;
} else {
err = Error(1, "Type mismatch");
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::field(CString const key, UUID *val) noexcept {
Error OrganicClawReader::field(const char *key, UUID *val) noexcept {
UUIDStr str;
OX_RETURN_ERROR(field(key, &str));
return UUID::fromString(str).moveTo(*val);
}
Result<size_t> OrganicClawReader::arrayLength(CString const key, bool) noexcept {
Result<std::size_t> OrganicClawReader::arrayLength(const char *key, bool) noexcept {
const auto &jv = value(key);
if (jv.empty()) {
return 0;
@@ -147,32 +147,32 @@ Result<size_t> OrganicClawReader::arrayLength(CString const key, bool) noexcept
if (jv.isArray()) {
return jv.size();
}
return Error(1, "Type mismatch");
return ox::Error(1, "Type mismatch");
}
[[nodiscard]]
size_t OrganicClawReader::stringLength(CString const key) noexcept {
CString begin = nullptr, end = nullptr;
std::size_t OrganicClawReader::stringLength(const char *key) noexcept {
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (jv.empty()) {
return 0;
}
if (jv.isString()) {
jv.getString(&begin, &end);
return static_cast<size_t>(end - begin);
return static_cast<std::size_t>(end - begin);
}
return Error(1, "Type mismatch");
return ox::Error(1, "Type mismatch");
}
OrganicClawReader OrganicClawReader::child(CString const key, int const unionIdx) noexcept {
OrganicClawReader OrganicClawReader::child(const char *key, int unionIdx) noexcept {
return OrganicClawReader(value(key), unionIdx);
}
bool OrganicClawReader::fieldPresent(CString const key) noexcept {
bool OrganicClawReader::fieldPresent(const char *key) noexcept {
return !m_json[key].empty();
}
int OrganicClawReader::whichFieldPresent(CString const name, ModelUnion const &u) const noexcept {
int OrganicClawReader::whichFieldPresent(const char *name, const ModelUnion &u) const noexcept {
const auto &obj = m_json[name];
if (!obj.isObject()) {
return -1;
@@ -184,7 +184,7 @@ int OrganicClawReader::whichFieldPresent(CString const name, ModelUnion const &u
return u.getKeyIdx(keys.front().c_str());
}
Json::Value &OrganicClawReader::value(CString const key) noexcept {
Json::Value &OrganicClawReader::value(const char *key) noexcept {
if (m_json.isArray()) {
return m_json[m_fieldIt];
} else {

View File

@@ -8,11 +8,7 @@
#pragma once
#include <ox/std/def.hpp>
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
#include <json/json.h>
OX_ALLOW_UNSAFE_BUFFERS_END
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
@@ -34,76 +30,75 @@ class OrganicClawReader {
private:
Json::Value m_json;
Json::ArrayIndex m_fieldIt = 0;
int const m_unionIdx = -1;
int m_unionIdx = -1;
public:
OrganicClawReader() noexcept = default;
OrganicClawReader(uint8_t const *buff, size_t buffSize);
OrganicClawReader(const uint8_t *buff, std::size_t buffSize);
OrganicClawReader(CString json, size_t buffSize);
OrganicClawReader(const char *json, std::size_t buffSize);
explicit OrganicClawReader(Json::Value json, int unionIdx = -1) noexcept;
Error field(CString key, bool *val) noexcept;
Error field(const char *key, bool *val) noexcept;
// array handler
template<typename T>
Error field(CString key, T *val, size_t len) noexcept;
Error field(const char *key, T *val, std::size_t len) noexcept;
template<typename T>
Error field(CString, HashMap<String, T> *val) noexcept;
Error field(const char*, HashMap<String, T> *val) noexcept;
template<typename T>
Error field(CString key, T *val) noexcept;
Error field(const char *key, T *val) noexcept;
template<typename U, bool force = false>
Error field(CString key, UnionView<U, force> val) noexcept;
Error field(const char *key, UnionView<U, force> val) noexcept;
template<size_t L>
Error field(CString key, BasicString<L> *val) noexcept;
template<std::size_t L>
Error field(const char *key, BasicString<L> *val) noexcept;
template<size_t L>
Error field(CString key, IString<L> *val) noexcept;
template<std::size_t L>
Error field(const char *key, IString<L> *val) noexcept;
Error fieldCString(CString key, char *val, size_t buffLen) noexcept;
Error fieldCString(const char *key, char *val, std::size_t buffLen) noexcept;
Error fieldCString(CString key, char **val) noexcept;
Error fieldCString(const char *key, char **val) noexcept;
Error fieldCString(CString key, char **val, size_t buffLen) noexcept;
Error fieldCString(const char *key, char **val, std::size_t buffLen) noexcept;
Error field(CString key, UUID *val) noexcept;
Error field(const char *key, UUID *val) noexcept;
/**
* Reads an array length from the current location in the buffer.
* @param key
* @param pass indicates that the parsing should iterate past the array length
*/
Result<size_t> arrayLength(CString key, bool pass = true) noexcept;
Result<std::size_t> arrayLength(const char *key, bool pass = true) noexcept;
/**
* Reads an string length from the current location in the buffer.
*/
[[nodiscard]]
size_t stringLength(CString key) noexcept;
std::size_t stringLength(const char *name) noexcept;
template<typename T = void>
constexpr Error setTypeInfo() noexcept {
constexpr ox::Error setTypeInfo() noexcept {
return {};
}
template<typename T = void>
constexpr Error setTypeInfo(CString) noexcept {
constexpr ox::Error setTypeInfo(const char*) noexcept {
return {};
}
template<typename T = void>
constexpr Error setTypeInfo(CString, int, const Vector<String>& = {}) noexcept {
constexpr ox::Error setTypeInfo(const char*, int, const Vector<String>& = {}) noexcept {
return {};
}
template<typename T = void>
constexpr Error setTypeInfo(CString, int, const Vector<String>& = {}, size_t = {}) noexcept {
constexpr ox::Error setTypeInfo(const char*, int, const Vector<String>& = {}, std::size_t = {}) noexcept {
return {};
}
@@ -111,16 +106,16 @@ class OrganicClawReader {
* Returns a OrganicClawReader to parse a child object.
*/
[[nodiscard]]
OrganicClawReader child(CString key, int unionIdx = -1) noexcept;
OrganicClawReader child(const char *key, int unionIdx = -1) noexcept;
// compatibility stub
constexpr void nextField() noexcept {}
[[nodiscard]]
bool fieldPresent(CString key) noexcept;
bool fieldPresent(const char *key) noexcept;
[[nodiscard]]
int whichFieldPresent(CString name, const ModelUnion &u) const noexcept;
int whichFieldPresent(const char *name, const ModelUnion &u) const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
@@ -129,7 +124,7 @@ class OrganicClawReader {
private:
[[nodiscard]]
Json::Value &value(CString key) noexcept;
Json::Value &value(const char *key) noexcept;
[[nodiscard]]
bool targetValid() const noexcept;
@@ -137,102 +132,98 @@ class OrganicClawReader {
};
template<typename T>
Error OrganicClawReader::field(CString key, T *val) noexcept {
Error err{};
Error OrganicClawReader::field(const char *key, T *val) noexcept {
auto err = ox::Error(0);
try {
if constexpr (is_integer_v<T>) {
if (targetValid()) {
auto const &jv = value(key);
auto const&jv = value(key);
auto const rightType = sizeof(T) == 8 ?
(is_signed_v<T> ? jv.isInt64() : jv.isUInt64()) :
(is_signed_v<T> ? jv.isInt() : jv.isUInt());
(ox::is_signed_v<T> ? jv.isInt64() : jv.isUInt64()) :
(ox::is_signed_v<T> ? jv.isInt() : jv.isUInt());
if (jv.empty()) {
*val = 0;
} else if (rightType) {
if constexpr(is_signed_v<T>) {
*val = static_cast<T>(jv.asInt64());
} else {
*val = static_cast<T>(jv.asUInt64());
}
*val = static_cast<T>(jv.asUInt());
} else {
err = Error{1, "Type mismatch"};
err = ox::Error(1, "Type mismatch");
}
}
} else if constexpr (isVector_v<T>) {
auto const &srcVal = value(key);
auto const srcSize = srcVal.size();
OX_RETURN_ERROR(resizeVector(*val, srcSize));
const auto&srcVal = value(key);
const auto srcSize = srcVal.size();
OX_RETURN_ERROR(ox::resizeVector(*val, srcSize));
err = field(key, val->data(), val->size());
} else if constexpr (isArray_v<T>) {
auto const &srcVal = value(key);
auto const srcSize = srcVal.size();
const auto&srcVal = value(key);
const auto srcSize = srcVal.size();
if (srcSize > val->size()) {
err = Error{1, "Input array is too long"};
err = ox::Error(1, "Input array is too long");
} else {
err = field(key, val->data(), val->size());
}
} else if (targetValid()) {
auto const &jv = value(key);
const auto&jv = value(key);
if (jv.empty() || jv.isObject()) {
auto reader = child(key);
ModelHandlerInterface handler(reader);
ModelHandlerInterface handler(&reader);
err = model(&handler, val);
} else {
err = Error{1, "Type mismatch"};
err = ox::Error(1, "Type mismatch");
}
}
} catch (Json::LogicError const &e) {
err = Error{1, "error reading JSON data"};
} catch (Json::LogicError const&) {
err = ox::Error(1, "error reading JSON data");
}
++m_fieldIt;
return err;
}
template<typename U, bool force>
Error OrganicClawReader::field(CString const key, UnionView<U, force> val) noexcept {
Error err{};
Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept {
auto err = ox::Error(0);
if (targetValid()) {
auto const &jv = value(key);
const auto &jv = value(key);
if (jv.empty() || jv.isObject()) {
auto reader = child(key, val.idx());
ModelHandlerInterface handler(reader);
ModelHandlerInterface handler(&reader);
err = model(&handler, val.get());
} else {
err = Error{1, "Type mismatch"};
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
template<size_t L>
Error OrganicClawReader::field(CString const key, BasicString<L> *val) noexcept {
Error err{};
template<std::size_t L>
Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
auto err = ox::Error(0);
if (targetValid()) {
auto const &jv = value(key);
const auto &jv = value(key);
if (jv.empty()) {
*val = BasicString<L>{};
} else if (jv.isString()) {
*val = jv.asString().c_str();
} else {
err = Error{1, "Type mismatch"};
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
template<size_t L>
Error OrganicClawReader::field(CString const key, IString<L> *val) noexcept {
Error err{};
template<std::size_t L>
Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept {
auto err = ox::Error(0);
if (targetValid()) {
auto const &jv = value(key);
const auto &jv = value(key);
if (jv.empty()) {
*val = IString<L>{};
} else if (jv.isString()) {
*val = jv.asString().c_str();
} else {
err = Error{1, "Type mismatch"};
err = ox::Error(1, "Type mismatch");
}
}
++m_fieldIt;
@@ -241,60 +232,60 @@ Error OrganicClawReader::field(CString const key, IString<L> *val) noexcept {
// array handler
template<typename T>
Error OrganicClawReader::field(CString const key, T *val, size_t valLen) noexcept {
auto const &srcVal = value(key);
Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noexcept {
const auto &srcVal = value(key);
if (!srcVal.isNull() && !srcVal.isArray()) {
return Error{1, "Type mismatch"};
return ox::Error(1, "Type mismatch");
}
auto srcSize = srcVal.size();
if (srcSize > valLen) {
return Error{1};
return ox::Error(1);
}
OrganicClawReader r(srcVal);
ModelHandlerInterface handler{r};
ModelHandlerInterface handler{&r};
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
return {};
return ox::Error(0);
}
template<typename T>
Error OrganicClawReader::field(CString const key, HashMap<String, T> *val) noexcept {
auto const &srcVal = value(key);
Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcept {
const auto &srcVal = value(key);
if (!srcVal.isObject()) {
return Error{1, "Type mismatch"};
return ox::Error(1, "Type mismatch");
}
auto keys = srcVal.getMemberNames();
auto srcSize = srcVal.size();
OrganicClawReader r(srcVal);
ModelHandlerInterface handler{r};
ModelHandlerInterface handler{&r};
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
auto const k = keys[i].c_str();
const auto k = keys[i].c_str();
OX_RETURN_ERROR(handler.field(k, &val->operator[](k)));
}
return {};
return ox::Error(0);
}
Error readOC(BufferView const buff, auto &val) noexcept {
Error readOC(BufferView buff, auto &val) noexcept {
// OrganicClawReader constructor can throw, but readOC should return its errors.
try {
Json::Value doc;
Json::CharReaderBuilder parserBuilder;
auto parser = UPtr<Json::CharReader>(parserBuilder.newCharReader());
auto parser = UniquePtr<Json::CharReader>(parserBuilder.newCharReader());
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
if (!parser->parse(buff.data(), buff.data() + buff.size(), &doc, nullptr)) {
OX_ALLOW_UNSAFE_BUFFERS_END
return Error{1, "Could not parse JSON"};
return ox::Error(1, "Could not parse JSON");
}
OrganicClawReader reader(buff.data(), buff.size());
ModelHandlerInterface handler(reader);
ModelHandlerInterface handler(&reader);
return model(&handler, &val);
} catch (Error const &err) {
} catch (const Error &err) {
return err;
} catch (...) {
return Error{1, "Unknown Error"};
return ox::Error(1, "Unknown Error");
}
}
@@ -306,8 +297,8 @@ Result<T> readOC(BufferView buff) noexcept {
}
template<typename T>
Result<T> readOC(StringViewCR json) noexcept {
return readOC<T>(BufferView{json.data(), json.size()});
Result<T> readOC(ox::StringView json) noexcept {
return readOC<T>(ox::BufferView{json.data(), json.len()});
}
}

View File

@@ -10,29 +10,29 @@
namespace ox {
OrganicClawWriter::OrganicClawWriter(int const unionIdx) noexcept: m_unionIdx(unionIdx) {
OrganicClawWriter::OrganicClawWriter(int unionIdx) noexcept: m_unionIdx(unionIdx) {
}
OrganicClawWriter::OrganicClawWriter(Json::Value json, int const unionIdx) noexcept:
OrganicClawWriter::OrganicClawWriter(Json::Value json, int unionIdx) noexcept:
m_json(std::move(json)),
m_unionIdx(unionIdx) {
}
Error OrganicClawWriter::fieldCString(const char *key, const char *const *val, int const len) noexcept {
Error OrganicClawWriter::fieldCString(const char *key, const char *const*val, int len) noexcept {
if (targetValid() && len) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error OrganicClawWriter::fieldCString(const char *key, const char *const *val) noexcept {
Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) noexcept {
return fieldCString(key, const_cast<const char**>(val), static_cast<int>(ox::strlen(val)));
}
Error OrganicClawWriter::field(const char *key, UUID const *uuid) noexcept {
Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept {
const auto uuidStr = uuid->toString();
if (targetValid() && uuidStr.size()) {
if (targetValid() && uuidStr.len()) {
value(key) = uuidStr.c_str();
}
++m_fieldIt;

View File

@@ -8,11 +8,7 @@
#pragma once
#include <ox/std/def.hpp>
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
#include <json/json.h>
OX_ALLOW_UNSAFE_BUFFERS_END
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
@@ -28,85 +24,85 @@ namespace ox {
class OrganicClawWriter {
friend Result<Buffer> writeOC(const auto &val) noexcept;
friend Result<String> writeOCString(const auto &val) noexcept;
friend Result<ox::Buffer> writeOC(const auto &val) noexcept;
friend Result<ox::String> writeOCString(const auto &val) noexcept;
protected:
Json::Value m_json{Json::Value(Json::objectValue)};
Json::ArrayIndex m_fieldIt = 0;
int const m_unionIdx = -1;
int m_unionIdx = -1;
public:
explicit OrganicClawWriter(int unionIdx = -1) noexcept;
explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept;
Error field(CString const key, int8_t const *val) noexcept {
Error field(const char *key, const int8_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, int16_t const *val) noexcept {
Error field(const char *key, const int16_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, int32_t const *val) noexcept {
Error field(const char *key, const int32_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, int64_t const *val) noexcept {
Error field(const char *key, const int64_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, uint8_t const *val) noexcept {
Error field(const char *key, const uint8_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, uint16_t const *val) noexcept {
Error field(const char *key, const uint16_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, uint32_t const *val) noexcept {
Error field(const char *key, const uint32_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(CString const key, uint64_t const *val) noexcept {
Error field(const char *key, const uint64_t *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error field(char const*key, bool const *val) noexcept {
Error field(char const*key, bool const*val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
@@ -118,12 +114,12 @@ class OrganicClawWriter {
Error field(char const*, UnionView<U, force> val) noexcept;
template<typename T>
Error field(char const*key, HashMap<String, T> const *val) noexcept {
Error field(char const*key, HashMap<String, T> const*val) noexcept {
if (targetValid()) {
const auto &keys = val->keys();
OrganicClawWriter w;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
for (size_t i = 0; i < keys.size(); ++i) {
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{&w};
for (std::size_t i = 0; i < keys.size(); ++i) {
const auto k = keys[i].c_str();
if (k) [[likely]] {
OX_REQUIRE_M(value, val->at(k));
@@ -136,49 +132,49 @@ class OrganicClawWriter {
return {};
}
template<size_t L>
Error field(char const*key, IString<L> const *val) noexcept {
if (targetValid() && val->size()) {
template<std::size_t L>
Error field(char const*key, IString<L> const*val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return {};
}
template<size_t L>
Error field(char const*key, BasicString<L> const *val) noexcept {
if (targetValid() && val->size()) {
template<std::size_t L>
Error field(char const*key, BasicString<L> const*val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Error fieldCString(CString, CString const *val, int len) noexcept;
Error fieldCString(const char*, const char *const*val, int len) noexcept;
Error fieldCString(CString name, CString const*val) noexcept;
Error fieldCString(const char *name, const char *const*val) noexcept;
Error field(CString key, UUID const *uuid) noexcept;
Error field(const char *key, const UUID *uuid) noexcept;
template<typename T>
Error field(CString, T const *val, size_t len) noexcept;
Error field(const char*, const T *val, std::size_t len) noexcept;
template<typename T>
Error field(CString, T const *val) noexcept;
Error field(const char*, const T *val) noexcept;
template<typename T>
constexpr Error setTypeInfo(
constexpr ox::Error setTypeInfo(
const char* = T::TypeName,
int = T::TypeVersion) noexcept {
return {};
}
template<typename T>
constexpr Error setTypeInfo(
constexpr ox::Error setTypeInfo(
const char*,
int,
Vector<String> const&,
size_t) noexcept {
const Vector<String>&,
std::size_t) noexcept {
return {};
}
@@ -194,16 +190,16 @@ class OrganicClawWriter {
}
[[nodiscard]]
Json::Value &value(CString key) noexcept;
Json::Value &value(const char *key) noexcept;
};
template<typename T>
Error OrganicClawWriter::field(CString key, T const *val, size_t const len) noexcept {
Error OrganicClawWriter::field(const char *key, const T *val, std::size_t len) noexcept {
if (targetValid() && len) {
OrganicClawWriter w((Json::Value(Json::arrayValue)));
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
for (size_t i = 0; i < len; ++i) {
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{&w};
for (std::size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
@@ -211,74 +207,70 @@ OX_ALLOW_UNSAFE_BUFFERS_END
value(key) = w.m_json;
}
++m_fieldIt;
return {};
return ox::Error(0);
}
template<typename T>
Error OrganicClawWriter::field(CString key, T const *val) noexcept {
Error OrganicClawWriter::field(const char *key, const T *val) noexcept {
if constexpr(is_integer_v<T>) {
if (targetValid() && (*val || m_json.isArray())) {
// the int type needs to be normalized because jsoncpp doesn't
// factor in every permutation unsigned long, etc.
if constexpr(is_signed_v<T>) {
value(key) = static_cast<Int<8 * sizeof(*val)>>(*val);
if constexpr(ox::is_signed_v<T>) {
value(key) = static_cast<ox::Int<8 * sizeof(*val)>>(*val);
} else {
value(key) = static_cast<Uint<8 * sizeof(*val)>>(*val);
value(key) = static_cast<ox::Uint<8 * sizeof(*val)>>(*val);
}
}
} else if constexpr(isVector_v<T> || isArray_v<T>) {
return field(key, val->data(), val->size());
} else if (val && targetValid()) {
OrganicClawWriter w;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{&w};
OX_RETURN_ERROR(model(&handler, val));
if (!w.m_json.empty() || m_json.isArray()) {
value(key) = w.m_json;
}
}
++m_fieldIt;
return {};
return ox::Error(0);
}
template<typename U, bool force>
Error OrganicClawWriter::field(CString key, UnionView<U, force> val) noexcept {
Error OrganicClawWriter::field(const char *key, UnionView<U, force> val) noexcept {
if (targetValid()) {
OrganicClawWriter w(val.idx());
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{&w};
OX_RETURN_ERROR(model(&handler, val.get()));
if (!w.m_json.isNull()) {
value(key) = w.m_json;
}
}
++m_fieldIt;
return {};
return ox::Error(0);
}
Result<Buffer> writeOC(auto const &val) noexcept {
Result<ox::Buffer> writeOC(const auto &val) noexcept {
OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer);
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(&writer);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json);
const auto str = Json::writeString(jsonBuilder, writer.m_json);
Result<Buffer> buff;
buff.value.resize(str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(buff.value.data(), str.data(), str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_END
return buff;
}
Result<String> writeOCString(auto const &val) noexcept {
Result<ox::String> writeOCString(const auto &val) noexcept {
OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer);
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(&writer);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json);
Result<String> buff;
const auto str = Json::writeString(jsonBuilder, writer.m_json);
Result<ox::String> buff;
buff.value.resize(str.size());
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(buff.value.data(), str.data(), str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_END
return buff;
}

View File

@@ -74,7 +74,7 @@ class Preloader: public ModelHandlerBase<Preloader<PlatSpec>, OpType::Reflect> {
const Preloader &operator=(const Preloader &src) = delete;
const Preloader &operator=(Preloader &&src) = delete;
constexpr static ox::Result<ox::UPtr<Preloader>> make(ox::ios_base::seekdir anchor = ox::ios_base::cur,
constexpr static ox::Result<ox::UniquePtr<Preloader>> make(ox::ios_base::seekdir anchor = ox::ios_base::cur,
std::size_t sz = 0) noexcept;
template<typename T>
@@ -141,9 +141,9 @@ class Preloader: public ModelHandlerBase<Preloader<PlatSpec>, OpType::Reflect> {
};
template<typename PlatSpec>
constexpr ox::Result<ox::UPtr<Preloader<PlatSpec>>>
constexpr ox::Result<ox::UniquePtr<Preloader<PlatSpec>>>
Preloader<PlatSpec>::make(ox::ios_base::seekdir anchor, std::size_t sz) noexcept {
auto p = ox::UPtr<Preloader>(new Preloader);
auto p = ox::UniquePtr<Preloader>(new Preloader);
if (const auto err = p->m_writer.seekp(0, anchor)) {
return {std::move(p), err};
}

View File

@@ -33,7 +33,6 @@ add_library(
concepts.cpp
fmt.cpp
heapmgr.cpp
istreamreader.cpp
math.cpp
memops.cpp
random.cpp

View File

@@ -9,25 +9,13 @@
#pragma once
#include "def.hpp"
#include "error.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename It, typename T>
constexpr ox::Result<size_t> findIdx(It begin, It end, T const&value) {
auto it = begin;
for (; it != end; ++it) {
if (*it == value) {
return it.offset();
}
}
return ox::Error{1, "item not found"};
}
template<typename It, typename T>
constexpr It find(It begin, It end, T const&value) {
constexpr It find(It begin, It end, const T &value) {
for (; begin != end; ++begin) {
if (*begin == value) {
return begin;

View File

@@ -15,24 +15,20 @@
namespace ox {
namespace detail {
template<bool unique>
class AnyPtrT {
class AnyPtr {
private:
struct WrapBase {
virtual constexpr ~WrapBase() = default;
virtual constexpr WrapBase *copyTo(Span<char> s) const noexcept = 0;
virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
virtual constexpr operator bool() const noexcept = 0;
virtual void free() noexcept = 0;
};
template<typename T>
struct Wrap final: WrapBase {
struct Wrap: public WrapBase {
T *data{};
explicit constexpr Wrap(T *pData) noexcept: data(pData) {
constexpr Wrap(T *pData) noexcept: data(pData) {
}
constexpr WrapBase *copyTo(Span<char> s) const noexcept override {
constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override {
oxAssert(s.size() >= sizeof(Wrap), "too small buffer");
if (std::is_constant_evaluated()) {
return new Wrap(data);
@@ -43,160 +39,71 @@ class AnyPtrT {
constexpr operator bool() const noexcept override {
return data != nullptr;
}
constexpr void free() noexcept override {
safeDelete(data);
data = {};
}
};
union {
WrapBase *m_wrapPtr{};
AllocAlias<Wrap<void*>> m_wrapData;
} m_data;
WrapBase *m_wrapPtr{};
ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
public:
constexpr AnyPtrT() noexcept = default;
constexpr AnyPtr() noexcept = default;
template<typename T>
constexpr AnyPtrT(T *ptr) noexcept {
constexpr AnyPtr(T *ptr) noexcept {
if (std::is_constant_evaluated()) {
setWrapPtr(new Wrap<T>(ptr));
m_wrapPtr = new Wrap(ptr);
} else {
new(m_data.m_wrapData.data()) Wrap<T>(ptr);
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
}
}
constexpr AnyPtrT(AnyPtrT const &other) noexcept requires(!unique) {
constexpr AnyPtr(AnyPtr const&other) noexcept {
if (other) {
setWrapPtr(other.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
}
}
constexpr AnyPtrT(AnyPtrT &&other) noexcept {
if (other) {
setWrapPtr(other.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
if (std::is_constant_evaluated()) {
ox::safeDelete(m_data.m_wrapPtr);
}
m_data.m_wrapData = {};
}
}
constexpr ~AnyPtrT() noexcept {
if constexpr(unique) {
free();
}
constexpr ~AnyPtr() noexcept {
if (std::is_constant_evaluated()) {
ox::safeDelete(m_data.m_wrapPtr);
ox::safeDelete(m_wrapPtr);
}
}
template<typename T>
constexpr AnyPtrT &operator=(T *ptr) noexcept {
if constexpr(unique) {
free();
} else if (std::is_constant_evaluated()) {
ox::safeDelete(m_data.m_wrapPtr);
}
constexpr AnyPtr &operator=(T *ptr) noexcept {
if (std::is_constant_evaluated()) {
setWrapPtr(new Wrap(ptr));
ox::safeDelete(m_wrapPtr);
m_wrapPtr = new Wrap(ptr);
} else {
new(m_data.m_wrapData.data()) Wrap(ptr);
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
}
return *this;
}
constexpr AnyPtrT &operator=(AnyPtrT const &ptr) noexcept requires(!unique) {
constexpr AnyPtr &operator=(AnyPtr const&ptr) noexcept {
if (this != &ptr) {
if (std::is_constant_evaluated()) {
ox::safeDelete(m_data.m_wrapPtr);
}
if (std::is_constant_evaluated()) {
if (ptr) {
ptr.getWrapPtr()->copyTo(m_data.m_wrapData.buff);
}
} else {
if (ptr) {
setWrapPtr(ptr.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
} else {
setWrapPtr(nullptr);
}
}
}
return *this;
}
constexpr AnyPtrT &operator=(AnyPtrT &&ptr) noexcept {
if (this != &ptr) {
if constexpr(unique) {
free();
} else if (std::is_constant_evaluated()) {
ox::safeDelete(m_data.m_wrapPtr);
}
if (ptr) {
setWrapPtr(ptr.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
if (std::is_constant_evaluated()) {
ox::safeDelete(ptr.m_data.m_wrapPtr);
setWrapPtr(nullptr);
}
ox::safeDelete(m_wrapPtr);
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
} else {
m_data = {};
m_wrapPtr = nullptr;
}
}
return *this;
}
constexpr operator bool() const noexcept {
return getWrapPtr() && *getWrapPtr();
}
constexpr void free() noexcept {
if (auto p = getWrapPtr()) {
p->free();
}
if (std::is_constant_evaluated()) {
ox::safeDelete(m_data.m_wrapPtr);
}
m_data.m_wrapData = {};
return m_wrapPtr && *m_wrapPtr;
}
template<typename T>
[[nodiscard]]
constexpr T *get() const noexcept {
if constexpr(defines::HasRTTI) {
return dynamic_cast<Wrap<T> const*>(getWrapPtr())->data;
}
return static_cast<Wrap<T> const*>(getWrapPtr())->data;
#ifdef OX_BARE_METAL
return static_cast<Wrap<T>*>(m_wrapPtr)->data;
#else
return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
#endif
}
private:
constexpr void setWrapPtr(WrapBase *ptr) noexcept {
if (std::is_constant_evaluated()) {
m_data.m_wrapPtr = ptr;
}
}
constexpr WrapBase *getWrapPtr() noexcept {
if (std::is_constant_evaluated()) {
return m_data.m_wrapPtr;
} else {
return std::launder(reinterpret_cast<WrapBase*>(m_data.m_wrapData.data()));
}
}
constexpr WrapBase const *getWrapPtr() const noexcept {
if (std::is_constant_evaluated()) {
return m_data.m_wrapPtr;
} else {
return std::launder(reinterpret_cast<WrapBase const*>(m_data.m_wrapData.data()));
}
}
};
}
using AnyPtr = detail::AnyPtrT<false>;
using UAnyPtr = detail::AnyPtrT<true>;
}

View File

@@ -181,13 +181,13 @@ constexpr Array<T, ArraySize> &Array<T, ArraySize>::operator=(Array &&other) noe
template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
boundsCheck(i, size(), "Array access overflow");
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i];
}
template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
boundsCheck(i, size(), "Array access overflow");
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i];
}

View File

@@ -7,7 +7,6 @@
*/
#include "fmt.hpp"
#include "realstd.hpp"
#include "stacktrace.hpp"
#include "trace.hpp"
@@ -15,85 +14,57 @@
namespace ox {
void panic(Error const &err, StringViewCR panicMsg, std::source_location const &src) noexcept {
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", src.file_name(), src.line(), panicMsg);
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err) noexcept {
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg);
}
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.src.file_name() != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
}
#ifdef OX_USE_STDLIB
printStackTrace(2);
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << src.file_name() << ":" << src.line() << ")";
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
std::abort();
#else
while (1);
#endif
}
#if __GNUC__ && !_WIN32
__attribute__((weak))
#endif
void panic(Error const &err, char const*panicMsg, std::source_location const &src) noexcept {
panic(err, StringView{panicMsg}, src);
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
panic(StringView{file}, line, StringView{panicMsg}, err);
}
void assertFailFuncRuntime(
StringViewCR assertTxt,
StringViewCR msg,
std::source_location const &src) noexcept {
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept {
#ifdef OX_USE_STDLIB
auto const st = genStackTrace(2);
oxTracef(
"assert", "Failed assert: {} ({}) [{}:{}]:\n{}",
msg,
assertTxt,
src.file_name(),
src.line(),
st);
abort();
auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
output += genStackTrace(2);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
std::abort();
#else
oxErrf(
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
src.file_name(),
src.line(),
msg);
oxTracef(
"assert", "Failed assert: {} ({}) [{}:{}]",
msg,
assertTxt,
src.file_name(),
src.line());
constexprPanic(msg, {}, src);
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
constexprPanic(file, line, msg);
#endif
}
void assertFailFuncRuntime(
[[maybe_unused]] Error const &err,
StringViewCR,
StringViewCR assertMsg,
std::source_location const &src) noexcept {
void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
#if defined(OX_USE_STDLIB)
auto msg = sfmt(
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
src.file_name(),
src.line(),
assertMsg);
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) {
msg += sfmt("\tError Message:\t{}\n", err.msg);
}
msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.src.file_name() != nullptr) {
msg += sfmt("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
if (err.file != nullptr) {
msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line);
}
msg += genStackTrace(2);
oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, src.file_name(), src.line());
abort();
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
std::abort();
#else
constexprPanic(assertMsg, {}, src);
constexprPanic(file, line, assertMsg);
#endif
}

View File

@@ -8,6 +8,10 @@
#pragma once
#if defined(OX_USE_STDLIB)
#include <iostream>
#endif
#include "def.hpp"
#include "defines.hpp"
#include "error.hpp"
@@ -18,96 +22,50 @@
namespace ox {
[[noreturn]]
void panic(
Error const&err,
StringViewCR panicMsg,
std::source_location const &src = std::source_location::current()) noexcept;
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept;
[[noreturn]]
inline void panic(
StringViewCR panicMsg,
std::source_location const &src = std::source_location::current()) noexcept {
panic(Error{1}, panicMsg, src);
}
[[noreturn]]
constexpr void constexprPanic(
StringViewCR panicMsg,
Error const &err = {},
std::source_location const &src = std::source_location::current()) noexcept {
constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept {
if (!std::is_constant_evaluated()) {
panic(err, panicMsg, src);
panic(file, line, panicMsg, err);
} else {
while (true);
}
}
void assertFailFuncRuntime(
StringViewCR assertTxt,
StringViewCR msg,
std::source_location const &src = std::source_location::current()) noexcept;
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept;
void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
void assertFailFuncRuntime(
Error const &err,
StringViewCR,
StringViewCR assertMsg,
std::source_location const &src = std::source_location::current()) noexcept;
constexpr void assertFunc(
bool const pass,
[[maybe_unused]]StringViewCR assertTxt,
[[maybe_unused]]StringViewCR msg,
std::source_location const &src = std::source_location::current()) noexcept {
constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept {
if (!pass) {
if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(assertTxt, msg, src);
assertFailFuncRuntime(file, line, assertTxt, msg);
} else {
while (true);
}
}
}
constexpr void assertFunc(
Error const &err,
StringViewCR,
StringViewCR assertMsg,
std::source_location const &src = std::source_location::current()) noexcept {
constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
if (err) {
if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(err, {}, assertMsg, src);
assertFailFuncRuntime(file, line, err, {}, assertMsg);
} else {
while (true);
}
}
}
constexpr void expect(
auto const &actual,
auto const &expected,
std::source_location const &src = std::source_location::current()) noexcept {
constexpr void expect(StringViewCR file, int line, const auto &actual, const auto &expected) noexcept {
if (actual != expected) {
if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
oxErrf(
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
src.file_name(),
src.line(),
"Value incorrect");
oxErrf(
"expected: {}\nactual: {}\n",
detail::toStringView<true>(expected),
detail::toStringView<true>(actual));
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, "Value incorrect");
oxErrf("expected: {}\nactual: {}\n", detail::toStringView<true>(expected), detail::toStringView<true>(actual));
printStackTrace(2);
oxTracef(
"assert.expect", "Failed assert: {} == {} [{}:{}]",
detail::toStringView<true>(actual),
detail::toStringView<true>(expected),
src.file_name(),
src.line());
oxTracef("assert.expect", "Failed assert: {} == {} [{}:{}]", detail::toStringView<true>(actual), detail::toStringView<true>(expected), file, line);
std::abort();
#else
constexprPanic("Comparison failed", {}, src);
constexprPanic(file, line, "Comparison failed");
#endif
} else {
while (true);

View File

@@ -185,7 +185,7 @@ class BaseStringView {
}
[[nodiscard]]
constexpr auto size() const noexcept {
constexpr auto len() const noexcept {
return m_len;
}

View File

@@ -17,19 +17,19 @@ namespace ox {
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 1) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 1, T>::type i) noexcept {
return i;
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 2) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 2, T>::type i) noexcept {
return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
}
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 4) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept {
return ((i >> 24) & 0x000000ff) |
((i >> 8) & 0x0000ff00) |
((i << 8) & 0x00ff0000) |
@@ -38,7 +38,7 @@ constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 4) {
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 8) {
constexpr T byteSwap(typename enable_if<sizeof(T) == 8, T>::type i) noexcept {
return ((i >> 56) & 0x00000000000000ff) |
((i >> 40) & 0x000000000000ff00) |
((i >> 24) & 0x0000000000ff0000) |

View File

@@ -32,8 +32,4 @@ concept Integral_c = ox::is_integral_v<T>;
template<typename T, size_t max>
concept IntegerRange_c = ox::is_integer_v<T> && ox::MaxValue<T> >= max;
template<typename Union>
concept Union_c = is_union_v<Union>;
}

View File

@@ -21,13 +21,13 @@ class CStringView: public detail::BaseStringView {
constexpr CStringView(CStringView const&sv) noexcept = default;
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(std::nullptr_t) noexcept {}
@@ -37,7 +37,7 @@ class CStringView: public detail::BaseStringView {
constexpr auto &operator=(CStringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.size());
set(other.data(), other.len());
}
return *this;
}

View File

@@ -30,12 +30,9 @@ constexpr T1 strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
}
[[nodiscard]]
constexpr size_t strnlen_s(const char *str, size_t const maxLen) noexcept {
if (!str) [[unlikely]] {
return 0;
}
size_t len = 0;
for (; len < maxLen && str[len]; len++);
constexpr auto strnlen(const char *str1, std::size_t maxLen) noexcept {
std::size_t len = 0;
for (; len < maxLen && str1[len]; len++);
return len;
}

View File

@@ -48,8 +48,9 @@
// Asserts
#define oxPanic(errCode, msg) ox::panic(__FILE__, __LINE__, msg, errCode)
#ifndef NDEBUG
#define oxAssert(pass, msg) ox::assertFunc(pass, #pass, msg)
#define oxAssert(pass, msg) ox::assertFunc(__FILE__, __LINE__, pass, #pass, msg)
#else
namespace ox {
struct [[nodiscard]] Error;
@@ -58,6 +59,8 @@ constexpr void oxAssert(bool, const char*) noexcept {}
constexpr void oxAssert(const ox::Error&, const char*) noexcept {}
#endif
#define oxExpect(actual, expected) ox::expect(__FILE__, __LINE__, actual, expected)
// Alloca
#if defined(_MSC_VER)

View File

@@ -41,24 +41,12 @@ constexpr auto Debug = true;
constexpr auto Debug = false;
#endif
#if defined(OX_CHECK_BOUNDS)
constexpr auto CheckBounds = true;
#else
constexpr auto CheckBounds = Debug;
#endif
#if defined(NDEBUG)
constexpr auto NDebug = true;
#else
constexpr auto NDebug = false;
#endif
#if defined(OX_BARE_METAL)
constexpr auto HasRTTI = false;
#else
constexpr auto HasRTTI = true;
#endif
#if defined(__BIG_ENDIAN__)
constexpr auto BigEndian = true;
constexpr auto LittleEndian = false;

View File

@@ -17,7 +17,7 @@ class exception {
virtual ~exception() = default;
[[nodiscard]]
virtual char const *what() const noexcept {
virtual char const*what() const noexcept {
return "";
}
};
@@ -36,25 +36,38 @@ using ErrorCode = uint16_t;
struct [[nodiscard]] Error {
std::source_location src;
CString msg = nullptr;
ox::CString msg = nullptr;
ox::CString file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0;
constexpr Error() noexcept = default;
explicit constexpr Error(
ox::CString file,
uint32_t const line,
ErrorCode const errCode,
std::source_location const &src = std::source_location::current()) noexcept:
src{src},
ox::CString msg = nullptr) noexcept:
msg{msg},
file{file},
line{static_cast<uint16_t>(line)},
errCode{errCode} {}
explicit constexpr Error(
ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept:
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode}
{}
explicit constexpr Error(
ErrorCode const errCode,
CString const msg,
std::source_location const &src = std::source_location::current()) noexcept:
src{src},
ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept:
msg{msg},
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode}
{}
@@ -62,85 +75,70 @@ struct [[nodiscard]] Error {
return errCode;
}
constexpr void throwException() const;
constexpr Error reoriginate(
ErrorCode const pErrCode,
CString const pMsg = nullptr,
std::source_location const &pSrc = std::source_location::current()) const noexcept {
return Error{pErrCode, pMsg, pSrc};
}
constexpr Error reoriginate(
std::source_location const &pSrc = std::source_location::current()) const noexcept {
return Error{errCode, msg, pSrc};
}
};
[[nodiscard]]
constexpr auto errCode(Error const &err) noexcept {
constexpr auto errCode(Error const&err) noexcept {
return err.errCode;
}
template<typename T = char const*>
[[nodiscard]]
constexpr auto toStr(Error const &err) noexcept {
constexpr auto toStr(Error const&err) noexcept {
return err.msg ? T{err.msg} : "";
}
struct Exception: public std::exception {
std::source_location src;
CString msg = nullptr;
ox::CString msg = nullptr;
ox::CString file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0;
explicit Exception(
explicit inline Exception(ox::CString file, uint32_t line, ErrorCode errCode, char const*msg = "") noexcept {
this->file = file;
this->line = static_cast<uint16_t>(line);
this->msg = msg;
this->errCode = errCode;
}
explicit inline Exception(
ErrorCode const errCode,
std::source_location const &src = std::source_location::current()) noexcept:
src{src},
std::source_location const&src = std::source_location::current()) noexcept:
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {}
explicit Exception(
explicit inline Exception(
ErrorCode const errCode,
CString msg,
std::source_location const &src = std::source_location::current()) noexcept:
src{src},
ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept:
msg{msg},
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {}
explicit Exception(Error const &err) noexcept:
src{err.src},
explicit inline Exception(Error const&err) noexcept:
msg{err.msg ? err.msg : ""},
file{err.file},
line{err.line},
errCode{err.errCode} {}
constexpr Error toError() const noexcept {
return Error(errCode, msg, src);
return Error(file, line, errCode, msg);
}
[[nodiscard]]
char const *what() const noexcept override {
char const*what() const noexcept override {
return msg;
}
};
constexpr void Error::throwException() const {
if (errCode) [[unlikely]] {
throw Exception{*this};
}
}
[[noreturn]]
void panic(
Error const &err,
CString panicMsg,
std::source_location const &src = std::source_location::current()) noexcept;
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
template<typename T>
struct [[nodiscard]] Result {
using type = remove_reference_t<T>;
using type = typename remove_reference<T>::type;
T value;
Error error;
@@ -149,25 +147,25 @@ struct [[nodiscard]] Result {
}
template<typename U>
constexpr Result(Result<U> const &other) noexcept: value(other.value), error(other.error) {
constexpr Result(Result<U> const&other) noexcept: value(other.value), error(other.error) {
}
template<typename U>
constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
}
constexpr Result(Error const &error) noexcept: value(), error(error) {
constexpr Result(Error const&error) noexcept: value(), error(error) {
}
constexpr Result(type const &value, Error const &error = {}) noexcept: value(value), error(error) {
constexpr Result(type const&value, Error const&error = {}) noexcept: value(value), error(error) {
}
constexpr Result(type &&value, Error const &error = {}) noexcept: value(std::move(value)), error(error) {
constexpr Result(type &&value, Error const&error = {}) noexcept: value(std::move(value)), error(error) {
}
constexpr ~Result() noexcept = default;
explicit constexpr operator type const &() const noexcept {
explicit constexpr operator type const&() const noexcept {
return value;
}
@@ -181,7 +179,7 @@ struct [[nodiscard]] Result {
}
template<typename U>
constexpr Error copyTo(U &val) const & noexcept {
constexpr Error copyTo(U &val) const& noexcept {
if (!error) [[likely]] {
val = value;
}
@@ -207,7 +205,7 @@ struct [[nodiscard]] Result {
[[nodiscard]]
constexpr T &unwrap() & noexcept {
if (error) {
ox::panic(error, "Failed unwrap");
oxPanic(error, "Failed unwrap");
}
return value;
}
@@ -215,15 +213,15 @@ struct [[nodiscard]] Result {
[[nodiscard]]
constexpr T &&unwrap() && noexcept {
if (error) {
ox::panic(error, "Failed unwrap");
oxPanic(error, "Failed unwrap");
}
return std::move(value);
}
[[nodiscard]]
constexpr T const &unwrap() const & noexcept {
constexpr T const&unwrap() const & noexcept {
if (error) [[unlikely]] {
ox::panic(error, "Failed unwrap");
oxPanic(error, "Failed unwrap");
}
return value;
}
@@ -231,7 +229,7 @@ struct [[nodiscard]] Result {
[[nodiscard]]
constexpr T &unwrapThrow() & {
if (error) {
throw Exception(error);
throw ox::Exception(error);
}
return value;
}
@@ -239,13 +237,13 @@ struct [[nodiscard]] Result {
[[nodiscard]]
constexpr T &&unwrapThrow() && {
if (error) {
throw Exception(error);
throw ox::Exception(error);
}
return std::move(value);
}
[[nodiscard]]
constexpr T const &unwrapThrow() const & {
constexpr T const&unwrapThrow() const & {
if (error) {
throw ox::Exception(error);
}
@@ -269,7 +267,7 @@ struct [[nodiscard]] Result {
}
template<typename U = T>
constexpr ox::Result<U> to(auto const &f) & noexcept {
constexpr ox::Result<U> to(auto const&f) & noexcept {
if (error) [[unlikely]] {
return error;
}
@@ -277,7 +275,7 @@ struct [[nodiscard]] Result {
}
template<typename U = T>
constexpr ox::Result<U> to(auto const &f) && noexcept {
constexpr ox::Result<U> to(auto const&f) && noexcept {
if (error) [[unlikely]] {
return error;
}
@@ -289,7 +287,7 @@ struct [[nodiscard]] Result {
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T &&alt) const & noexcept {
constexpr T or_value(T &&alt) const& noexcept {
if (error) {
return std::move(alt);
}
@@ -313,7 +311,7 @@ struct [[nodiscard]] Result {
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T const &alt) const & noexcept {
constexpr T or_value(T const&alt) const& noexcept {
if (error) {
return alt;
}
@@ -325,54 +323,32 @@ struct [[nodiscard]] Result {
* @param alt
* @return value of Result or alt
*/
constexpr T or_value(T const &alt) && noexcept {
constexpr T or_value(T const&alt) && noexcept {
if (error) {
return alt;
}
return std::move(value);
}
constexpr Result transformError(ErrorCode const ec, CString const msg) && {
if (error) {
error = Error{ec, msg};
}
return *this;
}
};
namespace detail {
constexpr Error toError(Error const &e) noexcept {
constexpr Error toError(Error const&e) noexcept {
return e;
}
template<typename T>
constexpr Error toError(Result<T> const &r) noexcept {
constexpr Error toError(Result<T> const&r) noexcept {
return r.error;
}
}
constexpr void primitiveAssert(
bool const pass,
char const *msg,
std::source_location const &src = std::source_location::current()) noexcept {
constexpr void primitiveAssert(char const*file, int line, bool pass, char const*msg) noexcept {
if constexpr(ox::defines::Debug) {
if (!pass) [[unlikely]] {
panic(ox::Error{1}, msg, src);
}
}
}
constexpr void boundsCheck(
size_t const i,
size_t const sz,
char const *msg,
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(defines::CheckBounds) {
if (i >= sz) [[unlikely]] {
panic(ox::Error{1}, msg, src);
panic(file, line, msg, ox::Error(1));
}
}
}

View File

@@ -11,7 +11,6 @@
#include "algorithm.hpp"
#include "hash.hpp"
#include "ignore.hpp"
#include "optional.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "vector.hpp"
@@ -27,12 +26,11 @@ class HashMap {
private:
struct Pair {
UPtr<Pair> next;
K key = {};
T value{};
};
Vector<K> m_keys;
Vector<UPtr<Pair>> m_pairs;
Vector<Pair*> m_pairs;
public:
explicit constexpr HashMap(std::size_t size = 127);
@@ -75,10 +73,10 @@ class HashMap {
constexpr void expand();
template<typename KK>
constexpr UPtr<Pair> const &access(Vector<UPtr<Pair>> const &pairs, KK const &key) const;
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
template<typename KK>
constexpr UPtr<Pair> &access(Vector<UPtr<Pair>> &pairs, KK const &key);
constexpr Pair *&access(Vector<Pair*> &pairs, KK const&key);
};
@@ -87,13 +85,14 @@ constexpr HashMap<K, T>::HashMap(std::size_t size): m_pairs(size) {
}
template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(HashMap const &other) {
operator=(other);
constexpr HashMap<K, T>::HashMap(HashMap<K, T> const&other) {
m_pairs = other.m_pairs;
}
template<typename K, typename T>
constexpr HashMap<K, T>::HashMap(HashMap &&other) noexcept {
operator=(std::move(other));
constexpr HashMap<K, T>::HashMap(HashMap<K, T> &&other) noexcept {
m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs);
}
template<typename K, typename T>
@@ -102,16 +101,13 @@ constexpr HashMap<K, T>::~HashMap() {
}
template<typename K, typename T>
constexpr bool HashMap<K, T>::operator==(HashMap const &other) const {
constexpr bool HashMap<K, T>::operator==(HashMap const&other) const {
if (m_keys != other.m_keys) {
return false;
}
for (auto &k : m_keys) {
auto const a = at(k).value;
auto const b = other.at(k).value;
if (
a != b && // handle one being null and other not
(a && b && *a != *b)) {
for (int i = 0; i < m_keys.size(); ++i) {
auto &k = m_keys[i];
if (at(k) != other.at(k)) {
return false;
}
}
@@ -119,25 +115,19 @@ constexpr bool HashMap<K, T>::operator==(HashMap const &other) const {
}
template<typename K, typename T>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap const &other) {
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> const&other) {
if (this != &other) {
clear();
m_keys = other.m_keys;
m_pairs.resize(other.m_pairs.size());
for (auto const&k : m_keys) {
auto const &src = access(other.m_pairs, k);
auto &dst = access(m_pairs, k);
dst = ox::make_unique<Pair>();
dst->key = src->key;
dst->value = src->value;
}
m_pairs = other.m_pairs;
}
return *this;
}
template<typename K, typename T>
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap &&other) noexcept {
constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) noexcept {
if (this != &other) {
clear();
m_keys = std::move(other.m_keys);
m_pairs = std::move(other.m_pairs);
}
@@ -145,52 +135,60 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap &&other) noexcept {
}
template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const &key) {
auto p = &access(m_pairs, key);
constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const&k) {
auto p = &access(m_pairs, k);
if (*p == nullptr) {
if (static_cast<double>(m_pairs.size()) * 0.7 <
static_cast<double>(m_keys.size())) {
expand();
p = &access(m_pairs, key);
p = &access(m_pairs, k);
}
*p = ox::make_unique<Pair>();
(*p)->key = key;
m_keys.emplace_back(key);
*p = new Pair;
(*p)->key = k;
m_keys.emplace_back(k);
}
return (*p)->value;
}
template<typename K, typename T>
constexpr Result<T*> HashMap<K, T>::at(MaybeView_t<K> const &key) noexcept {
auto &p = access(m_pairs, key);
constexpr Result<T*> HashMap<K, T>::at(MaybeView_t<K> const&k) noexcept {
auto p = access(m_pairs, k);
if (!p) {
return ox::Error{1, "value not found for given key"};
return {nullptr, ox::Error(1, "value not found for given key")};
}
return &p->value;
}
template<typename K, typename T>
constexpr Result<const T*> HashMap<K, T>::at(MaybeView_t<K> const &key) const noexcept {
auto &p = access(m_pairs, key);
constexpr Result<const T*> HashMap<K, T>::at(MaybeView_t<K> const&k) const noexcept {
auto p = access(m_pairs, k);
if (!p) {
return ox::Error{1, "value not found for given key"};
return {nullptr, ox::Error(1, "value not found for given key")};
}
return &p->value;
}
template<typename K, typename T>
constexpr void HashMap<K, T>::erase(MaybeView_t<K> const &key) {
if (!contains(key)) {
constexpr void HashMap<K, T>::erase(MaybeView_t<K> const&k) {
if (!contains(k)) {
return;
}
auto &c = access(m_pairs, key);
c = std::move(c->next);
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), key));
auto h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
while (true) {
const auto &p = m_pairs[h];
if (p == nullptr || p->key == k) {
std::ignore = m_pairs.erase(h);
break;
} else {
h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
}
}
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k));
}
template<typename K, typename T>
constexpr bool HashMap<K, T>::contains(MaybeView_t<K> const &key) const noexcept {
return access(m_pairs, key).get() != nullptr;
constexpr bool HashMap<K, T>::contains(MaybeView_t<K> const&k) const noexcept {
return access(m_pairs, k) != nullptr;
}
template<typename K, typename T>
@@ -199,33 +197,34 @@ constexpr std::size_t HashMap<K, T>::size() const noexcept {
}
template<typename K, typename T>
constexpr Vector<K> const &HashMap<K, T>::keys() const noexcept {
constexpr Vector<K> const&HashMap<K, T>::keys() const noexcept {
return m_keys;
}
template<typename K, typename T>
constexpr Vector<T> HashMap<K, T>::values() const noexcept {
Vector<T> out;
out.reserve(m_keys.size());
for (auto const &p : m_pairs) {
if (p) {
out.emplace_back(*p->value);
}
out.reserve(m_pairs.size());
for (auto const&p : m_pairs) {
out.emplace_back(p->value);
}
return out;
}
template<typename K, typename T>
constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear();
m_pairs.resize(127);
}
template<typename K, typename T>
constexpr void HashMap<K, T>::expand() {
Vector<UPtr<Pair>> r{m_pairs.size() * 2};
Vector<Pair*> r(m_pairs.size() * 2);
for (std::size_t i = 0; i < m_keys.size(); ++i) {
auto const &k = m_keys[i];
auto const&k = m_keys[i];
access(r, k) = std::move(access(m_pairs, k));
}
m_pairs = std::move(r);
@@ -233,39 +232,29 @@ constexpr void HashMap<K, T>::expand() {
template<typename K, typename T>
template<typename KK>
constexpr UPtr<typename HashMap<K, T>::Pair> const &HashMap<K, T>::access(
Vector<UPtr<Pair>> const& pairs,
KK const &key) const {
auto const h = static_cast<std::size_t>(ox::hash<KK>{}(key) % pairs.size());
auto const &p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == key) {
return p;
}
auto c = &p->next;
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*> const&pairs, KK const&k) const {
auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
while (true) {
if (*c == nullptr || (*c)->key == key) {
return *c;
auto const&p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == k) {
return p;
} else {
h = (h + 1) % pairs.size();
}
c = &(*c)->next;
}
}
template<typename K, typename T>
template<typename KK>
constexpr UPtr<typename HashMap<K, T>::Pair> &HashMap<K, T>::access(
Vector<UPtr<Pair>> &pairs,
KK const &key) {
auto const h = static_cast<std::size_t>(ox::hash<KK>{}(key) % pairs.size());
auto &p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == key) {
return p;
}
auto c = &p->next;
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, KK const&k) {
auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
while (true) {
if (*c == nullptr || (*c)->key == key) {
return *c;
auto &p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == k) {
return p;
} else {
h = (h + 1) % pairs.size();
}
c = &(*c)->next;
}
}

View File

@@ -77,7 +77,7 @@ static HeapSegment *findSegmentFor(std::size_t sz) noexcept {
return s;
}
}
ox::panic("malloc: could not find segment");
oxPanic(ox::Error(1), "malloc: could not find segment");
return nullptr;
}
@@ -102,7 +102,7 @@ void free(void *ptr) noexcept {
} else if (p.segment) {
p.segment->inUse = false;
} else {
ox::panic("Bad heap free");
oxPanic(ox::Error(1), "Bad heap free");
}
}

View File

@@ -16,7 +16,7 @@
namespace std {
inline constexpr struct ignore_t {
inline constexpr struct {
constexpr void operator=(auto&&) const noexcept {}
} ignore;

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#ifdef OX_USE_STDLIB
#include <istream>
#include "array.hpp"
#include "reader.hpp"
#include "istreamreader.hpp"
namespace ox {
[[nodiscard]]
constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
switch (in) {
case ox::ios_base::beg:
return std::ios_base::beg;
case ox::ios_base::end:
return std::ios_base::end;
case ox::ios_base::cur:
return std::ios_base::cur;
}
return std::ios_base::beg;
}
Result<char> StreamReader::peek() const noexcept {
try {
if (m_strm.eof()) {
return Error{1, "EOF"};
}
char c{};
m_strm.get(c);
if (m_strm.unget()) [[unlikely]] {
return ox::Error{1, "Unable to unget character"};
}
return static_cast<char>(c);
} catch (std::exception const&) {
return ox::Error(1, "peek failed");
}
}
Result<size_t> StreamReader::read(char *v, size_t cnt) noexcept {
return static_cast<size_t>(m_strm.read(v, static_cast<std::streamsize>(cnt)).gcount());
}
Error StreamReader::seekg(size_t p) noexcept {
try {
m_strm.seekg(static_cast<long long int>(p), std::ios_base::cur);
} catch (std::exception const&) {
return ox::Error(1, "seekg failed");
}
return {};
}
Error StreamReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
try {
m_strm.seekg(p, sdMap(sd));
} catch (std::exception const&) {
return ox::Error(1, "seekg failed");
}
return {};
}
Result<size_t> StreamReader::tellg() noexcept {
const auto sz = m_strm.tellg();
return {static_cast<size_t>(sz), ox::Error(sz == -1)};
}
}
#endif

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#ifdef OX_USE_STDLIB
#include <istream>
#endif
#include "reader.hpp"
namespace ox {
#ifdef OX_USE_STDLIB
class StreamReader: public Reader_v {
private:
std::istream &m_strm;
public:
constexpr explicit StreamReader(std::istream &stream) noexcept: m_strm(stream) {}
Result<char> peek() const noexcept override;
Result<size_t> read(char *v, size_t cnt) noexcept override;
Error seekg(size_t p) noexcept override;
Error seekg(int64_t p, ios_base::seekdir sd) noexcept override;
Result<size_t> tellg() noexcept override;
};
#endif
}

View File

@@ -72,7 +72,7 @@ class IString {
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t size() const noexcept;
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
@@ -121,7 +121,7 @@ constexpr IString<size> &IString<size>::operator=(Integer_c auto i) noexcept {
template<std::size_t size>
constexpr IString<size> &IString<size>::operator=(ox::StringViewCR str) noexcept {
std::size_t strLen = str.size();
std::size_t strLen = str.len();
if (cap() < strLen) {
strLen = cap();
}
@@ -171,7 +171,7 @@ constexpr char &IString<StrCap>::operator[](std::size_t i) noexcept {
template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noexcept {
Error err{};
auto const currentLen = size();
auto const currentLen = len();
if (cap() < currentLen + strLen) {
strLen = cap() - currentLen;
err = ox::Error(1, "Insufficient space for full string");
@@ -187,7 +187,7 @@ OX_CLANG_NOWARN_END
template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(ox::StringView str) noexcept {
return append(str.data(), str.size());
return append(str.data(), str.len());
}
template<std::size_t StrCap>
@@ -207,7 +207,7 @@ constexpr const char *IString<StrCap>::c_str() const noexcept {
template<std::size_t StrCap>
constexpr std::size_t IString<StrCap>::size() const noexcept {
constexpr std::size_t IString<StrCap>::len() const noexcept {
return m_size;
}
@@ -245,7 +245,7 @@ struct MaybeView<ox::IString<sz>> {
template<Integer_c Integer>
[[nodiscard]]
constexpr auto intToStr(Integer v) noexcept {
constexpr auto itoa(Integer v) noexcept {
constexpr auto Cap = [] {
auto out = 0;
switch (sizeof(Integer)) {

View File

@@ -133,17 +133,17 @@ struct SpanIterator {
}
constexpr PtrType operator->() const noexcept {
boundsCheck(m_offset, m_max, "SpanIterator access overflow");
ox::primitiveAssert(__FILE__, __LINE__, m_offset < m_max, "SpanIterator access overflow");
return &m_t[m_offset];
}
constexpr RefType operator*() const noexcept {
boundsCheck(m_offset, m_max, "SpanIterator access overflow");
ox::primitiveAssert(__FILE__, __LINE__, m_offset < m_max, "SpanIterator access overflow");
return m_t[m_offset];
}
constexpr RefType operator[](std::size_t s) const noexcept {
boundsCheck(s, m_max, "SpanIterator access overflow");
ox::primitiveAssert(__FILE__, __LINE__, s < m_max, "SpanIterator access overflow");
return m_t[s];
}

View File

@@ -179,26 +179,26 @@ constexpr bool operator!=(std::nullptr_t, const SharedPtr<T> &p2) noexcept {
template<typename T, typename Deleter = DefaultDelete>
class UPtr {
class UniquePtr {
private:
T *m_t = nullptr;
public:
using value_type = T;
explicit constexpr UPtr(T *t = nullptr) noexcept: m_t(t) {
explicit constexpr UniquePtr(T *t = nullptr) noexcept: m_t(t) {
}
constexpr UPtr(UPtr&) = delete;
constexpr UniquePtr(UniquePtr&) = delete;
constexpr UPtr(const UPtr&) = delete;
constexpr UniquePtr(const UniquePtr&) = delete;
template<typename U, typename UDeleter>
constexpr UPtr(UPtr<U, UDeleter> &&other) noexcept {
constexpr UniquePtr(UniquePtr<U, UDeleter> &&other) noexcept {
m_t = other.release();
}
constexpr ~UPtr() {
constexpr ~UniquePtr() {
Deleter()(m_t);
}
@@ -213,24 +213,25 @@ class UPtr {
return m_t;
}
constexpr void reset(UPtr &&other = UPtr()) {
template<typename U, typename UDeleter>
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
auto t = m_t;
m_t = other.release();
Deleter()(t);
}
constexpr UPtr &operator=(UPtr const&other) = delete;
constexpr UniquePtr &operator=(UniquePtr const&other) = delete;
template<typename U, typename UDeleter>
constexpr UPtr &operator=(UPtr<U, UDeleter> const&other) = delete;
constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> const&other) = delete;
constexpr UPtr &operator=(UPtr<T> &&other) noexcept {
constexpr UniquePtr &operator=(UniquePtr<T> &&other) noexcept {
reset(std::move(other));
return *this;
}
template<typename U, typename UDeleter>
constexpr UPtr &operator=(UPtr<U, UDeleter> &&other) noexcept {
constexpr UniquePtr &operator=(UniquePtr<U, UDeleter> &&other) noexcept {
reset(std::move(other));
return *this;
}
@@ -249,34 +250,37 @@ class UPtr {
};
template<typename T, typename Deleter = DefaultDelete>
using UPtr = UniquePtr<T, Deleter>;
template<typename T>
constexpr bool operator==(const UPtr<T> &p1, const UPtr<T> &p2) noexcept {
constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
return p1.get() == p2.get();
}
template<typename T>
constexpr bool operator==(const UPtr<T> &p1, std::nullptr_t) noexcept {
return p1.get() == nullptr;
constexpr bool operator==(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
return p1.get();
}
template<typename T>
constexpr bool operator==(std::nullptr_t, const UPtr<T> &p2) noexcept {
return p2.get() == nullptr;
constexpr bool operator==(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
return p2.get();
}
template<typename T>
constexpr bool operator!=(const UPtr<T> &p1, const UPtr<T> &p2) noexcept {
constexpr bool operator!=(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
return p1.get() != p2.get();
}
template<typename T>
constexpr bool operator!=(const UPtr<T> &p1, std::nullptr_t) noexcept {
constexpr bool operator!=(const UniquePtr<T> &p1, std::nullptr_t) noexcept {
return !p1.get();
}
template<typename T>
constexpr bool operator!=(std::nullptr_t, const UPtr<T> &p2) noexcept {
constexpr bool operator!=(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
return !p2.get();
}
@@ -284,14 +288,14 @@ constexpr bool operator!=(std::nullptr_t, const UPtr<T> &p2) noexcept {
template<typename T, typename U = T, typename ...Args>
[[nodiscard]]
constexpr auto make_unique(Args&&... args) {
return UPtr<U>(new T(ox::forward<Args>(args)...));
return UniquePtr<U>(new T(ox::forward<Args>(args)...));
}
template<typename T, typename U = T, typename ...Args>
[[nodiscard]]
constexpr Result<UPtr<U>> make_unique_catch(Args&&... args) noexcept {
constexpr Result<UniquePtr<U>> make_unique_catch(Args&&... args) noexcept {
try {
return UPtr<U>(new T(ox::forward<Args>(args)...));
return UniquePtr<U>(new T(ox::forward<Args>(args)...));
} catch (ox::Exception const&ex) {
return ex.toError();
}

View File

@@ -30,60 +30,22 @@ constexpr void *operator new(std::size_t, void *addr) noexcept {
constexpr void *operator new[](std::size_t, void *addr) noexcept {
return addr;
}
namespace std {
template<typename T>
[[nodiscard]]
constexpr T* launder(T* __p) noexcept {
return __builtin_launder(__p);
}
template<typename T, typename... Args, bool noex>
void launder(T(*)(Args...) noexcept(noex)) = delete;
template<typename T, typename... Args, bool noex>
void launder(T(*)(Args......) noexcept(noex)) = delete;
void launder(void*) = delete;
void launder(void const*) = delete;
void launder(volatile void*) = delete;
void launder(volatile void const*) = delete;
}
#endif
namespace ox {
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<T const*>(this);
}
};
template<typename T, typename U = T, typename ...Args>
[[nodiscard]]
constexpr U *make(Args &&...args) noexcept {
#ifdef __cpp_exceptions
try {
return new T(ox::forward<Args>(args)...);
} catch (std::exception const &ex) {
ox::panic(ox::Error(1, ex.what()), ex.what());
} catch (std::exception const&ex) {
oxPanic(ox::Error(1, ex.what()), ex.what());
return nullptr;
} catch (...) {
ox::panic(ox::Error(2, "Allocation or constructor failed"), "Allocation or constructor failed");
oxPanic(ox::Error(2, "Allocation or constructor failed"), "Allocation or constructor failed");
return nullptr;
}
#else

View File

@@ -5,3 +5,70 @@
* 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/.
*/
#ifdef OX_USE_STDLIB
#include <istream>
#include "array.hpp"
#include "reader.hpp"
namespace ox {
[[nodiscard]]
constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
switch (in) {
case ox::ios_base::beg:
return std::ios_base::beg;
case ox::ios_base::end:
return std::ios_base::end;
case ox::ios_base::cur:
return std::ios_base::cur;
}
return std::ios_base::beg;
}
ox::Result<char> StreamReader::peek() const noexcept {
try {
char c{};
m_strm.get(c);
auto const ok = c != EOF;
if (ok && m_strm.unget()) [[unlikely]] {
return ox::Error(1, "Unable to unget character");
}
return {static_cast<char>(c), ox::Error(!ok, "File peek failed")};
} catch (std::exception const&) {
return ox::Error(1, "peek failed");
}
}
ox::Result<std::size_t> StreamReader::read(char *v, std::size_t cnt) noexcept {
return static_cast<size_t>(m_strm.read(v, static_cast<std::streamsize>(cnt)).gcount());
}
ox::Error StreamReader::seekg(std::size_t p) noexcept {
try {
m_strm.seekg(static_cast<long long int>(p), std::ios_base::cur);
} catch (std::exception const&) {
return ox::Error(1, "seekg failed");
}
return {};
}
ox::Error StreamReader::seekg(int64_t p, ios_base::seekdir sd) noexcept {
try {
m_strm.seekg(p, sdMap(sd));
} catch (std::exception const&) {
return ox::Error(1, "seekg failed");
}
return {};
}
ox::Result<std::size_t> StreamReader::tellg() noexcept {
const auto sz = m_strm.tellg();
return {static_cast<std::size_t>(sz), ox::Error(sz == -1)};
}
}
#endif

View File

@@ -8,6 +8,10 @@
#pragma once
#ifdef OX_USE_STDLIB
#include <istream>
#endif
#include "concepts.hpp"
#include "error.hpp"
#include "types.hpp"
@@ -27,6 +31,7 @@ concept Reader_c = requires(T v) {
class Reader_v {
public:
virtual constexpr ~Reader_v() noexcept = default;
[[nodiscard]]
virtual constexpr ox::Result<char> peek() const noexcept = 0;
virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0;
virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;
@@ -59,4 +64,18 @@ class ReaderT: public Reader_v {
}
};
#ifdef OX_USE_STDLIB
class StreamReader: public Reader_v {
private:
std::istream &m_strm;
public:
constexpr explicit StreamReader(std::istream &stream) noexcept: m_strm(stream) {}
ox::Result<char> peek() const noexcept override;
ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override;
ox::Error seekg(std::size_t p) noexcept override;
ox::Error seekg(int64_t p, ios_base::seekdir sd) noexcept override;
ox::Result<std::size_t> tellg() noexcept override;
};
#endif
}

View File

@@ -12,13 +12,4 @@
#include <cassert>
#else
#define assert(e) while (!(e));
#endif
#if __has_include(<cstdlib>)
#include <cstdlib>
#else
extern "C" {
[[noreturn]]
void abort();
}
#endif

View File

@@ -18,7 +18,7 @@ namespace ox {
template<typename PlatSpec>
struct VectorMemMap {
size_t const smallVecSize = 0; // not a map value
const std::size_t smallVecSize = 0; // not a map value
typename PlatSpec::size_t size = 0;
typename PlatSpec::size_t cap = 0;
typename PlatSpec::PtrType items = 0;
@@ -26,11 +26,11 @@ struct VectorMemMap {
template<typename PlatSpec>
[[nodiscard]]
constexpr auto sizeOf(VectorMemMap<PlatSpec> const *t) noexcept {
constexpr auto padding = [](size_t const size, size_t const al) {
constexpr auto sizeOf(const VectorMemMap<PlatSpec> *t) noexcept {
constexpr auto padding = [](std::size_t size, std::size_t al) {
return size % al;
};
size_t size = 0;
std::size_t size = 0;
if (t->smallVecSize) {
size += t->smallVecSize;
size += padding(size, PlatSpec::alignOf(t->size));
@@ -43,17 +43,17 @@ constexpr auto sizeOf(VectorMemMap<PlatSpec> const *t) noexcept {
return size;
}
template<typename PlatSpec, size_t SmallVecSize = 0>
template<typename PlatSpec, std::size_t SmallVecSize = 0>
[[nodiscard]]
constexpr auto alignOf(VectorMemMap<PlatSpec> const&) noexcept {
typename PlatSpec::size_t const i = 0;
constexpr auto alignOf(const VectorMemMap<PlatSpec>&) noexcept {
const typename PlatSpec::size_t i = 0;
return PlatSpec::alignOf(i);
}
template<typename PlatSpec, typename T>
constexpr Error pad(Writer_c auto &w, T const *v) noexcept {
auto const a = PlatSpec::alignOf(*v);
auto const excess = w.tellp() % a;
constexpr ox::Error pad(Writer_c auto &w, const T *v) noexcept {
const auto a = PlatSpec::alignOf(*v);
const auto excess = w.tellp() % a;
if (excess) {
return w.write(nullptr, a - excess);
} else {
@@ -62,7 +62,7 @@ constexpr Error pad(Writer_c auto &w, T const *v) noexcept {
}
template<typename PlatSpec>
constexpr Error serialize(Writer_c auto &w, VectorMemMap<PlatSpec> const &vm) noexcept {
constexpr ox::Error serialize(Writer_c auto &w, const VectorMemMap<PlatSpec> &vm) noexcept {
OX_RETURN_ERROR(w.write(nullptr, vm.smallVecSize));
OX_RETURN_ERROR(serialize(w, PlatSpec::correctEndianness(vm.size)));
OX_RETURN_ERROR(serialize(w, PlatSpec::correctEndianness(vm.cap)));
@@ -70,20 +70,21 @@ constexpr Error serialize(Writer_c auto &w, VectorMemMap<PlatSpec> const &vm) no
return {};
}
constexpr Error serialize(Writer_c auto &w, Integral_c auto val) noexcept {
Array<char, sizeof(val)> tmp;
for (auto i = 0u; i < sizeof(val); ++i) {
template<typename T>
constexpr ox::Error serialize(Writer_c auto &w, T val) noexcept requires(is_integer_v<T>) {
ox::Array<char, sizeof(T)> tmp;
for (auto i = 0u; i < sizeof(T); ++i) {
tmp[i] = static_cast<char>((val >> i * 8) & 255);
}
return w.write(tmp.data(), tmp.size());
}
};
template<typename T>
constexpr Result<Array<char, sizeof(T)>> serialize(T const &in) noexcept {
Array<char, sizeof(T)> out = {};
constexpr ox::Result<ox::Array<char, sizeof(T)>> serialize(const T &in) noexcept {
ox::Array<char, sizeof(T)> out = {};
CharBuffWriter w(out);
OX_RETURN_ERROR(serialize(w, in));
return out;
}
};
}

View File

@@ -62,9 +62,6 @@ class SmallMap {
[[nodiscard]]
constexpr Vector<K> keys() const noexcept;
[[nodiscard]]
constexpr Vector<T> values() const noexcept;
[[nodiscard]]
constexpr K const&key(size_t i) const noexcept;
@@ -85,22 +82,14 @@ class SmallMap {
return m_pairs;
}
[[nodiscard]]
constexpr ox::Span<Pair> pairs() noexcept {
return m_pairs;
}
constexpr void clear();
private:
template<typename KK>
constexpr Pair const*access(PairVector const&pairs, KK const&key, bool &isNew) const;
constexpr Pair const&access(PairVector const&pairs, KK const&key, bool &isNew) const;
template<typename KK>
constexpr Pair *access(PairVector &pairs, KK const&key, bool &isNew);
template<typename KK>
constexpr Pair *accessNoCreate(PairVector &pairs, KK const&key);
constexpr Pair &access(PairVector &pairs, KK const&key, bool &isNew);
};
@@ -140,7 +129,7 @@ constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K
template<typename K, typename T, size_t SmallSz>
constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
bool isNew{};
auto p = access(m_pairs, k, isNew);
auto p = &access(m_pairs, k, isNew);
if (isNew) {
p->key = k;
}
@@ -149,7 +138,7 @@ constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
template<typename K, typename T, size_t SmallSz>
constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept {
auto const p = accessNoCreate(m_pairs, k);
auto p = access(m_pairs, k);
if (!p) {
return {nullptr, ox::Error(1, "value not found for given key")};
}
@@ -158,8 +147,7 @@ constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcep
template<typename K, typename T, size_t SmallSz>
constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept {
bool isNew{};
auto p = access(m_pairs, k, isNew);
auto p = access(m_pairs, k);
if (!p) {
return {nullptr, ox::Error(1, "value not found for given key")};
}
@@ -180,8 +168,7 @@ constexpr void SmallMap<K, T, SmallSz>::erase(MaybeView_t<K> const&k) {
template<typename K, typename T, size_t SmallSz>
constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept {
bool isNew{};
return access(m_pairs, k, isNew) != nullptr;
return access(m_pairs, k) != nullptr;
}
template<typename K, typename T, size_t SmallSz>
@@ -199,16 +186,6 @@ constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
return keys;
}
template<typename K, typename T, size_t SmallSz>
constexpr Vector<T> SmallMap<K, T, SmallSz>::values() const noexcept {
ox::Vector<T> keys;
keys.reserve(m_pairs.size());
for (auto const&p : m_pairs) {
keys.emplace_back(p.key);
}
return keys;
}
template<typename K, typename T, size_t SmallSz>
constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
return m_pairs[i].key;
@@ -241,42 +218,30 @@ constexpr void SmallMap<K, T, SmallSz>::clear() {
template<typename K, typename T, size_t SmallSz>
template<typename KK>
constexpr typename SmallMap<K, T, SmallSz>::Pair const*SmallMap<K, T, SmallSz>::access(
constexpr typename SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::access(
PairVector const&pairs, KK const&k, bool &isNew) const {
for (auto const&p : pairs) {
if (p.key == k) {
isNew = false;
return &p;
return p;
}
}
isNew = true;
return nullptr;
return pairs.emplace_back();
}
template<typename K, typename T, size_t SmallSz>
template<typename KK>
constexpr typename SmallMap<K, T, SmallSz>::Pair *SmallMap<K, T, SmallSz>::access(
constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::access(
PairVector &pairs, KK const&k, bool &isNew) {
for (auto &p : pairs) {
if (p.key == k) {
isNew = false;
return &p;
return p;
}
}
isNew = true;
return &pairs.emplace_back();
}
template<typename K, typename T, size_t SmallSz>
template<typename KK>
constexpr typename SmallMap<K, T, SmallSz>::Pair *SmallMap<K, T, SmallSz>::accessNoCreate(
PairVector &pairs, KK const&k) {
for (auto &p : pairs) {
if (p.key == k) {
return &p;
}
}
return nullptr;
return pairs.emplace_back();
}
template<typename T, typename K, typename V, size_t SmallSz>

View File

@@ -8,17 +8,13 @@
#pragma once
#if __has_include(<array>)
#include <array>
#endif
#include "array.hpp"
#include "bit.hpp"
#include "def.hpp"
#include "iterator.hpp"
#include "vector.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
@@ -39,20 +35,6 @@ class Span {
constexpr Span() noexcept = default;
#if __has_include(<array>)
template<std::size_t sz>
constexpr Span(std::array<T, sz> &a) noexcept:
m_items(a.data()),
m_size(a.size()) {
}
template<std::size_t sz>
constexpr Span(std::array<ox::remove_const_t<T>, sz> const &a) noexcept:
m_items(a.data()),
m_size(a.size()) {
}
#endif
template<std::size_t sz>
constexpr Span(ox::Array<T, sz> &a) noexcept:
m_items(a.data()),
@@ -60,7 +42,7 @@ class Span {
}
template<std::size_t sz>
constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const &a) noexcept:
constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const&a) noexcept:
m_items(a.data()),
m_size(a.size()) {
}
@@ -72,7 +54,7 @@ class Span {
}
template<std::size_t sz, typename Allocator>
constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const &v) noexcept:
constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const&v) noexcept:
m_items(v.data()),
m_size(v.size()) {
}
@@ -146,41 +128,28 @@ class Span {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
}
constexpr T &operator[](std::size_t i) const noexcept {
boundsCheck(i, size(), "Span access overflow");
constexpr T &operator[](std::size_t i) noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return m_items[i];
}
constexpr const T &operator[](std::size_t i) const noexcept {
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return m_items[i];
}
constexpr Span operator+(size_t i) const noexcept {
boundsCheck(i, size(), "Span access overflow");
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return {m_items + i, m_size - i};
}
constexpr Span operator+=(size_t i) noexcept {
boundsCheck(i, size(), "Span access overflow");
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
m_items += i;
m_size -= i;
return *this;
}
constexpr Span operator++(int) noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
constexpr Span operator++() noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_items;
@@ -199,20 +168,8 @@ class Span {
};
template<typename T>
using SpanView = Span<T const>;
template<typename T>
constexpr void spancpy(ox::Span<T> const dst, ox::SpanView<T> const src) noexcept {
auto const sz = ox::min(dst.size(), src.size());
if (std::is_constant_evaluated() || std::is_trivially_copyable_v<T>) {
for (size_t i{}; i < sz; ++i) {
dst.data()[i] = src.data()[i];
}
} else {
memcpy(dst.data(), src.data(), sz * sizeof(T));
}
}
using SpanView = Span<const T>;
}
OX_ALLOW_UNSAFE_BUFFERS_END
OX_CLANG_NOWARN_END

View File

@@ -17,41 +17,35 @@
namespace ox {
template<Integer_c Integer>
constexpr ox::Error writeItoa(Integer const v, ox::Writer_c auto &writer) noexcept {
if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10;
auto it = 0;
if (val < 0) {
OX_RETURN_ERROR(writer.put('-'));
val = ~val + 1;
}
if constexpr(sizeof(v) == 8 && !ox::is_signed_v<Integer>) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (digit) {
digit -= 10;
OX_RETURN_ERROR(writer.put('1'));
OX_RETURN_ERROR(writer.put(static_cast<char>('0' + digit)));
constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept {
if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10;
auto it = 0;
if (val < 0) {
OX_RETURN_ERROR(writer.put('-'));
++it;
}
}
while (mod) {
auto const digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
OX_RETURN_ERROR(writer.put(static_cast<char>('0' + digit)));
++it;
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
ox::ResizedInt_t<Integer, 64> start = '0';
if (digit >= 10) {
start = 'a';
digit -= 10;
}
OX_RETURN_ERROR(writer.put(static_cast<char>(start + digit)));
++it;
}
}
} else {
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
}
} else {
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
}
return {};
return {};
}
}

View File

@@ -28,7 +28,7 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename Integer>
constexpr ox::IString<21> intToStr(Integer v) noexcept;
constexpr ox::IString<21> itoa(Integer v) noexcept;
template<std::size_t SmallStringSize_v>
class BasicString {
@@ -139,7 +139,7 @@ class BasicString {
constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringViewCR src) noexcept;
constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(BasicString const&src) noexcept;
@@ -171,22 +171,22 @@ class BasicString {
constexpr bool operator>=(BasicString const&other) const noexcept;
constexpr char const&operator[](std::size_t i) const noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept {
auto currentLen = size();
auto currentLen = len();
m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&m_buff[currentLen], str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
// this can't fail, but it returns an Error to match BString::append
return {};
return ox::Error(0);
}
constexpr Error append(StringViewCR sv) noexcept {
return append(sv.data(), sv.size());
constexpr Error append(ox::StringView sv) noexcept {
return append(sv.data(), sv.len());
}
[[nodiscard]]
@@ -213,22 +213,22 @@ class BasicString {
[[nodiscard]]
constexpr const char *c_str() const noexcept {
return m_buff.data();
return static_cast<const char*>(m_buff.data());
}
[[nodiscard]]
constexpr explicit operator const char*() const {
inline explicit operator const char*() const {
return c_str();
}
#if __has_include(<string>)
[[nodiscard]]
std::string toStdString() const {
inline std::string toStdString() const {
return c_str();
}
[[nodiscard]]
explicit operator std::string() const {
inline explicit operator std::string() const {
return c_str();
}
#endif
@@ -237,7 +237,7 @@ class BasicString {
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t size() const noexcept;
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
@@ -277,7 +277,7 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept:
BasicString(StringView{str.data(), str.size()}) {
BasicString(StringView{str.data(), str.len()}) {
}
template<std::size_t SmallStringSize_v>
@@ -317,13 +317,13 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
set(ox::intToStr(i));
set(ox::itoa(i));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
set(ox::intToStr(i));
set(ox::itoa(i));
return *this;
}
@@ -371,12 +371,12 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
auto const str = ox::intToStr(i);
auto const str = ox::itoa(i);
return this->operator+=(str.c_str());
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringViewCR s) noexcept {
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
std::ignore = append(s.data(), strLen);
return *this;
@@ -384,15 +384,15 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
std::ignore = append(src.c_str(), src.size());
std::ignore = append(src.c_str(), src.len());
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox::strlen(str);
const auto currentLen = size();
BasicString<SmallStringSize_v> cpy;
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
ox::listcpy(&cpy.m_buff[currentLen], str, strLen);
@@ -414,31 +414,29 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
auto const str = ox::intToStr(i);
auto const str = ox::itoa(i);
return *this + str;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(StringViewCR src) const noexcept {
const std::size_t strLen = src.size();
const auto currentLen = size();
const std::size_t strLen = src.len();
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen);
cpy.m_buff[cpy.m_buff.size() - 1] = 0;
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
return cpy;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
const std::size_t strLen = src.size();
const auto currentLen = size();
const std::size_t strLen = src.len();
const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen);
cpy.m_buff[cpy.m_buff.size() - 1] = 0;
ox::listcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
return cpy;
}
@@ -456,7 +454,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) con
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return StringView(*this) == StringView(other);
return ox::StringView(*this) == ox::StringView(other);
}
template<std::size_t SmallStringSize_v>
@@ -490,7 +488,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator>=(BasicString const&othe
}
template<std::size_t SmallStringSize_v>
constexpr char const&BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
constexpr char BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
@@ -521,7 +519,7 @@ constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
}
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::size() const noexcept {
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
return m_buff.size() - 1;
}
@@ -548,28 +546,28 @@ using StringCR = String const&;
[[nodiscard]]
constexpr String toString(StringViewCR sv) noexcept {
constexpr ox::String toString(ox::StringViewCR sv) noexcept {
return ox::String(sv);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto sizeOf(BasicString<SmallStringSize_v> const*) noexcept {
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto alignOf(BasicString<SmallStringSize_v> const&) noexcept {
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v);
}
template<size_t sz>
struct MaybeView<BasicString<sz>> {
using type = StringView;
struct MaybeView<ox::BasicString<sz>> {
using type = ox::StringView;
};
}

View File

@@ -16,28 +16,33 @@ namespace ox {
* StringLiteral is used for functions that want to ensure that they are taking
* string literals, and not strings outside of the data section of the program
* that might get deleted.
* This type cannot force you to use it correctly, so don't give it something
* that is not a literal.
* If you do this:
* StringLiteral(str.c_str())
* the resulting segfault is on you.
*/
class StringLiteral: public detail::BaseStringView {
public:
constexpr StringLiteral() noexcept = default;
constexpr StringLiteral(StringLiteral const &sv) noexcept = default;
constexpr StringLiteral(StringLiteral const&sv) noexcept = default;
consteval StringLiteral(std::nullptr_t) noexcept {}
constexpr explicit StringLiteral(std::nullptr_t) noexcept {}
consteval StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {}
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
consteval StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
OX_ALLOW_UNSAFE_BUFFERS_END
constexpr explicit StringLiteral(char const *str) noexcept: StringLiteral(str, ox::strlen(str)) {}
constexpr StringLiteral &operator=(StringLiteral const &other) noexcept {
set(other.data(), other.size());
constexpr StringLiteral &operator=(StringLiteral const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
}
return *this;
}
[[nodiscard]]
constexpr char const *c_str() const noexcept {
constexpr const char *c_str() const noexcept {
return data();
}

View File

@@ -8,7 +8,6 @@
#pragma once
#include "cstringview.hpp"
#include "string.hpp"
namespace ox {
@@ -21,8 +20,6 @@ class StringParam {
constexpr StringParam(StringParam &&o) noexcept: m_value{std::move(o.m_value)} {}
constexpr StringParam(char const*value) noexcept: m_value{value} {}
constexpr StringParam(detail::BaseStringView const&value) noexcept: m_value{value} {}
template<size_t sz>
constexpr StringParam(ox::IString<sz> const&value) noexcept: m_value{value} {}
constexpr StringParam(ox::String const&value) noexcept: m_value{value} {}
constexpr StringParam(ox::String &&value) noexcept: m_value{std::move(value)} {}
constexpr operator ox::String() && noexcept { return std::move(m_value); }

View File

@@ -40,10 +40,10 @@ class StringView: public detail::BaseStringView {
constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr StringView(std::nullptr_t) noexcept {}
@@ -53,24 +53,24 @@ class StringView: public detail::BaseStringView {
constexpr auto &operator=(StringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.size());
set(other.data(), other.len());
}
return *this;
}
};
using StringViewCR = StringView const&;
using StringViewCR = const StringView&;
constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept {
if (s2.size() != s1.size()) {
if (s2.len() != s1.len()) {
return false;
}
return ox::strncmp(s1.data(), s2.data(), s1.size()) == 0;
return ox::strncmp(s1.data(), s2.data(), s1.len()) == 0;
}
constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
const auto maxLen = ox::min(s1.size(), s2.size());
const auto maxLen = ox::min(s1.len(), s2.len());
const auto a = &s1.front();
const auto b = &s2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
@@ -80,16 +80,16 @@ constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
return 1;
}
}
if (s1.size() > s2.size()) {
if (s1.len() > s2.len()) {
return 1;
} else if (s1.size() < s2.size()) {
} else if (s1.len() < s2.len()) {
return -1;
} else {
return 0;
}
}
constexpr auto write(Writer_c auto &writer, StringViewCR sv) noexcept {
constexpr auto write(Writer_c auto &writer, ox::StringViewCR sv) noexcept {
return writer.write(sv.data(), sv.bytes());
}
@@ -100,24 +100,19 @@ constexpr auto toStdStringView(StringViewCR sv) noexcept {
#endif
constexpr ox::Result<int> strToInt(StringViewCR str) noexcept {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
constexpr ox::Result<int> atoi(ox::StringViewCR str) noexcept {
int total = 0;
int multiplier = 1;
if (str.size() == 0) [[unlikely]] {
return Error{1, "Empty string passed to strToInt"};
}
for (auto i = static_cast<int64_t>(str.size()) - 1; i != -1; --i) {
for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) {
auto s = static_cast<std::size_t>(i);
if (str[s] >= '0' && str[s] <= '9') {
total += (str[s] - '0') * multiplier;
multiplier *= 10;
} else {
return ox::Error{1};
return ox::Error(1);
}
}
return total;
OX_ALLOW_UNSAFE_BUFFERS_END
}

View File

@@ -7,10 +7,8 @@
*/
#include "def.hpp"
#include "span.hpp"
#include "strops.hpp"
static_assert(ox::strcmp("asdf", "hijk") < 0, "asdf < hijk");
static_assert(ox::strcmp("hijk", "asdf") > 0, "hijk > asdf");
static_assert(ox::strcmp("resize", "read") > 0, "resize > read");
@@ -19,28 +17,27 @@ static_assert(ox::strcmp("resize", "resize") == 0, "resize == resize");
static_assert(ox::strcmp("", "") == 0, "\"\" == \"\"");
static_assert([] {
auto constexpr testStr = ox::Span{"asdf"};
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
return ox::strchr(testStr.data(), 0, 4) == &testStr[4];
OX_ALLOW_UNSAFE_BUFFERS_END
auto testStr = "asdf";
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
return ox::strchr(testStr, 0, 4) == &testStr[4];
OX_CLANG_NOWARN_END
}(), "ox::strchr 0");
static_assert([] {
auto constexpr testStr = "aaaa";
int retval = 0;
auto testStr = "aaaa";
// test the const and non-const versions of ox::lastIndexOf
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
return ox::lastIndexOf(testStr, 'a', ox::strlen(testStr)) == 3;
OX_ALLOW_UNSAFE_BUFFERS_END
retval |= !(ox::lastIndexOf(const_cast<char*>(testStr), 'a', ox::strlen(testStr)) == 3);
retval |= !(ox::lastIndexOf(testStr, 'a', ox::strlen(testStr)) == 3);
return retval == 0;
}(), "ox::lastIndexOf aaaa a");
#ifndef OX_USE_STDLIB
extern "C"
size_t strlen(const char *str) {
size_t len{};
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
while (str[len]) { ++len; }
OX_ALLOW_UNSAFE_BUFFERS_END
std::size_t strlen(const char *str) {
std::size_t len = 0;
for (; str[len]; len++);
return len;
}

View File

@@ -21,47 +21,37 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
[[nodiscard]]
constexpr StringView substr(StringViewCR str, std::size_t const pos) noexcept {
if (str.size() >= pos) {
return {&str[pos], str.size() - pos};
constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept {
if (str.len() >= pos) {
return {&str[pos], str.len() - pos};
}
return {};
}
[[nodiscard]]
constexpr StringView substr(StringViewCR str, std::size_t const start, std::size_t const end) noexcept {
if (str.size() >= start && end >= start) {
constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept {
if (str.len() >= start && end >= start) {
return {&str[start], end - start};
}
return {};
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept {
return base.size() && base[0] == beginning;
}
[[nodiscard]]
constexpr bool endsWith(StringViewCR base, char const ending) noexcept {
return base.size() && base[base.size() - 1] == ending;
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept {
const auto beginningLen = ox::min(beginning.size(), base.size());
return base.size() >= beginning.size() && ox::strncmp(base.data(), beginning, beginningLen) == 0;
const auto beginningLen = ox::min(beginning.len(), base.len());
return base.len() >= beginning.len() && ox::strncmp(base.data(), beginning, beginningLen) == 0;
}
[[nodiscard]]
constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept {
const auto endingLen = ending.size();
return base.size() >= endingLen && ox::strcmp(base.data() + (base.size() - endingLen), ending) == 0;
const auto endingLen = ending.len();
return base.len() >= endingLen && ox::strcmp(base.data() + (base.len() - endingLen), ending) == 0;
}
[[nodiscard]]
constexpr std::size_t find(StringViewCR str, char const search) noexcept {
constexpr std::size_t find(StringViewCR str, char search) noexcept {
std::size_t i = 0;
for (; i < str.size(); ++i) {
for (; i < str.len(); ++i) {
if (str[i] == search) {
break;
}
@@ -72,7 +62,7 @@ constexpr std::size_t find(StringViewCR str, char const search) noexcept {
[[nodiscard]]
constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
std::size_t i = 0;
for (; i < str.size(); ++i) {
for (; i < str.len(); ++i) {
if (beginsWith(substr(str, i), search)) {
break;
}
@@ -82,14 +72,14 @@ constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
template<std::size_t smallSz = 0>
[[nodiscard]]
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char const del) noexcept {
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, char del) {
return substr(current, find(current, del) + 1);
};
for (auto current = str; current.size(); current = nextSeg(current, del)) {
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.size()) {
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
@@ -102,11 +92,11 @@ template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringViewCR del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, StringViewCR del) {
return substr(current, find(current, del) + del.size());
return substr(current, find(current, del) + del.len());
};
for (auto current = str; current.size(); current = nextSeg(current, del)) {
for (auto current = str; current.len(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.size()) {
if (const auto s = substr(current, 0, next); s.len()) {
out.emplace_back(s);
}
current = substr(current, next);
@@ -115,7 +105,7 @@ constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringView
}
[[nodiscard]]
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int const character) noexcept {
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int character) noexcept {
ox::Result<std::size_t> retval = ox::Error(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) {

View File

@@ -17,8 +17,6 @@ add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
add_test("[ox/std] Vector::shrink_to_fit" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector::shrink_to_fit")
add_test("[ox/std] findIdx" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "findIdx")
add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int")
@@ -28,4 +26,3 @@ add_test("[ox/std] FromHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "FromHex")
add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex")
add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID")
add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")
add_test("[ox/std] intToStr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "intToStr")

View File

@@ -30,7 +30,7 @@ static uint64_t steadyNowMs() {
}
template<typename Map = ox::SmallMap<ox::String, ox::UUID>>
uint64_t timeMapStrToUuid(int const elemCnt, int const lookups, uint64_t seed = 4321) noexcept {
uint64_t timeMapStrToUuid(int elemCnt, int lookups, uint64_t seed = 4321) noexcept {
ox::UUID::seedGenerator({1234, seed});
Map map;
// setup test map
@@ -43,16 +43,15 @@ uint64_t timeMapStrToUuid(int const elemCnt, int const lookups, uint64_t seed =
// start
auto const startTime = steadyNowMs();
for (int i = 0; i < lookups; ++i) {
auto const &k = keys[rand.gen() % keys.size()];
auto const&k = keys[rand.gen() % keys.size()];
map[k];
ox::expect(map[k], ox::UUID::fromString(k).unwrap());
oxExpect(map[k], ox::UUID::fromString(k).unwrap());
}
return steadyNowMs() - startTime;
}
template<typename Map = ox::SmallMap<ox::UUID, ox::String>>
[[nodiscard]]
uint64_t timeMapUuidToStr(int const elemCnt, int const lookups, uint64_t seed = 4321) noexcept {
uint64_t timeMapUuidToStr(int elemCnt, int lookups, uint64_t seed = 4321) noexcept {
ox::UUID::seedGenerator({1234, seed});
Map map;
// setup test map
@@ -65,13 +64,13 @@ uint64_t timeMapUuidToStr(int const elemCnt, int const lookups, uint64_t seed =
// start
auto const startTime = steadyNowMs();
for (int i = 0; i < lookups; ++i) {
auto const &k = keys[rand.gen() % keys.size()];
ox::expect(map[k], k.toString());
auto const&k = keys[rand.gen() % keys.size()];
oxExpect(map[k], k.toString());
}
return steadyNowMs() - startTime;
}
static ox::Error compareMaps(int const lookupCnt = 1'000'000) {
static ox::Error compareMaps(int lookupCnt = 1'000'000) {
auto const seed = steadyNowMs();
uint64_t hashTime{};
uint64_t smallTime{};
@@ -127,7 +126,7 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
OX_CLANG_NOWARN_END
ox::heapmgr::free(a1);
ox::heapmgr::free(a2);
return ox::Error{};
return ox::Error(0);
}
},
{
@@ -136,17 +135,16 @@ OX_CLANG_NOWARN_END
ox::Array<char, 10> buff;
ox::CharBuffWriter bw(buff);
oxAssert(ox::writeItoa(5, bw), "ox::writeItoa returned Error");
ox::expect(ox::StringView(buff.data()), ox::StringView("5"));
oxExpect(ox::StringView(buff.data()), ox::StringView("5"));
OX_RETURN_ERROR(bw.seekp(0));
oxAssert(ox::writeItoa(50, bw), "ox::writeItoa returned Error");
ox::expect(ox::StringView(buff.data()), ox::StringView("50"));
oxExpect(ox::StringView(buff.data()), ox::StringView("50"));
OX_RETURN_ERROR(bw.seekp(0));
oxAssert(ox::writeItoa(500, bw), "ox::writeItoa returned Error");
ox::expect(ox::StringView(buff.data()), ox::StringView("500"));
oxExpect(ox::StringView(buff.data()), ox::StringView("500"));
return ox::Error{};
}
},
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
{
"ABCDEFG != HIJKLMN",
[]() {
@@ -171,7 +169,6 @@ OX_CLANG_NOWARN_END
return ox::Error(ox::memcmp("ABCDEFGHI", "ABCDEFG", 7) != 0);
}
},
OX_ALLOW_UNSAFE_BUFFERS_END
{
"IString",
[]() {
@@ -184,8 +181,8 @@ OX_CLANG_NOWARN_END
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken");
oxAssert(s.size() == 4, "String assign broken");
return ox::Error{};
oxAssert(s.len() == 4, "String assign broken");
return ox::Error(0);
}
},
{
@@ -215,11 +212,11 @@ OX_CLANG_NOWARN_END
oxAssert(ox::StringView("Write") != ox::String(""), "String / StringView comparison broken");
oxAssert(ox::String("Write") != ox::StringView(""), "String / StringView comparison broken");
oxAssert(ox::String("Write") == ox::StringView("Write"), "String / StringView comparison broken");
ox::expect(ox::String("asdf").substr(1, 3), "sd");
oxExpect(ox::String("asdf").substr(1, 3), "sd");
oxAssert(
ox::String(ox::StringView("Write")) == ox::StringView("Write"),
"String / StringView comparison broken");
return ox::Error{};
return ox::Error(0);
}
},
{
@@ -228,60 +225,16 @@ OX_CLANG_NOWARN_END
ox::Vector<int> v;
oxAssert(v.size() == 0, "Initial Vector size not 0");
oxAssert(v.empty(), "Vector::empty() is broken");
auto insertTest = [&v](int const val, std::size_t const size) {
auto insertTest = [&v](int val, std::size_t size) {
v.push_back(val);
OX_RETURN_ERROR(ox::Error(v.size() != size, "Vector size incorrect"));
OX_RETURN_ERROR(ox::Error(v[v.size() - 1] != val, "Vector value wrong"));
return ox::Error{};
return ox::Error(0);
};
oxAssert(insertTest(42, 1), "Vector insertion failed");
oxAssert(insertTest(100, 2), "Vector insertion failed");
oxAssert(insertTest(102, 3), "Vector insertion failed");
return ox::Error{};
}
},
{
"Vector::shrink_to_fit",
[] {
{
ox::Vector<ox::IString<8>> v;
v.reserve(50);
v.emplace_back("asdf");
v.emplace_back("aoeu");
auto const origData = v.data();
v.shrink_to_fit();
ox::expect(v[0], "asdf");
ox::expect(v[1], "aoeu");
ox::expect(v.capacity(), 2u);
oxAssert(origData != v.data(), "shrink_to_fit did not create a new allocation");
}
{
ox::Vector<ox::IString<8>> v;
v.reserve(2);
v.emplace_back("asdf");
v.emplace_back("aoeu");
auto const origData = v.data();
v.shrink_to_fit();
ox::expect(v[0], "asdf");
ox::expect(v[1], "aoeu");
ox::expect(v.capacity(), 2u);
oxAssert(origData == v.data(), "shrink_to_fit inappropriately created a new allocation");
}
return ox::Error{};
}
},
{
"findIdx",
[] {
ox::Vector<ox::IString<8>> const v {"zero", "one", "two", "three", "four"};
ox::expect(ox::findIdx(v.begin(), v.end(), "zero").or_value(5), 0u);
ox::expect(ox::findIdx(v.begin(), v.end(), "one").or_value(5), 1u);
ox::expect(ox::findIdx(v.begin(), v.end(), "two").or_value(5), 2u);
ox::expect(ox::findIdx(v.begin(), v.end(), "three").or_value(5), 3u);
ox::expect(ox::findIdx(v.begin(), v.end(), "four").or_value(5), 4u);
ox::expect(ox::findIdx(v.begin(), v.end(), "five").or_value(5), 5u);
ox::expect(ox::findIdx(v.begin(), v.end(), "six").or_value(6), 6u);
return ox::Error{};
return ox::Error(0);
}
},
{
@@ -289,22 +242,11 @@ OX_CLANG_NOWARN_END
[] {
ox::SmallMap<ox::String, ox::String> map;
map["asdf"] = "aoeu";
ox::expect(map["asdf"], "aoeu");
ox::expect(map.size(), 1u);
ox::expect(map["aoeu"], "");
ox::expect(map.size(), 2u);
ox::SmallMap<ox::String, ox::String> cmap;
cmap["asdf"] = "aoeu";
auto constexpr constTest = [](ox::SmallMap<ox::String, ox::String> const &map) {
OX_REQUIRE(asdf, map.at("asdf"));
ox::expect(*asdf, "aoeu");
ox::expect(map.size(), 1u);
auto const aoeu = map.at("aoeu");
ox::expect(aoeu.ok(), false);
ox::expect(map.size(), 1u);
return ox::Error{};
};
return constTest(cmap);
oxExpect(map["asdf"], "aoeu");
oxExpect(map.size(), 1u);
oxExpect(map["aoeu"], "");
oxExpect(map.size(), 2u);
return ox::Error(0);
}
},
{
@@ -320,7 +262,7 @@ OX_CLANG_NOWARN_END
ii[5] = 100;
oxAssert(ii[4] == 42, "4 != 42");
oxAssert(ii[5] == 100, "5 != 100");
return ox::Error{};
return ox::Error(0);
}
},
{
@@ -331,21 +273,12 @@ OX_CLANG_NOWARN_END
si["aoeu"] = 100;
oxAssert(si["asdf"] == 42, "asdf != 42");
oxAssert(si["aoeu"] == 100, "aoeu != 100");
si.erase("asdf");
oxAssert(!si.contains("asdf"), "wrongly contains asdf");
oxAssert(si.contains("aoeu"), "does not contains aoeu");
oxAssert(!si.at("asdf").ok(), "asdf != 0");
ox::expect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si;
ox::expect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii;
ii[4] = 42;
ii[5] = 100;
oxAssert(ii[4] == 42, "4 != 42");
oxAssert(ii[5] == 100, "5 != 100");
return ox::Error{};
return ox::Error(0);
}
},
{
@@ -378,15 +311,15 @@ OX_CLANG_NOWARN_END
static_cast<int>(actual[1]),
static_cast<int>(actual[2]),
static_cast<int>(actual[3]));
ox::expect(ox::serialize<int32_t>(4).unwrap(), BA({4, 0, 0, 0}));
ox::expect(ox::serialize<int32_t>(256).unwrap(), BA({0, 1, 0, 0}));
ox::expect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));
ox::expect(ox::serialize<uint32_t>(4).unwrap(), BA({4, 0, 0, 0}));
ox::expect(ox::serialize<uint32_t>(256).unwrap(), BA({0, 1, 0, 0}));
ox::expect(ox::serialize<uint32_t>(257).unwrap(), BA({1, 1, 0, 0}));
oxExpect(ox::serialize<int32_t>(4).unwrap(), BA({4, 0, 0, 0}));
oxExpect(ox::serialize<int32_t>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(4).unwrap(), BA({4, 0, 0, 0}));
oxExpect(ox::serialize<uint32_t>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(257).unwrap(), BA({1, 1, 0, 0}));
constexpr auto neg1 = static_cast<char>(-1); // ARM64 Linux assumes -1 literals are ints...
ox::expect(ox::serialize<uint32_t>(0xffff'ffff).unwrap(), BA({neg1, neg1, neg1, neg1}));
return ox::Error{};
oxExpect(ox::serialize<uint32_t>(0xffff'ffff).unwrap(), BA({neg1, neg1, neg1, neg1}));
return ox::Error(0);
}
},
{
@@ -395,58 +328,58 @@ OX_CLANG_NOWARN_END
ox::Buffer b;
ox::BufferWriter w(&b);
oxAssert(w.write("asdf", 4), "write failed");
ox::expect(b.size(), 4u);
oxExpect(b.size(), 4u);
oxAssert(w.write("aoeu", 4), "write failed");
ox::expect(b.size(), 8u);
ox::expect(ox::StringView(b.data(), b.size()), "asdfaoeu");
oxExpect(b.size(), 8u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeu");
ox::StringView constexpr qwerty = "qwerty";
oxAssert(w.write(qwerty.data(), qwerty.bytes()), "write failed");
ox::expect(b.size(), 14u);
ox::expect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty");
return ox::Error{};
oxExpect(b.size(), 14u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty");
return ox::Error(0);
}
},
{
"FromHex",
[] {
ox::expect(ox::detail::fromHex("01").unwrap(), 0x01);
ox::expect(ox::detail::fromHex("02").unwrap(), 0x02);
ox::expect(ox::detail::fromHex("03").unwrap(), 0x03);
ox::expect(ox::detail::fromHex("04").unwrap(), 0x04);
ox::expect(ox::detail::fromHex("05").unwrap(), 0x05);
ox::expect(ox::detail::fromHex("06").unwrap(), 0x06);
ox::expect(ox::detail::fromHex("07").unwrap(), 0x07);
ox::expect(ox::detail::fromHex("08").unwrap(), 0x08);
ox::expect(ox::detail::fromHex("0d").unwrap(), 0x0d);
ox::expect(ox::detail::fromHex("0e").unwrap(), 0x0e);
ox::expect(ox::detail::fromHex("0f").unwrap(), 0x0f);
ox::expect(ox::detail::fromHex("0F").unwrap(), 0x0f);
ox::expect(ox::detail::fromHex("fF").unwrap(), 0xff);
ox::expect(ox::detail::fromHex("ff").unwrap(), 0xff);
ox::expect(ox::detail::fromHex("a0").unwrap(), 0xa0);
ox::expect(ox::detail::fromHex("93").unwrap(), 0x93);
ox::expect(ox::detail::fromHex("40").unwrap(), 0x40);
return ox::Error{};
oxExpect(ox::detail::fromHex("01").unwrap(), 0x01);
oxExpect(ox::detail::fromHex("02").unwrap(), 0x02);
oxExpect(ox::detail::fromHex("03").unwrap(), 0x03);
oxExpect(ox::detail::fromHex("04").unwrap(), 0x04);
oxExpect(ox::detail::fromHex("05").unwrap(), 0x05);
oxExpect(ox::detail::fromHex("06").unwrap(), 0x06);
oxExpect(ox::detail::fromHex("07").unwrap(), 0x07);
oxExpect(ox::detail::fromHex("08").unwrap(), 0x08);
oxExpect(ox::detail::fromHex("0d").unwrap(), 0x0d);
oxExpect(ox::detail::fromHex("0e").unwrap(), 0x0e);
oxExpect(ox::detail::fromHex("0f").unwrap(), 0x0f);
oxExpect(ox::detail::fromHex("0F").unwrap(), 0x0f);
oxExpect(ox::detail::fromHex("fF").unwrap(), 0xff);
oxExpect(ox::detail::fromHex("ff").unwrap(), 0xff);
oxExpect(ox::detail::fromHex("a0").unwrap(), 0xa0);
oxExpect(ox::detail::fromHex("93").unwrap(), 0x93);
oxExpect(ox::detail::fromHex("40").unwrap(), 0x40);
return ox::Error(0);
}
},
{
"ToHex",
[] {
ox::expect(ox::detail::toHex(0x01), "01");
ox::expect(ox::detail::toHex(0x02), "02");
ox::expect(ox::detail::toHex(0x03), "03");
ox::expect(ox::detail::toHex(0x04), "04");
ox::expect(ox::detail::toHex(0x05), "05");
ox::expect(ox::detail::toHex(0x06), "06");
ox::expect(ox::detail::toHex(0x07), "07");
ox::expect(ox::detail::toHex(0x08), "08");
ox::expect(ox::detail::toHex(0x0d), "0d");
ox::expect(ox::detail::toHex(0x0e), "0e");
ox::expect(ox::detail::toHex(0x0f), "0f");
ox::expect(ox::detail::toHex(0x93), "93");
ox::expect(ox::detail::toHex(0x40), "40");
ox::expect(ox::detail::toHex(0xf0), "f0");
return ox::Error{};
oxExpect(ox::detail::toHex(0x01), "01");
oxExpect(ox::detail::toHex(0x02), "02");
oxExpect(ox::detail::toHex(0x03), "03");
oxExpect(ox::detail::toHex(0x04), "04");
oxExpect(ox::detail::toHex(0x05), "05");
oxExpect(ox::detail::toHex(0x06), "06");
oxExpect(ox::detail::toHex(0x07), "07");
oxExpect(ox::detail::toHex(0x08), "08");
oxExpect(ox::detail::toHex(0x0d), "0d");
oxExpect(ox::detail::toHex(0x0e), "0e");
oxExpect(ox::detail::toHex(0x0f), "0f");
oxExpect(ox::detail::toHex(0x93), "93");
oxExpect(ox::detail::toHex(0x40), "40");
oxExpect(ox::detail::toHex(0xf0), "f0");
return ox::Error(0);
}
},
{
@@ -454,20 +387,20 @@ OX_CLANG_NOWARN_END
[] {
constexpr ox::StringView uuidStr = "8d814442-f46e-4cc3-8edc-ca3c01cc86db";
OX_REQUIRE(uuid, ox::UUID::fromString(uuidStr));
ox::expect(uuid.toString(), uuidStr);
ox::expect(ox::UUID{}.isNull(), true);
ox::expect(ox::UUID::fromString(uuidStr).value.isNull(), false);
return ox::Error{};
oxExpect(uuid.toString(), uuidStr);
oxExpect(ox::UUID{}.isNull(), true);
oxExpect(ox::UUID::fromString(uuidStr).value.isNull(), false);
return ox::Error(0);
}
},
{
"UUID::generate",
[] {
ox::UUID::seedGenerator({1234, 4321});
ox::expect(ox::UUID::generate().unwrap().toString(), "5c3f4b5e-ccbf-4727-7f03-3053dedc8827");
ox::expect(ox::UUID::generate().unwrap().toString(), "90d0274a-2774-4afa-88e5-0c1d60ba3abf");
ox::expect(ox::UUID::generate().unwrap().toString(), "7df77910-841c-48ba-ea2e-44521ac47c2e");
return ox::Error{};
oxExpect(ox::UUID::generate().unwrap().toString(), "5c3f4b5e-ccbf-4727-7f03-3053dedc8827");
oxExpect(ox::UUID::generate().unwrap().toString(), "90d0274a-2774-4afa-88e5-0c1d60ba3abf");
oxExpect(ox::UUID::generate().unwrap().toString(), "7df77910-841c-48ba-ea2e-44521ac47c2e");
return ox::Error(0);
}
},
{
@@ -475,100 +408,71 @@ OX_CLANG_NOWARN_END
[] {
ox::StringView sv = "ab.cd";
auto list = ox::split(sv, ".");
ox::expect(list.size(), 2u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = "ab.cd.fg";
list = ox::split(sv, ".");
ox::expect(list.size(), 3u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
ox::expect(list[2], "fg");
oxExpect(list.size(), 3u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
oxExpect(list[2], "fg");
sv = "ab.cd.";
list = ox::split(sv, ".");
ox::expect(list.size(), 2u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".ab.cd.";
list = ox::split(sv, ".");
ox::expect(list.size(), 2u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".";
list = ox::split(sv, ".");
ox::expect(list.size(), 0u);
oxExpect(list.size(), 0u);
sv = ".";
list = ox::split(sv, ".");
ox::expect(list.size(), 0u);
oxExpect(list.size(), 0u);
sv = "";
list = ox::split(sv, ".");
ox::expect(list.size(), 0u);
oxExpect(list.size(), 0u);
// split by single char
sv = "ab.cd";
list = ox::split(sv, '.');
ox::expect(list.size(), 2u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = "ab.cd.fg";
list = ox::split(sv, '.');
ox::expect(list.size(), 3u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
ox::expect(list[2], "fg");
oxExpect(list.size(), 3u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
oxExpect(list[2], "fg");
sv = "ab.cd.";
list = ox::split(sv, '.');
ox::expect(list.size(), 2u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".ab.cd.";
list = ox::split(sv, '.');
ox::expect(list.size(), 2u);
ox::expect(list[0], "ab");
ox::expect(list[1], "cd");
oxExpect(list.size(), 2u);
oxExpect(list[0], "ab");
oxExpect(list[1], "cd");
sv = ".";
list = ox::split(sv, '.');
ox::expect(list.size(), 0u);
oxExpect(list.size(), 0u);
sv = ".";
list = ox::split(sv, '.');
ox::expect(list.size(), 0u);
oxExpect(list.size(), 0u);
sv = "";
list = ox::split(sv, '.');
ox::expect(list.size(), 0u);
return ox::Error{};
}
},
{
"intToStr",
[] {
ox::expect(ox::intToStr<uint8_t>(255u), "255");
ox::expect(ox::intToStr<int8_t>(127), "127");
ox::expect(ox::intToStr<int8_t>(-128), "-128");
ox::expect(ox::intToStr<uint16_t>(65535u), "65535");
ox::expect(ox::intToStr<int16_t>(32767), "32767");
ox::expect(ox::intToStr<int16_t>(-32768), "-32768");
ox::expect(ox::intToStr<uint32_t>(4294967295u), "4294967295");
ox::expect(ox::intToStr<int32_t>(2147483647), "2147483647");
ox::expect(ox::intToStr<int32_t>(-2147483648), "-2147483648");
ox::expect(ox::intToStr<uint64_t>(18446744073709551615u), "18446744073709551615");
ox::expect(ox::intToStr<int64_t>(9223372036854775807), "9223372036854775807");
ox::expect(ox::intToStr<int64_t>(-9223372036854775807), "-9223372036854775807");
ox::expect(ox::intToStr<uint64_t>(0), "0");
ox::expect(ox::intToStr<uint64_t>(5), "5");
ox::expect(ox::intToStr(0), "0");
ox::expect(ox::intToStr(5), "5");
ox::expect(ox::intToStr(5000), "5000");
ox::expect(ox::intToStr(50000), "50000");
ox::expect(ox::intToStr(500000), "500000");
ox::expect(ox::intToStr(-5), "-5");
ox::expect(ox::intToStr(-5000), "-5000");
ox::expect(ox::intToStr(-50000), "-50000");
ox::expect(ox::intToStr(-500000), "-500000");
return ox::Error{};
oxExpect(list.size(), 0u);
return ox::Error(0);
}
},
};
int main(int const argc, const char **argv) {
int main(int argc, const char **argv) {
if (argc < 2) {
oxError("Must specify test to run");
return -1;

View File

@@ -166,7 +166,7 @@ class OutStream {
constexpr OutStream &operator<<(Integer_c auto v) noexcept;
constexpr OutStream &operator<<(char v) noexcept {
if (m_msg.msg.size()) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
@@ -174,7 +174,7 @@ class OutStream {
}
constexpr OutStream &operator<<(StringViewCR v) noexcept {
if (m_msg.msg.size()) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
@@ -209,7 +209,7 @@ class OutStream {
private:
constexpr OutStream &appendSignedInt(int64_t v) noexcept {
if (m_msg.msg.size()) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(v);
@@ -217,7 +217,7 @@ class OutStream {
}
constexpr OutStream &appendUnsignedInt(uint64_t v) noexcept {
if (m_msg.msg.size()) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(v);
@@ -227,7 +227,7 @@ class OutStream {
};
constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept {
if (m_msg.msg.size()) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
@@ -268,9 +268,9 @@ using TraceStream = NullStream;
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox.error");
if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
TraceStream trc(file, line, "ox::error");
if (err.file != nullptr) {
trc << "Error: (" << err.file << ":" << err.line << "):";
} else {
trc << "Error:";
}
@@ -280,10 +280,10 @@ inline void logError(const char *file, int line, const char *fmt, const Error &e
inline void logError(const char *file, int line, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox.error");
TraceStream trc(file, line, "ox::error");
trc << "Error:" << err;
if (err.src.file_name() != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";
if (err.file != nullptr) {
trc << "(" << err.file << ":" << err.line << ")";
}
}
}

View File

@@ -39,8 +39,6 @@ enum LogChan {
Debug = 4,
};
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
template<LogChan chan>
static void log(ox::StringViewCR str) {
const auto sz = ox::min<std::size_t>(0x100, str.bytes());
@@ -105,7 +103,5 @@ void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line,
#endif
}
OX_ALLOW_UNSAFE_BUFFERS_END
}

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