Compare commits
222 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10830fb412 | |||
| cc499028fb | |||
| 572b8b2c78 | |||
| 88e901e214 | |||
| d42e10fcbe | |||
| bc88333a59 | |||
| 4048753205 | |||
| 5c146c6660 | |||
| 0885919dbd | |||
| 8c7d8cd08b | |||
| 110d4a2e6a | |||
| e29a50d0dc | |||
| 93d16cafb2 | |||
| 54d7c706eb | |||
| c9cb186462 | |||
| f204d01a3d | |||
| 62337bd29e | |||
| 7b24b33849 | |||
| 86c2c26d8d | |||
| f8b2700ea7 | |||
| 7848cbbbff | |||
| 96c5223e44 | |||
| d19b848427 | |||
| c812051ec0 | |||
| 3c07eb2df7 | |||
| ca851e1059 | |||
| 11e75cb6ca | |||
| 8c4add57e4 | |||
| 5e1698a321 | |||
| 3e95bc0842 | |||
| 58e19fad48 | |||
| a3a56b24e8 | |||
| 7681830ca6 | |||
| 46a7331754 | |||
| 56c19ad2a6 | |||
| c6ecadf9a8 | |||
| 2ed469f2dd | |||
| 53aea9731d | |||
| 0e028ff653 | |||
| 07688a2c29 | |||
| 9ce4d3f8c7 | |||
| 4aa8255c55 | |||
| bfdfc10425 | |||
| cdd574d873 | |||
| bc05bd12e5 | |||
| b754c66cf5 | |||
| 6a42303239 | |||
| 7477ede222 | |||
| 65e3153dda | |||
| 53a224cf8f | |||
| 592e641ba9 | |||
| 689da4a019 | |||
| bdf7755ee2 | |||
| 63f627377d | |||
| ff9002ad9a | |||
| 4d0da022cf | |||
| 02332d99b5 | |||
| a566ed2a8b | |||
| 815c3d19bf | |||
| 522bb14f18 | |||
| f40d5515f9 | |||
| 941d1d90dc | |||
| 3e880dcdcc | |||
| 03328ac10f | |||
| 63d0abaa3c | |||
| ef2a8cda77 | |||
| 671fa54f6f | |||
| 517432679b | |||
| b31c01f724 | |||
| f41213f13f | |||
| 28be7c4650 | |||
| 2f340b13b2 | |||
| 312c818866 | |||
| 0d69d0c4a2 | |||
| 81a0b8c820 | |||
| 172b5aee90 | |||
| 2b5338a9df | |||
| 8a430faf4c | |||
| e59382dd60 | |||
| 3006e77ef3 | |||
| 59c112a69c | |||
| 31b39982c5 | |||
| 5476417be2 | |||
| e03be694c2 | |||
| 490c0368bc | |||
| a24fc407c5 | |||
| e38b85b4f4 | |||
| f7c3c02c4c | |||
| 8f0f1fea39 | |||
| 2f36a3f6f0 | |||
| 07e5bf9054 | |||
| aacff3daf9 | |||
| e27eee50f0 | |||
| fd610454d6 | |||
| e61d4647b5 | |||
| c275c5f5e6 | |||
| fbf49ba511 | |||
| 92f74b27d1 | |||
| 934f0c9232 | |||
| ee9a3e1152 | |||
| 16886cdf1c | |||
| 08b9508d83 | |||
| 69bd968f98 | |||
| 4e7dc66610 | |||
| bea0cf5a0c | |||
| c7bc2a954f | |||
| 7372036a0a | |||
| 7461d832b6 | |||
| 6052798fea | |||
| fae1e73e54 | |||
| 51f2905c9c | |||
| 0c866d1b96 | |||
| fdf39d1a25 | |||
| a523a75e4b | |||
| cdaa64ed3f | |||
| 801d35c823 | |||
| 37b5fcc0f7 | |||
| f5f2c3bee6 | |||
| f6ef2b5acb | |||
| bf958a4a6e | |||
| 6a70e478a6 | |||
| 671b8edaad | |||
| 952637a1ea | |||
| 7569698e95 | |||
| 21713ba945 | |||
| 73273b6fa7 | |||
| 9f040392c7 | |||
| f4f7e5d053 | |||
| f847289bd4 | |||
| 94b0020d15 | |||
| c54c0bad38 | |||
| b9ffae0269 | |||
| 003f3e01c6 | |||
| 9028e74af0 | |||
| f5ccab5f2c | |||
| c27726a4a9 | |||
| 37cfa927d1 | |||
| 0efed70b57 | |||
| baf5fa3199 | |||
| bd24a775b2 | |||
| 857587c18b | |||
| eb3d53c955 | |||
| 14d58f3f5b | |||
| 5f2397903a | |||
| 58e0ecb469 | |||
| 8838bf420e | |||
| bddc544d7c | |||
| a9437191bf | |||
| 9d8da7ccda | |||
| 394b568e72 | |||
| 78e9f70db6 | |||
| 12e5623fe6 | |||
| cfdfb0a8c9 | |||
| 56e665301f | |||
| 7415ce4bd9 | |||
| 05f42150a1 | |||
| 8ea2bc6934 | |||
| c780924122 | |||
| 8c538560ca | |||
| c3e75bdb55 | |||
| 4419dff299 | |||
| e78c405046 | |||
| 6b7c5d896e | |||
| a33a73d73a | |||
| 536999c070 | |||
| e1cfcc8b5f | |||
| 514cb97835 | |||
| 4b5218c4f1 | |||
| 2ca77173d3 | |||
| cce5f52f96 | |||
| b55993294a | |||
| d8f847d707 | |||
| a5535ef59a | |||
| 8419b137e5 | |||
| ed1160ec74 | |||
| 1e21778059 | |||
| 78379f58c8 | |||
| 4322f720ba | |||
| 26f1a6051f | |||
| c4c1d4777b | |||
| fab012d3e7 | |||
| a90380f377 | |||
| 312097a799 | |||
| a40198ab8d | |||
| 52d8c0bdc8 | |||
| c19d7f4ea3 | |||
| 159b7e7ee7 | |||
| c93eec4f05 | |||
| e7e7a22390 | |||
| 26d5048e67 | |||
| 3b8f97cc41 | |||
| f1e68e0a04 | |||
| d6e4ab7a24 | |||
| 2000b2deee | |||
| 7d92400f6d | |||
| cb304ecf28 | |||
| ea17377700 | |||
| c424bde06d | |||
| ee7d5c6d51 | |||
| 99247cee32 | |||
| 7b8ddc189a | |||
| a6814030ee | |||
| 9937a01042 | |||
| abcf2adc56 | |||
| 05f9023550 | |||
| 5ba0bcf963 | |||
| 3ccadba2f5 | |||
| 00e52b6491 | |||
| ae40487990 | |||
| 84b612c693 | |||
| 3c2a6b047e | |||
| 626da322d9 | |||
| 0de428a2e5 | |||
| 8a52df4f76 | |||
| efec6eb3c8 | |||
| 56eeb24900 | |||
| ae81f6b3de | |||
| c1108301c0 | |||
| 83fbe6ac74 | |||
| 80b452833f | |||
| 0fa394333b | |||
| cae7535034 |
@@ -0,0 +1 @@
|
||||
sample_project text eol=lf
|
||||
@@ -6,12 +6,14 @@
|
||||
.mypy_cache
|
||||
.stfolder
|
||||
.stignore
|
||||
.vs
|
||||
util/scripts/__pycache__
|
||||
pyenv
|
||||
CMakeLists.txt.user
|
||||
ROM.oxfs
|
||||
Session.vim
|
||||
build
|
||||
cmake-build-*
|
||||
compile_commands.json
|
||||
dist
|
||||
graph_info.json
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
BC_VAR_PROJECT_NAME=nostalgia
|
||||
BC_VAR_PROJECT_NAME_CAP=Nostalgia
|
||||
BC_VAR_DEVENV_ROOT=util
|
||||
BUILDCORE_PATH=deps/buildcore
|
||||
BUILDCORE_PATH=deps/ox/deps/buildcore
|
||||
include ${BUILDCORE_PATH}/base.mk
|
||||
|
||||
ifeq ($(BC_VAR_OS),darwin)
|
||||
@@ -13,38 +13,70 @@ else
|
||||
endif
|
||||
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
|
||||
|
||||
.PHONY: git-setup-ox-remote
|
||||
git-setup-ox-remote:
|
||||
git remote add -f ox-master git@git.drinkingtea.net:drinkingtea/ox.git
|
||||
|
||||
.PHONY: git-pull-ox
|
||||
git-pull-ox:
|
||||
git fetch ox-master master
|
||||
git subtree pull --prefix deps/ox ox-master master --squash
|
||||
|
||||
.PHONY: git-push-ox
|
||||
git-push-ox:
|
||||
git subtree push --prefix=deps/ox ox-master master
|
||||
|
||||
.PHONY: pkg-gba
|
||||
pkg-gba: build
|
||||
pkg-gba: build-pack build-gba-player
|
||||
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
|
||||
|
||||
.PHONY: pkg-mac
|
||||
pkg-mac: install
|
||||
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-dmg.py
|
||||
${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
|
||||
run: build-player
|
||||
${PROJECT_PLAYER} sample_project
|
||||
|
||||
.PHONY: build-studio
|
||||
build-studio:
|
||||
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
|
||||
|
||||
.PHONY: run-studio
|
||||
run-studio: build
|
||||
run-studio: build-studio
|
||||
${PROJECT_STUDIO}
|
||||
|
||||
.PHONY: gba-run
|
||||
gba-run: pkg-gba
|
||||
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
|
||||
|
||||
.PHONY: debug
|
||||
debug: build
|
||||
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
|
||||
|
||||
.PHONY: debug-studio
|
||||
debug-studio: build
|
||||
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
|
||||
|
||||
|
||||
.PHONY: configure-gba
|
||||
configure-gba:
|
||||
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}
|
||||
@@ -52,3 +84,25 @@ configure-gba:
|
||||
.PHONY: configure-gba-debug
|
||||
configure-gba-debug:
|
||||
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=debug --build_root=${BC_VAR_BUILD_PATH}
|
||||
|
||||
.PHONY: loc
|
||||
loc:
|
||||
${BC_PY3} util/scripts/loc.py \
|
||||
--search-dirs \
|
||||
src \
|
||||
deps/ox/src \
|
||||
deps/buildcore \
|
||||
deps/gbabuildcore \
|
||||
deps/glutils \
|
||||
deps/teagba \
|
||||
--include-exts \
|
||||
.cpp \
|
||||
.hpp \
|
||||
.py \
|
||||
.s \
|
||||
.cmake \
|
||||
--exclude-paths \
|
||||
deps/teagba/src/gba_crt0.s \
|
||||
src/olympic/studio/applib/src/font.cpp \
|
||||
src/olympic/studio/applib/src/font.hpp \
|
||||
src/nostalgia/studio/icondata.cpp
|
||||
|
||||
+23
-23
@@ -89,7 +89,7 @@ struct GLObject: public Base {
|
||||
return id;
|
||||
}
|
||||
|
||||
constexpr operator const GLuint&() const noexcept {
|
||||
constexpr operator GLuint const&() const noexcept {
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ struct FrameBuffer {
|
||||
return fbo.id;
|
||||
}
|
||||
|
||||
constexpr operator const GLuint&() const noexcept {
|
||||
constexpr operator GLuint const&() const noexcept {
|
||||
return fbo.id;
|
||||
}
|
||||
|
||||
@@ -158,14 +158,14 @@ struct FrameBuffer {
|
||||
|
||||
class FrameBufferBind {
|
||||
private:
|
||||
static const FrameBuffer *s_activeFb;
|
||||
const FrameBuffer *m_restoreFb = nullptr;
|
||||
static FrameBuffer const *s_activeFb;
|
||||
FrameBuffer const *m_restoreFb = nullptr;
|
||||
public:
|
||||
explicit FrameBufferBind(const FrameBuffer &fb) noexcept;
|
||||
explicit FrameBufferBind(FrameBuffer const &fb) noexcept;
|
||||
~FrameBufferBind() noexcept;
|
||||
};
|
||||
|
||||
void bind(const FrameBuffer &fb) noexcept;
|
||||
void bind(FrameBuffer const &fb) noexcept;
|
||||
|
||||
struct ShaderVarSet {
|
||||
GLsizei len{};
|
||||
@@ -176,7 +176,7 @@ struct ProgramSource {
|
||||
ox::Vector<glutils::ShaderVarSet> const shaderParams;
|
||||
GLsizei const rowLen = [this] {
|
||||
GLsizei len{};
|
||||
for (auto const&v : shaderParams) {
|
||||
for (auto const &v : shaderParams) {
|
||||
len += v.len;
|
||||
}
|
||||
return len;
|
||||
@@ -187,23 +187,23 @@ struct ProgramSource {
|
||||
ox::String const geomShader{};
|
||||
};
|
||||
|
||||
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept;
|
||||
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept;
|
||||
|
||||
ox::Result<GLProgram> buildShaderProgram(
|
||||
ox::CStringView const&vert,
|
||||
ox::CStringView const&frag,
|
||||
ox::CStringView const&geo = "") noexcept;
|
||||
ox::CStringView const &vert,
|
||||
ox::CStringView const &frag,
|
||||
ox::CStringView const &geo = "") noexcept;
|
||||
|
||||
void setupShaderParams(
|
||||
GLProgram const&shader,
|
||||
ox::Vector<ShaderVarSet> const&vars,
|
||||
GLProgram const &shader,
|
||||
ox::Vector<ShaderVarSet> const &vars,
|
||||
GLsizei vertexRowLen) noexcept;
|
||||
|
||||
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept;
|
||||
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept;
|
||||
|
||||
glutils::GLVertexArray generateVertexArrayObject() noexcept;
|
||||
GLVertexArray generateVertexArrayObject() noexcept;
|
||||
|
||||
glutils::GLBuffer generateBuffer() noexcept;
|
||||
GLBuffer generateBuffer() noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
FrameBuffer generateFrameBuffer(int width, int height) noexcept;
|
||||
@@ -215,20 +215,20 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
|
||||
*/
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
|
||||
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept;
|
||||
|
||||
struct BufferSet {
|
||||
glutils::GLVertexArray vao;
|
||||
glutils::GLBuffer vbo;
|
||||
glutils::GLBuffer ebo;
|
||||
glutils::GLTexture tex;
|
||||
GLVertexArray vao;
|
||||
GLBuffer vbo;
|
||||
GLBuffer ebo;
|
||||
GLTexture tex;
|
||||
ox::Vector<float> vertices;
|
||||
ox::Vector<GLuint> elements;
|
||||
};
|
||||
|
||||
void sendVbo(BufferSet const&bs) noexcept;
|
||||
void sendVbo(BufferSet const &bs) noexcept;
|
||||
|
||||
void sendEbo(BufferSet const&bs) noexcept;
|
||||
void sendEbo(BufferSet const &bs) noexcept;
|
||||
|
||||
void clearScreen() noexcept;
|
||||
|
||||
|
||||
Vendored
+47
-24
@@ -46,9 +46,9 @@ template struct GLObject<deleteVertexArray>;
|
||||
template struct GLObject<deleteProgram>;
|
||||
template struct GLObject<deleteShader>;
|
||||
|
||||
const FrameBuffer *FrameBufferBind::s_activeFb = nullptr;
|
||||
FrameBuffer const *FrameBufferBind::s_activeFb = nullptr;
|
||||
|
||||
FrameBufferBind::FrameBufferBind(const FrameBuffer &fb) noexcept: m_restoreFb(s_activeFb) {
|
||||
FrameBufferBind::FrameBufferBind(FrameBuffer const &fb) noexcept: m_restoreFb(s_activeFb) {
|
||||
s_activeFb = &fb;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
glViewport(0, 0, fb.width, fb.height);
|
||||
@@ -64,15 +64,15 @@ FrameBufferBind::~FrameBufferBind() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void bind(const FrameBuffer &fb) noexcept {
|
||||
void bind(FrameBuffer const &fb) noexcept {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
glViewport(0, 0, fb.width, fb.height);
|
||||
}
|
||||
|
||||
|
||||
static ox::Result<GLShader> buildShader(
|
||||
GLuint shaderType,
|
||||
const GLchar *src,
|
||||
GLuint const shaderType,
|
||||
GLchar const *src,
|
||||
ox::StringViewCR shaderName) noexcept {
|
||||
GLShader shader(glCreateShader(shaderType));
|
||||
glShaderSource(shader, 1, &src, nullptr);
|
||||
@@ -88,7 +88,7 @@ static ox::Result<GLShader> buildShader(
|
||||
return shader;
|
||||
}
|
||||
|
||||
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
|
||||
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
|
||||
OX_REQUIRE_M(program, buildShaderProgram(
|
||||
src.vertShader,
|
||||
src.fragShader,
|
||||
@@ -98,11 +98,11 @@ ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
|
||||
}
|
||||
|
||||
void setupShaderParams(
|
||||
GLProgram const&shader,
|
||||
ox::Vector<ShaderVarSet> const&vars,
|
||||
GLProgram const &shader,
|
||||
ox::Vector<ShaderVarSet> const &vars,
|
||||
GLsizei vertexRowLen) noexcept {
|
||||
// setup vars
|
||||
for (size_t lenWritten = 0; auto const&v : vars) {
|
||||
for (size_t lenWritten = 0; auto const &v : vars) {
|
||||
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
|
||||
glEnableVertexAttribArray(attr);
|
||||
glVertexAttribPointer(
|
||||
@@ -113,19 +113,19 @@ void setupShaderParams(
|
||||
}
|
||||
}
|
||||
|
||||
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept {
|
||||
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept {
|
||||
// get row len
|
||||
GLsizei vertexRowLen{};
|
||||
for (auto const&v : vars) {
|
||||
for (auto const &v : vars) {
|
||||
vertexRowLen += v.len;
|
||||
}
|
||||
setupShaderParams(shader, vars, vertexRowLen);
|
||||
}
|
||||
|
||||
ox::Result<GLProgram> buildShaderProgram(
|
||||
ox::CStringView const&vert,
|
||||
ox::CStringView const&frag,
|
||||
ox::CStringView const&geo) noexcept {
|
||||
ox::CStringView const &vert,
|
||||
ox::CStringView const &frag,
|
||||
ox::CStringView const &geo) noexcept {
|
||||
GLProgram prgm(glCreateProgram());
|
||||
OX_REQUIRE(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad"));
|
||||
glAttachShader(prgm, vs);
|
||||
@@ -162,16 +162,30 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
|
||||
// color texture
|
||||
glGenTextures(1, &fb.color.id);
|
||||
glBindTexture(GL_TEXTURE_2D, fb.color);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL_RGB,
|
||||
GL_UNSIGNED_BYTE,
|
||||
nullptr);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
|
||||
// depth texture
|
||||
glGenRenderbuffers(1, &fb.depth.id);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
|
||||
glFramebufferRenderbuffer(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER,
|
||||
fb.depth);
|
||||
// verify FBO
|
||||
oxAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame Buffer is incomplete");
|
||||
// restore primary FB
|
||||
@@ -189,7 +203,16 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
// color texture
|
||||
glBindTexture(GL_TEXTURE_2D, fb.color);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL_RGB,
|
||||
GL_UNSIGNED_BYTE,
|
||||
nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// depth texture
|
||||
@@ -201,7 +224,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) noexcept {
|
||||
if (!fb) {
|
||||
fb = generateFrameBuffer(width, height);
|
||||
return;
|
||||
@@ -209,18 +232,18 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
|
||||
resizeFrameBuffer(fb, width, height);
|
||||
}
|
||||
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
|
||||
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept {
|
||||
resizeInitFrameBuffer(fb, sz.width, sz.height);
|
||||
}
|
||||
|
||||
void sendVbo(BufferSet const&bs) noexcept {
|
||||
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
|
||||
void sendVbo(BufferSet const &bs) noexcept {
|
||||
auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
void sendEbo(BufferSet const&bs) noexcept {
|
||||
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
|
||||
void sendEbo(BufferSet const &bs) noexcept {
|
||||
auto const bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"log_functions": [
|
||||
{
|
||||
"function": "ox::trace::gdblogger::captureLogFunc",
|
||||
"ignore_frames": 3,
|
||||
"file_var": "file",
|
||||
"line_var": "line",
|
||||
"channel_var": "ch",
|
||||
"msg_var": "msg"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
name: Build
|
||||
run-name: ${{ gitea.actor }} build and test
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: olympic
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
- run: make purge configure-debug
|
||||
- run: make build
|
||||
- run: make test
|
||||
- run: make purge configure-asan
|
||||
- run: make build
|
||||
- run: make test
|
||||
- run: make purge configure-release
|
||||
- run: make build
|
||||
- run: make test
|
||||
- run: make install
|
||||
@@ -3,7 +3,9 @@ build/gba
|
||||
build/*-asan
|
||||
build/*-debug
|
||||
build/*-release
|
||||
.current_build
|
||||
tags
|
||||
compile_commands.json
|
||||
conanbuildinfo.cmake
|
||||
conanbuildinfo.txt
|
||||
conaninfo.txt
|
||||
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
dist: trusty
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cmake
|
||||
script: ./scripts/cibuild
|
||||
Vendored
+9
-2
@@ -3,8 +3,8 @@ set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
|
||||
|
||||
project(Ox CXX)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
include(address_sanitizer)
|
||||
include(deps/buildcore/base.cmake)
|
||||
|
||||
|
||||
if(NOT DEFINED OX_RUN_TESTS)
|
||||
set(OX_RUN_TESTS ON)
|
||||
@@ -78,6 +78,13 @@ include_directories(src)
|
||||
|
||||
install(FILES OxConfig.cmake DESTINATION lib/cmake/ox)
|
||||
|
||||
install(
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
if(OX_USE_STDLIB)
|
||||
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
|
||||
add_subdirectory(deps/jsoncpp)
|
||||
|
||||
Vendored
+15
-65
@@ -1,68 +1,18 @@
|
||||
OS=$(shell uname | tr [:upper:] [:lower:])
|
||||
HOST_ENV=${OS}-$(shell uname -m)
|
||||
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
|
||||
DEVENV_IMAGE=wombatant/devenv
|
||||
ifneq ($(shell which docker 2>&1),)
|
||||
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
|
||||
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
|
||||
endif
|
||||
endif
|
||||
BC_VAR_PROJECT_NAME=ox
|
||||
BC_VAR_PROJECT_NAME_CAP=Ox
|
||||
BC_VAR_DEVENV_ROOT=util
|
||||
BUILDCORE_PATH=deps/buildcore
|
||||
include ${BUILDCORE_PATH}/base.mk
|
||||
|
||||
all:
|
||||
${ENV_RUN} ./scripts/run-make build
|
||||
preinstall:
|
||||
${ENV_RUN} ./scripts/run-make build preinstall
|
||||
install:
|
||||
${ENV_RUN} ./scripts/run-make build install
|
||||
clean:
|
||||
${ENV_RUN} ./scripts/run-make build clean
|
||||
purge:
|
||||
${ENV_RUN} rm -rf build
|
||||
test:
|
||||
${ENV_RUN} ./scripts/run-make build test
|
||||
.PHONY: git-setup-buildcore-remote
|
||||
git-setup-buildcore-remote:
|
||||
git remote add -f buildcore-master git@git.drinkingtea.net:drinkingtea/buildcore.git
|
||||
|
||||
devenv:
|
||||
docker pull ${DEVENV_IMAGE}
|
||||
docker run -d -v $(shell pwd):/usr/src/project \
|
||||
-e LOCAL_USER_ID=$(shell id -u ${USER}) \
|
||||
--name ${DEVENV} -t ${DEVENV_IMAGE} bash
|
||||
devenv-destroy:
|
||||
docker rm -f ${DEVENV}
|
||||
devenv-shell:
|
||||
${ENV_RUN} bash
|
||||
.PHONY: git-pull-buildcore
|
||||
git-pull-buildcore:
|
||||
git fetch buildcore-master master
|
||||
git subtree pull --prefix deps/buildcore buildcore-master master --squash
|
||||
|
||||
configure-release:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-release
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV}
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-release build/current
|
||||
|
||||
configure-debug:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-debug
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-debug build/current
|
||||
|
||||
configure-asan:
|
||||
${ENV_RUN} rm -rf build/${HOST_ENV}-asan
|
||||
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} asan
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s ${HOST_ENV}-asan build/current
|
||||
|
||||
configure-windows:
|
||||
${ENV_RUN} rm -rf build/windows
|
||||
${ENV_RUN} ./scripts/setup_build windows
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s windows build/current
|
||||
|
||||
configure-windows-debug:
|
||||
${ENV_RUN} rm -rf build/windows
|
||||
${ENV_RUN} ./scripts/setup_build windows debug
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s windows build/current
|
||||
|
||||
configure-gba:
|
||||
${ENV_RUN} rm -rf build/gba-release
|
||||
${ENV_RUN} ./scripts/setup_build gba
|
||||
${ENV_RUN} rm -f build/current
|
||||
${ENV_RUN} ln -s gba-release build/current
|
||||
.PHONY: git-push-buildcore
|
||||
git-push-buildcore:
|
||||
git subtree push --prefix=deps/buildcore buildcore-master master
|
||||
|
||||
Vendored
-24
@@ -1,24 +0,0 @@
|
||||
set(CMAKE_SYSTEM_NAME "Generic")
|
||||
|
||||
set(DEVKITARM $ENV{DEVKITARM})
|
||||
|
||||
if(NOT DEVKITARM)
|
||||
message(FATAL_ERROR "DEVKITARM environment variable not set")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_COMPILER ${DEVKITARM}/bin/arm-none-eabi-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${DEVKITARM}/bin/arm-none-eabi-g++)
|
||||
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
|
||||
set(LINKER_FLAGS "-specs=gba.specs")
|
||||
add_definitions (
|
||||
-DARM7
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
|
||||
|
||||
# cross compilers to use for C and C++
|
||||
set(CMAKE_C_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-g++)
|
||||
set(CMAKE_RC_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-windres)
|
||||
|
||||
# target environment on the build host system
|
||||
# set 1st to dir with the cross compiler's C/C++ headers/libs
|
||||
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
|
||||
|
||||
# modify default behavior of FIND_XXX() commands to
|
||||
# search for headers/libs in the target environment and
|
||||
# search for programs in the build host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
# This file belongs Nick Overdijk, and is from https://github.com/NickNick/wubwubcmake
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2013 Nick Overdijk
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" ON)
|
||||
|
||||
option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" OFF)
|
||||
if(USE_ASAN)
|
||||
include(CheckCXXSourceCompiles)
|
||||
# If the compiler understands -fsanitize=address, add it to the flags (gcc since 4.8 & clang since version 3.2)
|
||||
set(CMAKE_REQUIRED_FLAGS_BAK "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize=address")
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FSANA_SUPPORTED)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
|
||||
|
||||
if(FLAG_FSANA_SUPPORTED)
|
||||
set(asan_flag "-fsanitize=address")
|
||||
else(FLAG_FSANA_SUPPORTED)
|
||||
# Alternatively, try if it understands -faddress-sanitizer (clang until version 3.2)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -faddress-sanitizer")
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FASAN_SUPPORTED)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
|
||||
|
||||
if(FLAG_FASAN_SUPPORTED)
|
||||
set(asan_flag "-faddress-sanitizer")
|
||||
endif(FLAG_FASAN_SUPPORTED)
|
||||
endif(FLAG_FSANA_SUPPORTED)
|
||||
|
||||
if(FLAG_FSANA_SUPPORTED OR FLAG_FASAN_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${asan_flag}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${asan_flag}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${asan_flag}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${asan_flag}")
|
||||
endif()
|
||||
|
||||
endif(USE_ASAN)
|
||||
Vendored
Vendored
+212
-5
@@ -28,10 +28,7 @@ All components have a platform indicator next to them:
|
||||
Ox provides ```ox::Error``` to report errors.
|
||||
```ox::Error``` is a struct that has overloaded operators to behave like an
|
||||
integer error code, plus some extra fields to enhance debuggability.
|
||||
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```.
|
||||
```ox::Error```s will also include the file and line of the error.
|
||||
|
||||
In addition to ```ox::Error``` there is also the template ```ox::Result<T>```.
|
||||
```ox::Result``` simply wraps the type T value in a struct that also includes
|
||||
@@ -49,7 +46,7 @@ ox::Result<int> foo(int i) noexcept {
|
||||
if (i < 10) {
|
||||
return i + 1; // implicitly calls ox::Result<T>::Result(T)
|
||||
}
|
||||
return OxError(1); // implicitly calls ox::Result<T>::Result(ox::Error)
|
||||
return ox::Error(1); // implicitly calls ox::Result<T>::Result(ox::Error)
|
||||
}
|
||||
|
||||
int caller1() {
|
||||
@@ -181,6 +178,216 @@ variant for creating a non-const value.
|
||||
|
||||
* ```OX_REQUIRE_M``` - OX_REQUIRE Mutable
|
||||
|
||||
### Ox String Types
|
||||
|
||||
Ox has six different major string types.
|
||||
These types are divided into two categories: store types and view types.
|
||||
|
||||
String stores maintain a copy of the string data, whereas view types only
|
||||
maintain a reference to the data.
|
||||
Views should be used where you otherwise might use a const reference to a
|
||||
string store type.
|
||||
|
||||
Having all of these different string types may sound like an interoperability
|
||||
nightmare, but taking string view types extensively where applicable makes the
|
||||
imagined interoperability issues virtually non-existent.
|
||||
|
||||
#### String Store Types
|
||||
|
||||
##### String / BasicString
|
||||
|
||||
```ox::String```, or really ```ox::BasicString```, is Ox's version of
|
||||
```std::string```.
|
||||
Like ```std::string```, ```String``` allocates to store the string data.
|
||||
Also like ```std::string```, ```String``` allows for small string
|
||||
optimization for strings under 8 bytes.
|
||||
Unlike ```std::string```, the template that ```String``` is based on,
|
||||
```BasicString```, takes a parameter that allows adjusting to different size
|
||||
small string buffers.
|
||||
```ox::String``` is an alias to ```ox::BasicString<8>```.
|
||||
|
||||
```cpp
|
||||
// s can hold up to 100 bytes, plus one for a null terminator before allocating
|
||||
ox::BasicString<100> s;
|
||||
```
|
||||
Also unlike ```std::string```, ```ox::String``` has an explicit C-string conversion
|
||||
constructor.
|
||||
This prevents accidental instantiations of ```String```.
|
||||
|
||||
Consider the following:
|
||||
|
||||
```cpp
|
||||
void fStd(std::string const&);
|
||||
void fOx(ox::String const&);
|
||||
|
||||
int main() {
|
||||
// implicit and silent instantiation of std::string, which includes an
|
||||
// allocation
|
||||
fStd("123456789");
|
||||
// Will fail to compile:
|
||||
fOx("123456789");
|
||||
// But explicit String instantiation will work:
|
||||
fOx(ox::String{"123456789"});
|
||||
}
|
||||
```
|
||||
|
||||
##### IString
|
||||
|
||||
```IString```, or "inline string", is like ```BasicString```, but it will cut
|
||||
off strings that exceed that limit.
|
||||
|
||||
```cpp
|
||||
ox::IString<5> s; // s can hold up to 5 characters, plus a null terminator
|
||||
s = "12345"; // valid
|
||||
s = "123456"; // will compile and run, but will get cut off at '5'
|
||||
```
|
||||
|
||||
This is useful for certain string categories that have fixed lengths, like UUID
|
||||
strings or for numbers.
|
||||
|
||||
Ox makes use of ```IString``` in the following ways:
|
||||
|
||||
```cpp
|
||||
using UUIDStr = ox::IString<36>;
|
||||
|
||||
// and
|
||||
|
||||
template<Integer_c Integer>
|
||||
[[nodiscard]]
|
||||
constexpr auto intToStr(Integer v) noexcept {
|
||||
constexpr auto Cap = [] {
|
||||
auto out = 0;
|
||||
switch (sizeof(Integer)) {
|
||||
case 1:
|
||||
out = 3;
|
||||
break;
|
||||
case 2:
|
||||
out = 5;
|
||||
break;
|
||||
case 4:
|
||||
out = 10;
|
||||
break;
|
||||
case 8:
|
||||
out = 21;
|
||||
break;
|
||||
}
|
||||
return out + ox::is_signed_v<Integer>;
|
||||
}();
|
||||
ox::IString<Cap> out;
|
||||
std::ignore = out.resize(out.cap());
|
||||
ox::CharBuffWriter w{{out.data(), out.cap()}};
|
||||
std::ignore = writeItoa(v, w);
|
||||
std::ignore = out.resize(w.tellp());
|
||||
return out;
|
||||
}
|
||||
```
|
||||
|
||||
##### StringParam
|
||||
|
||||
```StringParam``` is a weird type.
|
||||
Because ```String::String(const char*)``` is explicit, it becomes a pain for
|
||||
functions to take ```String```s.
|
||||
|
||||
```cpp
|
||||
struct Type {
|
||||
ox::String m_s;
|
||||
explicit Type(ox::String p): m_s(std::move(p)) {
|
||||
}
|
||||
};
|
||||
|
||||
void f() {
|
||||
ox::String s{"asdf"};
|
||||
Type t1{"asdf"}; // invalid - will not compile
|
||||
Type t2{s}; // invalid - will not compile
|
||||
Type t3{std::move(s)}; // valid
|
||||
Type t4{ox::String{"asdf"}}; // valid
|
||||
}
|
||||
```
|
||||
|
||||
```StringParam``` has implicit conversion constructors, and will appropriately
|
||||
move from r-value ```String```s or create a ```String``` if not passed
|
||||
ownership of an existing ```String```.
|
||||
Think of ```StringParam``` as a way to opt-in to implicit instantiation with
|
||||
strings.
|
||||
|
||||
```StringParam``` can access the string as a view through the ```view()```
|
||||
function, and the ```String``` inside can be accessed by moving from the
|
||||
```StringParam```.
|
||||
|
||||
```cpp
|
||||
struct Type {
|
||||
ox::String m_s;
|
||||
explicit Type(ox::StringParam p): m_s(std::move(p)) {
|
||||
}
|
||||
};
|
||||
|
||||
void f() {
|
||||
ox::String s{"asdf"};
|
||||
Type t1{"asdf"}; // valid
|
||||
Type t2{s}; // valid
|
||||
Type t3{std::move(s)}; // valid
|
||||
Type t4{ox::String{"asdf"}}; // valid
|
||||
}
|
||||
```
|
||||
|
||||
#### String View Types
|
||||
|
||||
##### StringView
|
||||
|
||||
```ox::StringView``` is Ox's version of ```std::string_view```.
|
||||
```StringView``` contains a pointer to a string, along with its size.
|
||||
|
||||
This should be the normal type taken when a function needs a string that will
|
||||
exist until it returns.
|
||||
|
||||
##### CStringView
|
||||
|
||||
```CStringView``` is like ```StringView```, but it comes with the promise that
|
||||
the string ends with a null terminator.
|
||||
Accordingly, it has a ```c_str()``` function in addition to the ```data()```
|
||||
function that ```StringView``` has.
|
||||
|
||||
```CStringView``` should be used when wrapping a C API that only takes C
|
||||
strings.
|
||||
|
||||
##### StringLiteral
|
||||
|
||||
```StringLiteral``` is a string view type, but it kind of straddles the line
|
||||
between view and store types.
|
||||
Creating a ```StringLiteral``` is a promise that you are passing a string
|
||||
literal into the constructor.
|
||||
This means you can treat it like a store, that can be safely used as a copy of
|
||||
the data.
|
||||
Functions that take ```StringLiteral```s are allowed to assume that the data
|
||||
will have no lifetime concerns and hold onto it without any need to make a
|
||||
copy.
|
||||
It has a consteval constructor to enforce the promise that it is a compile time
|
||||
string.
|
||||
|
||||
```cpp
|
||||
void f(ox::StringLiteral const&);
|
||||
|
||||
int main() {
|
||||
f("123456789"); // valid
|
||||
f(ox::String{"123456789"}.c_str()); // invalid - will not compile
|
||||
}
|
||||
```
|
||||
|
||||
#### Other Variants
|
||||
|
||||
There are a few convenience aliases as well.
|
||||
|
||||
* StringCR = String const&
|
||||
* StringViewCR = StringView const&
|
||||
* CStringViewCR = CStringView const&
|
||||
* CString = const char*
|
||||
|
||||
String views do not generally need const references, but it does make debugging
|
||||
easier, as we can skip the constructor call if a string view already exists.
|
||||
|
||||
These kind of aliases probably should not exist for most types, but strings are
|
||||
fundamental and ease of use is desirable.
|
||||
|
||||
### Logging and Output
|
||||
|
||||
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.
|
||||
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
make -j release
|
||||
make -j debug
|
||||
make -j
|
||||
make -j test
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
for f in $(find $1 -maxdepth 1 -mindepth 1 -type d)
|
||||
do
|
||||
cmake --build "$f" --target $2 --
|
||||
done
|
||||
Vendored
-34
@@ -1,34 +0,0 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
project=$(pwd)/
|
||||
|
||||
TARGET=$1
|
||||
BUILD_TYPE=$2
|
||||
|
||||
if [[ $TARGET == windows ]]; then
|
||||
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/Mingw.cmake"
|
||||
elif [[ $TARGET == gba ]]; then
|
||||
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/GBA.cmake -DOX_USE_STDLIB=OFF -DCMAKE_INSTALL_PREFIX=$DEVKITARM"
|
||||
fi
|
||||
|
||||
if [[ $BUILD_TYPE == asan ]]; then
|
||||
buildTypeArgs="-DUSE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug"
|
||||
buildDir="build/${TARGET}-asan"
|
||||
elif [[ $BUILD_TYPE == debug ]]; then
|
||||
buildTypeArgs="-DCMAKE_BUILD_TYPE=Debug"
|
||||
buildDir="build/${TARGET}-debug"
|
||||
else
|
||||
buildTypeArgs="-DCMAKE_BUILD_TYPE=Release"
|
||||
buildDir="build/${TARGET}-release"
|
||||
fi
|
||||
|
||||
mkdir -p $buildDir
|
||||
pushd $buildDir
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-GNinja \
|
||||
$buildTypeArgs \
|
||||
$toolchain \
|
||||
$project
|
||||
popd
|
||||
Vendored
+27
-1
@@ -1 +1,27 @@
|
||||
add_subdirectory(ox)
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
set(OX_OS_WINDOWS TRUE)
|
||||
endif()
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(OX_OS_FREEBSD TRUE)
|
||||
else()
|
||||
set(OX_OS_FREEBSD FALSE)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(OX_OS_LINUX TRUE)
|
||||
else()
|
||||
set(OX_OS_LINUX FALSE)
|
||||
endif()
|
||||
|
||||
if(OX_USE_STDLIB)
|
||||
add_subdirectory(oc)
|
||||
endif()
|
||||
add_subdirectory(clargs)
|
||||
add_subdirectory(claw)
|
||||
add_subdirectory(event)
|
||||
add_subdirectory(fs)
|
||||
add_subdirectory(logconn)
|
||||
add_subdirectory(mc)
|
||||
add_subdirectory(model)
|
||||
add_subdirectory(preloader)
|
||||
add_subdirectory(std)
|
||||
|
||||
@@ -7,7 +7,7 @@ endif()
|
||||
|
||||
add_library(
|
||||
OxClArgs
|
||||
clargs.cpp
|
||||
src/clargs.cpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
@@ -27,11 +27,16 @@ target_link_libraries(
|
||||
OxStd
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
OxClArgs PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
clargs.hpp
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include/ox/clargs
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <ox/std/string.hpp>
|
||||
#include "clargs.hpp"
|
||||
#include <ox/clargs/clargs.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
@@ -15,16 +15,16 @@ ClArgs::ClArgs(int argc, const char **args) noexcept: ClArgs({args, static_cast<
|
||||
|
||||
ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
|
||||
for (auto i = 0u; i < args.size(); ++i) {
|
||||
auto arg = StringView(args[i]);
|
||||
auto arg = StringView{args[i]};
|
||||
if (arg[0] == '-') {
|
||||
while (arg[0] == '-' && arg.len()) {
|
||||
while (arg[0] == '-' && arg.size()) {
|
||||
arg = substr(arg, 1);
|
||||
}
|
||||
m_bools[arg] = true;
|
||||
// parse additional arguments
|
||||
if (i < args.size() && args[i + 1]) {
|
||||
auto val = String(args[i + 1]);
|
||||
if (val.len() && val[i] != '-') {
|
||||
auto const val = StringView{args[i + 1]};
|
||||
if (val.size() && val[0] != '-') {
|
||||
if (val == "false") {
|
||||
m_bools[arg] = false;
|
||||
}
|
||||
@@ -40,17 +40,17 @@ ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
|
||||
}
|
||||
|
||||
bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept {
|
||||
auto [value, err] = m_ints.at(arg);
|
||||
auto const [value, err] = m_ints.at(arg);
|
||||
return !err ? *value : defaultValue;
|
||||
}
|
||||
|
||||
String ClArgs::getString(ox::StringViewCR arg, ox::StringView defaultValue) const noexcept {
|
||||
auto [value, err] = m_strings.at(arg);
|
||||
auto const [value, err] = m_strings.at(arg);
|
||||
return !err ? ox::String(*value) : ox::String(defaultValue);
|
||||
}
|
||||
|
||||
int ClArgs::getInt(ox::StringViewCR arg, int defaultValue) const noexcept {
|
||||
auto [value, err] = m_ints.at(arg);
|
||||
auto const [value, err] = m_ints.at(arg);
|
||||
return !err ? *value : defaultValue;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
add_library(
|
||||
OxClaw
|
||||
read.cpp
|
||||
write.cpp
|
||||
src/read.cpp
|
||||
src/write.cpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
@@ -27,9 +27,22 @@ target_link_libraries(
|
||||
# )
|
||||
#endif()
|
||||
|
||||
install(TARGETS OxClaw
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
target_include_directories(
|
||||
OxClaw PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS OxClaw
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
@@ -52,8 +52,7 @@ Error readClaw(ox::BufferView buff, T &val) {
|
||||
{
|
||||
ox::BufferReader br({header.data, header.dataSize});
|
||||
MetalClawReader reader(br);
|
||||
ModelHandlerInterface handler(&reader);
|
||||
return model(&handler, &val);
|
||||
return model(reader.interface(), &val);
|
||||
}
|
||||
case ClawFormat::Organic:
|
||||
{
|
||||
@@ -39,7 +39,7 @@ struct TypeInfoCatcher {
|
||||
}
|
||||
|
||||
constexpr Error field(...) noexcept {
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
#include <ox/std/buffer.hpp>
|
||||
|
||||
#include "read.hpp"
|
||||
#include <ox/claw/read.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
|
||||
Result<StringView> readClawTypeId(BufferView const buff) noexcept {
|
||||
auto buffRaw = buff.data();
|
||||
auto buffLen = buff.size();
|
||||
size_t outSz{};
|
||||
@@ -43,7 +43,7 @@ ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
|
||||
return {{buff.data() + fmtSz, outSz - fmtSz - 1}};
|
||||
}
|
||||
|
||||
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
|
||||
Result<ClawHeader> readClawHeader(BufferView const buff) noexcept {
|
||||
auto buffRaw = buff.data();
|
||||
auto buffLen = buff.size();
|
||||
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
|
||||
@@ -87,7 +87,7 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
|
||||
return hdr;
|
||||
}
|
||||
|
||||
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
|
||||
Result<BufferView> stripClawHeader(BufferView const buff) noexcept {
|
||||
OX_REQUIRE(header, readClawHeader(buff));
|
||||
return {{header.data, header.dataSize}};
|
||||
}
|
||||
@@ -106,15 +106,14 @@ Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
|
||||
{
|
||||
ox::BufferReader br({header.data, header.dataSize});
|
||||
MetalClawReader reader(br);
|
||||
ModelHandlerInterface handler(&reader);
|
||||
OX_RETURN_ERROR(model(&handler, &obj));
|
||||
OX_RETURN_ERROR(model(reader.interface(), &obj));
|
||||
return obj;
|
||||
}
|
||||
case ClawFormat::Organic:
|
||||
{
|
||||
#ifdef OX_USE_STDLIB
|
||||
OrganicClawReader reader({header.data, header.dataSize});
|
||||
ModelHandlerInterface handler(&reader);
|
||||
ModelHandlerInterface handler(reader);
|
||||
OX_RETURN_ERROR(model(&handler, &obj));
|
||||
return obj;
|
||||
#else
|
||||
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "write.hpp"
|
||||
#include <ox/claw/write.hpp>
|
||||
|
||||
namespace ox::detail {
|
||||
|
||||
@@ -109,7 +109,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||
"ClawHeaderReader",
|
||||
[] {
|
||||
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
|
||||
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
|
||||
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
|
||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
|
||||
@@ -121,7 +121,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||
"ClawHeaderReader2",
|
||||
[] {
|
||||
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
|
||||
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
|
||||
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
|
||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
|
||||
@@ -134,8 +134,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||
[] {
|
||||
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
|
||||
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
|
||||
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.len() + 1}));
|
||||
oxExpect(actual, expected);
|
||||
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
|
||||
ox::expect(actual, expected);
|
||||
return ox::Error{};
|
||||
}
|
||||
},
|
||||
Vendored
+51
@@ -0,0 +1,51 @@
|
||||
add_library(
|
||||
OxEvent
|
||||
src/signal.cpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(OxEvent PRIVATE -Wsign-conversion)
|
||||
target_compile_options(OxEvent PRIVATE -Wconversion)
|
||||
endif()
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxEvent
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(
|
||||
OxEvent PUBLIC
|
||||
$<$<BOOL:${OX_USE_STDLIB}>:OX_USE_STDLIB>
|
||||
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxEvent PUBLIC
|
||||
OxStd
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
OxEvent PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS OxEvent
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
+4
-4
@@ -122,7 +122,7 @@ class Signal {
|
||||
}
|
||||
};
|
||||
|
||||
mutable Vector<UniquePtr<BaseSlot>> m_slots;
|
||||
mutable Vector<UPtr<BaseSlot>> m_slots;
|
||||
|
||||
public:
|
||||
~Signal() noexcept;
|
||||
@@ -218,7 +218,7 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
|
||||
for (auto &f : m_slots) {
|
||||
f->call(args...);
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} catch (const ox::Exception &ex) {
|
||||
return ox::Error(ex.errCode, ex.msg, ex.src);
|
||||
}
|
||||
@@ -303,7 +303,7 @@ class Signal<Error(Args...)> {
|
||||
}
|
||||
};
|
||||
|
||||
mutable Vector<UniquePtr<BaseSlot>> m_slots;
|
||||
mutable Vector<UPtr<BaseSlot>> m_slots;
|
||||
|
||||
public:
|
||||
~Signal() noexcept;
|
||||
@@ -410,7 +410,7 @@ Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept {
|
||||
for (auto &f : m_slots) {
|
||||
OX_RETURN_ERROR(f->call(ox::forward<Args>(args)...));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "signal.hpp"
|
||||
#include <ox/event/signal.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
@@ -5,14 +5,12 @@ endif()
|
||||
|
||||
add_library(
|
||||
OxFS
|
||||
ptrarith/nodebuffer.hpp
|
||||
ptrarith/ptr.hpp
|
||||
filestore/filestoretemplate.cpp
|
||||
filesystem/filelocation.cpp
|
||||
filesystem/pathiterator.cpp
|
||||
filesystem/directory.cpp
|
||||
filesystem/filesystem.cpp
|
||||
filesystem/passthroughfs.cpp
|
||||
src/filestore/filestoretemplate.cpp
|
||||
src/filesystem/filelocation.cpp
|
||||
src/filesystem/pathiterator.cpp
|
||||
src/filesystem/directory.cpp
|
||||
src/filesystem/filesystem.cpp
|
||||
src/filesystem/passthroughfs.cpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
@@ -33,10 +31,22 @@ target_link_libraries(
|
||||
OxMetalClaw
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
OxFS PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
add_executable(
|
||||
oxfs-tool
|
||||
tool.cpp
|
||||
src/tool.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
@@ -52,29 +62,6 @@ if(NOT OX_BARE_METAL)
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
filestore/filestoretemplate.hpp
|
||||
DESTINATION
|
||||
include/ox/fs/filestore
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
filesystem/filesystem.hpp
|
||||
filesystem/pathiterator.hpp
|
||||
DESTINATION
|
||||
include/ox/fs/filesystem
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
ptrarith/nodebuffer.hpp
|
||||
ptrarith/ptr.hpp
|
||||
DESTINATION
|
||||
include/ox/fs/ptrarith
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
OxFS
|
||||
+13
-13
@@ -230,7 +230,7 @@ template<typename size_t>
|
||||
Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
|
||||
OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate());
|
||||
++item->links;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
@@ -240,7 +240,7 @@ Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
|
||||
if (item->links == 0) {
|
||||
OX_RETURN_ERROR(remove(item));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
@@ -298,7 +298,7 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
|
||||
dest->id.get(), dest.offset(), destData.size());
|
||||
fsData->rootNode = dest.offset();
|
||||
oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get());
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header.");
|
||||
@@ -427,7 +427,7 @@ Error FileStoreTemplate<size_t>::resize() {
|
||||
oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize);
|
||||
OX_RETURN_ERROR(m_buffer->setSize(newSize));
|
||||
oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size());
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
@@ -479,7 +479,7 @@ Error FileStoreTemplate<size_t>::walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) {
|
||||
for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
|
||||
OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
@@ -503,7 +503,7 @@ Error FileStoreTemplate<size_t>::compact() {
|
||||
return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> Error {
|
||||
if (isFirstItem) {
|
||||
isFirstItem = false;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
if (!item.valid()) {
|
||||
return ox::Error(1);
|
||||
@@ -524,7 +524,7 @@ Error FileStoreTemplate<size_t>::compact() {
|
||||
parent->right = item;
|
||||
}
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
|
||||
item->left = root->left;
|
||||
item->right = root->right;
|
||||
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get());
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
return placeItem(root, item);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
|
||||
item->right = right->right;
|
||||
}
|
||||
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
return placeItem(right, item, depth + 1);
|
||||
}
|
||||
@@ -586,7 +586,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
|
||||
item->right = left->right;
|
||||
}
|
||||
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
return placeItem(left, item, depth + 1);
|
||||
}
|
||||
@@ -624,7 +624,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
|
||||
} else {
|
||||
fsData->rootNode = 0;
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
return unplaceItem(root, item);
|
||||
}
|
||||
@@ -661,7 +661,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
|
||||
if (item->left) {
|
||||
OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left)));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t>
|
||||
@@ -669,7 +669,7 @@ Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
|
||||
if (item.valid()) {
|
||||
OX_RETURN_ERROR(unplaceItem(item));
|
||||
OX_RETURN_ERROR(m_buffer->free(item));
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
return ox::Error(1);
|
||||
}
|
||||
Vendored
+2
-2
@@ -52,7 +52,7 @@ struct OX_PACKED DirectoryEntry {
|
||||
if (d.valid()) {
|
||||
d->inode = inode;
|
||||
auto const maxStrSz = bufferSize - 1 - sizeof(*this);
|
||||
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.len()));
|
||||
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.size()));
|
||||
return {};
|
||||
}
|
||||
return ox::Error(1);
|
||||
@@ -219,7 +219,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
|
||||
oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory");
|
||||
return ox::Error(1, "Could not read existing version of Directory");
|
||||
}
|
||||
const auto pathSize = name.len() + 1;
|
||||
const auto pathSize = name.size() + 1;
|
||||
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
|
||||
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
|
||||
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);
|
||||
deps/ox/src/ox/fs/filesystem/filesystem.hpp → deps/ox/src/fs/include/ox/fs/filesystem/filesystem.hpp
Vendored
+6
-6
@@ -87,7 +87,7 @@ class FileSystem {
|
||||
return writeFilePath(path, buffer, size, FileType::NormalFile);
|
||||
}
|
||||
|
||||
Error write(StringViewCR path, ox::Span<char> const&buff) noexcept {
|
||||
Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept {
|
||||
return write(path, buff.data(), buff.size(), FileType::NormalFile);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class FileSystem {
|
||||
return write(inode, buffer, size, FileType::NormalFile);
|
||||
}
|
||||
|
||||
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept {
|
||||
Error write(uint64_t inode, ox::SpanView<char> const&buff) noexcept {
|
||||
return write(inode, buff.data(), buff.size(), FileType::NormalFile);
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
|
||||
return ox::Error(1);
|
||||
}
|
||||
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
@@ -346,7 +346,7 @@ Error FileSystemTemplate<FileStore, Directory>::move(StringViewCR src, StringVie
|
||||
OX_REQUIRE_M(inode, rootDir.find(src));
|
||||
OX_RETURN_ERROR(rootDir.write(dest, inode));
|
||||
OX_RETURN_ERROR(rootDir.remove(src));
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
@@ -407,7 +407,7 @@ Error FileSystemTemplate<FileStore, Directory>::removePath(StringViewCR path, bo
|
||||
oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
|
||||
return ox::Error(1);
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename FileStore, typename Directory>
|
||||
@@ -424,7 +424,7 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(StringViewCR
|
||||
Vector<String> out;
|
||||
OX_RETURN_ERROR(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) {
|
||||
out.emplace_back(name);
|
||||
return ox::Error(0);
|
||||
return ox::Error{};
|
||||
}));
|
||||
return out;
|
||||
}
|
||||
+1
-1
@@ -99,7 +99,7 @@ Error PassThroughFS::ls(StringViewCR dir, F cb) const noexcept {
|
||||
for (auto &p : di) {
|
||||
OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+3
-3
@@ -354,7 +354,7 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
|
||||
}
|
||||
}
|
||||
m_header.bytesUsed -= item.size();
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
@@ -370,7 +370,7 @@ Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept {
|
||||
m_header.size = static_cast<size_t>(size);
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + end;
|
||||
ox::memset(data, 0, size - end);
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
|
||||
src = ptr(dest->next);
|
||||
dest = uninitializedPtr(dest.offset() + dest->fullSize());
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "filestoretemplate.hpp"
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "directory.hpp"
|
||||
#include <ox/fs/filesystem/directory.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <ox/model/modelops.hpp>
|
||||
|
||||
#include "filelocation.hpp"
|
||||
#include <ox/fs/filesystem/filelocation.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/utility.hpp>
|
||||
|
||||
#include "filesystem.hpp"
|
||||
#include <ox/fs/filesystem/filesystem.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
Vendored
+5
-5
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <ox/std/error.hpp>
|
||||
|
||||
#include "passthroughfs.hpp"
|
||||
#include <ox/fs/filesystem/passthroughfs.hpp>
|
||||
|
||||
#if defined(OX_HAS_PASSTHROUGHFS)
|
||||
|
||||
@@ -60,7 +60,7 @@ Error PassThroughFS::move(StringViewCR src, StringViewCR dest) noexcept {
|
||||
if (ec.value()) {
|
||||
return ox::Error(1);
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
|
||||
@@ -148,7 +148,7 @@ Error PassThroughFS::readFilePath(StringViewCR path, void *buffer, std::size_t b
|
||||
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
|
||||
return ox::Error(2);
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept {
|
||||
@@ -197,7 +197,7 @@ Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64
|
||||
oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
|
||||
return ox::Error(1);
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept {
|
||||
@@ -206,7 +206,7 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
|
||||
}
|
||||
|
||||
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
|
||||
for (auto i = 0u; i < path.len() && path[0] == '/'; i++) {
|
||||
for (auto i = 0u; i < path.size() && path[0] == '/'; i++) {
|
||||
path = substr(path, 1);
|
||||
}
|
||||
return {path.data(), path.bytes()};
|
||||
Vendored
+7
-7
@@ -9,7 +9,7 @@
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include "pathiterator.hpp"
|
||||
#include <ox/fs/filesystem/pathiterator.hpp>
|
||||
|
||||
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
|
||||
|
||||
@@ -36,7 +36,7 @@ Error PathIterator::dirPath(char *out, std::size_t outSize) {
|
||||
if (idx >= 0 && size < outSize) {
|
||||
ox::memcpy(out, m_path, size);
|
||||
out[size] = 0;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
return ox::Error(1);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ Error PathIterator::get(StringView &fileName) {
|
||||
if (size && fileName[size - 1] == '/') {
|
||||
fileName = ox::substr(m_path, start, start + size - 1);
|
||||
}
|
||||
oxAssert(fileName[fileName.len()-1] != '/', "name ends in /");
|
||||
oxAssert(fileName[fileName.size()-1] != '/', "name ends in /");
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ Error PathIterator::next(StringView &fileName) {
|
||||
std::size_t size = 0;
|
||||
auto retval = ox::Error(1);
|
||||
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
|
||||
retval = ox::Error(0);
|
||||
retval = {};
|
||||
if (m_path[m_iterator] == '/') {
|
||||
m_iterator++;
|
||||
}
|
||||
@@ -104,11 +104,11 @@ Error PathIterator::next(StringView &fileName) {
|
||||
}
|
||||
fileName = ox::substr(m_path, start, start + size);
|
||||
// truncate trailing /
|
||||
while (fileName.len() && fileName[fileName.len() - 1] == '/') {
|
||||
while (fileName.size() && fileName[fileName.size() - 1] == '/') {
|
||||
fileName = ox::substr(m_path, start, start + size);
|
||||
}
|
||||
m_iterator += size;
|
||||
oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /");
|
||||
oxAssert(fileName.size() == 0 || fileName[fileName.size()-1] != '/', "name ends in /");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -118,7 +118,7 @@ Result<std::size_t> PathIterator::nextSize() const {
|
||||
auto retval = ox::Error(1);
|
||||
auto it = m_iterator;
|
||||
if (it < m_maxSize && ox::strlen(&m_path[it])) {
|
||||
retval = ox::Error(0);
|
||||
retval = {};
|
||||
if (m_path[it] == '/') {
|
||||
it++;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
static ox::Result<ox::UniquePtr<ox::FileSystem>> loadFs(const char *path) noexcept {
|
||||
static ox::Result<ox::UPtr<ox::FileSystem>> loadFs(const char *path) noexcept {
|
||||
OX_REQUIRE(buff, loadFsBuff(path));
|
||||
return {ox::make_unique<ox::FileSystem32>(buff.data, buff.size)};
|
||||
}
|
||||
@@ -48,7 +48,7 @@ static ox::Error runLs(ox::FileSystem *fs, ox::Span<const char*> args) noexcept
|
||||
for (const auto &file : files) {
|
||||
oxOutf("{}\n", file);
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
|
||||
@@ -60,7 +60,7 @@ static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcep
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
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 {
|
||||
@@ -59,7 +59,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
||||
"PathIterator::next1",
|
||||
[](ox::StringView) {
|
||||
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
|
||||
ox::PathIterator it(path.c_str(), path.len());
|
||||
ox::PathIterator it(path.c_str(), path.size());
|
||||
ox::StringView buff;
|
||||
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
|
||||
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
|
||||
@@ -74,9 +74,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
||||
ox::PathIterator it(path);
|
||||
ox::StringView buff;
|
||||
oxAssert(it.next(buff), "PathIterator::next returned error");
|
||||
oxExpect(buff, "usr");
|
||||
ox::expect(buff, "usr");
|
||||
oxAssert(it.next(buff), "PathIterator::next returned error");
|
||||
oxExpect(buff, "share");
|
||||
ox::expect(buff, "share");
|
||||
return ox::Error(0);
|
||||
}
|
||||
},
|
||||
@@ -84,7 +84,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
||||
"PathIterator::next3",
|
||||
[](ox::StringView) {
|
||||
auto const path = ox::String("/");
|
||||
ox::PathIterator it(path.c_str(), path.len());
|
||||
ox::PathIterator it(path.c_str(), path.size());
|
||||
ox::StringView buff;
|
||||
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
|
||||
return ox::Error(0);
|
||||
@@ -106,7 +106,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
||||
"PathIterator::next5",
|
||||
[](ox::StringView) {
|
||||
auto const path = ox::String("usr/share/");
|
||||
ox::PathIterator it(path.c_str(), path.len());
|
||||
ox::PathIterator it(path.c_str(), path.size());
|
||||
ox::StringView buff;
|
||||
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
|
||||
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
|
||||
@@ -117,10 +117,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
||||
"PathIterator::dirPath",
|
||||
[] (ox::StringView) {
|
||||
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
|
||||
ox::PathIterator it(path.c_str(), path.len());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
|
||||
ox::PathIterator it(path.c_str(), path.size());
|
||||
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
oxAssert(it.dirPath(buff, path.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);
|
||||
}
|
||||
@@ -175,8 +175,8 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
||||
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
|
||||
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
|
||||
ox::FileStore32 fileStore(list, buffLen);
|
||||
oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed.");
|
||||
oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed.");
|
||||
oxAssert(fileStore.write(4, str1, str1Len, 1), "FileStore::write 1 failed.");
|
||||
oxAssert(fileStore.write(5, str2, str2Len, 1), "FileStore::write 2 failed.");
|
||||
|
||||
char str1Read[str1Len];
|
||||
size_t str1ReadSize = 0;
|
||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
add_library(
|
||||
OxLogConn
|
||||
logconn.cpp
|
||||
src/logconn.cpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
@@ -24,12 +24,16 @@ target_link_libraries(
|
||||
$<$<BOOL:${OX_OS_WINDOWS}>:ws2_32>
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
OxLogConn PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
circularbuff.hpp
|
||||
logconn.hpp
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include/ox/logconn
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
Vendored
@@ -23,7 +23,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "logconn.hpp"
|
||||
#include <ox/logconn/logconn.hpp>
|
||||
|
||||
|
||||
namespace ox {
|
||||
@@ -91,23 +91,28 @@ ox::Error LoggerConn::sendInit(const InitTraceMsg &msg) noexcept {
|
||||
}
|
||||
|
||||
void LoggerConn::msgSend() noexcept {
|
||||
while (true) {
|
||||
std::unique_lock lk(m_waitMut);
|
||||
m_waitCond.wait(lk);
|
||||
if (!m_running) {
|
||||
break;
|
||||
}
|
||||
std::lock_guard const buffLk(m_buffMut);
|
||||
try {
|
||||
while (true) {
|
||||
Array<char, units::KB> tmp;
|
||||
const auto read = m_buff.read(tmp.data(), tmp.size());
|
||||
if (!read) {
|
||||
std::unique_lock lk(m_waitMut);
|
||||
m_waitCond.wait(lk);
|
||||
if (!m_running) {
|
||||
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);
|
||||
std::lock_guard const buffLk(m_buffMut);
|
||||
while (true) {
|
||||
Array<char, units::KB> tmp;
|
||||
const auto read = m_buff.read(tmp.data(), tmp.size());
|
||||
if (!read) {
|
||||
break;
|
||||
}
|
||||
oxAssert(read <= tmp.size(), "logger trying to read too much data");
|
||||
//std::printf("LoggerConn: sending %lu bytes\n", read);
|
||||
std::ignore = send(tmp.data(), read);
|
||||
}
|
||||
}
|
||||
} catch (std::exception const &e) {
|
||||
oxErrf("Exception in logger thread: {}\n", e.what());
|
||||
oxAssert(false, "logger thread exception");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
add_library(
|
||||
OxMetalClaw
|
||||
presenceindicator.cpp
|
||||
read.cpp
|
||||
write.cpp
|
||||
src/read.cpp
|
||||
src/write.cpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
@@ -25,22 +24,22 @@ if(NOT OX_BARE_METAL)
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
intops.hpp
|
||||
err.hpp
|
||||
mc.hpp
|
||||
presenceindicator.hpp
|
||||
read.hpp
|
||||
types.hpp
|
||||
write.hpp
|
||||
DESTINATION
|
||||
include/ox/mc
|
||||
target_include_directories(
|
||||
OxMetalClaw PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(TARGETS OxMetalClaw
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
install(
|
||||
DIRECTORY
|
||||
include/ox
|
||||
DESTINATION
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS OxMetalClaw
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
@@ -18,25 +18,25 @@
|
||||
|
||||
namespace ox::mc {
|
||||
|
||||
template<typename T>
|
||||
template<Integer_c T>
|
||||
static constexpr auto Bits = sizeof(T) << 3;
|
||||
|
||||
/**
|
||||
* Returns highest bit other than possible signed bit.
|
||||
* Bit numbering starts at 0.
|
||||
*/
|
||||
template<typename I>
|
||||
template<Integer_c I>
|
||||
[[nodiscard]]
|
||||
constexpr std::size_t highestBit(I val) noexcept {
|
||||
constexpr size_t highestBit(I const val) noexcept {
|
||||
unsigned shiftStart = sizeof(I) * 8 - 1;
|
||||
// find most significant non-sign indicator bit
|
||||
std::size_t highestBit = 0;
|
||||
// find the most significant non-sign indicator bit
|
||||
size_t highestBit = 0;
|
||||
// start at one bit lower if signed
|
||||
if constexpr(is_signed_v<I>) {
|
||||
--shiftStart;
|
||||
}
|
||||
for (auto i = shiftStart; i > 0; --i) {
|
||||
const auto bitValue = (val >> i) & 1;
|
||||
auto const bitValue = (val >> i) & 1;
|
||||
if (bitValue) {
|
||||
highestBit = i;
|
||||
break;
|
||||
@@ -45,7 +45,7 @@ constexpr std::size_t highestBit(I val) noexcept {
|
||||
return highestBit;
|
||||
}
|
||||
|
||||
static_assert(highestBit(int8_t(0b10000000)) == 0);
|
||||
static_assert(highestBit(static_cast<int8_t>(0b10000000)) == 0);
|
||||
static_assert(highestBit(~static_cast<int8_t>(-1)) == 0);
|
||||
static_assert(highestBit(~static_cast<int8_t>(-2)) == 0);
|
||||
static_assert(highestBit(~static_cast<int8_t>(-3)) == 1);
|
||||
@@ -53,42 +53,39 @@ static_assert(highestBit(1) == 0);
|
||||
static_assert(highestBit(2) == 1);
|
||||
static_assert(highestBit(4) == 2);
|
||||
static_assert(highestBit(8) == 3);
|
||||
static_assert(highestBit(uint64_t(1) << 31) == 31);
|
||||
static_assert(highestBit(uint64_t(1) << 63) == 63);
|
||||
static_assert(highestBit(static_cast<uint64_t>(1) << 31) == 31);
|
||||
static_assert(highestBit(static_cast<uint64_t>(1) << 63) == 63);
|
||||
|
||||
struct McInt {
|
||||
ox::Array<uint8_t, 9> data{};
|
||||
Array<uint8_t, 9> data{};
|
||||
// length of integer in bytes
|
||||
std::size_t length = 0;
|
||||
size_t length = 0;
|
||||
};
|
||||
|
||||
template<typename I>
|
||||
template<Integer_c I>
|
||||
[[nodiscard]]
|
||||
constexpr McInt encodeInteger(I pInput) noexcept {
|
||||
auto const input = ox::ResizedInt_t<I, 64>{pInput};
|
||||
constexpr McInt encodeInteger(I const pInput) noexcept {
|
||||
auto const input = ResizedInt_t<I, 64>{pInput};
|
||||
McInt out;
|
||||
const auto inputNegative = is_signed_v<I> && input < 0;
|
||||
// move input to uint64_t to allow consistent bit manipulation, and to avoid
|
||||
auto const inputNegative = is_signed_v<I> && input < 0;
|
||||
// move input to uint64_t to allow consistent bit manipulation and to avoid
|
||||
// overflow concerns
|
||||
uint64_t val = 0;
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
ox::memcpy(&val, &input, sizeof(input));
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
auto const val = std::bit_cast<uint64_t>(input);
|
||||
if (val) {
|
||||
// bits needed to represent number factoring in space possibly
|
||||
// needed for signed bit
|
||||
const auto highBit = inputNegative ? highestBit(~val) : highestBit(val);
|
||||
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
|
||||
auto const highBit = inputNegative ? highestBit(~val) : highestBit(val);
|
||||
auto const bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
|
||||
// bytes needed to store value
|
||||
std::size_t bytes = bits / 8 + (bits % 8 != 0);
|
||||
const auto bitsAvailable = bytes * 8; // bits available to integer value
|
||||
const auto bitsNeeded = bits + bytes;
|
||||
size_t bytes = bits / 8 + (bits % 8 != 0);
|
||||
auto const bitsAvailable = bytes * 8; // bits available to integer value
|
||||
auto const bitsNeeded = bits + bytes;
|
||||
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
|
||||
// bits for integer + bits needed to represent bytes > bits available
|
||||
if (bitsNeeded > bitsAvailable && bytes != 9) {
|
||||
++bytes;
|
||||
}
|
||||
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
|
||||
auto const bytesIndicator = onMask<uint8_t>(bytes - 1);
|
||||
// ensure we are copying from little endian representation
|
||||
LittleEndian<uint64_t> leVal = val;
|
||||
if (inputNegative) {
|
||||
@@ -103,9 +100,9 @@ constexpr McInt encodeInteger(I pInput) noexcept {
|
||||
out.data[1] |= 0b1000'0000;
|
||||
}
|
||||
} else {
|
||||
const auto valBits = bytes * 8;
|
||||
uint64_t negBit = inputNegative ? 1 : 0;
|
||||
auto intermediate =
|
||||
auto const valBits = bytes * 8;
|
||||
uint64_t const negBit = inputNegative ? 1 : 0;
|
||||
auto const intermediate =
|
||||
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
|
||||
static_cast<uint64_t>(bytesIndicator);
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
@@ -122,8 +119,8 @@ constexpr McInt encodeInteger(I pInput) noexcept {
|
||||
* length integer.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr std::size_t countBytes(unsigned b) noexcept {
|
||||
std::size_t i = 0;
|
||||
constexpr size_t countBytes(unsigned const b) noexcept {
|
||||
size_t i = 0;
|
||||
while ((b >> i) & 1) ++i;
|
||||
return i + 1;
|
||||
}
|
||||
@@ -138,39 +135,39 @@ static_assert(countBytes(0b0011'1111) == 7);
|
||||
static_assert(countBytes(0b0111'1111) == 8);
|
||||
static_assert(countBytes(0b1111'1111) == 9);
|
||||
|
||||
template<typename I>
|
||||
constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept {
|
||||
template<Integer_c I>
|
||||
constexpr Result<I> decodeInteger(Reader_c auto &rdr, size_t &bytesRead) noexcept {
|
||||
uint8_t firstByte = 0;
|
||||
OX_RETURN_ERROR(rdr.read(&firstByte, 1));
|
||||
OX_RETURN_ERROR(rdr.seekg(-1, ox::ios_base::cur));
|
||||
const auto bytes = countBytes(firstByte);
|
||||
auto const bytes = countBytes(firstByte);
|
||||
if (bytes == 9) {
|
||||
*bytesRead = bytes;
|
||||
bytesRead = bytes;
|
||||
I out = 0;
|
||||
OX_RETURN_ERROR(rdr.seekg(1, ox::ios_base::cur));
|
||||
OX_RETURN_ERROR(rdr.read(&out, sizeof(I)));
|
||||
return fromLittleEndian<I>(out);
|
||||
}
|
||||
*bytesRead = bytes;
|
||||
bytesRead = bytes;
|
||||
uint64_t decoded = 0;
|
||||
OX_RETURN_ERROR(rdr.read(&decoded, bytes));
|
||||
decoded >>= bytes;
|
||||
// move sign bit
|
||||
if constexpr(is_signed_v<I>) {
|
||||
const auto negBit = bytes * 8 - bytes - 1;
|
||||
auto const negBit = bytes * 8 - bytes - 1;
|
||||
// move sign
|
||||
const auto negative = (decoded >> negBit) == 1;
|
||||
auto const negative = (decoded >> negBit) == 1;
|
||||
if (negative) {
|
||||
// fill in all bits between encoded sign and real sign with 1s
|
||||
// split it up because the 32-bit ARM can't shift more than 32 bits
|
||||
ox::Array<uint32_t, 2> d = {};
|
||||
Array<uint32_t, 2> d = {};
|
||||
//d[0] = decoded & 0xffff'ffff;
|
||||
//d[1] = decoded >> 32;
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
ox::memcpy(&d[0], &decoded, sizeof(decoded));
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
auto bit = negBit;
|
||||
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
|
||||
for (; bit < ox::min<size_t>(Bits<I>, 32); ++bit) {
|
||||
d[0] |= 1 << bit;
|
||||
}
|
||||
bit -= 32;
|
||||
@@ -179,7 +176,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
|
||||
}
|
||||
I out = 0;
|
||||
if constexpr(ox::defines::BigEndian) {
|
||||
const auto d0Tmp = d[0];
|
||||
auto const d0Tmp = d[0];
|
||||
d[0] = d[1];
|
||||
d[1] = d0Tmp;
|
||||
}
|
||||
@@ -192,11 +189,11 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
|
||||
return static_cast<I>(decoded);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Result<I> decodeInteger(McInt m) noexcept {
|
||||
std::size_t bytesRead{};
|
||||
template<Integer_c I>
|
||||
Result<I> decodeInteger(McInt const &m) noexcept {
|
||||
size_t bytesRead{};
|
||||
BufferReader br({reinterpret_cast<const char*>(m.data.data()), 9});
|
||||
return decodeInteger<I>(br, &bytesRead);
|
||||
return decodeInteger<I>(br, bytesRead);
|
||||
}
|
||||
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2015 - 2025 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/array.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/span.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/reader.hpp>
|
||||
|
||||
#include "err.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<Reader_c Reader>
|
||||
class FieldBitmapReader {
|
||||
protected:
|
||||
mutable size_t m_mapBlockIdx = ~size_t{};
|
||||
mutable uint64_t m_mapBlock{};
|
||||
size_t m_mapStart{};
|
||||
Reader &m_reader;
|
||||
|
||||
public:
|
||||
explicit constexpr FieldBitmapReader(Reader &reader) noexcept:
|
||||
m_mapStart(reader.tellg()),
|
||||
m_reader(reader) {
|
||||
}
|
||||
|
||||
constexpr Result<bool> get(size_t idx) const noexcept {
|
||||
constexpr auto blockBits = sizeof(m_mapBlock);
|
||||
auto const blockIdx = idx / blockBits;
|
||||
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
|
||||
OX_RETURN_ERROR(loadMapBlock(blockIdx));
|
||||
}
|
||||
idx %= blockBits;
|
||||
return (m_mapBlock >> idx) & 1;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr Error loadMapBlock(size_t const idx) const noexcept {
|
||||
OX_REQUIRE(g, m_reader.tellg());
|
||||
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
|
||||
Array<char, sizeof(m_mapBlock)> mapBlock{};
|
||||
OX_RETURN_ERROR(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
|
||||
// Warning: narrow-conv
|
||||
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
|
||||
m_mapBlock = 0;
|
||||
for (uint64_t i{}; auto b : mapBlock) {
|
||||
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
|
||||
i += 8;
|
||||
}
|
||||
m_mapBlockIdx = idx;
|
||||
return {};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class FieldBitmapWriter {
|
||||
protected:
|
||||
Span<char> m_map;
|
||||
size_t m_mapLen{};
|
||||
|
||||
public:
|
||||
explicit constexpr FieldBitmapWriter(Span<char> const &map) noexcept:
|
||||
m_map(map),
|
||||
m_mapLen(m_map.size()) {
|
||||
}
|
||||
|
||||
constexpr auto setBuffer(Span<char> const &map) noexcept {
|
||||
m_map = map;
|
||||
m_mapLen = map.size();
|
||||
}
|
||||
|
||||
constexpr Result<bool> get(size_t const i) const noexcept {
|
||||
if (i / 8 < m_mapLen) {
|
||||
return (std::bit_cast<uint8_t>(m_map[i / 8]) >> (i % 8)) & 1;
|
||||
}
|
||||
return Error{McPresenceMapOverflow};
|
||||
}
|
||||
|
||||
constexpr Error setFields(int const fields) noexcept {
|
||||
m_mapLen = static_cast<size_t>((fields / 8 + 1) - (fields % 8 == 0));
|
||||
if (m_mapLen > m_map.size()) [[unlikely]] {
|
||||
return Error{McPresenceMapOverflow};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr void setMaxLen(int const maxLen) noexcept {
|
||||
m_mapLen = static_cast<size_t>(maxLen);
|
||||
}
|
||||
|
||||
constexpr int64_t getMaxLen() const noexcept {
|
||||
return static_cast<int64_t>(m_mapLen);
|
||||
}
|
||||
|
||||
constexpr Error set(size_t const i, bool const on) noexcept {
|
||||
if (i / 8 < m_mapLen) {
|
||||
char &actual = m_map[i / 8];
|
||||
uint8_t v = std::bit_cast<uint8_t>(actual);
|
||||
if (on) {
|
||||
v |= 1 << (i % 8);
|
||||
} else {
|
||||
v &= ~static_cast<uint8_t>(1 << (i % 8));
|
||||
}
|
||||
actual = std::bit_cast<char>(v);
|
||||
return {};
|
||||
}
|
||||
return Error{McPresenceMapOverflow};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
+141
-140
@@ -32,58 +32,58 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
||||
|
||||
private:
|
||||
FieldBitmapReader<Reader> m_fieldPresence;
|
||||
std::size_t m_fields = 0;
|
||||
std::size_t m_field = 0;
|
||||
ox::Optional<int> m_unionIdx;
|
||||
size_t m_fields{};
|
||||
size_t m_field{};
|
||||
Optional<int> const m_unionIdx{};
|
||||
Reader &m_reader;
|
||||
|
||||
public:
|
||||
explicit constexpr MetalClawReaderTemplate(
|
||||
Reader &reader,
|
||||
ox::Optional<int> const&unionIdx = {}) noexcept;
|
||||
Optional<int> const &unionIdx = {}) noexcept;
|
||||
|
||||
constexpr ~MetalClawReaderTemplate() noexcept;
|
||||
|
||||
constexpr Error field(const char*, int8_t *val) noexcept;
|
||||
constexpr Error field(const char*, int16_t *val) noexcept;
|
||||
constexpr Error field(const char*, int32_t *val) noexcept;
|
||||
constexpr Error field(const char*, int64_t *val) noexcept;
|
||||
constexpr Error field(CString, int8_t *val) noexcept;
|
||||
constexpr Error field(CString, int16_t *val) noexcept;
|
||||
constexpr Error field(CString, int32_t *val) noexcept;
|
||||
constexpr Error field(CString, int64_t *val) noexcept;
|
||||
|
||||
constexpr Error field(const char*, uint8_t *val) noexcept;
|
||||
constexpr Error field(const char*, uint16_t *val) noexcept;
|
||||
constexpr Error field(const char*, uint32_t *val) noexcept;
|
||||
constexpr Error field(const char*, uint64_t *val) noexcept;
|
||||
constexpr Error field(CString, uint8_t *val) noexcept;
|
||||
constexpr Error field(CString, uint16_t *val) noexcept;
|
||||
constexpr Error field(CString, uint32_t *val) noexcept;
|
||||
constexpr Error field(CString, uint64_t *val) noexcept;
|
||||
|
||||
constexpr Error field(const char*, bool *val) noexcept;
|
||||
constexpr Error field(CString, bool *val) noexcept;
|
||||
|
||||
// array handler
|
||||
constexpr Error field(const char*, auto *val, std::size_t len) noexcept;
|
||||
constexpr Error field(CString, auto *val, size_t valLen) noexcept;
|
||||
|
||||
// map handler
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
|
||||
constexpr Error field(CString, HashMap<String, T> *val) noexcept;
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename CB>
|
||||
constexpr Error field(const char*, CB cb) noexcept;
|
||||
constexpr Error field(CString, CB cb) noexcept;
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T *val) noexcept;
|
||||
constexpr Error field(CString, T *val) noexcept;
|
||||
|
||||
template<typename U, bool force>
|
||||
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
|
||||
constexpr Error field(CString, UnionView<U, force> val) noexcept;
|
||||
|
||||
template<std::size_t SmallStringSize>
|
||||
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
|
||||
template<size_t SmallStringSize>
|
||||
constexpr Error field(CString, BasicString<SmallStringSize> *val) noexcept;
|
||||
|
||||
template<std::size_t L>
|
||||
constexpr Error field(const char*, IString<L> *val) noexcept;
|
||||
template<size_t L>
|
||||
constexpr Error field(CString, IString<L> *val) noexcept;
|
||||
|
||||
constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept;
|
||||
constexpr Error fieldCString(CString, char *val, size_t buffLen) noexcept;
|
||||
|
||||
constexpr Error fieldCString(const char*, char **val) noexcept;
|
||||
constexpr Error fieldCString(CString, char **val) noexcept;
|
||||
|
||||
constexpr Error fieldCString(const char*, char **val, std::size_t buffLen) noexcept;
|
||||
constexpr Error fieldCString(CString, char **val, size_t buffLen) noexcept;
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
@@ -101,13 +101,13 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
||||
const char *name = T::TypeName,
|
||||
int version = T::TypeVersion,
|
||||
const Vector<String>& = {},
|
||||
std::size_t fields = ModelFieldCount_v<T>) noexcept;
|
||||
size_t fields = ModelFieldCount_v<T>) noexcept;
|
||||
|
||||
/**
|
||||
* Returns a MetalClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr MetalClawReaderTemplate<Reader> child(const char *name, ox::Optional<int> unionIdx = {}) noexcept;
|
||||
constexpr MetalClawReaderTemplate<Reader> child(const char *name, Optional<int> unionIdx = {}) noexcept;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the next field to be read is present.
|
||||
@@ -122,20 +122,20 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
|
||||
constexpr bool fieldPresent(int fieldNo) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr int whichFieldPresent(const char *name, const ModelUnion&) const noexcept;
|
||||
constexpr int whichFieldPresent(const char *name, ModelUnion const&) const noexcept;
|
||||
|
||||
constexpr void nextField() noexcept;
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
constexpr Error readInteger(I *val) noexcept;
|
||||
constexpr Error readInteger(I &val) noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
|
||||
Reader &reader,
|
||||
ox::Optional<int> const&unionIdx) noexcept:
|
||||
Optional<int> const &unionIdx) noexcept:
|
||||
m_fieldPresence(reader),
|
||||
m_unionIdx(unionIdx),
|
||||
m_reader(reader) {
|
||||
@@ -149,71 +149,72 @@ constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int8_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int16_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int32_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int64_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint8_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint16_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint32_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept {
|
||||
return readInteger(val);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint64_t *val) noexcept {
|
||||
return readInteger(*val);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, bool *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
auto const result = m_fieldPresence.get(static_cast<size_t>(m_field));
|
||||
*val = result.value;
|
||||
OX_RETURN_ERROR(result);
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
// array handler
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(
|
||||
const char *name, auto *val, size_t const valLen) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
|
||||
// read the list
|
||||
if (valLen >= len) {
|
||||
auto reader = child({});
|
||||
auto &handler = *reader.interface();
|
||||
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
OX_RETURN_ERROR(handler.field({}, &val[i]));
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
@@ -230,18 +231,18 @@ OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, HashMap<String, T> *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
OX_REQUIRE(g, m_reader.tellg());
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
|
||||
OX_RETURN_ERROR(m_reader.seekg(g));
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
auto &handler = *reader.interface();
|
||||
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
|
||||
// this loop body needs to be in a lambda because of the potential alloca call
|
||||
constexpr auto loopBody = [](auto &handler, auto &val) {
|
||||
OX_REQUIRE(keyLen, handler.stringLength(nullptr));
|
||||
@@ -250,22 +251,22 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<Stri
|
||||
OX_RETURN_ERROR(handler.fieldCString("", &wkeyPtr, keyLen + 1));
|
||||
return handler.field("", &val[wkeyPtr]);
|
||||
};
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
OX_RETURN_ERROR(loopBody(handler, *val));
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
|
||||
if constexpr(isVector_v<T>) {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
// set size of val if the field is present, don't worry about it if not
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
OX_REQUIRE(len, arrayLength(name, false));
|
||||
OX_RETURN_ERROR(ox::resizeVector(*val, len));
|
||||
return field(name, val->data(), val->size());
|
||||
@@ -275,9 +276,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
||||
++m_field;
|
||||
return {};
|
||||
} else if constexpr(isArray_v<T>) {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
// set size of val if the field is present, don't worry about it if not
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
OX_REQUIRE(len, arrayLength(name, false));
|
||||
if (len > val->size()) {
|
||||
return ox::Error(1, "Input array is too long");
|
||||
@@ -288,8 +289,8 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
||||
++m_field;
|
||||
return {};
|
||||
} else {
|
||||
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
auto reader = child("");
|
||||
OX_RETURN_ERROR(model(reader.interface(), val));
|
||||
}
|
||||
@@ -301,9 +302,9 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename U, bool force>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
|
||||
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, UnionView<U, force> val) noexcept {
|
||||
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val.get()) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
|
||||
OX_RETURN_ERROR(model(reader.interface(), val.get()));
|
||||
}
|
||||
@@ -313,13 +314,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U,
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<std::size_t SmallStringSize>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
template<size_t SmallStringSize>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, BasicString<SmallStringSize> *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
|
||||
const auto cap = size;
|
||||
*val = BasicString<SmallStringSize>(cap);
|
||||
auto data = val->data();
|
||||
@@ -330,17 +331,17 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<std::size_t L>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
template<size_t L>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, IString<L> *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
|
||||
*val = IString<L>();
|
||||
OX_RETURN_ERROR(val->resize(size));
|
||||
auto const data = val->data();
|
||||
@@ -355,11 +356,12 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(
|
||||
CString, char *val, size_t const buffLen) noexcept {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
|
||||
if (size > buffLen) {
|
||||
return ox::Error(McOutputBuffEnded);
|
||||
}
|
||||
@@ -370,15 +372,15 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
||||
data[size] = 0;
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val) noexcept {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val) noexcept {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
|
||||
// re-allocate in case too small
|
||||
safeDelete(*val);
|
||||
*val = new char[size + 1];
|
||||
@@ -388,16 +390,16 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
||||
data[size] = 0;
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val, size_t buffLen) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
|
||||
// re-allocate if too small
|
||||
if (buffLen < size + 1) {
|
||||
safeDelete(*val);
|
||||
@@ -416,17 +418,17 @@ constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(CString, bool const pass) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(g, m_reader.tellg());
|
||||
OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
|
||||
if (!pass) {
|
||||
OX_RETURN_ERROR(m_reader.seekg(g));
|
||||
}
|
||||
@@ -437,12 +439,12 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(CString) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<StringLength>(m_reader, &bytesRead);
|
||||
size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<StringLength>(m_reader, bytesRead);
|
||||
OX_RETURN_ERROR(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur));
|
||||
return len;
|
||||
}
|
||||
@@ -452,34 +454,34 @@ constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(con
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename I>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
std::size_t bytesRead = 0;
|
||||
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I &val) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
size_t bytesRead = 0;
|
||||
auto const result = mc::decodeInteger<I>(m_reader, bytesRead);
|
||||
OX_RETURN_ERROR(result);
|
||||
*val = result.value;
|
||||
val = result.value;
|
||||
} else {
|
||||
*val = 0;
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename T, typename CB>
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, CB cb) noexcept {
|
||||
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
|
||||
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
|
||||
size_t bytesRead = 0;
|
||||
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
auto &handler = *reader.interface();
|
||||
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
T val;
|
||||
OX_RETURN_ERROR(handler.field("", &val));
|
||||
OX_RETURN_ERROR(cb(i, &val));
|
||||
@@ -487,13 +489,13 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexc
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
template<typename T>
|
||||
constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
|
||||
const char*, int, const Vector<String>&, std::size_t fields) noexcept {
|
||||
CString, int, const Vector<String>&, size_t const fields) noexcept {
|
||||
m_fields = fields;
|
||||
// Warning: narrow-conv
|
||||
return m_reader.seekg(
|
||||
@@ -503,24 +505,24 @@ constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
|
||||
const char*,
|
||||
ox::Optional<int> unionIdx) noexcept {
|
||||
CString,
|
||||
Optional<int> const unionIdx) noexcept {
|
||||
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(const char*) const noexcept {
|
||||
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
|
||||
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(CString) const noexcept {
|
||||
return m_fieldPresence.get(static_cast<size_t>(m_field)).value;
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept {
|
||||
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
|
||||
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int const fieldNo) const noexcept {
|
||||
return m_fieldPresence.get(static_cast<size_t>(fieldNo)).value;
|
||||
}
|
||||
|
||||
template<Reader_c Reader>
|
||||
[[nodiscard]]
|
||||
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
|
||||
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(CString, ModelUnion const &u) const noexcept {
|
||||
FieldBitmapReader<Reader> p(m_reader);
|
||||
for (auto i = 0u; i < u.fieldCount(); ++i) {
|
||||
if (p.get(i)) {
|
||||
@@ -538,11 +540,10 @@ constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
|
||||
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
|
||||
|
||||
template<typename T>
|
||||
Error readMC(ox::BufferView buff, T &val) noexcept {
|
||||
Error readMC(ox::BufferView const buff, T &val) noexcept {
|
||||
BufferReader br(buff);
|
||||
MetalClawReader reader(br);
|
||||
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
|
||||
return model(&handler, &val);
|
||||
return model(reader.interface(), &val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright 2015 - 2025 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/model/fieldcounter.hpp>
|
||||
#include <ox/model/modelhandleradaptor.hpp>
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/buffer.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/optional.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/units.hpp>
|
||||
|
||||
#include "intops.hpp"
|
||||
#include "err.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<Writer_c Writer>
|
||||
class MetalClawWriter: public ModelHandlerBase<MetalClawWriter<Writer>, OpType::Write> {
|
||||
|
||||
private:
|
||||
Vector<char, 16> m_presenceMapBuff{};
|
||||
FieldBitmapWriter m_fieldPresence{m_presenceMapBuff};
|
||||
int m_field{};
|
||||
Optional<int> m_unionIdx;
|
||||
size_t m_writerBeginP{};
|
||||
Writer &m_writer;
|
||||
|
||||
public:
|
||||
constexpr explicit MetalClawWriter(Writer &writer, Optional<int> const &unionIdx = {}) noexcept;
|
||||
|
||||
constexpr ~MetalClawWriter() noexcept = default;
|
||||
|
||||
constexpr Error field(CString, int8_t const *val) noexcept;
|
||||
constexpr Error field(CString, int16_t const *val) noexcept;
|
||||
constexpr Error field(CString, int32_t const *val) noexcept;
|
||||
constexpr Error field(CString, int64_t const *val) noexcept;
|
||||
|
||||
constexpr Error field(CString, uint8_t const *val) noexcept;
|
||||
constexpr Error field(CString, uint16_t const *val) noexcept;
|
||||
constexpr Error field(CString, uint32_t const *val) noexcept;
|
||||
constexpr Error field(CString, uint64_t const *val) noexcept;
|
||||
|
||||
constexpr Error field(CString, bool const *val) noexcept;
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(CString, T const *val, size_t len) noexcept;
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(CString name, HashMap<String, T> const *val) noexcept;
|
||||
|
||||
template<size_t SmallStringSize>
|
||||
constexpr Error field(CString, BasicString<SmallStringSize> const *val) noexcept;
|
||||
|
||||
template<size_t L>
|
||||
constexpr Error field(CString, IString<L> const *val) noexcept;
|
||||
|
||||
constexpr Error fieldCString(CString name, CString const*val, size_t buffLen) noexcept;
|
||||
|
||||
constexpr Error fieldCString(CString name, CString *val) noexcept;
|
||||
|
||||
constexpr Error fieldCString(CString name, CString const*val) noexcept;
|
||||
|
||||
constexpr Error fieldCString(CString name, CString val, size_t strLen) noexcept;
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(CString, T const *val) noexcept;
|
||||
|
||||
template<typename U, bool force = false>
|
||||
constexpr Error field(CString, UnionView<U, force> val) noexcept;
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr Error setTypeInfo(
|
||||
CString name = T::TypeName,
|
||||
int version = T::TypeVersion,
|
||||
Vector<String> const& = {},
|
||||
size_t fields = ModelFieldCount_v<T>) noexcept;
|
||||
|
||||
/**
|
||||
* stringLength is not implemented in MetalClawWriter
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr auto stringLength(CString) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stringLength is not implemented in MetalClawWriter
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr auto arrayLength(CString, bool = true) noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr Error finalize() noexcept;
|
||||
|
||||
private:
|
||||
constexpr Error appendInteger(Integer_c auto val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
auto mi = mc::encodeInteger(val);
|
||||
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(mi.data.data()), mi.length));
|
||||
fieldSet = true;
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
|
||||
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, Optional<int> const &unionIdx) noexcept:
|
||||
m_unionIdx(unionIdx),
|
||||
m_writerBeginP(writer.tellp()),
|
||||
m_writer(writer) {
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, int8_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, int16_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, int32_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, int64_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, uint8_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, uint16_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, uint32_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, uint64_t const *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, bool const *val) noexcept {
|
||||
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), *val));
|
||||
}
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<size_t SmallStringSize>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, BasicString<SmallStringSize> const *val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val->size() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
auto const strLen = mc::encodeInteger(val->size());
|
||||
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLen.data.data()), strLen.length));
|
||||
// write the string
|
||||
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<size_t>(val->size())));
|
||||
fieldSet = true;
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<size_t L>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString name, IString<L> const *val) noexcept {
|
||||
return fieldCString(name, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const *val, size_t) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
// this strlen is tolerated because sometimes 0 gets passed to
|
||||
// the size param, which is a lie
|
||||
// this code should be cleaned up at some point...
|
||||
auto const strLen = *val ? ox::strlen(*val) : 0;
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
// write the length
|
||||
auto const strLenBuff = mc::encodeInteger(strLen);
|
||||
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
|
||||
// write the string
|
||||
OX_RETURN_ERROR(m_writer.write(*val, static_cast<size_t>(strLen)));
|
||||
fieldSet = true;
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString *val) noexcept {
|
||||
return fieldCString(name, val, {});
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString const *val) noexcept {
|
||||
return fieldCString(name, val, {});
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const val, size_t const strLen) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
auto const strLenBuff = mc::encodeInteger(strLen);
|
||||
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
|
||||
// write the string
|
||||
OX_RETURN_ERROR(m_writer.write(val, static_cast<size_t>(strLen)));
|
||||
fieldSet = true;
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val) noexcept {
|
||||
if constexpr(isVector_v<T> || isArray_v<T>) {
|
||||
return field(nullptr, val->data(), val->size());
|
||||
} else {
|
||||
bool fieldSet = false;
|
||||
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
auto const writeIdx = m_writer.tellp();
|
||||
MetalClawWriter writer(m_writer);
|
||||
OX_RETURN_ERROR(model(writer.interface(), val));
|
||||
OX_RETURN_ERROR(writer.finalize());
|
||||
fieldSet = writeIdx != m_writer.tellp();
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<typename U, bool force>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, UnionView<U, force> val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
auto const writeIdx = m_writer.tellp();
|
||||
MetalClawWriter writer(m_writer, Optional<int>(in_place, val.idx()));
|
||||
OX_RETURN_ERROR(model(writer.interface(), val.get()));
|
||||
OX_RETURN_ERROR(writer.finalize());
|
||||
fieldSet = writeIdx != m_writer.tellp();
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val, size_t const len) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
auto const arrLen = mc::encodeInteger(len);
|
||||
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
|
||||
auto const writeIdx = m_writer.tellp();
|
||||
MetalClawWriter writer(m_writer);
|
||||
OX_RETURN_ERROR(writer.interface()->template setTypeInfo<T>("List", 0, {}, static_cast<size_t>(len)));
|
||||
// write the array
|
||||
for (size_t i{}; i < len; ++i) {
|
||||
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||
OX_RETURN_ERROR(writer.interface()->field("", &val[i]));
|
||||
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||
}
|
||||
OX_RETURN_ERROR(writer.finalize());
|
||||
fieldSet = writeIdx != m_writer.tellp();
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawWriter<Writer>::field(CString, HashMap<String, T> const *val) noexcept {
|
||||
auto const &keys = val->keys();
|
||||
auto const len = keys.size();
|
||||
bool fieldSet = false;
|
||||
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
auto const arrLen = mc::encodeInteger(len);
|
||||
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
|
||||
// write map
|
||||
MetalClawWriter writer(m_writer);
|
||||
// double len for both key and value
|
||||
OX_RETURN_ERROR(writer.interface()->setTypeInfo("Map", 0, {}, len * 2));
|
||||
// this loop body needs to be in a lambda because of the potential alloca call
|
||||
constexpr auto loopBody = [](auto &handler, auto const &key, auto const &val) -> Error {
|
||||
auto const keyLen = key.size();
|
||||
auto wkey = ox_malloca(keyLen + 1, char, 0);
|
||||
memcpy(wkey.get(), key.c_str(), keyLen + 1);
|
||||
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));
|
||||
OX_REQUIRE_M(value, val.at(key));
|
||||
return handler.field("", value);
|
||||
};
|
||||
// write the array
|
||||
for (size_t i{}; i < len; ++i) {
|
||||
auto const &key = keys[i];
|
||||
OX_RETURN_ERROR(loopBody(*writer.interface(), key, *val));
|
||||
}
|
||||
OX_RETURN_ERROR(writer.finalize());
|
||||
fieldSet = true;
|
||||
}
|
||||
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
|
||||
++m_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
template<typename T>
|
||||
constexpr Error MetalClawWriter<Writer>::setTypeInfo(
|
||||
CString,
|
||||
int,
|
||||
Vector<String> const&,
|
||||
size_t const fields) noexcept {
|
||||
auto const fieldPresenceLen = (fields - 1) / 8 + 1;
|
||||
OX_RETURN_ERROR(m_writer.write(nullptr, fieldPresenceLen));
|
||||
m_presenceMapBuff.resize(fieldPresenceLen);
|
||||
m_fieldPresence.setBuffer(m_presenceMapBuff);
|
||||
return m_fieldPresence.setFields(static_cast<int>(fields));
|
||||
}
|
||||
|
||||
template<Writer_c Writer>
|
||||
constexpr Error MetalClawWriter<Writer>::finalize() noexcept {
|
||||
auto const end = m_writer.tellp();
|
||||
OX_RETURN_ERROR(m_writer.seekp(m_writerBeginP));
|
||||
OX_RETURN_ERROR(m_writer.write(
|
||||
m_presenceMapBuff.data(),
|
||||
m_presenceMapBuff.size()));
|
||||
OX_RETURN_ERROR(m_writer.seekp(end));
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<Buffer> writeMC(Writer_c auto &writer, auto const &val) noexcept {
|
||||
MetalClawWriter mcWriter(writer);
|
||||
OX_RETURN_ERROR(model(mcWriter.interface(), &val));
|
||||
OX_RETURN_ERROR(mcWriter.finalize());
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<Buffer> writeMC(auto const &val, size_t const buffReserveSz = 2 * units::KB) noexcept {
|
||||
Buffer buff(buffReserveSz);
|
||||
BufferWriter bw(&buff, 0);
|
||||
OX_RETURN_ERROR(writeMC(bw, val));
|
||||
buff.resize(bw.tellp());
|
||||
return buff;
|
||||
}
|
||||
|
||||
Error writeMC(char *buff, size_t const buffLen, auto const &val, size_t *sizeOut = nullptr) noexcept {
|
||||
CharBuffWriter bw{{buff, buffLen}};
|
||||
OX_RETURN_ERROR(writeMC(bw, val));
|
||||
if (sizeOut) {
|
||||
*sizeOut = bw.tellp();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <ox/std/buffer.hpp>
|
||||
#include <ox/std/reader.hpp>
|
||||
|
||||
#include "read.hpp"
|
||||
#include <ox/mc/read.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
|
||||
#include "write.hpp"
|
||||
#include <ox/mc/write.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
@@ -157,8 +157,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||
oxDebugf("{}", testOut.IString.len());
|
||||
oxExpect(testIn.IString, testOut.IString);
|
||||
ox::expect(testIn.IString, testOut.IString);
|
||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
add_library(
|
||||
OxModel
|
||||
src/desctypes.cpp
|
||||
src/descwrite.cpp
|
||||
src/modelvalue.cpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(OxModel PRIVATE -Wconversion)
|
||||
target_compile_options(OxModel PRIVATE -Wsign-conversion)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
OxModel PUBLIC
|
||||
OxStd
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
OxModel
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
OxModel PUBLIC
|
||||
OxStd
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
OxModel PUBLIC
|
||||
include
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS OxModel
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
@@ -13,7 +13,7 @@
|
||||
// oxModelFwdDecl is necessary because Apple-Clang is broken...
|
||||
#define OX_MODEL_FWD_DECL(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
|
||||
#define OX_MODEL_BEGIN(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { OX_RETURN_ERROR(io->template setTypeInfo<modelName>());
|
||||
#define OX_MODEL_END() return ox::Error(0); }
|
||||
#define OX_MODEL_END() return {}; }
|
||||
#define OX_MODEL_FIELD(fieldName) OX_RETURN_ERROR(io->field(#fieldName, &o->fieldName));
|
||||
#define OX_MODEL_FIELD_RENAME(objFieldName, serFieldName) OX_RETURN_ERROR(io->field(#serFieldName, &o->objFieldName));
|
||||
#define OX_MODEL_FRIEND(modelName) friend constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
|
||||
@@ -0,0 +1,7 @@
|
||||
<Type> : <TypeName><FieldList>
|
||||
<FieldList> : <FieldList> | <FieldList><Field>
|
||||
<Field> : <FieldType><TypeID><FieldName>
|
||||
<TypeID> : <TypeName> | <TypeName><Type>
|
||||
<TypeName> : <string>
|
||||
<FieldType> : <0: single> | <1: list>
|
||||
<FieldName> : <string>
|
||||
+2
-2
@@ -43,7 +43,7 @@ static constexpr auto buildTypeId(
|
||||
for (const auto &p : typeParams) {
|
||||
tp += p + ",";
|
||||
}
|
||||
tp.resize(tp.len() - 1);
|
||||
tp.resize(tp.size() - 1);
|
||||
tp += "#";
|
||||
}
|
||||
return ox::sfmt("{}{};{}", name, tp, version);
|
||||
@@ -244,7 +244,7 @@ constexpr Error model(TypeDescReader<T> *io, CommonPtrWith<DescriptorField> auto
|
||||
// defaultValue is unused now, but placeholder for backwards compatibility
|
||||
int defaultValue = 0;
|
||||
oxReturnError(io->field("defaultValue", &defaultValue));
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
+8
-8
@@ -51,7 +51,7 @@ constexpr auto buildSubscriptStack(const T**, SubscriptStack *s) noexcept {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr auto buildSubscriptStack(const UniquePtr<T>*, SubscriptStack *s) noexcept {
|
||||
constexpr auto buildSubscriptStack(const UPtr<T>*, SubscriptStack *s) noexcept {
|
||||
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
|
||||
PrimitiveType pt;
|
||||
if constexpr(is_union_v<T>) {
|
||||
pt = PrimitiveType::Union;
|
||||
} else if constexpr(isBasicString_v<T> || isBString_v<T>) {
|
||||
} else if constexpr(isBasicString_v<T> || isIString_v<T>) {
|
||||
pt = PrimitiveType::String;
|
||||
} else {
|
||||
pt = PrimitiveType::Struct;
|
||||
@@ -205,7 +205,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t,
|
||||
const auto t = type(p);
|
||||
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
|
||||
m_type->fieldList.emplace_back(t, String(name), detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t));
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
return ox::Error(1);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t)
|
||||
auto const lvls = detail::indirectionLevels_v<T> + 1;
|
||||
SubscriptStack subscriptStack{lvls};
|
||||
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
return ox::Error(1);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val
|
||||
const auto t = type(val);
|
||||
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
|
||||
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
return ox::Error(1);
|
||||
}
|
||||
@@ -357,7 +357,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
|
||||
template<std::size_t sz>
|
||||
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(types::BString, 0, PT, 0);
|
||||
return getType(types::IString, 0, PT, 0);
|
||||
}
|
||||
|
||||
constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typeVersion, PrimitiveType pt, int b,
|
||||
@@ -380,7 +380,7 @@ constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typ
|
||||
template<typename T>
|
||||
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
|
||||
TypeDescWriter writer(&typeStore);
|
||||
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
|
||||
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
|
||||
if (std::is_constant_evaluated()) {
|
||||
std::allocator<T> a;
|
||||
T *t = a.allocate(1);
|
||||
@@ -396,7 +396,7 @@ constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
|
||||
template<typename T>
|
||||
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept {
|
||||
TypeDescWriter writer(&typeStore);
|
||||
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
|
||||
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer);
|
||||
OX_RETURN_ERROR(model(&handler, &val));
|
||||
return writer.definition();
|
||||
}
|
||||
Vendored
+4
-4
@@ -31,25 +31,25 @@ class FieldCounter {
|
||||
template<typename U>
|
||||
constexpr ox::Error field(StringViewCR, U) noexcept {
|
||||
++fields;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
constexpr ox::Error field(StringViewCR, U, std::size_t) noexcept {
|
||||
++fields;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U, typename Handler>
|
||||
constexpr Error field(StringViewCR, Handler) {
|
||||
++fields;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
constexpr Error fieldCString(Args&&...) noexcept {
|
||||
++fields;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
static constexpr auto opType() noexcept {
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2015 - 2025 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/utility.hpp>
|
||||
|
||||
#include "modelvalue.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename Handler, OpType opType_v = Handler::opType()>
|
||||
class ModelHandlerInterface {
|
||||
private:
|
||||
Handler &m_handler;
|
||||
|
||||
public:
|
||||
constexpr explicit ModelHandlerInterface(Handler &handler) noexcept: m_handler(handler) {
|
||||
}
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr ox::Error setTypeInfo(
|
||||
CString name = T::TypeName,
|
||||
int version = T::TypeVersion,
|
||||
Vector<String> const &typeParams = {}) noexcept {
|
||||
return m_handler.template setTypeInfo<T>(name, version, typeParams, ModelFieldCount_v<T>);
|
||||
}
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr ox::Error setTypeInfo(
|
||||
CString name,
|
||||
int version,
|
||||
Vector<String> const &typeParams,
|
||||
size_t fields) noexcept {
|
||||
return m_handler.template setTypeInfo<T>(name, version, typeParams, fields);
|
||||
}
|
||||
|
||||
template<size_t len>
|
||||
constexpr Error fieldCString(CString name, char val[len]) noexcept {
|
||||
return m_handler.fieldCString(name, &val[0], len);
|
||||
}
|
||||
|
||||
template<size_t len>
|
||||
constexpr Error fieldCString(CString name, char const val[len]) noexcept requires(opType_v != OpType::Read) {
|
||||
if constexpr(opType_v != OpType::Read) {
|
||||
return m_handler.fieldCString(name, &val[0], len);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Error fieldCString(CString name, char **val) noexcept {
|
||||
return m_handler.fieldCString(name, val);
|
||||
}
|
||||
|
||||
constexpr Error fieldCString(CString name, char const *const*val) noexcept requires(opType_v != OpType::Read) {
|
||||
// this check looks pointless, but it's to address a Clang bug
|
||||
if constexpr(opType_v != OpType::Read) {
|
||||
return m_handler.fieldCString(name, val);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Error fieldCString(CString name, char const **val) noexcept requires(opType_v != OpType::Read) {
|
||||
// this check looks pointless, but it's to address a Clang bug
|
||||
if constexpr(opType_v != OpType::Read) {
|
||||
return m_handler.fieldCString(name, val);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Error fieldCString(CString name, char **val, size_t buffLen) noexcept {
|
||||
return m_handler.fieldCString(name, val, buffLen);
|
||||
}
|
||||
|
||||
constexpr Error fieldCString(CString name, char const **val, size_t buffLen) noexcept requires(opType_v != OpType::Read) {
|
||||
// this check looks pointless, but it's to address a Clang bug
|
||||
if constexpr(opType_v != OpType::Read) {
|
||||
return m_handler.fieldCString(name, val, buffLen);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
constexpr Error fieldCString(CString name, char *val, size_t buffLen) noexcept {
|
||||
return m_handler.fieldCString(name, val, buffLen);
|
||||
}
|
||||
|
||||
constexpr Error fieldModelValue(char const *name, CommonPtrWith<ModelValue> auto *v) noexcept {
|
||||
switch (v->type()) {
|
||||
case ModelValue::Type::Undefined:
|
||||
break;
|
||||
case ModelValue::Type::Bool:
|
||||
return m_handler.field(name, &v->template get<bool>());
|
||||
case ModelValue::Type::UnsignedInteger8:
|
||||
return m_handler.field(name, &v->template get<uint8_t>());
|
||||
case ModelValue::Type::UnsignedInteger16:
|
||||
return m_handler.field(name, &v->template get<uint16_t>());
|
||||
case ModelValue::Type::UnsignedInteger32:
|
||||
return m_handler.field(name, &v->template get<uint32_t>());
|
||||
case ModelValue::Type::UnsignedInteger64:
|
||||
return m_handler.field(name, &v->template get<uint64_t>());
|
||||
case ModelValue::Type::SignedInteger8:
|
||||
return m_handler.field(name, &v->template get<int8_t>());
|
||||
case ModelValue::Type::SignedInteger16:
|
||||
return m_handler.field(name, &v->template get<int16_t>());
|
||||
case ModelValue::Type::SignedInteger32:
|
||||
return m_handler.field(name, &v->template get<int32_t>());
|
||||
case ModelValue::Type::SignedInteger64:
|
||||
return m_handler.field(name, &v->template get<int64_t>());
|
||||
case ModelValue::Type::String:
|
||||
return m_handler.field(name, &v->template get<String>());
|
||||
case ModelValue::Type::Object:
|
||||
return m_handler.field(name, &v->template get<ModelObject>());
|
||||
case ModelValue::Type::Union:
|
||||
{
|
||||
auto &u = v->template get<ModelUnion>();
|
||||
if constexpr(opType_v == OpType::Read) {
|
||||
u.setActiveField(whichFieldPresent(m_handler, name, u));
|
||||
return m_handler.field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
|
||||
} else {
|
||||
return m_handler.field(name, UnionView<ModelUnion const, true>(&u, u.unionIdx()));
|
||||
}
|
||||
}
|
||||
case ModelValue::Type::Vector:
|
||||
return m_handler.field(name, &v->template get<ModelValueVector>());
|
||||
case ModelValue::Type::InlineArray:
|
||||
return m_handler.field(name, &v->template get<ModelValueArray>());
|
||||
}
|
||||
oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type()));
|
||||
ox::panic("invalid type");
|
||||
return ox::Error(1, "invalid type");
|
||||
}
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename Callback>
|
||||
constexpr Error field(CString name, Callback cb) noexcept {
|
||||
return m_handler.template field<T, Callback>(name, cb);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(CString name, const T *v) noexcept {
|
||||
if constexpr(ox::is_same_v<T, ModelValue>) {
|
||||
return fieldModelValue(name, v);
|
||||
} else {
|
||||
return m_handler.field(name, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(CString name, T *v) noexcept {
|
||||
if constexpr(ox::is_same_v<T, ModelValue>) {
|
||||
return fieldModelValue(name, v);
|
||||
} else {
|
||||
return m_handler.field(name, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename U, bool force = false>
|
||||
constexpr Error field(CString name, UnionView<U, force> val) noexcept {
|
||||
return m_handler.field(name, val);
|
||||
}
|
||||
|
||||
constexpr Error field(CString name, auto *val, size_t len) noexcept {
|
||||
return m_handler.field(name, val, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
* @param name
|
||||
* @param pass indicates that the parsing should iterate past the array length
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr auto arrayLength(CString name, bool pass = true) noexcept {
|
||||
return m_handler.arrayLength(name, pass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
constexpr auto stringLength(CString name) noexcept {
|
||||
return m_handler.stringLength(name);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static constexpr auto opType() noexcept {
|
||||
return Handler::opType();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr auto handler() noexcept {
|
||||
return m_handler;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename H>
|
||||
static constexpr int whichFieldPresent(H &h, CString name, ModelUnion const &u) noexcept
|
||||
requires(H::opType() == OpType::Read) {
|
||||
return h.whichFieldPresent(name, u);
|
||||
}
|
||||
|
||||
template<typename H>
|
||||
static constexpr int whichFieldPresent(H&, CString, ModelUnion const&) noexcept
|
||||
requires(H::opType() != OpType::Read) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename Handler, OpType opType_v = Handler::opType()>
|
||||
class ModelHandlerBase {
|
||||
private:
|
||||
ModelHandlerInterface<Handler, opType_v> m_interface{*static_cast<Handler*>(this)};
|
||||
public:
|
||||
[[nodiscard]]
|
||||
constexpr auto interface() noexcept {
|
||||
return &m_interface;
|
||||
}
|
||||
[[nodiscard]]
|
||||
static constexpr OpType opType() noexcept {
|
||||
return opType_v;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
constexpr ox::Error resizeVector(auto &vec, size_t sz) {
|
||||
if constexpr(ox::is_same_v<decltype(vec.resize(0)), ox::Error>) {
|
||||
return vec.resize(sz);
|
||||
} else {
|
||||
vec.resize(sz);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+12
-12
@@ -56,19 +56,19 @@ class MemberList {
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T *v) noexcept {
|
||||
vars[m_i++] = static_cast<void*>(v);
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T *v, int) noexcept {
|
||||
vars[m_i++] = static_cast<void*>(v);
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U, bool force = false>
|
||||
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
|
||||
vars[m_i++] = static_cast<void*>(u.get());
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -107,7 +107,7 @@ class Copier {
|
||||
auto &dst = *cbit_cast<FT*>(m_dst->vars[m_i]);
|
||||
dst = src;
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ class Copier {
|
||||
dst = src;
|
||||
}
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U, bool force = false>
|
||||
@@ -128,7 +128,7 @@ class Copier {
|
||||
auto &src = *u.get();
|
||||
dst = src;
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T = void>
|
||||
@@ -168,7 +168,7 @@ class Mover {
|
||||
dst = std::move(src);
|
||||
src = FT{};
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ class Mover {
|
||||
src = FT{};
|
||||
}
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U, bool force = false>
|
||||
@@ -190,7 +190,7 @@ class Mover {
|
||||
auto &src = *u.get();
|
||||
dst = std::move(src);
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T = void>
|
||||
@@ -228,7 +228,7 @@ class Equals {
|
||||
const auto &dst = std::bit_cast<FT>(*m_other->vars[m_i]);
|
||||
++m_i;
|
||||
if (dst == src) {
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
this->value = false;
|
||||
return ox::Error(1);
|
||||
@@ -246,7 +246,7 @@ class Equals {
|
||||
}
|
||||
}
|
||||
++m_i;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U, bool force = false>
|
||||
@@ -255,7 +255,7 @@ class Equals {
|
||||
const auto &src = *u.get();
|
||||
++m_i;
|
||||
if (dst == src) {
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
} else {
|
||||
this->value = false;
|
||||
return ox::Error(1);
|
||||
+20
-26
@@ -100,7 +100,7 @@ class ModelValue {
|
||||
return Type::Union;
|
||||
} else if constexpr(is_same_v<U, ModelObject>) {
|
||||
return Type::Object;
|
||||
} else if constexpr(isBasicString_v<U> || isBString_v<U>) {
|
||||
} else if constexpr(isBasicString_v<U> || isIString_v<U>) {
|
||||
return Type::String;
|
||||
} else if constexpr(is_same_v<U, ModelValueVector>) {
|
||||
return Type::Vector;
|
||||
@@ -168,7 +168,7 @@ class ModelValue {
|
||||
constexpr const auto &get() const noexcept {
|
||||
constexpr auto type = getType<T>();
|
||||
if (m_type != type) [[unlikely]] {
|
||||
oxPanic(ox::Error(1), "invalid cast");
|
||||
ox::panic("invalid cast");
|
||||
}
|
||||
return getValue<type>(*this);
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class ModelValue {
|
||||
constexpr auto &get() noexcept {
|
||||
constexpr auto type = getType<T>();
|
||||
if (m_type != type) [[unlikely]] {
|
||||
oxPanic(ox::Error(1), "invalid cast");
|
||||
ox::panic("invalid cast");
|
||||
}
|
||||
return getValue<type>(*this);
|
||||
}
|
||||
@@ -187,7 +187,7 @@ class ModelValue {
|
||||
constexpr Type type() const noexcept;
|
||||
|
||||
constexpr Error setType(
|
||||
DescriptorType const*type,
|
||||
DescriptorType const *type,
|
||||
SubscriptStack const& = {},
|
||||
int subscriptLevels = 0) noexcept;
|
||||
|
||||
@@ -200,8 +200,6 @@ class ModelValue {
|
||||
template<typename T>
|
||||
constexpr Error set(T &&v) noexcept;
|
||||
|
||||
constexpr ModelValue &operator=(ModelValue &val) noexcept;
|
||||
|
||||
constexpr ModelValue &operator=(const ModelValue &val) noexcept;
|
||||
|
||||
constexpr ModelValue &operator=(ModelValue &&val) noexcept;
|
||||
@@ -275,7 +273,7 @@ class ModelValueArray {
|
||||
}
|
||||
|
||||
constexpr Error setType(
|
||||
DescriptorType const*type,
|
||||
DescriptorType const *type,
|
||||
SubscriptStack subscriptStack,
|
||||
int subscriptLevels) noexcept {
|
||||
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
|
||||
@@ -418,7 +416,7 @@ class ModelValueVector {
|
||||
}
|
||||
|
||||
constexpr Error setType(
|
||||
DescriptorType const*type,
|
||||
DescriptorType const *type,
|
||||
SubscriptStack subscriptStack,
|
||||
int subscriptLevels) noexcept {
|
||||
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
|
||||
@@ -521,7 +519,7 @@ class ModelObject {
|
||||
protected:
|
||||
OX_MODEL_FRIEND(ModelObject);
|
||||
friend ModelValue;
|
||||
Vector<UniquePtr<Field>> m_fieldsOrder;
|
||||
Vector<UPtr<Field>> m_fieldsOrder;
|
||||
HashMap<String, ModelValue*> m_fields;
|
||||
const DescriptorType *m_type = nullptr;
|
||||
|
||||
@@ -694,7 +692,7 @@ class ModelUnion {
|
||||
};
|
||||
friend constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept;
|
||||
friend ModelValue;
|
||||
Vector<UniquePtr<Field>> m_fieldsOrder;
|
||||
Vector<UPtr<Field>> m_fieldsOrder;
|
||||
HashMap<String, Field*> m_fields;
|
||||
const DescriptorType *m_type = nullptr;
|
||||
int m_unionIdx = -1;
|
||||
@@ -720,14 +718,14 @@ class ModelUnion {
|
||||
m_unionIdx = other.m_unionIdx;
|
||||
}
|
||||
|
||||
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept {
|
||||
UniquePtr<ModelUnion> out(new ModelUnion);
|
||||
static constexpr Result<UPtr<ModelUnion>> make(const DescriptorType *type) noexcept {
|
||||
UPtr<ModelUnion> out(new ModelUnion);
|
||||
OX_RETURN_ERROR(out->setType(type));
|
||||
return out;
|
||||
}
|
||||
|
||||
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept {
|
||||
return UniquePtr<ModelUnion>(new ModelUnion(other));
|
||||
static constexpr Result<UPtr<ModelUnion>> make(const ModelUnion &other) noexcept {
|
||||
return UPtr<ModelUnion>(new ModelUnion(other));
|
||||
}
|
||||
|
||||
constexpr ox::Result<ModelValue*> at(StringView const&k) noexcept {
|
||||
@@ -821,7 +819,7 @@ class ModelUnion {
|
||||
|
||||
template<typename PlatSpec>
|
||||
[[nodiscard]]
|
||||
constexpr std::size_t sizeOf(ModelValueArray const*v) noexcept {
|
||||
constexpr std::size_t sizeOf(ModelValueArray const *v) noexcept {
|
||||
return sizeOf<PlatSpec>(&(*v)[0]) * v->size();
|
||||
}
|
||||
|
||||
@@ -972,7 +970,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
|
||||
for (auto &f : obj->m_fieldsOrder) {
|
||||
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
|
||||
@@ -981,7 +979,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
|
||||
for (auto &f : obj->m_fieldsOrder) {
|
||||
OX_RETURN_ERROR(h->field(f->name.c_str(), &f->value));
|
||||
}
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
|
||||
@@ -1098,7 +1096,7 @@ constexpr Error ModelValue::setType(
|
||||
} else if (type->typeName == types::Bool) {
|
||||
m_type = Type::Bool;
|
||||
} else if (type->typeName == types::BasicString ||
|
||||
type->typeName == types::BString ||
|
||||
type->typeName == types::IString ||
|
||||
type->typeName == types::String) {
|
||||
m_type = Type::String;
|
||||
m_data.str = new String;
|
||||
@@ -1129,7 +1127,7 @@ constexpr Error ModelValue::setType(
|
||||
OX_RETURN_ERROR(m_data.uni->setType(type));
|
||||
}
|
||||
oxAssert(m_type != Type::Undefined, "No type set");
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -1176,7 +1174,7 @@ template<typename T>
|
||||
constexpr Error ModelValue::set(const T &v) noexcept {
|
||||
constexpr auto type = getType<T>();
|
||||
if (m_type != type) [[unlikely]] {
|
||||
return ox::Error(1, "type mismatch");
|
||||
return Error(1, "type mismatch");
|
||||
}
|
||||
auto &value = getValue<type>(*this);
|
||||
if constexpr(type == Type::Vector || type == Type::Object ||
|
||||
@@ -1184,7 +1182,7 @@ constexpr Error ModelValue::set(const T &v) noexcept {
|
||||
safeDelete(&value);
|
||||
}
|
||||
value = v;
|
||||
return ox::Error(0);
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -1199,11 +1197,7 @@ constexpr Error ModelValue::set(T &&v) noexcept {
|
||||
safeDelete(&value);
|
||||
}
|
||||
value = std::move(v);
|
||||
return ox::Error(0);
|
||||
}
|
||||
|
||||
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
|
||||
return this->operator=(const_cast<const ModelValue&>(other));
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
|
||||
Vendored
+20
-62
@@ -17,77 +17,35 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
struct TypeNameCatcher {
|
||||
|
||||
const char *name = "";
|
||||
int version = 0;
|
||||
|
||||
constexpr TypeNameCatcher() noexcept = default;
|
||||
|
||||
template<typename T>
|
||||
constexpr ox::Error setTypeInfo(
|
||||
const char *n = T::TypeName,
|
||||
int v = T::TypeVersion,
|
||||
const Vector<String>& = {},
|
||||
std::size_t = ModelFieldCount_v<T>) noexcept {
|
||||
this->name = n;
|
||||
this->version = v;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T*, std::size_t) noexcept {
|
||||
return ox::Error(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T) noexcept {
|
||||
return ox::Error(0);
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
constexpr Error fieldCString(Args&&...) noexcept {
|
||||
return ox::Error(0);
|
||||
}
|
||||
|
||||
static constexpr auto opType() noexcept {
|
||||
return OpType::Reflect;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct TypeInfoCatcher {
|
||||
|
||||
const char *name = "";
|
||||
CString name = "";
|
||||
int version = 0;
|
||||
|
||||
constexpr TypeInfoCatcher() noexcept = default;
|
||||
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr ox::Error setTypeInfo(
|
||||
const char *n = T::TypeName,
|
||||
int v = T::TypeVersion,
|
||||
const Vector<String>& = {},
|
||||
std::size_t = 0) noexcept {
|
||||
constexpr Error setTypeInfo(
|
||||
CString const n = T::TypeName,
|
||||
int const v = T::TypeVersion,
|
||||
Vector<String> const& = {},
|
||||
size_t = 0) noexcept {
|
||||
this->name = n;
|
||||
this->version = v;
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T*, std::size_t) noexcept {
|
||||
return ox::Error(0);
|
||||
constexpr Error field(CString, T*, size_t) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error field(const char*, T) noexcept {
|
||||
return ox::Error(0);
|
||||
constexpr Error field(CString, T const&) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr Error fieldCString(const char*, T) noexcept {
|
||||
return ox::Error(0);
|
||||
constexpr Error fieldCString(CString, T const&) noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
static constexpr auto opType() noexcept {
|
||||
@@ -125,14 +83,14 @@ consteval int requireModelTypeVersion() noexcept {
|
||||
template<typename T, typename Str = const char*>
|
||||
[[nodiscard]]
|
||||
constexpr Str getModelTypeName(T *val) noexcept {
|
||||
TypeNameCatcher nc;
|
||||
TypeInfoCatcher nc;
|
||||
std::ignore = model(&nc, val);
|
||||
return nc.name;
|
||||
}
|
||||
|
||||
template<typename T, typename Str = const char*>
|
||||
[[nodiscard]]
|
||||
constexpr Str getModelTypeName() noexcept {
|
||||
consteval Str getModelTypeName() noexcept {
|
||||
std::allocator<T> a;
|
||||
auto t = a.allocate(1);
|
||||
auto out = getModelTypeName(t);
|
||||
@@ -140,15 +98,15 @@ constexpr Str getModelTypeName() noexcept {
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T, typename Str = const char*>
|
||||
template<typename T, typename Str = StringLiteral>
|
||||
[[nodiscard]]
|
||||
consteval auto requireModelTypeName() noexcept {
|
||||
constexpr auto name = getModelTypeName<T, Str>();
|
||||
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
|
||||
static_assert(StringView{name}.size(), "Type lacks required TypeName");
|
||||
return name;
|
||||
}
|
||||
|
||||
template<typename T, typename Str = const char*>
|
||||
template<typename T, typename Str = StringLiteral>
|
||||
constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
|
||||
|
||||
template<typename T, typename Str = const char*>
|
||||
@@ -156,10 +114,10 @@ constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
|
||||
|
||||
template<typename T>
|
||||
constexpr auto ModelTypeId_v = [] {
|
||||
constexpr auto name = ModelTypeName_v<T, ox::StringView>;
|
||||
constexpr auto name = ModelTypeName_v<T, StringView>;
|
||||
constexpr auto version = ModelTypeVersion_v<T>;
|
||||
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version);
|
||||
return ox::sfmt<ox::IString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr);
|
||||
constexpr auto versionStr = ox::sfmt<IString<19>>("{}", version);
|
||||
return ox::sfmt<IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
|
||||
}();
|
||||
|
||||
}
|
||||
+18
-18
@@ -31,18 +31,18 @@
|
||||
namespace ox {
|
||||
|
||||
namespace types {
|
||||
constexpr StringView BasicString = "net.drinkingtea.ox.BasicString";
|
||||
constexpr StringView BString = "net.drinkingtea.ox.BString";
|
||||
constexpr StringView String = "B.string";
|
||||
constexpr StringView Bool = "B.bool";
|
||||
constexpr StringView Uint8 = "B.uint8";
|
||||
constexpr StringView Uint16 = "B.uint16";
|
||||
constexpr StringView Uint32 = "B.uint32";
|
||||
constexpr StringView Uint64 = "B.uint64";
|
||||
constexpr StringView Int8 = "B.int8";
|
||||
constexpr StringView Int16 = "B.int16";
|
||||
constexpr StringView Int32 = "B.int32";
|
||||
constexpr StringView Int64 = "B.int64";
|
||||
constexpr StringLiteral BasicString = "net.drinkingtea.ox.BasicString";
|
||||
constexpr StringLiteral IString = "net.drinkingtea.ox.IString";
|
||||
constexpr StringLiteral String = "B.string";
|
||||
constexpr StringLiteral Bool = "B.bool";
|
||||
constexpr StringLiteral Uint8 = "B.uint8";
|
||||
constexpr StringLiteral Uint16 = "B.uint16";
|
||||
constexpr StringLiteral Uint32 = "B.uint32";
|
||||
constexpr StringLiteral Uint64 = "B.uint64";
|
||||
constexpr StringLiteral Int8 = "B.int8";
|
||||
constexpr StringLiteral Int16 = "B.int16";
|
||||
constexpr StringLiteral Int32 = "B.int32";
|
||||
constexpr StringLiteral Int64 = "B.int64";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -63,17 +63,17 @@ static_assert(isBasicString_v<ox::BasicString<8ul>>);
|
||||
static_assert(isBasicString_v<ox::String>);
|
||||
|
||||
template<typename T>
|
||||
consteval bool isBString(const T*) noexcept {
|
||||
consteval bool isIString(const T*) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<std::size_t SmallVecSize>
|
||||
consteval bool isBString(const BasicString<SmallVecSize>*) noexcept {
|
||||
consteval bool isIString(const BasicString<SmallVecSize>*) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool isBString_v = isBasicString(static_cast<const T*>(nullptr));
|
||||
constexpr bool isIString_v = isIString(static_cast<const T*>(nullptr));
|
||||
|
||||
static_assert(isBasicString_v<ox::BasicString<0ul>>);
|
||||
static_assert(isBasicString_v<ox::BasicString<8ul>>);
|
||||
@@ -161,7 +161,7 @@ template<typename T>
|
||||
constexpr bool isSmartPtr_v = false;
|
||||
|
||||
template<typename T>
|
||||
constexpr bool isSmartPtr_v<::ox::UniquePtr<T>> = true;
|
||||
constexpr bool isSmartPtr_v<::ox::UPtr<T>> = true;
|
||||
|
||||
#if __has_include(<array>)
|
||||
template<typename T>
|
||||
@@ -169,12 +169,12 @@ constexpr bool isSmartPtr_v<::std::unique_ptr<T>> = true;
|
||||
#endif
|
||||
|
||||
|
||||
template<typename Union, bool force = false>
|
||||
template<typename Union, bool force = false> requires(force || is_union_v<Union>)
|
||||
class UnionView {
|
||||
|
||||
protected:
|
||||
int m_idx = -1;
|
||||
typename enable_if<is_union_v<Union> || force, Union>::type *m_union = nullptr;
|
||||
Union *m_union = nullptr;
|
||||
|
||||
public:
|
||||
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user