Compare commits

..

29 Commits

Author SHA1 Message Date
fd2fb6e0c1 [nostalgia/studio] Bump version to 2024.12.4
All checks were successful
Build / build (push) Successful in 3m24s
2025-01-26 21:08:52 -06:00
449022f9ae [ox/std] Fix HashMap collision handling
Some checks failed
Build / build (push) Has been cancelled
2025-01-26 21:01:35 -06:00
6898f8eda1 [ox/std] Fix UPtr compare with nullptr 2025-01-26 21:01:35 -06:00
1f5c5a72ef [ox/model] Fix possible infinite recursion 2025-01-23 23:46:42 -06:00
a18c5d9294 [ox/std] Fix string append issues
All checks were successful
Build / build (push) Successful in 3m21s
2025-01-19 17:12:22 -06:00
c753881747 [ox/std] Fix possible error that occurs with appending on boundary of small string size 2025-01-19 09:27:44 -06:00
ba1bf950a8 [nostalgia/core/studio/paletteeditor] Fix adding page if there is no existing page
All checks were successful
Build / build (push) Successful in 3m19s
2025-01-18 21:31:22 -06:00
95950441d1 [nostalgia/core/studio/tilesheeteditor] Fix subsheet and palette scrolling 2025-01-18 21:31:22 -06:00
1b32bdfcad [nostalgia/studio] Bump version to d2024.12.3
All checks were successful
Build / build (push) Successful in 3m14s
2025-01-17 21:45:37 -06:00
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
399 changed files with 6292 additions and 36430 deletions

1
.gitattributes vendored
View File

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

View File

@@ -4,7 +4,7 @@ on: [push]
jobs: jobs:
build: build:
runs-on: olympic runs-on: nostalgia
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -17,10 +17,3 @@ jobs:
- run: make purge configure-release - run: make purge configure-release
- run: make build - run: make build
- run: make test - 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 .mypy_cache
.stfolder .stfolder
.stignore .stignore
.vs scripts/__pycache__
util/scripts/__pycache__
pyenv pyenv
CMakeLists.txt.user CMakeLists.txt.user
ROM.oxfs ROM.oxfs
Session.vim Session.vim
build build
cmake-build-*
compile_commands.json compile_commands.json
dist dist
graph_info.json graph_info.json

View File

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

View File

@@ -1,68 +1,35 @@
BC_VAR_PROJECT_NAME=nostalgia BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia BC_VAR_PROJECT_NAME_CAP=Nostalgia
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin) 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 MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
else 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 MGBA=mgba-qt
endif endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build-pack build-gba-player pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.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
.PHONY: run .PHONY: run
run: build-player run: build
${PROJECT_PLAYER} sample_project ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio .PHONY: run-studio
run-studio: build-studio run-studio: build
${PROJECT_STUDIO} ${NOSTALGIA_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba ${MGBA} ${BC_VAR_PROJECT_NAME}.gba
.PHONY: debug .PHONY: debug
debug: build 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 .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
configure-gba: configure-gba:
@@ -71,25 +38,3 @@ configure-gba:
.PHONY: configure-gba-debug .PHONY: configure-gba-debug
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} ${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 ${BC_CMD_RM_RF} compile_commands.json
.PHONY: test .PHONY: test
test: build 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 ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test
.PHONY: test-verbose .PHONY: test-verbose
test-verbose: build test-verbose: build

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules) 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} -nostdlib")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++") 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-unwind-tables")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") 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-rtti")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ endif()
# DrinkingTea: end # DrinkingTea: end
add_library( add_library(
imgui imgui OBJECT
imgui.cpp imgui.cpp
imgui_demo.cpp imgui_demo.cpp
imgui_draw.cpp imgui_draw.cpp
@@ -19,12 +19,4 @@ add_library(
target_include_directories( target_include_directories(
imgui SYSTEM PUBLIC 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) project(nativefiledialog-extended VERSION 1.1.1)
set(nfd_ROOT_PROJECT OFF) set(nfd_ROOT_PROJECT OFF)

View File

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

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

View File

@@ -81,7 +81,7 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
return ox::Error(4, "Claw format does not match any supported format/version combo"); return ox::Error(4, "Claw format does not match any supported format/version combo");
} }
hdr.typeName = typeName; hdr.typeName = typeName;
std::ignore = ox::strToInt(versionStr).copyTo(hdr.typeVersion); std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
hdr.data = buffRaw; hdr.data = buffRaw;
hdr.dataSize = buffLen; hdr.dataSize = buffLen;
return hdr; return hdr;

View File

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

View File

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

View File

@@ -143,11 +143,6 @@ class Signal {
Error disconnectObject(const void *receiver) const noexcept; Error disconnectObject(const void *receiver) const noexcept;
[[nodiscard]]
size_t connectionCnt() const noexcept {
return m_slots.size();
}
void emit(Args... args) const; void emit(Args... args) const;
Error emitCheckError(Args... args) const noexcept; Error emitCheckError(Args... args) const noexcept;
@@ -218,9 +213,9 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) { for (auto &f : m_slots) {
f->call(args...); f->call(args...);
} }
return {}; return ox::Error(0);
} catch (const ox::Exception &ex) { } 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);
} }
} }
@@ -324,11 +319,6 @@ class Signal<Error(Args...)> {
Error disconnectObject(const void *receiver) const noexcept; Error disconnectObject(const void *receiver) const noexcept;
[[nodiscard]]
size_t connectionCnt() const noexcept {
return m_slots.size();
}
void emit(Args... args) const noexcept; void emit(Args... args) const noexcept;
Error emitCheckError(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) { for (auto &f : m_slots) {
OX_RETURN_ERROR(f->call(ox::forward<Args>(args)...)); 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) { Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate()); OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate());
++item->links; ++item->links;
return {}; return ox::Error(0);
} }
template<typename size_t> template<typename size_t>
@@ -240,7 +240,7 @@ Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
if (item->links == 0) { if (item->links == 0) {
OX_RETURN_ERROR(remove(item)); OX_RETURN_ERROR(remove(item));
} }
return {}; return ox::Error(0);
} }
template<typename size_t> 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()); dest->id.get(), dest.offset(), destData.size());
fsData->rootNode = dest.offset(); fsData->rootNode = dest.offset();
oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get()); oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get());
return {}; return ox::Error(0);
} }
} else { } else {
oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header."); 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); oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize);
OX_RETURN_ERROR(m_buffer->setSize(newSize)); OX_RETURN_ERROR(m_buffer->setSize(newSize));
oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size()); oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size());
return {}; return ox::Error(0);
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) { Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
if (m_buffer->size() > size) { 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); m_buffSize = static_cast<size_t>(size);
if (newBuff) { 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))); OX_RETURN_ERROR(m_buffer->setSize(static_cast<size_t>(size)));
} }
return {}; return ox::Error(0);
} }
template<typename size_t> 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()) { for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end())); OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
} }
return {}; return ox::Error(0);
} }
template<typename size_t> 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 { return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> Error {
if (isFirstItem) { if (isFirstItem) {
isFirstItem = false; isFirstItem = false;
return {}; return ox::Error(0);
} }
if (!item.valid()) { if (!item.valid()) {
return ox::Error(1); return ox::Error(1);
@@ -524,7 +524,7 @@ Error FileStoreTemplate<size_t>::compact() {
parent->right = item; parent->right = item;
} }
} }
return {}; return ox::Error(0);
}); });
} }
@@ -552,7 +552,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
item->left = root->left; item->left = root->left;
item->right = root->right; item->right = root->right;
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get());
return {}; return ox::Error(0);
} else { } else {
return placeItem(root, item); return placeItem(root, item);
} }
@@ -573,7 +573,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = right->right; item->right = right->right;
} }
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return {}; return ox::Error(0);
} else { } else {
return placeItem(right, item, depth + 1); 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; item->right = left->right;
} }
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return {}; return ox::Error(0);
} else { } else {
return placeItem(left, item, depth + 1); return placeItem(left, item, depth + 1);
} }
@@ -624,7 +624,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
} else { } else {
fsData->rootNode = 0; fsData->rootNode = 0;
} }
return {}; return ox::Error(0);
} else { } else {
return unplaceItem(root, item); return unplaceItem(root, item);
} }
@@ -661,7 +661,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
if (item->left) { if (item->left) {
OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left))); OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left)));
} }
return {}; return ox::Error(0);
} }
template<typename size_t> template<typename size_t>
@@ -669,7 +669,7 @@ Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
if (item.valid()) { if (item.valid()) {
OX_RETURN_ERROR(unplaceItem(item)); OX_RETURN_ERROR(unplaceItem(item));
OX_RETURN_ERROR(m_buffer->free(item)); OX_RETURN_ERROR(m_buffer->free(item));
return {}; return ox::Error(0);
} }
return ox::Error(1); return ox::Error(1);
} }

View File

@@ -52,7 +52,7 @@ struct OX_PACKED DirectoryEntry {
if (d.valid()) { if (d.valid()) {
d->inode = inode; d->inode = inode;
auto const maxStrSz = bufferSize - 1 - sizeof(*this); 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 {};
} }
return ox::Error(1); 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"); oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory");
return ox::Error(1, "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 entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize); const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size); 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 { FileAddress::FileAddress(ox::StringViewCR path) noexcept {
auto pathSize = path.bytes(); auto pathSize = path.bytes();
m_data.path = new char[pathSize + 1]; m_data.path = new char[pathSize + 1];
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(m_data.path, path.data(), pathSize); memcpy(m_data.path, path.data(), pathSize);
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
m_data.path[pathSize] = 0; m_data.path[pathSize] = 0;
OX_ALLOW_UNSAFE_BUFFERS_END OX_CLANG_NOWARN_END
m_type = FileAddressType::Path; m_type = FileAddressType::Path;
} }
@@ -48,11 +48,9 @@ FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
case FileAddressType::Path: case FileAddressType::Path:
{ {
if (other.m_data.path) { if (other.m_data.path) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
auto strSize = ox::strlen(other.m_data.path) + 1; auto strSize = ox::strlen(other.m_data.path) + 1;
m_data.path = new char[strSize]; m_data.path = new char[strSize];
ox::memcpy(m_data.path, other.m_data.path, strSize); ox::memcpy(m_data.path, other.m_data.path, strSize);
OX_ALLOW_UNSAFE_BUFFERS_END
} else { } else {
m_data.constPath = ""; m_data.constPath = "";
m_type = FileAddressType::ConstPath; m_type = FileAddressType::ConstPath;

View File

@@ -24,6 +24,9 @@ enum class FileAddressType: int8_t {
Inode, Inode,
}; };
template<typename T>
constexpr Error model(T *h, CommonPtrWith<class FileAddress> auto *fa) noexcept;
class FileAddress { class FileAddress {
template<typename T> 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 { Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
OX_REQUIRE(s, stat(addr)); OX_REQUIRE(s, stat(addr));
Buffer buff(static_cast<std::size_t>(s.size)); Buffer buff(static_cast<std::size_t>(s.size));
@@ -75,31 +51,28 @@ Result<Buffer> FileSystem::read(StringViewCR path) noexcept {
return buff; return buff;
} }
Error FileSystem::read( Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
FileAddress const &addr,
std::size_t const readStart,
std::size_t const readSize,
void *buffer,
std::size_t *size) noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: 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::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return readFilePathRange(addr.getPath().value, readStart, readSize, buffer, size); return ox::Error(2, "Unsupported for path lookups");
default: default:
return ox::Error(1); return ox::Error(1);
} }
} }
Result<size_t> FileSystem::read( Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
StringViewCR path, switch (addr.type()) {
std::size_t const readStart, case FileAddressType::Inode:
std::size_t const readSize, return remove(addr.getInode().value, recursive);
Span<char> buff) noexcept { case FileAddressType::ConstPath:
size_t szOut{buff.size()}; case FileAddressType::Path:
OX_RETURN_ERROR(readFilePathRange(path, readStart, readSize, buff.data(), &szOut)); return remove(StringView(addr.getPath().value), recursive);
return szOut; default:
return ox::Error(1);
}
} }
Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept {

View File

@@ -20,7 +20,7 @@
namespace ox { namespace ox {
namespace detail { namespace detail {
inline void fsBuffFree(char *buff) noexcept { static inline void fsBuffFree(char *buff) noexcept {
safeDelete(buff); safeDelete(buff);
} }
} }
@@ -41,45 +41,25 @@ class FileSystem {
Error read(const FileAddress &addr, void *buffer, std::size_t size) noexcept; 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(const FileAddress &addr) noexcept;
Result<Buffer> read(StringViewCR path) 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); 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); return readFileInode(inode, buffer, buffSize);
} }
Error read( Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept;
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;
virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0; virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0;
Error remove(StringViewCR path, bool recursive = false) noexcept { virtual Error remove(StringViewCR path, bool recursive) noexcept = 0;
return removePath(path, recursive);
} Error remove(const FileAddress &addr, bool recursive = false) noexcept;
virtual Error resize(uint64_t size, void *buffer) noexcept = 0; virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
@@ -87,7 +67,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile); 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); return write(path, buff.data(), buff.size(), FileType::NormalFile);
} }
@@ -95,42 +75,42 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile); 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); 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(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); 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); 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); return statInode(inode);
} }
Result<FileStat> stat(StringViewCR path) const noexcept { inline Result<FileStat> stat(StringViewCR path) const noexcept {
return statPath(path); return statPath(path);
} }
Result<FileStat> stat(const FileAddress &addr) const noexcept; Result<FileStat> stat(const FileAddress &addr) const noexcept;
[[nodiscard]] [[nodiscard]]
bool exists(uint64_t inode) const noexcept { inline bool exists(uint64_t inode) const noexcept {
return statInode(inode).ok(); return statInode(inode).ok();
} }
[[nodiscard]] [[nodiscard]]
bool exists(ox::StringView path) const noexcept { inline bool exists(ox::StringView path) const noexcept {
return statPath(path).ok(); return statPath(path).ok();
} }
[[nodiscard]] [[nodiscard]]
bool exists(FileAddress const&addr) const noexcept { inline bool exists(FileAddress const&addr) const noexcept {
return stat(addr).ok(); 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 readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
virtual Error readFilePathRange( virtual Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0;
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 writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) 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: public:
Result<const char*> directAccess(const FileAddress &addr) const noexcept; 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); 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); 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 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<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(StringViewCR dir) const noexcept override; Result<Vector<String>> ls(StringViewCR dir) const noexcept override;
@@ -246,6 +216,8 @@ class FileSystemTemplate: public MemFS {
template<typename F> template<typename F>
Error ls(StringViewCR path, F cb) const; Error ls(StringViewCR path, F cb) const;
Error remove(StringViewCR path, bool recursive) noexcept override;
/** /**
* Resizes FileSystem to minimum possible size. * 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 ox::Error(1);
} }
return {}; return ox::Error(0);
} }
template<typename FileStore, typename Directory> 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_REQUIRE_M(inode, rootDir.find(src));
OX_RETURN_ERROR(rootDir.write(dest, inode)); OX_RETURN_ERROR(rootDir.write(dest, inode));
OX_RETURN_ERROR(rootDir.remove(src)); OX_RETURN_ERROR(rootDir.remove(src));
return {}; return ox::Error(0);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
@@ -385,14 +357,35 @@ Error FileSystemTemplate<FileStore, Directory>::readFileInodeRange(uint64_t inod
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::readFilePathRange( Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept { auto data = m_fs.read(inode);
OX_REQUIRE(s, stat(path)); if (!data.valid()) {
return readFileInodeRange(s.inode, readStart, readSize, buffer, buffSize); return ox::Error(1, "Data not valid");
}
return reinterpret_cast<char*>(data.get());
} }
template<typename FileStore, typename Directory> 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()); OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode); Directory rootDir(m_fs, fd.rootDirInode);
OX_REQUIRE(inode, rootDir.find(path)); 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."); oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return ox::Error(1); return ox::Error(1);
} }
return {}; return ox::Error(0);
}
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);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
@@ -468,7 +433,7 @@ Error FileSystemTemplate<FileStore, Directory>::writeFilePath(
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept { 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)); 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()) { if (ec.value()) {
return ox::Error(1); return ox::Error(1);
} }
return {}; return ox::Error(0);
} }
Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept { Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
@@ -75,6 +75,14 @@ Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
return out; 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 { Error PassThroughFS::resize(uint64_t, void*) noexcept {
// unsupported // unsupported
return ox::Error(1, "resize is not supported by PassThroughFS"); 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); oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec); const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec);
oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size); oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size);
if (auto err = ec.value()) { OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
return ox::Error{static_cast<ox::ErrorCode>(err), "PassThroughFS: stat failed"};
}
return FileStat{0, 0, size, type}; 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()); oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return ox::Error(2); return ox::Error(2);
} }
return {}; return ox::Error(0);
} }
Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept { 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"); 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 { Error PassThroughFS::readFileInodeRange(uint64_t, std::size_t, std::size_t, void*, std::size_t*) noexcept {
// unsupported // unsupported
return ox::Error(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS"); 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 { Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType) noexcept {
const auto p = (m_path / stripSlash(path)); const auto p = (m_path / stripSlash(path));
try { 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()); oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return ox::Error(1); return ox::Error(1);
} }
return {}; return ox::Error(0);
} }
Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept { 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 { 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); path = substr(path, 1);
} }
return {path.data(), path.bytes()}; return {path.data(), path.bytes()};

View File

@@ -45,6 +45,8 @@ class PassThroughFS: public FileSystem {
template<typename F> template<typename F>
Error ls(StringViewCR dir, F cb) const noexcept; 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; Error resize(uint64_t size, void *buffer) noexcept override;
Result<FileStat> statInode(uint64_t inode) const 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 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 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 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; 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) { for (auto &p : di) {
OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0)); 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) { if (idx >= 0 && size < outSize) {
ox::memcpy(out, m_path, size); ox::memcpy(out, m_path, size);
out[size] = 0; out[size] = 0;
return {}; return ox::Error(0);
} else { } else {
return ox::Error(1); return ox::Error(1);
} }
@@ -74,7 +74,7 @@ Error PathIterator::get(StringView &fileName) {
if (size && fileName[size - 1] == '/') { if (size && fileName[size - 1] == '/') {
fileName = ox::substr(m_path, start, start + 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 {}; return {};
} }
@@ -85,7 +85,7 @@ Error PathIterator::next(StringView &fileName) {
std::size_t size = 0; std::size_t size = 0;
auto retval = ox::Error(1); auto retval = ox::Error(1);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) { if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = {}; retval = ox::Error(0);
if (m_path[m_iterator] == '/') { if (m_path[m_iterator] == '/') {
m_iterator++; m_iterator++;
} }
@@ -104,11 +104,11 @@ Error PathIterator::next(StringView &fileName) {
} }
fileName = ox::substr(m_path, start, start + size); fileName = ox::substr(m_path, start, start + size);
// truncate trailing / // truncate trailing /
while (fileName.size() && fileName[fileName.size() - 1] == '/') { while (fileName.len() && fileName[fileName.len() - 1] == '/') {
fileName = ox::substr(m_path, start, start + size); fileName = ox::substr(m_path, start, start + size);
} }
m_iterator += 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; return retval;
} }
@@ -118,7 +118,7 @@ Result<std::size_t> PathIterator::nextSize() const {
auto retval = ox::Error(1); auto retval = ox::Error(1);
auto it = m_iterator; auto it = m_iterator;
if (it < m_maxSize && ox::strlen(&m_path[it])) { if (it < m_maxSize && ox::strlen(&m_path[it])) {
retval = {}; retval = ox::Error(0);
if (m_path[it] == '/') { if (m_path[it] == '/') {
it++; it++;
} }

View File

@@ -354,7 +354,7 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
} }
} }
m_header.bytesUsed -= item.size(); m_header.bytesUsed -= item.size();
return {}; return ox::Error(0);
} }
template<typename size_t, typename Item> 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); m_header.size = static_cast<size_t>(size);
auto data = reinterpret_cast<uint8_t*>(this) + end; auto data = reinterpret_cast<uint8_t*>(this) + end;
ox::memset(data, 0, size - 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); src = ptr(dest->next);
dest = uninitializedPtr(dest.offset() + dest->fullSize()); dest = uninitializedPtr(dest.offset() + dest->fullSize());
} }
return {}; return ox::Error(0);
} }
template<typename size_t, typename Item> 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", "PathIterator::next1",
[](ox::StringView) { [](ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag"); 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; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -84,7 +84,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next3", "PathIterator::next3",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("/"); auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.size()); ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return ox::Error(0); return ox::Error(0);
@@ -106,7 +106,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next5", "PathIterator::next5",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("usr/share/"); 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; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "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", "PathIterator::dirPath",
[] (ox::StringView) { [] (ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag"); 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());
auto buff = static_cast<char*>(ox_alloca(path.size() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
oxAssert(it.dirPath(buff, path.size()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
OX_ALLOW_UNSAFE_BUFFERS_END
return ox::Error(0); return ox::Error(0);
} }
}, },
@@ -129,9 +127,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::hasNext", "PathIterator::hasNext",
[](ox::StringView) { [](ox::StringView) {
const auto path = "/file1"; const auto path = "/file1";
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::PathIterator it(path, ox::strlen(path)); ox::PathIterator it(path, ox::strlen(path));
OX_ALLOW_UNSAFE_BUFFERS_END
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext"); oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext"); oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
return ox::Error(0); return ox::Error(0);
@@ -167,11 +163,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
constexpr auto str1 = "Hello, World!"; constexpr auto str1 = "Hello, World!";
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
constexpr auto str1Len = ox::strlen(str1) + 1; constexpr auto str1Len = ox::strlen(str1) + 1;
constexpr auto str2 = "Hello, Moon!"; constexpr auto str2 = "Hello, Moon!";
constexpr auto str2Len = ox::strlen(str2) + 1; 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); auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed."); oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
ox::FileStore32 fileStore(list, buffLen); ox::FileStore32 fileStore(list, buffLen);

View File

@@ -48,7 +48,7 @@ static ox::Error runLs(ox::FileSystem *fs, ox::Span<const char*> args) noexcept
for (const auto &file : files) { for (const auto &file : files) {
oxOutf("{}\n", file); oxOutf("{}\n", file);
} }
return {}; return ox::Error(0);
} }
static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept { 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); return ox::Error(1);
} }
OX_REQUIRE(buff, fs->read(ox::StringView(args[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); std::ignore = fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
OX_ALLOW_UNSAFE_BUFFERS_END return ox::Error(0);
return {};
} }
static ox::Error run(int argc, const char **argv) noexcept { static ox::Error run(int argc, const char **argv) noexcept {

View File

@@ -14,7 +14,7 @@
{ \ { \
const auto loggerErr = (loggerName).initConn(appName); \ const auto loggerErr = (loggerName).initConn(appName); \
if (loggerErr) { \ 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 { \ } else { \
ox::trace::setLogger(&(loggerName)); \ ox::trace::setLogger(&(loggerName)); \
} \ } \

View File

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

View File

@@ -71,9 +71,7 @@ constexpr McInt encodeInteger(I pInput) noexcept {
// move input to uint64_t to allow consistent bit manipulation, and to avoid // move input to uint64_t to allow consistent bit manipulation, and to avoid
// overflow concerns // overflow concerns
uint64_t val = 0; uint64_t val = 0;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&val, &input, sizeof(input)); ox::memcpy(&val, &input, sizeof(input));
OX_ALLOW_UNSAFE_BUFFERS_END
if (val) { if (val) {
// bits needed to represent number factoring in space possibly // bits needed to represent number factoring in space possibly
// needed for signed bit // needed for signed bit
@@ -96,9 +94,7 @@ constexpr McInt encodeInteger(I pInput) noexcept {
} }
if (bytes == 9) { if (bytes == 9) {
out.data[0] = bytesIndicator; out.data[0] = bytesIndicator;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out.data[1], &leVal, 8); ox::memcpy(&out.data[1], &leVal, 8);
OX_ALLOW_UNSAFE_BUFFERS_END
if (inputNegative) { if (inputNegative) {
out.data[1] |= 0b1000'0000; out.data[1] |= 0b1000'0000;
} }
@@ -108,9 +104,7 @@ constexpr McInt encodeInteger(I pInput) noexcept {
auto intermediate = auto intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes | static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator); static_cast<uint64_t>(bytesIndicator);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out.data[0], &intermediate, sizeof(intermediate)); ox::memcpy(&out.data[0], &intermediate, sizeof(intermediate));
OX_ALLOW_UNSAFE_BUFFERS_END
} }
out.length = bytes; out.length = bytes;
} }
@@ -157,37 +151,33 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
decoded >>= bytes; decoded >>= bytes;
// move sign bit // move sign bit
if constexpr(is_signed_v<I>) { if constexpr(is_signed_v<I>) {
const auto negBit = bytes * 8 - bytes - 1; const auto negBit = bytes * 8 - bytes - 1;
// move sign // move sign
const auto negative = (decoded >> negBit) == 1; const auto negative = (decoded >> negBit) == 1;
if (negative) { if (negative) {
// fill in all bits between encoded sign and real sign with 1s // fill in all bits between encoded sign and real sign with 1s
// split it up because the 32-bit ARM can't shift more than 32 bits // split it up because the 32-bit ARM can't shift more than 32 bits
ox::Array<uint32_t, 2> d = {}; ox::Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff; //d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32; //d[1] = decoded >> 32;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN ox::memcpy(&d[0], &decoded, sizeof(decoded));
ox::memcpy(&d[0], &decoded, sizeof(decoded)); auto bit = negBit;
OX_ALLOW_UNSAFE_BUFFERS_END for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
auto bit = negBit; d[0] |= 1 << bit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) { }
d[0] |= 1 << bit; bit -= 32;
} for (; bit < Bits<I>; ++bit) {
bit -= 32; d[1] |= 1 << bit;
for (; bit < Bits<I>; ++bit) { }
d[1] |= 1 << bit; I out = 0;
} if constexpr(ox::defines::BigEndian) {
I out = 0; const auto d0Tmp = d[0];
if constexpr(ox::defines::BigEndian) { d[0] = d[1];
const auto d0Tmp = d[0]; d[1] = d0Tmp;
d[0] = d[1]; }
d[1] = d0Tmp; ox::memcpy(&out, &d[0], sizeof(out));
} return out;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN }
ox::memcpy(&out, &d[0], sizeof(out));
OX_ALLOW_UNSAFE_BUFFERS_END
return out;
}
} }
return static_cast<I>(decoded); return static_cast<I>(decoded);
} }

View File

@@ -197,7 +197,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) n
OX_RETURN_ERROR(result); OX_RETURN_ERROR(result);
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
// array handler // array handler
@@ -256,7 +256,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<Stri
} }
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -330,7 +330,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
} }
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -370,7 +370,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
data[size] = 0; data[size] = 0;
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -388,7 +388,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
data[size] = 0; data[size] = 0;
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -416,7 +416,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
} }
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -464,7 +464,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
} }
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>
@@ -487,7 +487,7 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexc
} }
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Reader_c Reader> template<Reader_c Reader>

View File

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

View File

@@ -122,7 +122,7 @@ class MetalClawWriter {
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
}; };
@@ -184,42 +184,37 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noe
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
} }
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Writer_c Writer> template<Writer_c Writer>
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false; 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 // write the length
const auto strLen = mc::encodeInteger(val->size()); const auto strLen = mc::encodeInteger(val->len());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length)); OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length));
// write the string // write the string
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->size()))); OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
fieldSet = true; fieldSet = true;
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Writer_c Writer> template<Writer_c Writer>
template<std::size_t L> template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->size()); return fieldCString(name, val->data(), val->len());
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept { constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) { 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...
const auto strLen = *val ? ox::strlen(*val) : 0; const auto strLen = *val ? ox::strlen(*val) : 0;
OX_ALLOW_UNSAFE_BUFFERS_END
// write the length // write the length
const auto strLenBuff = mc::encodeInteger(strLen); const auto strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data.data()), strLenBuff.length)); OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data.data()), strLenBuff.length));
@@ -229,7 +224,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *c
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -255,7 +250,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *v
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -319,7 +314,7 @@ OX_ALLOW_UNSAFE_BUFFERS_END
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Writer_c Writer> template<Writer_c Writer>
@@ -339,7 +334,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
OX_RETURN_ERROR(handler.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 // 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) -> ox::Error { constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto keyLen = key.size(); const auto keyLen = key.len();
auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1); memcpy(wkey.get(), key.c_str(), keyLen + 1);
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen)); OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));
@@ -356,7 +351,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
} }
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return {}; return ox::Error(0);
} }
template<Writer_c Writer> template<Writer_c Writer>

View File

@@ -13,7 +13,7 @@
// oxModelFwdDecl is necessary because Apple-Clang is broken... // 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_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_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(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_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 #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) { for (const auto &p : typeParams) {
tp += p + ","; tp += p + ",";
} }
tp.resize(tp.size() - 1); tp.resize(tp.len() - 1);
tp += "#"; tp += "#";
} }
return ox::sfmt("{}{};{}", name, tp, version); 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 // defaultValue is unused now, but placeholder for backwards compatibility
int defaultValue = 0; int defaultValue = 0;
oxReturnError(io->field("defaultValue", &defaultValue)); oxReturnError(io->field("defaultValue", &defaultValue));
return {}; return ox::Error(0);
} }
#endif #endif

View File

@@ -205,7 +205,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t,
const auto t = type(p); const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); 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)); 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); 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; auto const lvls = detail::indirectionLevels_v<T> + 1;
SubscriptStack subscriptStack{lvls}; SubscriptStack subscriptStack{lvls};
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t)); m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
return {}; return ox::Error(0);
} }
return ox::Error(1); return ox::Error(1);
} }
@@ -231,7 +231,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val
const auto t = type(val); const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); 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)); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return {}; return ox::Error(0);
} }
return ox::Error(1); return ox::Error(1);
} }

View File

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

View File

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

View File

@@ -18,6 +18,6 @@ static_assert([]() -> ox::Error {
} }
//oxReturnError(v.set<int32_t>(5)); //oxReturnError(v.set<int32_t>(5));
return {}; return {};
}() == ox::Error{}); }() == ox::Error(0));
} }

View File

@@ -972,7 +972,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
for (auto &f : obj->m_fieldsOrder) { for (auto &f : obj->m_fieldsOrder) {
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value)); 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 { constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
@@ -981,7 +981,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
for (auto &f : obj->m_fieldsOrder) { for (auto &f : obj->m_fieldsOrder) {
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value)); OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
} }
return {}; return ox::Error(0);
} }
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept { constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
@@ -997,7 +997,7 @@ constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
case Type::SignedInteger16: case Type::SignedInteger16:
case Type::SignedInteger32: case Type::SignedInteger32:
case Type::SignedInteger64: case Type::SignedInteger64:
m_data = other.m_data; ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
break; break;
case Type::String: case Type::String:
m_data.str = new String(other.get<String>()); m_data.str = new String(other.get<String>());
@@ -1030,8 +1030,8 @@ constexpr ModelValue::ModelValue(ModelValue &&other) noexcept {
case Type::SignedInteger16: case Type::SignedInteger16:
case Type::SignedInteger32: case Type::SignedInteger32:
case Type::SignedInteger64: case Type::SignedInteger64:
m_data = other.m_data; ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
other.m_data.ui64 = 0; ox::memset(&other.m_data, 0, sizeof(m_data));
break; break;
case Type::String: case Type::String:
m_data.str = other.m_data.str; m_data.str = other.m_data.str;
@@ -1129,7 +1129,7 @@ constexpr Error ModelValue::setType(
OX_RETURN_ERROR(m_data.uni->setType(type)); OX_RETURN_ERROR(m_data.uni->setType(type));
} }
oxAssert(m_type != Type::Undefined, "No type set"); oxAssert(m_type != Type::Undefined, "No type set");
return {}; return ox::Error(0);
} }
template<typename T> template<typename T>
@@ -1184,7 +1184,7 @@ constexpr Error ModelValue::set(const T &v) noexcept {
safeDelete(&value); safeDelete(&value);
} }
value = v; value = v;
return {}; return ox::Error(0);
} }
template<typename T> template<typename T>
@@ -1199,7 +1199,7 @@ constexpr Error ModelValue::set(T &&v) noexcept {
safeDelete(&value); safeDelete(&value);
} }
value = std::move(v); value = std::move(v);
return {}; return ox::Error(0);
} }
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept { constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
@@ -1223,7 +1223,7 @@ constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
case Type::SignedInteger16: case Type::SignedInteger16:
case Type::SignedInteger32: case Type::SignedInteger32:
case Type::SignedInteger64: case Type::SignedInteger64:
m_data = other.m_data; ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
break; break;
case Type::String: case Type::String:
m_data.str = new String(other.get<String>()); m_data.str = new String(other.get<String>());
@@ -1261,8 +1261,8 @@ constexpr ModelValue &ModelValue::operator=(ModelValue &&other) noexcept {
case Type::SignedInteger16: case Type::SignedInteger16:
case Type::SignedInteger32: case Type::SignedInteger32:
case Type::SignedInteger64: case Type::SignedInteger64:
m_data = other.m_data; ox::memcpy(&m_data, &other.m_data, sizeof(m_data));
other.m_data = {}; ox::memset(&other.m_data, 0, sizeof(m_data));
break; break;
case Type::String: case Type::String:
m_data.str = other.m_data.str; m_data.str = other.m_data.str;

View File

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

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

View File

@@ -15,7 +15,7 @@ namespace ox {
OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) { OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) {
auto json = reinterpret_cast<const char*>(buff); auto json = reinterpret_cast<const char*>(buff);
auto jsonLen = ox::strnlen_s(json, buffSize); auto jsonLen = ox::strnlen(json, buffSize);
Json::CharReaderBuilder parserBuilder; Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader()); auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) { if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
@@ -37,7 +37,7 @@ OrganicClawReader::OrganicClawReader(Json::Value json, int unionIdx) noexcept:
} }
Error OrganicClawReader::field(const char *key, bool *val) noexcept { Error OrganicClawReader::field(const char *key, bool *val) noexcept {
ox::Error err{}; auto err = ox::Error(0);
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@@ -53,7 +53,7 @@ Error OrganicClawReader::field(const char *key, bool *val) noexcept {
} }
Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept { Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept {
ox::Error err{}; auto err = ox::Error(0);
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key); const auto &jv = value(key);
if (targetValid()) { if (targetValid()) {
@@ -81,7 +81,7 @@ Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t bu
} }
Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept { Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
ox::Error err{}; auto err = ox::Error(0);
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key); const auto &jv = value(key);
auto &data = *val; auto &data = *val;
@@ -106,7 +106,7 @@ Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
} }
Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept { Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept {
ox::Error err{}; auto err = ox::Error(0);
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key); const auto &jv = value(key);
if (targetValid()) { if (targetValid()) {

View File

@@ -8,11 +8,7 @@
#pragma once #pragma once
#include <ox/std/def.hpp>
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
#include <json/json.h> #include <json/json.h>
OX_ALLOW_UNSAFE_BUFFERS_END
#include <ox/model/fieldcounter.hpp> #include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp> #include <ox/model/modelhandleradaptor.hpp>
@@ -137,7 +133,7 @@ class OrganicClawReader {
template<typename T> template<typename T>
Error OrganicClawReader::field(const char *key, T *val) noexcept { Error OrganicClawReader::field(const char *key, T *val) noexcept {
ox::Error err{}; auto err = ox::Error(0);
try { try {
if constexpr (is_integer_v<T>) { if constexpr (is_integer_v<T>) {
if (targetValid()) { if (targetValid()) {
@@ -148,11 +144,7 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
if (jv.empty()) { if (jv.empty()) {
*val = 0; *val = 0;
} else if (rightType) { } else if (rightType) {
if constexpr(ox::is_signed_v<T>) { *val = static_cast<T>(jv.asUInt());
*val = static_cast<T>(jv.asInt64());
} else {
*val = static_cast<T>(jv.asUInt64());
}
} else { } else {
err = ox::Error(1, "Type mismatch"); err = ox::Error(1, "Type mismatch");
} }
@@ -180,7 +172,7 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
err = ox::Error(1, "Type mismatch"); err = ox::Error(1, "Type mismatch");
} }
} }
} catch (Json::LogicError const&e) { } catch (Json::LogicError const&) {
err = ox::Error(1, "error reading JSON data"); err = ox::Error(1, "error reading JSON data");
} }
++m_fieldIt; ++m_fieldIt;
@@ -189,7 +181,7 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
template<typename U, bool force> template<typename U, bool force>
Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept { Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept {
ox::Error err{}; auto err = ox::Error(0);
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty() || jv.isObject()) { if (jv.empty() || jv.isObject()) {
@@ -206,7 +198,7 @@ Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcep
template<std::size_t L> template<std::size_t L>
Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept { Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
ox::Error err{}; auto err = ox::Error(0);
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@@ -223,7 +215,7 @@ Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
template<std::size_t L> template<std::size_t L>
Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept { Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept {
ox::Error err{}; auto err = ox::Error(0);
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@@ -256,7 +248,7 @@ OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field("", &val[i])); OX_RETURN_ERROR(handler.field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
} }
return {}; return ox::Error(0);
} }
template<typename T> template<typename T>
@@ -273,7 +265,7 @@ Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcep
const auto k = keys[i].c_str(); const auto k = keys[i].c_str();
OX_RETURN_ERROR(handler.field(k, &val->operator[](k))); OX_RETURN_ERROR(handler.field(k, &val->operator[](k)));
} }
return {}; return ox::Error(0);
} }
Error readOC(BufferView buff, auto &val) noexcept { Error readOC(BufferView buff, auto &val) noexcept {
@@ -306,7 +298,7 @@ Result<T> readOC(BufferView buff) noexcept {
template<typename T> template<typename T>
Result<T> readOC(ox::StringView json) noexcept { Result<T> readOC(ox::StringView json) noexcept {
return readOC<T>(ox::BufferView{json.data(), json.size()}); return readOC<T>(ox::BufferView{json.data(), json.len()});
} }
} }

View File

@@ -23,7 +23,7 @@ Error OrganicClawWriter::fieldCString(const char *key, const char *const*val, in
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++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 {
@@ -32,7 +32,7 @@ Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) no
Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept { Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept {
const auto uuidStr = uuid->toString(); const auto uuidStr = uuid->toString();
if (targetValid() && uuidStr.size()) { if (targetValid() && uuidStr.len()) {
value(key) = uuidStr.c_str(); value(key) = uuidStr.c_str();
} }
++m_fieldIt; ++m_fieldIt;

View File

@@ -8,11 +8,7 @@
#pragma once #pragma once
#include <ox/std/def.hpp>
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
#include <json/json.h> #include <json/json.h>
OX_ALLOW_UNSAFE_BUFFERS_END
#include <ox/model/fieldcounter.hpp> #include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp> #include <ox/model/modelhandleradaptor.hpp>
@@ -46,7 +42,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error field(const char *key, const int16_t *val) noexcept { Error field(const char *key, const int16_t *val) noexcept {
@@ -54,7 +50,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error field(const char *key, const int32_t *val) noexcept { Error field(const char *key, const int32_t *val) noexcept {
@@ -62,7 +58,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error field(const char *key, const int64_t *val) noexcept { Error field(const char *key, const int64_t *val) noexcept {
@@ -70,7 +66,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
@@ -79,7 +75,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error field(const char *key, const uint16_t *val) noexcept { Error field(const char *key, const uint16_t *val) noexcept {
@@ -87,7 +83,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error field(const char *key, const uint32_t *val) noexcept { Error field(const char *key, const uint32_t *val) noexcept {
@@ -95,7 +91,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error field(const char *key, const uint64_t *val) noexcept { Error field(const char *key, const uint64_t *val) noexcept {
@@ -103,7 +99,7 @@ class OrganicClawWriter {
value(key) = *val; value(key) = *val;
} }
++m_fieldIt; ++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 {
@@ -138,7 +134,7 @@ class OrganicClawWriter {
template<std::size_t L> template<std::size_t L>
Error field(char const*key, IString<L> const*val) noexcept { Error field(char const*key, IString<L> const*val) noexcept {
if (targetValid() && val->size()) { if (targetValid() && val->len()) {
value(key) = val->c_str(); value(key) = val->c_str();
} }
++m_fieldIt; ++m_fieldIt;
@@ -147,11 +143,11 @@ class OrganicClawWriter {
template<std::size_t L> template<std::size_t L>
Error field(char const*key, BasicString<L> const*val) noexcept { Error field(char const*key, BasicString<L> const*val) noexcept {
if (targetValid() && val->size()) { if (targetValid() && val->len()) {
value(key) = val->c_str(); value(key) = val->c_str();
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Error fieldCString(const char*, const char *const*val, int len) noexcept; Error fieldCString(const char*, const char *const*val, int len) noexcept;
@@ -211,7 +207,7 @@ OX_ALLOW_UNSAFE_BUFFERS_END
value(key) = w.m_json; value(key) = w.m_json;
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
template<typename T> template<typename T>
@@ -237,7 +233,7 @@ Error OrganicClawWriter::field(const char *key, const T *val) noexcept {
} }
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
template<typename U, bool force> template<typename U, bool force>
@@ -251,7 +247,7 @@ Error OrganicClawWriter::field(const char *key, UnionView<U, force> val) noexcep
} }
} }
++m_fieldIt; ++m_fieldIt;
return {}; return ox::Error(0);
} }
Result<ox::Buffer> writeOC(const auto &val) noexcept { Result<ox::Buffer> writeOC(const auto &val) noexcept {
@@ -262,9 +258,7 @@ Result<ox::Buffer> writeOC(const auto &val) noexcept {
const auto str = Json::writeString(jsonBuilder, writer.m_json); const auto str = Json::writeString(jsonBuilder, writer.m_json);
Result<Buffer> buff; Result<Buffer> buff;
buff.value.resize(str.size() + 1); buff.value.resize(str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(buff.value.data(), str.data(), str.size() + 1); memcpy(buff.value.data(), str.data(), str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_END
return buff; return buff;
} }
@@ -276,9 +270,7 @@ Result<ox::String> writeOCString(const auto &val) noexcept {
const auto str = Json::writeString(jsonBuilder, writer.m_json); const auto str = Json::writeString(jsonBuilder, writer.m_json);
Result<ox::String> buff; Result<ox::String> buff;
buff.value.resize(str.size()); buff.value.resize(str.size());
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(buff.value.data(), str.data(), str.size() + 1); memcpy(buff.value.data(), str.data(), str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_END
return buff; return buff;
} }

View File

@@ -9,25 +9,13 @@
#pragma once #pragma once
#include "def.hpp" #include "def.hpp"
#include "error.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage) OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox { namespace ox {
template<typename It, typename T> template<typename It, typename T>
constexpr ox::Result<size_t> findIdx(It begin, It end, T const&value) { constexpr It find(It begin, It end, const T &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) {
for (; begin != end; ++begin) { for (; begin != end; ++begin) {
if (*begin == value) { if (*begin == value) {
return begin; return begin;

View File

@@ -15,22 +15,18 @@
namespace ox { namespace ox {
namespace detail { class AnyPtr {
template<bool unique>
class AnyPtrT {
private: private:
struct WrapBase { struct WrapBase {
virtual constexpr ~WrapBase() = default; virtual constexpr ~WrapBase() = default;
virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0; virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
virtual constexpr operator bool() const noexcept = 0; virtual constexpr operator bool() const noexcept = 0;
virtual void free() noexcept = 0;
}; };
template<typename T> template<typename T>
struct Wrap final: WrapBase { struct Wrap: public WrapBase {
T *data{}; T *data{};
explicit constexpr Wrap(T *pData) noexcept: data(pData) { constexpr Wrap(T *pData) noexcept: data(pData) {
} }
constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override { constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override {
oxAssert(s.size() >= sizeof(Wrap), "too small buffer"); oxAssert(s.size() >= sizeof(Wrap), "too small buffer");
@@ -43,60 +39,39 @@ class AnyPtrT {
constexpr operator bool() const noexcept override { constexpr operator bool() const noexcept override {
return data != nullptr; return data != nullptr;
} }
constexpr void free() noexcept override {
safeDelete(data);
data = {};
}
}; };
WrapBase *m_wrapPtr{}; WrapBase *m_wrapPtr{};
ox::Array<char, sizeof(Wrap<void*>)> m_wrapData; ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
public: public:
constexpr AnyPtrT() noexcept = default; constexpr AnyPtr() noexcept = default;
template<typename T> template<typename T>
constexpr AnyPtrT(T *ptr) noexcept { constexpr AnyPtr(T *ptr) noexcept {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
m_wrapPtr = new Wrap<T>(ptr); m_wrapPtr = new Wrap(ptr);
} else { } else {
m_wrapPtr = new(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) { if (other) {
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData); m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
} }
} }
constexpr AnyPtrT(AnyPtrT &&other) noexcept { constexpr ~AnyPtr() noexcept {
if (other) {
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
other.m_wrapPtr = {};
}
}
constexpr ~AnyPtrT() noexcept {
if constexpr(unique) {
free();
}
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_wrapPtr);
} }
} }
template<typename T> template<typename T>
constexpr AnyPtrT &operator=(T *ptr) noexcept { constexpr AnyPtr &operator=(T *ptr) noexcept {
if constexpr(unique) {
free();
} else if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
m_wrapPtr = new Wrap(ptr); m_wrapPtr = new Wrap(ptr);
} else { } else {
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr); m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
@@ -104,33 +79,11 @@ class AnyPtrT {
return *this; return *this;
} }
constexpr AnyPtrT &operator=(AnyPtrT const&ptr) noexcept requires(!unique) { constexpr AnyPtr &operator=(AnyPtr const&ptr) noexcept {
if (this != &ptr) { if (this != &ptr) {
if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
if (ptr) { if (ptr) {
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
} else {
m_wrapPtr = 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_wrapPtr); ox::safeDelete(m_wrapPtr);
}
if (ptr) {
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData); m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
if (std::is_constant_evaluated()) {
ox::safeDelete(ptr.m_wrapPtr);
ptr.m_wrapPtr = nullptr;
}
} else { } else {
m_wrapPtr = nullptr; m_wrapPtr = nullptr;
} }
@@ -142,16 +95,6 @@ class AnyPtrT {
return m_wrapPtr && *m_wrapPtr; return m_wrapPtr && *m_wrapPtr;
} }
constexpr void free() noexcept {
if (m_wrapPtr) {
m_wrapPtr->free();
}
if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr);
}
m_wrapPtr = nullptr;
}
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T *get() const noexcept { constexpr T *get() const noexcept {
@@ -161,12 +104,6 @@ class AnyPtrT {
return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data; return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
#endif #endif
} }
}; };
}
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> template<typename T, std::size_t ArraySize>
constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept { constexpr T &Array<T, ArraySize>::operator[](std::size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Array access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t ArraySize> template<typename T, std::size_t ArraySize>
constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept { constexpr const T &Array<T, ArraySize>::operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Array access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Array access overflow");
return m_items[i]; return m_items[i];
} }

View File

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

View File

@@ -22,15 +22,9 @@
namespace ox { namespace ox {
[[noreturn]] void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept;
void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept;
[[noreturn]] constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept {
constexpr void constexprPanic(
StringViewCR file,
int const line,
StringViewCR panicMsg,
Error const&err = {}) noexcept {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
panic(file, line, panicMsg, err); panic(file, line, panicMsg, err);
} else { } else {
@@ -38,24 +32,10 @@ constexpr void constexprPanic(
} }
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept;
StringViewCR file, void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
int line,
StringViewCR assertTxt,
StringViewCR msg) noexcept;
void assertFailFuncRuntime(
StringViewCR file,
int line,
Error const&err,
StringViewCR,
StringViewCR assertMsg) noexcept;
constexpr void assertFunc( constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept {
StringViewCR file,
int const line,
bool const pass,
[[maybe_unused]]StringViewCR assertTxt,
[[maybe_unused]]StringViewCR msg) noexcept {
if (!pass) { if (!pass) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(file, line, assertTxt, msg); assertFailFuncRuntime(file, line, assertTxt, msg);
@@ -65,12 +45,7 @@ constexpr void assertFunc(
} }
} }
constexpr void assertFunc( constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
StringViewCR file,
int const line,
Error const&err,
StringViewCR,
StringViewCR assertMsg) noexcept {
if (err) { if (err) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(file, line, err, {}, assertMsg); assertFailFuncRuntime(file, line, err, {}, assertMsg);
@@ -80,11 +55,7 @@ constexpr void assertFunc(
} }
} }
constexpr void expect( constexpr void expect(StringViewCR file, int line, const auto &actual, const auto &expected) noexcept {
StringViewCR file,
int const line,
auto const&actual,
auto const&expected) noexcept {
if (actual != expected) { if (actual != expected) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)

View File

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

View File

@@ -21,13 +21,13 @@ class CStringView: public detail::BaseStringView {
constexpr CStringView(CStringView const&sv) noexcept = default; 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> 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> 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 {} constexpr CStringView(std::nullptr_t) noexcept {}
@@ -37,7 +37,7 @@ class CStringView: public detail::BaseStringView {
constexpr auto &operator=(CStringView const&other) noexcept { constexpr auto &operator=(CStringView const&other) noexcept {
if (&other != this) { if (&other != this) {
set(other.data(), other.size()); set(other.data(), other.len());
} }
return *this; return *this;
} }

View File

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

View File

@@ -41,12 +41,6 @@ constexpr auto Debug = true;
constexpr auto Debug = false; constexpr auto Debug = false;
#endif #endif
#if defined(OX_CHECK_BOUNDS)
constexpr auto CheckBounds = true;
#else
constexpr auto CheckBounds = Debug;
#endif
#if defined(NDEBUG) #if defined(NDEBUG)
constexpr auto NDebug = true; constexpr auto NDebug = true;
#else #else

View File

@@ -36,16 +36,28 @@ using ErrorCode = uint16_t;
struct [[nodiscard]] Error { struct [[nodiscard]] Error {
std::source_location src;
ox::CString msg = nullptr; ox::CString msg = nullptr;
ox::CString file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 0; ErrorCode errCode = 0;
constexpr Error() noexcept = default; constexpr Error() noexcept = default;
explicit constexpr Error(
ox::CString file,
uint32_t const line,
ErrorCode const errCode,
ox::CString msg = nullptr) noexcept:
msg{msg},
file{file},
line{static_cast<uint16_t>(line)},
errCode{errCode} {}
explicit constexpr Error( explicit constexpr Error(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} errCode{errCode}
{} {}
@@ -53,8 +65,9 @@ struct [[nodiscard]] Error {
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src},
msg{msg}, msg{msg},
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} errCode{errCode}
{} {}
@@ -76,31 +89,42 @@ constexpr auto toStr(Error const&err) noexcept {
} }
struct Exception: public std::exception { struct Exception: public std::exception {
std::source_location src;
ox::CString msg = nullptr; ox::CString msg = nullptr;
ox::CString file = nullptr;
uint16_t line = 0;
ErrorCode errCode = 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, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {} errCode{errCode} {}
explicit Exception( explicit inline Exception(
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, ox::CString msg,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src},
msg{msg}, msg{msg},
file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {} errCode{errCode} {}
explicit Exception(Error const&err) noexcept: explicit inline Exception(Error const&err) noexcept:
src{err.src},
msg{err.msg ? err.msg : ""}, msg{err.msg ? err.msg : ""},
file{err.file},
line{err.line},
errCode{err.errCode} {} errCode{err.errCode} {}
constexpr Error toError() const noexcept { constexpr Error toError() const noexcept {
return Error(errCode, msg, src); return Error(file, line, errCode, msg);
} }
[[nodiscard]] [[nodiscard]]
@@ -109,7 +133,6 @@ struct Exception: public std::exception {
} }
}; };
[[noreturn]]
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept; void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
template<typename T> template<typename T>
@@ -307,13 +330,6 @@ struct [[nodiscard]] Result {
return std::move(value); return std::move(value);
} }
constexpr Result transformError(ErrorCode const ec, CString const msg) && {
if (error) {
error = Error{ec, msg};
}
return *this;
}
}; };
namespace detail { namespace detail {
@@ -337,17 +353,4 @@ constexpr void primitiveAssert(char const*file, int line, bool pass, char const*
} }
} }
constexpr void boundsCheck(
char const*file,
int const line,
size_t const i,
size_t const sz,
char const*msg) noexcept {
if constexpr(defines::CheckBounds) {
if (i >= sz) [[unlikely]] {
panic(file, line, msg, ox::Error{1});
}
}
}
} }

View File

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

View File

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

View File

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

View File

@@ -213,7 +213,8 @@ class UniquePtr {
return m_t; return m_t;
} }
constexpr void reset(UniquePtr &&other = UniquePtr()) { template<typename U, typename UDeleter>
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
auto t = m_t; auto t = m_t;
m_t = other.release(); m_t = other.release();
Deleter()(t); Deleter()(t);

View File

@@ -30,49 +30,11 @@ constexpr void *operator new(std::size_t, void *addr) noexcept {
constexpr void *operator new[](std::size_t, void *addr) noexcept { constexpr void *operator new[](std::size_t, void *addr) noexcept {
return addr; 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 #endif
namespace ox { 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> template<typename T, typename U = T, typename ...Args>
[[nodiscard]] [[nodiscard]]
constexpr U *make(Args &&...args) noexcept { constexpr U *make(Args &&...args) noexcept {

View File

@@ -30,15 +30,13 @@ constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
ox::Result<char> StreamReader::peek() const noexcept { ox::Result<char> StreamReader::peek() const noexcept {
try { try {
if (m_strm.eof()) {
return Error{1, "EOF"};
}
char c{}; char c{};
m_strm.get(c); m_strm.get(c);
if (m_strm.unget()) [[unlikely]] { auto const ok = c != EOF;
return ox::Error{1, "Unable to unget character"}; if (ok && m_strm.unget()) [[unlikely]] {
return ox::Error(1, "Unable to unget character");
} }
return static_cast<char>(c); return {static_cast<char>(c), ox::Error(!ok, "File peek failed")};
} catch (std::exception const&) { } catch (std::exception const&) {
return ox::Error(1, "peek failed"); return ox::Error(1, "peek failed");
} }

View File

@@ -31,6 +31,7 @@ concept Reader_c = requires(T v) {
class Reader_v { class Reader_v {
public: public:
virtual constexpr ~Reader_v() noexcept = default; virtual constexpr ~Reader_v() noexcept = default;
[[nodiscard]]
virtual constexpr ox::Result<char> peek() const noexcept = 0; 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> read(char*, std::size_t) noexcept = 0;
virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0; virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;

View File

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

View File

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

View File

@@ -8,17 +8,13 @@
#pragma once #pragma once
#if __has_include(<array>)
#include <array>
#endif
#include "array.hpp" #include "array.hpp"
#include "bit.hpp" #include "bit.hpp"
#include "def.hpp" #include "def.hpp"
#include "iterator.hpp" #include "iterator.hpp"
#include "vector.hpp" #include "vector.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox { namespace ox {
@@ -39,20 +35,6 @@ class Span {
constexpr Span() noexcept = default; 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> template<std::size_t sz>
constexpr Span(ox::Array<T, sz> &a) noexcept: constexpr Span(ox::Array<T, sz> &a) noexcept:
m_items(a.data()), m_items(a.data()),
@@ -146,41 +128,28 @@ class Span {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size); return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size);
} }
constexpr T &operator[](std::size_t i) const noexcept { constexpr T &operator[](std::size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); 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]; return m_items[i];
} }
constexpr Span operator+(size_t i) const noexcept { constexpr Span operator+(size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
return {m_items + i, m_size - i}; return {m_items + i, m_size - i};
} }
constexpr Span operator+=(size_t i) noexcept { constexpr Span operator+=(size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
m_items += i; m_items += i;
m_size -= i; m_size -= i;
return *this; 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]] [[nodiscard]]
constexpr auto data() const noexcept { constexpr auto data() const noexcept {
return m_items; return m_items;
@@ -199,20 +168,8 @@ class Span {
}; };
template<typename T> template<typename T>
using SpanView = Span<T const>; using SpanView = Span<const T>;
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));
}
}
} }
OX_ALLOW_UNSAFE_BUFFERS_END OX_CLANG_NOWARN_END

View File

@@ -18,34 +18,34 @@ namespace ox {
template<Integer_c Integer> template<Integer_c Integer>
constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept { constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept {
if (v) { if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000; ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v; ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10; constexpr auto base = 10;
auto it = 0; auto it = 0;
if (val < 0) { if (val < 0) {
OX_RETURN_ERROR(writer.put('-')); OX_RETURN_ERROR(writer.put('-'));
val = ~val + 1;
}
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
ox::ResizedInt_t<Integer, 64> start = '0';
if (digit >= 10) [[unlikely]] {
digit -= 10;
OX_RETURN_ERROR(writer.put('1'));
}
OX_RETURN_ERROR(writer.put(static_cast<char>(start + digit)));
++it; ++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 { return {};
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
}
return {};
} }
} }

View File

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

View File

@@ -8,7 +8,6 @@
#pragma once #pragma once
#include "cstringview.hpp"
#include "string.hpp" #include "string.hpp"
namespace ox { namespace ox {
@@ -21,8 +20,6 @@ class StringParam {
constexpr StringParam(StringParam &&o) noexcept: m_value{std::move(o.m_value)} {} constexpr StringParam(StringParam &&o) noexcept: m_value{std::move(o.m_value)} {}
constexpr StringParam(char const*value) noexcept: m_value{value} {} constexpr StringParam(char const*value) noexcept: m_value{value} {}
constexpr StringParam(detail::BaseStringView 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 const&value) noexcept: m_value{value} {}
constexpr StringParam(ox::String &&value) noexcept: m_value{std::move(value)} {} constexpr StringParam(ox::String &&value) noexcept: m_value{std::move(value)} {}
constexpr operator ox::String() && noexcept { return std::move(m_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()) {} constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}
template<std::size_t SmallStrSz> 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> 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 {} constexpr StringView(std::nullptr_t) noexcept {}
@@ -53,24 +53,24 @@ class StringView: public detail::BaseStringView {
constexpr auto &operator=(StringView const&other) noexcept { constexpr auto &operator=(StringView const&other) noexcept {
if (&other != this) { if (&other != this) {
set(other.data(), other.size()); set(other.data(), other.len());
} }
return *this; return *this;
} }
}; };
using StringViewCR = StringView const&; using StringViewCR = const StringView&;
constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept { constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept {
if (s2.size() != s1.size()) { if (s2.len() != s1.len()) {
return false; 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 { 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 a = &s1.front();
const auto b = &s2.front(); const auto b = &s2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) { 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; return 1;
} }
} }
if (s1.size() > s2.size()) { if (s1.len() > s2.len()) {
return 1; return 1;
} else if (s1.size() < s2.size()) { } else if (s1.len() < s2.len()) {
return -1; return -1;
} else { } else {
return 0; 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()); return writer.write(sv.data(), sv.bytes());
} }
@@ -100,24 +100,19 @@ constexpr auto toStdStringView(StringViewCR sv) noexcept {
#endif #endif
constexpr ox::Result<int> strToInt(StringViewCR str) noexcept { constexpr ox::Result<int> atoi(ox::StringViewCR str) noexcept {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
int total = 0; int total = 0;
int multiplier = 1; int multiplier = 1;
if (str.size() == 0) [[unlikely]] { for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) {
return Error{1, "Empty string passed to strToInt"};
}
for (auto i = static_cast<int64_t>(str.size()) - 1; i != -1; --i) {
auto s = static_cast<std::size_t>(i); auto s = static_cast<std::size_t>(i);
if (str[s] >= '0' && str[s] <= '9') { if (str[s] >= '0' && str[s] <= '9') {
total += (str[s] - '0') * multiplier; total += (str[s] - '0') * multiplier;
multiplier *= 10; multiplier *= 10;
} else { } else {
return ox::Error{1}; return ox::Error(1);
} }
} }
return total; return total;
OX_ALLOW_UNSAFE_BUFFERS_END
} }

View File

@@ -9,8 +9,6 @@
#include "def.hpp" #include "def.hpp"
#include "strops.hpp" #include "strops.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
static_assert(ox::strcmp("asdf", "hijk") < 0, "asdf < hijk"); static_assert(ox::strcmp("asdf", "hijk") < 0, "asdf < hijk");
static_assert(ox::strcmp("hijk", "asdf") > 0, "hijk > asdf"); static_assert(ox::strcmp("hijk", "asdf") > 0, "hijk > asdf");
static_assert(ox::strcmp("resize", "read") > 0, "resize > read"); static_assert(ox::strcmp("resize", "read") > 0, "resize > read");
@@ -44,5 +42,3 @@ std::size_t strlen(const char *str) {
} }
#endif #endif
OX_ALLOW_UNSAFE_BUFFERS_END

View File

@@ -21,47 +21,37 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox { namespace ox {
[[nodiscard]] [[nodiscard]]
constexpr StringView substr(StringViewCR str, std::size_t const pos) noexcept { constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept {
if (str.size() >= pos) { if (str.len() >= pos) {
return {&str[pos], str.size() - pos}; return {&str[pos], str.len() - pos};
} }
return {}; return {};
} }
[[nodiscard]] [[nodiscard]]
constexpr StringView substr(StringViewCR str, std::size_t const start, std::size_t const end) noexcept { constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept {
if (str.size() >= start && end >= start) { if (str.len() >= start && end >= start) {
return {&str[start], end - start}; return {&str[start], end - start};
} }
return {}; 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]] [[nodiscard]]
constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept { constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept {
const auto beginningLen = ox::min(beginning.size(), base.size()); const auto beginningLen = ox::min(beginning.len(), base.len());
return base.size() >= beginning.size() && ox::strncmp(base.data(), beginning, beginningLen) == 0; return base.len() >= beginning.len() && ox::strncmp(base.data(), beginning, beginningLen) == 0;
} }
[[nodiscard]] [[nodiscard]]
constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept { constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept {
const auto endingLen = ending.size(); const auto endingLen = ending.len();
return base.size() >= endingLen && ox::strcmp(base.data() + (base.size() - endingLen), ending) == 0; return base.len() >= endingLen && ox::strcmp(base.data() + (base.len() - endingLen), ending) == 0;
} }
[[nodiscard]] [[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; std::size_t i = 0;
for (; i < str.size(); ++i) { for (; i < str.len(); ++i) {
if (str[i] == search) { if (str[i] == search) {
break; break;
} }
@@ -72,7 +62,7 @@ constexpr std::size_t find(StringViewCR str, char const search) noexcept {
[[nodiscard]] [[nodiscard]]
constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept { constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
std::size_t i = 0; std::size_t i = 0;
for (; i < str.size(); ++i) { for (; i < str.len(); ++i) {
if (beginsWith(substr(str, i), search)) { if (beginsWith(substr(str, i), search)) {
break; break;
} }
@@ -82,14 +72,14 @@ constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
template<std::size_t smallSz = 0> template<std::size_t smallSz = 0>
[[nodiscard]] [[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; ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, char del) { constexpr auto nextSeg = [](StringViewCR current, char del) {
return substr(current, find(current, del) + 1); 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); 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); out.emplace_back(s);
} }
current = substr(current, next); 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 { constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringViewCR del) noexcept {
ox::Vector<ox::StringView, smallSz> out; ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, StringViewCR del) { 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); 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); out.emplace_back(s);
} }
current = substr(current, next); current = substr(current, next);
@@ -115,7 +105,7 @@ constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringView
} }
[[nodiscard]] [[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"); ox::Result<std::size_t> retval = ox::Error(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) { for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) { 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] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2") 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" ${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] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc) add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int") 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] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex")
add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID") 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] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")
add_test("[ox/std] intToStr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "intToStr")

View File

@@ -145,7 +145,6 @@ OX_CLANG_NOWARN_END
return ox::Error{}; return ox::Error{};
} }
}, },
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
{ {
"ABCDEFG != HIJKLMN", "ABCDEFG != HIJKLMN",
[]() { []() {
@@ -170,7 +169,6 @@ OX_CLANG_NOWARN_END
return ox::Error(ox::memcmp("ABCDEFGHI", "ABCDEFG", 7) != 0); return ox::Error(ox::memcmp("ABCDEFGHI", "ABCDEFG", 7) != 0);
} }
}, },
OX_ALLOW_UNSAFE_BUFFERS_END
{ {
"IString", "IString",
[]() { []() {
@@ -183,7 +181,7 @@ OX_CLANG_NOWARN_END
s = "asdf"; s = "asdf";
oxAssert(s == "asdf", "String assign broken"); oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken"); oxAssert(s != "aoeu", "String assign broken");
oxAssert(s.size() == 4, "String assign broken"); oxAssert(s.len() == 4, "String assign broken");
return ox::Error(0); return ox::Error(0);
} }
}, },
@@ -239,50 +237,6 @@ OX_CLANG_NOWARN_END
return ox::Error(0); return ox::Error(0);
} }
}, },
{
"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();
oxExpect(v[0], "asdf");
oxExpect(v[1], "aoeu");
oxExpect(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();
oxExpect(v[0], "asdf");
oxExpect(v[1], "aoeu");
oxExpect(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"};
oxExpect(ox::findIdx(v.begin(), v.end(), "zero").or_value(5), 0u);
oxExpect(ox::findIdx(v.begin(), v.end(), "one").or_value(5), 1u);
oxExpect(ox::findIdx(v.begin(), v.end(), "two").or_value(5), 2u);
oxExpect(ox::findIdx(v.begin(), v.end(), "three").or_value(5), 3u);
oxExpect(ox::findIdx(v.begin(), v.end(), "four").or_value(5), 4u);
oxExpect(ox::findIdx(v.begin(), v.end(), "five").or_value(5), 5u);
oxExpect(ox::findIdx(v.begin(), v.end(), "six").or_value(6), 6u);
return ox::Error{};
}
},
{ {
"SmallMap", "SmallMap",
[] { [] {
@@ -292,18 +246,7 @@ OX_CLANG_NOWARN_END
oxExpect(map.size(), 1u); oxExpect(map.size(), 1u);
oxExpect(map["aoeu"], ""); oxExpect(map["aoeu"], "");
oxExpect(map.size(), 2u); oxExpect(map.size(), 2u);
ox::SmallMap<ox::String, ox::String> cmap; return ox::Error(0);
cmap["asdf"] = "aoeu";
auto constexpr constTest = [](ox::SmallMap<ox::String, ox::String> const&map) {
OX_REQUIRE(asdf, map.at("asdf"));
oxExpect(*asdf, "aoeu");
oxExpect(map.size(), 1u);
auto const aoeu = map.at("aoeu");
oxExpect(aoeu.ok(), false);
oxExpect(map.size(), 1u);
return ox::Error{};
};
return constTest(cmap);
} }
}, },
{ {
@@ -337,6 +280,7 @@ OX_CLANG_NOWARN_END
oxExpect(si["asdf"], 0); oxExpect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100"); oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si; auto si2 = si;
oxDebugf("{}", si2["asdf"]);
oxExpect(si2["asdf"], 0); oxExpect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100"); oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii; ox::HashMap<int, int> ii;
@@ -536,33 +480,6 @@ OX_CLANG_NOWARN_END
return ox::Error(0); return ox::Error(0);
} }
}, },
{
"intToStr",
[] {
oxExpect(ox::intToStr(static_cast<int8_t>(127)), "127");
oxExpect(ox::intToStr(static_cast<int8_t>(-128)), "-128");
oxExpect(ox::intToStr(static_cast<uint8_t>(255)), "255");
oxExpect(ox::intToStr(static_cast<uint16_t>(65535)), "65535");
oxExpect(ox::intToStr(static_cast<int16_t>(32767)), "32767");
oxExpect(ox::intToStr(static_cast<int16_t>(-32768)), "-32768");
oxExpect(ox::intToStr(static_cast<uint32_t>(4294967295)), "4294967295");
oxExpect(ox::intToStr(static_cast<int32_t>(2147483647)), "2147483647");
oxExpect(ox::intToStr(static_cast<int32_t>(-2147483648)), "-2147483648");
oxExpect(ox::intToStr(static_cast<uint64_t>(18446744073709551615u)), "18446744073709551615");
oxExpect(ox::intToStr(static_cast<int64_t>(9223372036854775807)), "9223372036854775807");
oxExpect(ox::intToStr(static_cast<int64_t>(-9223372036854775807)), "-9223372036854775807");
oxExpect(ox::intToStr(0), "0");
oxExpect(ox::intToStr(5), "5");
oxExpect(ox::intToStr(5000), "5000");
oxExpect(ox::intToStr(50000), "50000");
oxExpect(ox::intToStr(500000), "500000");
oxExpect(ox::intToStr(-5), "-5");
oxExpect(ox::intToStr(-5000), "-5000");
oxExpect(ox::intToStr(-50000), "-50000");
oxExpect(ox::intToStr(-500000), "-500000");
return ox::Error{};
}
},
}; };
int main(int argc, const char **argv) { int main(int argc, const char **argv) {

View File

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

View File

@@ -39,8 +39,6 @@ enum LogChan {
Debug = 4, Debug = 4,
}; };
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
template<LogChan chan> template<LogChan chan>
static void log(ox::StringViewCR str) { static void log(ox::StringViewCR str) {
const auto sz = ox::min<std::size_t>(0x100, str.bytes()); 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 #endif
} }
OX_ALLOW_UNSAFE_BUFFERS_END
} }

View File

@@ -63,6 +63,25 @@ namespace ox {
using CString = char const*; using CString = char const*;
/**
* 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<const T*>(this);
}
};
template<std::size_t sz> template<std::size_t sz>
struct SignedType { struct SignedType {
}; };

View File

@@ -19,15 +19,12 @@
namespace std { namespace std {
template<typename T> template<typename T>
inline constexpr bool is_union_v = __is_union(T); constexpr bool is_union_v = __is_union(T);
inline constexpr bool is_constant_evaluated() noexcept { constexpr bool is_constant_evaluated() noexcept {
return __builtin_is_constant_evaluated(); return __builtin_is_constant_evaluated();
} }
template<typename T>
inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
} }
#endif #endif
@@ -159,9 +156,6 @@ static_assert(is_class<int>::value == false);
template<typename T> template<typename T>
constexpr bool is_class_v = is_class<T>(); constexpr bool is_class_v = is_class<T>();
template<typename T>
inline constexpr bool is_trivially_copyable_v = std::is_trivially_copyable_v<T>;
template<typename T> template<typename T>
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value; constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;

View File

@@ -27,55 +27,6 @@ constexpr void swap(T &a, T &b) noexcept {
b = std::move(temp); b = std::move(temp);
} }
template<typename T, typename U>
constexpr bool cmp_equal(T const t, U const u) noexcept {
if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) {
return t == u;
} else if constexpr(ox::is_signed_v<T>) {
return t >= 0 && static_cast<ox::Unsigned<T>>(t) == u;
} else {
return u >= 0 && t == static_cast<ox::Unsigned<U>>(u);
}
}
template<typename T, typename U>
constexpr bool cmp_less(T const t, U const u) noexcept {
if constexpr(ox::is_signed_v<T> == ox::is_signed_v<U>) {
return t < u;
} else if constexpr(ox::is_signed_v<T>) {
return t < 0 || static_cast<ox::Unsigned<T>>(t) < u;
} else {
return u >= 0 && t < static_cast<ox::Unsigned<U>>(u);
}
}
template<typename T, typename U>
constexpr bool cmp_not_equal(T const t, U const u) noexcept {
return !std::cmp_equal(t, u);
}
template<typename T, typename U>
constexpr bool cmp_greater(T const t, U const u) noexcept {
return std::cmp_less(u, t);
}
template<typename T, typename U>
constexpr bool cmp_less_equal(T const t, U const u) noexcept {
return !std::cmp_less(u, t);
}
template<typename T, typename U>
constexpr bool cmp_greater_equal(T const t, U const u) noexcept {
return !std::cmp_less(t, u);
}
static_assert(cmp_less(-1, 5u));
static_assert(!cmp_less(5u, -1));
static_assert(cmp_equal(5u, 5));
static_assert(cmp_equal(5, 5u));
static_assert(!cmp_equal(-5, 5u));
static_assert(!cmp_equal(4u, 5u));
} }
#endif #endif

View File

@@ -58,7 +58,7 @@ constexpr ox::Result<uint8_t> fromHex(ox::StringViewCR v) noexcept {
if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) { if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) {
return ox::Error(1, "Invalid UUID"); return ox::Error(1, "Invalid UUID");
} }
if (v.size() != 2) { if (v.len() != 2) {
return ox::Error(2); return ox::Error(2);
} }
uint8_t out = 0; uint8_t out = 0;
@@ -105,10 +105,6 @@ class UUID {
ox::Array<uint8_t, 16> m_value{}; ox::Array<uint8_t, 16> m_value{};
public: public:
static constexpr auto TypeName = "net.drinkingtea.ox.UUID";
static constexpr auto TypeVersion = 1;
static void seedGenerator(const RandomSeed &seed) noexcept; static void seedGenerator(const RandomSeed &seed) noexcept;
static ox::Result<UUID> generate() noexcept; static ox::Result<UUID> generate() noexcept;
@@ -133,18 +129,18 @@ class UUID {
} }
static constexpr ox::Result<ox::UUID> fromString(ox::StringViewCR s) noexcept { static constexpr ox::Result<ox::UUID> fromString(ox::StringViewCR s) noexcept {
if (s.size() < 36) { if (s.len() < 36) {
return ox::Error(1, "Insufficient data to contain a complete UUID"); return ox::Error(1, "Insufficient data to contain a complete UUID");
} }
UUID out; UUID out;
auto valueI = 0u; auto valueI = 0u;
for (size_t i = 0; i < s.size();) { for (size_t i = 0; i < s.len();) {
if (s[i] == '-') { if (s[i] == '-') {
++i; ++i;
continue; continue;
} }
const auto seg = substr(s, i, i + 2); const auto seg = substr(s, i, i + 2);
if (seg.size() != 2) { if (seg.len() != 2) {
return ox::Error(1, "Invalid UUID"); return ox::Error(1, "Invalid UUID");
} }
OX_REQUIRE(val, detail::fromHex(seg)); OX_REQUIRE(val, detail::fromHex(seg));
@@ -174,7 +170,7 @@ class UUID {
for (auto i = 0u; i < cnt; ++i) { for (auto i = 0u; i < cnt; ++i) {
const auto v = value[valueI]; const auto v = value[valueI];
const auto h = detail::toHex(v); const auto h = detail::toHex(v);
std::ignore = writer.write(h.c_str(), h.size()); std::ignore = writer.write(h.c_str(), h.len());
++valueI; ++valueI;
} }
}; };

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {}; ox::Array<AllocAlias<T>, Size> m_data = {};
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default; constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept { constexpr void allocate(T **items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) { if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
@@ -49,31 +49,45 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T **items, T **items,
VectorAllocator *src, VectorAllocator *src,
std::size_t const count, const std::size_t count,
std::size_t const cap) noexcept { const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later // try removing it later
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) { if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) { for (auto i = 0u; i < count; ++i) {
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i])); const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
new (&m_data[i]) T(std::move(*srcItem)); const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
} std::construct_at<T>(dstItem, std::move(*srcItem));
if (count) {
*items = std::launder(reinterpret_cast<T*>(m_data.data()));
} else {
*items = reinterpret_cast<T*>(m_data.data());
} }
*items = reinterpret_cast<T*>(m_data.data());
} }
} }
} }
constexpr void deallocate(T *const items, std::size_t const cap) noexcept { constexpr void moveItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (std::size_t i = 0; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
*dstItem = std::move(*srcItem);
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
if (items) { Allocator{}.deallocate(items, cap);
Allocator{}.deallocate(items, cap);
}
} else { } else {
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) { if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
@@ -87,10 +101,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> { struct VectorAllocator<T, Allocator, 0> {
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default; constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept { constexpr void allocate(T **items, std::size_t cap) noexcept {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
} }
@@ -98,15 +112,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T**, T**,
VectorAllocator*, VectorAllocator*,
std::size_t const, const std::size_t,
std::size_t const) noexcept { const std::size_t) noexcept {
} }
[[maybe_unused]] [[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, std::size_t const, std::size_t const) noexcept { constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
} }
constexpr void deallocate(T *const items, std::size_t const cap) noexcept { constexpr void deallocate(T *items, std::size_t cap) noexcept {
if (items) { if (items) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
} }
@@ -247,8 +261,6 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr void resize(std::size_t size) noexcept(useNoexcept); constexpr void resize(std::size_t size) noexcept(useNoexcept);
constexpr void reserveResize(std::size_t size) noexcept(useNoexcept);
[[nodiscard]] [[nodiscard]]
constexpr T *data() noexcept { constexpr T *data() noexcept {
return m_items; return m_items;
@@ -273,9 +285,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args> template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept); constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T const &item) noexcept(useNoexcept); constexpr void push_back(T item) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept); constexpr void pop_back() noexcept(useNoexcept);
@@ -301,12 +311,8 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
*/ */
constexpr Error unordered_erase(std::size_t pos) noexcept(useNoexcept); constexpr Error unordered_erase(std::size_t pos) noexcept(useNoexcept);
constexpr Error remove(MaybeView_t<T> const &val);
constexpr void reserve(std::size_t cap) noexcept(useNoexcept); constexpr void reserve(std::size_t cap) noexcept(useNoexcept);
constexpr void shrink_to_fit() noexcept(useNoexcept);
private: private:
constexpr void reserveInsert( constexpr void reserveInsert(
std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept); std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept);
@@ -335,7 +341,6 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexce
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
reserve(list.size());
for (auto &item : list) { for (auto &item : list) {
emplace_back(std::move(item)); emplace_back(std::move(item));
} }
@@ -409,7 +414,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
m_items = other.m_items; m_items = other.m_items;
this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap); this->moveItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0; other.m_size = 0;
other.m_cap = 0; other.m_cap = 0;
other.m_items = nullptr; other.m_items = nullptr;
@@ -419,13 +424,13 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept { constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept { constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow"); ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
@@ -519,12 +524,6 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
m_size = size; m_size = size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(std::size_t const size) noexcept(useNoexcept) {
reserve(size);
resize(size);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept { constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
for (std::size_t i = 0; i < m_size; ++i) { for (std::size_t i = 0; i < m_size; ++i) {
@@ -611,16 +610,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], item);
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
} }
@@ -663,18 +653,7 @@ constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size
--m_size; --m_size;
m_items[pos] = std::move(m_items[m_size]); m_items[pos] = std::move(m_items[m_size]);
m_items[m_size].~T(); m_items[m_size].~T();
return {}; return ox::Error(0);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(MaybeView_t<T> const &val) {
for (size_t i{}; auto const &v : *this) {
if (v == val) {
return erase(i).error;
}
++i;
}
return ox::Error{1, "element not found"};
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
@@ -696,24 +675,6 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) n
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(useNoexcept) {
if (m_size == m_cap) {
return;
}
const auto oldItems = m_items;
const auto oldCap = m_cap;
m_cap = m_size;
this->allocate(&m_items, m_size);
if (oldItems) { // move over old items
for (std::size_t i = 0; i < m_size; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T();
}
this->deallocate(oldItems, oldCap);
}
}
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert( constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
std::size_t cap, std::size_t cap,

View File

@@ -5,117 +5,103 @@
#pragma once #pragma once
#include <ox/std/array.hpp> #include <ox/std/array.hpp>
#include <ox/std/units.hpp> #include <ox/std/types.hpp>
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Interrupt Handler // Interrupt Handler
using InterruptHandler = void(*)(); using interrupt_handler = void (*)();
#define REG_ISR (*reinterpret_cast<InterruptHandler*>(0x0300'7FFC)) #define REG_ISR *reinterpret_cast<interrupt_handler*>(0x0300'7FFC)
#define REG_IE (*reinterpret_cast<volatile uint16_t*>(0x0400'0200)) #define REG_IE *reinterpret_cast<volatile uint16_t*>(0x0400'0200)
#define REG_IF (*reinterpret_cast<volatile uint16_t*>(0x0400'0202)) #define REG_IF *reinterpret_cast<volatile uint16_t*>(0x0400'0202)
#define REG_IME (*reinterpret_cast<volatile uint16_t*>(0x0400'0208)) #define REG_IME *reinterpret_cast<volatile uint16_t*>(0x0400'0208)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Display Registers // Display Registers
#define REG_DISPCTL (*reinterpret_cast<volatile uint32_t*>(0x0400'0000)) #define REG_DISPCTL *reinterpret_cast<volatile uint32_t*>(0x0400'0000)
#define REG_DISPSTAT (*reinterpret_cast<volatile uint32_t*>(0x0400'0004)) #define REG_DISPSTAT *reinterpret_cast<volatile uint32_t*>(0x0400'0004)
#define REG_VCOUNT (*reinterpret_cast<volatile uint32_t*>(0x0400'0006)) #define REG_VCOUNT *reinterpret_cast<volatile uint32_t*>(0x0400'0006)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Timers // Timers
#define REG_TIMER0 (*reinterpret_cast<volatile uint16_t*>(0x0400'0100)) #define REG_TIMER0 *reinterpret_cast<volatile uint16_t*>(0x0400'0100)
#define REG_TIMER0CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'0102)) #define REG_TIMER0CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0102)
#define REG_TIMER1 (*reinterpret_cast<volatile uint16_t*>(0x0400'0104)) #define REG_TIMER1 *reinterpret_cast<volatile uint16_t*>(0x0400'0104)
#define REG_TIMER1CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'0106)) #define REG_TIMER1CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0106)
#define REG_TIMER2 (*reinterpret_cast<volatile uint16_t*>(0x0400'0108)) #define REG_TIMER2 *reinterpret_cast<volatile uint16_t*>(0x0400'0108)
#define REG_TIMER2CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'010a)) #define REG_TIMER2CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010a)
#define REG_TIMER3 (*reinterpret_cast<volatile uint16_t*>(0x0400'010c)) #define REG_TIMER3 *reinterpret_cast<volatile uint16_t*>(0x0400'010c)
#define REG_TIMER3CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'010e)) #define REG_TIMER3CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010e)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// background registers // background registers
// background control registers // background control registers
using BgCtl = uint16_t; using BgCtl = uint16_t;
#define REG_BG0CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'0008)) #define REG_BG0CTL *reinterpret_cast<volatile BgCtl*>(0x0400'0008)
#define REG_BG1CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000a)) #define REG_BG1CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000a)
#define REG_BG2CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000c)) #define REG_BG2CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000c)
#define REG_BG3CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000e)) #define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e)
[[nodiscard]] [[nodiscard]]
inline volatile BgCtl &regBgCtl(uintptr_t const bgIdx) noexcept { inline volatile BgCtl &regBgCtl(uintptr_t bgIdx) noexcept {
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx); return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
} }
// background horizontal scrolling registers // background horizontal scrolling registers
#define REG_BG0HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0010)) #define REG_BG0HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0010)
#define REG_BG1HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0014)) #define REG_BG1HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0014)
#define REG_BG2HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0018)) #define REG_BG2HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0018)
#define REG_BG3HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001c)) #define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
[[nodiscard]] [[nodiscard]]
volatile int16_t &regBgHofs(auto const bgIdx) noexcept { inline volatile uint32_t &regBgHofs(auto bgIdx) noexcept {
return *reinterpret_cast<volatile int16_t*>(0x0400'0010 + 4 * bgIdx); return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
} }
// background vertical scrolling registers // background vertical scrolling registers
#define REG_BG0VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0012)) #define REG_BG0VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0012)
#define REG_BG1VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0016)) #define REG_BG1VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0016)
#define REG_BG2VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001a)) #define REG_BG2VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001a)
#define REG_BG3VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001e)) #define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
[[nodiscard]] [[nodiscard]]
volatile int16_t &regBgVofs(auto const bgIdx) noexcept { inline volatile uint32_t &regBgVofs(auto bgIdx) noexcept {
return *reinterpret_cast<volatile int16_t*>(0x0400'0012 + 4 * bgIdx); return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
}
// background scrolling registers
struct OffsetPair {
int16_t x{}, y{};
};
#define REG_BG0OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0010))
#define REG_BG1OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0014))
#define REG_BG2OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0018))
#define REG_BG3OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'001c))
[[nodiscard]]
volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile OffsetPair*>(0x0400'0010 + sizeof(OffsetPair) * bgIdx);
} }
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// User Input // User Input
#define REG_GAMEPAD (*reinterpret_cast<volatile uint16_t*>(0x0400'0130)) #define REG_GAMEPAD *reinterpret_cast<volatile uint16_t*>(0x0400'0130)
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Memory Addresses // Memory Addresses
#define MEM_EWRAM (*(reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000))) #define MEM_EWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0200'0000)
#define MEM_EWRAM_END reinterpret_cast<uint8_t*>(0x0203'FFFF)
#define MEM_IWRAM (*(reinterpret_cast<ox::Array<uint8_t, 0x0300'7FFF - 0x0300'0000>*>(0x0300'0000))) #define MEM_IWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0300'0000)
#define MEM_IWRAM_END reinterpret_cast<uint8_t*>(0x0300'7FFF)
#define REG_BLNDCTL (*reinterpret_cast<uint16_t*>(0x0400'0050)) #define REG_BLNDCTL *reinterpret_cast<uint16_t*>(0x0400'0050)
using Palette = ox::Array<uint16_t, 128>; #define MEM_BG_PALETTE reinterpret_cast<uint16_t*>(0x0500'0000)
#define MEM_BG_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0000))) #define MEM_SPRITE_PALETTE reinterpret_cast<uint16_t*>(0x0500'0200)
#define MEM_SPRITE_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0200)))
using BgMapTile = ox::Array<uint16_t, 8192>; using BgMapTile = ox::Array<uint16_t, 8192>;
#define MEM_BG_TILES (*(reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000))) #define MEM_BG_TILES reinterpret_cast<BgMapTile*>(0x0600'0000)
#define MEM_BG_MAP (*(reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000))) #define MEM_BG_MAP reinterpret_cast<BgMapTile*>(0x0600'e000)
#define MEM_SPRITE_TILES (*(reinterpret_cast<ox::Array<uint16_t, 32 * ox::units::KB>*>(0x0601'0000))) #define MEM_SPRITE_TILES reinterpret_cast<uint16_t*>(0x0601'0000)
#define MEM_OAM (*(reinterpret_cast<ox::Array<uint64_t, 64>*>(0x0700'0000))) #define MEM_OAM reinterpret_cast<uint64_t*>(0x0700'0000)
#define MEM_ROM (*(reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000))) #define MEM_ROM reinterpret_cast<char*>(0x0800'0000)
#define MEM_SRAM (*(reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000))) #define MEM_SRAM reinterpret_cast<char*>(0x0e00'0000)
#define MEM_SRAM_SIZE 65535

View File

@@ -37,10 +37,8 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate {
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept; GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept;
void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept; void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept;
void applySpriteUpdates() noexcept; void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
} }

View File

@@ -2,42 +2,29 @@
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved. * Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/ */
#ifdef __GNUC__
#include <ox/std/heapmgr.hpp> #include <ox/std/heapmgr.hpp>
#include <teagba/bios.hpp>
#include <teagba/registers.hpp>
namespace mgba { namespace mgba {
void initConsole(); void initConsole();
} }
#define MEM_HEAP_BEGIN reinterpret_cast<char*>(0x02000000) #define MEM_EWRAM_BEGIN reinterpret_cast<char*>(0x02000000)
#define MEM_HEAP_END reinterpret_cast<char*>(0x0203FFFF) #define MEM_EWRAM_END reinterpret_cast<char*>(0x0203FFFF)
#define HEAP_BEGIN reinterpret_cast<char*>(MEM_HEAP_BEGIN) #define HEAP_BEGIN reinterpret_cast<char*>(MEM_EWRAM_BEGIN)
// set size to half of EWRAM // set size to half of EWRAM
#define HEAP_SIZE ((MEM_HEAP_END - MEM_HEAP_BEGIN) / 2) #define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
#define HEAP_END reinterpret_cast<char*>(MEM_HEAP_BEGIN + HEAP_SIZE) #define HEAP_END reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE)
extern void (*__preinit_array_start[]) (void); extern void (*__preinit_array_start[]) (void);
extern void (*__preinit_array_end[]) (void); extern void (*__preinit_array_end[]) (void);
extern void (*__init_array_start[]) (void); extern void (*__init_array_start[]) (void);
extern void (*__init_array_end[]) (void); extern void (*__init_array_end[]) (void);
int main(int argc, char const **argv); int main(int argc, const char **argv);
extern "C" { extern "C" {
void abort() {
REG_IE = 0;
teagba::intrwait(0, 0);
while (true);
}
void *__gxx_personality_v0{};
void __libc_init_array() { void __libc_init_array() {
auto preInits = __preinit_array_end - __preinit_array_start; auto preInits = __preinit_array_end - __preinit_array_start;
for (decltype(preInits) i = 0; i < preInits; i++) { for (decltype(preInits) i = 0; i < preInits; i++) {
@@ -50,7 +37,7 @@ void __libc_init_array() {
} }
int c_start() { int c_start() {
char const *args[2] = {"", "rom.oxfs"}; const char *args[2] = {"", "rom.oxfs"};
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END); ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
mgba::initConsole(); mgba::initConsole();
#pragma GCC diagnostic push #pragma GCC diagnostic push
@@ -60,5 +47,3 @@ int c_start() {
} }
} }
#endif

View File

@@ -12,13 +12,13 @@ namespace teagba {
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer; static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
GbaSpriteAttrUpdate &spriteAttr(size_t const i) noexcept { GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
return g_spriteBuffer[i]; return g_spriteBuffer[i];
} }
void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept { void addSpriteUpdate(const GbaSpriteAttrUpdate &upd) noexcept {
const auto ie = REG_IE; // disable vblank interrupt handler const auto ie = REG_IE; // disable vblank interrupt handler
REG_IE = REG_IE & static_cast<uint16_t>(~Int_vblank); // disable vblank interrupt handler REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler
g_spriteBuffer[upd.idx] = upd; g_spriteBuffer[upd.idx] = upd;
REG_IE = ie; // enable vblank interrupt handler REG_IE = ie; // enable vblank interrupt handler
} }
@@ -29,10 +29,4 @@ void applySpriteUpdates() noexcept {
} }
} }
void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = x;
o.y = y;
}
} }

View File

@@ -27,9 +27,9 @@ All components have a platform indicator next to them:
* opengl - OpenGL implementation (P-) * opengl - OpenGL implementation (P-)
* studio - studio plugin for core (P-) * studio - studio plugin for core (P-)
* keel - keel plugin for core (PG) * keel - keel plugin for core (PG)
* sound - sound system for Nostalgia (PG) * scene - defines & processes map data (PG)
* studio - studio plugin for sound (P-) * studio - studio plugin for scene (P-)
* keel - keel plugin for sound (PG) * keel - keel plugin for scene (PG)
* player - plays the games (PG) * player - plays the games (PG)
* studio - makes the games (P-) * studio - makes the games (P-)
* tools - command line tools (P-) * tools - command line tools (P-)
@@ -48,7 +48,7 @@ All components have a platform indicator next to them:
Not really that external... (PG) Not really that external... (PG)
* GlUtils - OpenGL helpers (P-) * GlUtils - OpenGL helpers (P-)
* teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL * teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL
2.0), and custom GBA hardware interop code (-G) 2.0), and custom GBA hardware interop code (-G)
Most GBA code is built on PC because it is small and helps to work on both Most GBA code is built on PC because it is small and helps to work on both
projects with the same CMake build dir, but GBA code is never linked with any projects with the same CMake build dir, but GBA code is never linked with any
@@ -89,8 +89,7 @@ The GBA has two major resources for learning about its hardware:
On the surface, it seems like C++ changes the way we do things from C for no On the surface, it seems like C++ changes the way we do things from C for no
reason, but there are reasons for many of these duplications of functionality. reason, but there are reasons for many of these duplications of functionality.
The C++ language designers aren't stupid. The C++ language designers aren't stupid. Question them, but don't ignore them.
Question them, but don't ignore them.
#### Casting #### Casting
@@ -163,12 +162,13 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling ### Error Handling
Instead of throwing exceptions, generally try to use The GBA build has exceptions disabled.
[ox::Error](deps/ox/ox-docs.md#error-handling) for error reporting. Instead of throwing exceptions, all engine code should return
Exceptions may be used where errors-as-values will not work, but catch them and [ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting.
convert them to ```ox::Error``` as soon as possible. For the sake of consistency, try to stick to ```ox::Error``` in non-engine code
as well, but non-engine code is free to use exceptions when they make sense.
Exceptions should generally just use ```ox::Exception```, which is basically an Exceptions should generally just use ```OxException```, which is bascially an
exception form of ```ox::Error```. exception form of ```ox::Error```.
### File I/O ### File I/O

View File

@@ -1,75 +0,0 @@
# d2025.07.0
* Add sub-command for exporting TileSheets as PNG files.
* Add 'Reload Project' menu item under File.
* Fix opening a project to mark an unopenable file as closed in the config file on startup.
# d2025.06.0
* Add ability to remember recent projects in config
* Add navigation support (back and forward)
* Fix file deletion to close file even if not active
* Fix file copy to work when creating a copy with the name of a previously
deleted file
* Fix crash that could occur after switching projects
* Make file picker popup accept on double click of a file
* TileSheetEditor: Fix copy/cut/paste enablement when there is no selection
* TileSheetEditor: Fix manual redo of draw actions, fix drawing to pixel 0, 0
as first action
* TileSheetEditor: Fix draw command to work on same pixel after switching
subsheets
* PaletteEditor: Add RGB key shortcuts for focusing color channels
* PaletteEditor: Add color preview to color editor
# d2025.05.1
* TileSheetEditor: Fix overrun errors when switching subsheets, clear selection
on switch (261e324acd)
* Fix new build error that occurs in MSVC (26d5048e6720c4c2d52508a6ee44c67dd9fe3ee5)
# d2025.05.0
* Add app icon for both window and file
* Change application font to Roboto Medium
* Closing application will now confirm with user if any files have unsaved
changes.
* UUID duplicates will now be reported when opening a project.
* Deleting a directory now closes files in that directory.
* Delete key now initiates deletion of selected directory.
* Remove ability to re-order tabs. There were bugs associated with that.
* Mac: Menu bar shortcuts now say Cmd instead of Ctrl.
* TileSheetEditor: Fix selection clearing to work when clicking outside image.
* TileSheetEditor: Fix Delete Tile functionality, which was completely broken
* TileSheetEditor: Fix Insert Tile functionality, which was completely broken
* PaletteEditor: Fix color number key range. Previously, pressing A caused the
editor to jump to the last color.
* PaletteEditor: Page rename will now take effect upon pressing enter if the
text input has focus
# d2025.02.1
* Fix closing tab with unsaved changes (a44c5acc4b)
# d2025.02.0
* Rename core namespace to gfx.
* Add PaletteV5 to accommodate namespace change.
* Add TileSheetV5. TileSheetV5 retains the bpp field for the sake of
CompactTileSheet, but always store it pixel as 8 bpp for itself.
* Add ability to move subsheets in the subsheet tree.
* Add Flip X and Flip Y functionality to TileSheet Editor.
* Add rotate functionality to TileSheet Editor.
* Add draw line tool to TileSheet editor
* Replace file picker combo boxes with a browse button and file picker, and
support for dragging files from the project explorer.
* Add ability to jump to a color in a Palette by double clicking on the
color from the TileSheet editor
* Add ability to create directories.
* Add ability to add files to specific directories.
* Add ability to delete files from the project explorer.
* Ctrl-<num key> keyboard shortcuts for jumping between tabs.
* Fix Palette Editor to ignore keyboard input when popups are open.
* Palette Editor move color mechanism now uses drag and drop.
* Add ability to reorder Palette pages.
* Add warning for closing a tab with unsaved changes.
* Add ability to close a tab with Ctrl/Cmd-W

View File

@@ -1,23 +0,0 @@
O1;net.drinkingtea.ox.TypeDescriptor;1;{
"fieldList" :
[
{
"fieldName" : "pages",
"subscriptLevels" : 2,
"subscriptStack" :
[
{
"subscriptType" : 4
},
{
"subscriptType" : 4
}
],
"typeId" : "B.uint16;0"
}
],
"preloadable" : true,
"primitiveType" : 5,
"typeName" : "net.drinkingtea.nostalgia.gfx.CompactPalette",
"typeVersion" : 1
}

View File

@@ -1,28 +0,0 @@
O1;net.drinkingtea.ox.TypeDescriptor;1;{
"fieldList" :
[
{
"fieldName" : "bpp",
"typeId" : "B.int8;0"
},
{
"fieldName" : "defaultPalette",
"typeId" : "net.drinkingtea.ox.FileAddress;1"
},
{
"fieldName" : "pixels",
"subscriptLevels" : 1,
"subscriptStack" :
[
{
"subscriptType" : 4
}
],
"typeId" : "B.uint8;0"
}
],
"preloadable" : true,
"primitiveType" : 5,
"typeName" : "net.drinkingtea.nostalgia.gfx.CompactTileSheet",
"typeVersion" : 1
}

View File

@@ -1,23 +0,0 @@
O1;net.drinkingtea.ox.TypeDescriptor;1;{
"fieldList" :
[
{
"fieldName" : "name",
"typeId" : "net.drinkingtea.ox.BasicString#8#;1"
},
{
"fieldName" : "colors",
"subscriptLevels" : 1,
"subscriptStack" :
[
{
"subscriptType" : 4
}
],
"typeId" : "net.drinkingtea.nostalgia.gfx.PaletteColor;2"
}
],
"primitiveType" : 5,
"typeName" : "net.drinkingtea.nostalgia.gfx.Palette.PalettePage",
"typeVersion" : 2
}

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