Compare commits

..

5 Commits

Author SHA1 Message Date
1057099fcf [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m17s
2025-06-22 01:01:46 -05:00
17577b6e8b [nostalgia/gfx/studio/tilesheet] Disable paste when nothing is selected 2025-06-22 01:01:44 -05:00
db442e2775 [nostalgia/gfx] Address a couple of implicit conversions
All checks were successful
Build / build (push) Successful in 1m20s
2025-06-21 14:21:23 -05:00
23cd50d29e [studio] Fix Studio to clear editor pointers when opening a new project 2025-06-21 14:21:12 -05:00
28088d1ed1 [nostalgia/studio] Set version to d2025.06.0
All checks were successful
Build / build (push) Successful in 1m16s
2025-06-21 08:55:52 -05:00
187 changed files with 1849 additions and 2761 deletions

View File

@@ -14,7 +14,7 @@ endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP} PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build-pack build-gba-player pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac .PHONY: pkg-mac
@@ -26,44 +26,25 @@ 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/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/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 .PHONY: build-player
build-player: build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP} ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run .PHONY: run
run: build-player run: build-player
${PROJECT_PLAYER} sample_project ${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 .PHONY: run-studio
run-studio: build-studio run-studio: build
${PROJECT_STUDIO} ${PROJECT_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba ${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug .PHONY: debug
debug: build debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project ${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
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} ${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}

View File

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

View File

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

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

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

View File

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

View File

@@ -106,14 +106,15 @@ Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
{ {
ox::BufferReader br({header.data, header.dataSize}); ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br); MetalClawReader reader(br);
OX_RETURN_ERROR(model(reader.interface(), &obj)); ModelHandlerInterface handler(&reader);
OX_RETURN_ERROR(model(&handler, &obj));
return obj; return obj;
} }
case ClawFormat::Organic: case ClawFormat::Organic:
{ {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
OrganicClawReader reader({header.data, header.dataSize}); OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(reader); ModelHandlerInterface handler(&reader);
OX_RETURN_ERROR(model(&handler, &obj)); OX_RETURN_ERROR(model(&handler, &obj));
return obj; return obj;
#else #else

View File

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

View File

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

View File

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

View File

@@ -87,7 +87,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile); return writeFilePath(path, buffer, size, FileType::NormalFile);
} }
Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept { Error write(StringViewCR path, ox::Span<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile); return write(path, buff.data(), buff.size(), FileType::NormalFile);
} }
@@ -95,7 +95,7 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile); return write(inode, buffer, size, FileType::NormalFile);
} }
Error write(uint64_t inode, ox::SpanView<char> const&buff) noexcept { Error write(uint64_t inode, ox::Span<char> const&buff) noexcept {
return write(inode, buff.data(), buff.size(), FileType::NormalFile); return write(inode, buff.data(), buff.size(), FileType::NormalFile);
} }

View File

@@ -206,7 +206,7 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
} }
std::string_view PassThroughFS::stripSlash(StringView path) noexcept { std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
for (auto i = 0u; i < path.size() && path[0] == '/'; i++) { for (auto i = 0u; i < path.len() && path[0] == '/'; i++) {
path = substr(path, 1); path = substr(path, 1);
} }
return {path.data(), path.bytes()}; return {path.data(), path.bytes()};

View File

@@ -74,7 +74,7 @@ Error PathIterator::get(StringView &fileName) {
if (size && fileName[size - 1] == '/') { if (size && fileName[size - 1] == '/') {
fileName = ox::substr(m_path, start, start + size - 1); fileName = ox::substr(m_path, start, start + size - 1);
} }
oxAssert(fileName[fileName.size()-1] != '/', "name ends in /"); oxAssert(fileName[fileName.len()-1] != '/', "name ends in /");
return {}; return {};
} }
@@ -104,11 +104,11 @@ Error PathIterator::next(StringView &fileName) {
} }
fileName = ox::substr(m_path, start, start + size); fileName = ox::substr(m_path, start, start + size);
// truncate trailing / // truncate trailing /
while (fileName.size() && fileName[fileName.size() - 1] == '/') { while (fileName.len() && fileName[fileName.len() - 1] == '/') {
fileName = ox::substr(m_path, start, start + size); fileName = ox::substr(m_path, start, start + size);
} }
m_iterator += size; m_iterator += size;
oxAssert(fileName.size() == 0 || fileName[fileName.size()-1] != '/', "name ends in /"); oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /");
} }
return retval; return retval;
} }

View File

@@ -59,7 +59,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next1", "PathIterator::next1",
[](ox::StringView) { [](ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.size()); ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -74,9 +74,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
ox::PathIterator it(path); ox::PathIterator it(path);
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error"); oxAssert(it.next(buff), "PathIterator::next returned error");
ox::expect(buff, "usr"); oxExpect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error"); oxAssert(it.next(buff), "PathIterator::next returned error");
ox::expect(buff, "share"); oxExpect(buff, "share");
return ox::Error(0); return ox::Error(0);
} }
}, },
@@ -84,7 +84,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next3", "PathIterator::next3",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("/"); auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.size()); ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return ox::Error(0); return ox::Error(0);
@@ -106,7 +106,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next5", "PathIterator::next5",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("usr/share/"); auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.size()); ox::PathIterator it(path.c_str(), path.len());
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -117,10 +117,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::dirPath", "PathIterator::dirPath",
[] (ox::StringView) { [] (ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.size()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.size() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxAssert(it.dirPath(buff, path.size()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path"); oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
return ox::Error(0); return ox::Error(0);
} }

View File

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

View File

@@ -11,7 +11,7 @@
namespace ox { namespace ox {
template class FieldBitmapWriterBase<uint8_t>; template class FieldBitmapWriterBase<uint8_t*>;
template class FieldBitmapWriterBase<uint8_t const>; template class FieldBitmapWriterBase<const uint8_t*>;
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ static constexpr auto buildTypeId(
for (const auto &p : typeParams) { for (const auto &p : typeParams) {
tp += p + ","; tp += p + ",";
} }
tp.resize(tp.size() - 1); tp.resize(tp.len() - 1);
tp += "#"; tp += "#";
} }
return ox::sfmt("{}{};{}", name, tp, version); return ox::sfmt("{}{};{}", name, tp, version);

View File

@@ -187,7 +187,7 @@ constexpr ox::Error TypeDescWriter::setTypeInfo(
PrimitiveType pt; PrimitiveType pt;
if constexpr(is_union_v<T>) { if constexpr(is_union_v<T>) {
pt = PrimitiveType::Union; pt = PrimitiveType::Union;
} else if constexpr(isBasicString_v<T> || isIString_v<T>) { } else if constexpr(isBasicString_v<T> || isBString_v<T>) {
pt = PrimitiveType::String; pt = PrimitiveType::String;
} else { } else {
pt = PrimitiveType::Struct; pt = PrimitiveType::Struct;
@@ -357,7 +357,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
template<std::size_t sz> template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept { constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String; constexpr auto PT = PrimitiveType::String;
return getType(types::IString, 0, PT, 0); return getType(types::BString, 0, PT, 0);
} }
constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typeVersion, PrimitiveType pt, int b, 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> template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
TypeDescWriter writer(&typeStore); TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer); ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
std::allocator<T> a; std::allocator<T> a;
T *t = a.allocate(1); T *t = a.allocate(1);
@@ -396,7 +396,7 @@ constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
template<typename T> template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept {
TypeDescWriter writer(&typeStore); TypeDescWriter writer(&typeStore);
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(writer); ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
OX_RETURN_ERROR(model(&handler, &val)); OX_RETURN_ERROR(model(&handler, &val));
return writer.definition(); return writer.definition();
} }

View File

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

View File

@@ -20,7 +20,4 @@ static_assert([]() -> ox::Error {
return {}; return {};
}() == ox::Error{}); }() == ox::Error{});
// a dummy function to prevent linker errors in a library that has no other symbols
void modelDummyFunc() noexcept {}
} }

View File

@@ -100,7 +100,7 @@ class ModelValue {
return Type::Union; return Type::Union;
} else if constexpr(is_same_v<U, ModelObject>) { } else if constexpr(is_same_v<U, ModelObject>) {
return Type::Object; return Type::Object;
} else if constexpr(isBasicString_v<U> || isIString_v<U>) { } else if constexpr(isBasicString_v<U> || isBString_v<U>) {
return Type::String; return Type::String;
} else if constexpr(is_same_v<U, ModelValueVector>) { } else if constexpr(is_same_v<U, ModelValueVector>) {
return Type::Vector; return Type::Vector;
@@ -168,7 +168,7 @@ class ModelValue {
constexpr const auto &get() const noexcept { constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
ox::panic("invalid cast"); oxPanic(ox::Error(1), "invalid cast");
} }
return getValue<type>(*this); return getValue<type>(*this);
} }
@@ -178,7 +178,7 @@ class ModelValue {
constexpr auto &get() noexcept { constexpr auto &get() noexcept {
constexpr auto type = getType<T>(); constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] { if (m_type != type) [[unlikely]] {
ox::panic("invalid cast"); oxPanic(ox::Error(1), "invalid cast");
} }
return getValue<type>(*this); return getValue<type>(*this);
} }
@@ -187,7 +187,7 @@ class ModelValue {
constexpr Type type() const noexcept; constexpr Type type() const noexcept;
constexpr Error setType( constexpr Error setType(
DescriptorType const *type, DescriptorType const*type,
SubscriptStack const& = {}, SubscriptStack const& = {},
int subscriptLevels = 0) noexcept; int subscriptLevels = 0) noexcept;
@@ -275,7 +275,7 @@ class ModelValueArray {
} }
constexpr Error setType( constexpr Error setType(
DescriptorType const *type, DescriptorType const*type,
SubscriptStack subscriptStack, SubscriptStack subscriptStack,
int subscriptLevels) noexcept { int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch"); oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
@@ -418,7 +418,7 @@ class ModelValueVector {
} }
constexpr Error setType( constexpr Error setType(
DescriptorType const *type, DescriptorType const*type,
SubscriptStack subscriptStack, SubscriptStack subscriptStack,
int subscriptLevels) noexcept { int subscriptLevels) noexcept {
oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch"); oxAssert(subscriptLevels <= static_cast<int>(subscriptStack.size()), "subscript level mismatch");
@@ -821,7 +821,7 @@ class ModelUnion {
template<typename PlatSpec> template<typename PlatSpec>
[[nodiscard]] [[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(); return sizeOf<PlatSpec>(&(*v)[0]) * v->size();
} }
@@ -1098,7 +1098,7 @@ constexpr Error ModelValue::setType(
} else if (type->typeName == types::Bool) { } else if (type->typeName == types::Bool) {
m_type = Type::Bool; m_type = Type::Bool;
} else if (type->typeName == types::BasicString || } else if (type->typeName == types::BasicString ||
type->typeName == types::IString || type->typeName == types::BString ||
type->typeName == types::String) { type->typeName == types::String) {
m_type = Type::String; m_type = Type::String;
m_data.str = new String; m_data.str = new String;

View File

@@ -144,7 +144,7 @@ template<typename T, typename Str = const char*>
[[nodiscard]] [[nodiscard]]
consteval auto requireModelTypeName() noexcept { consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T, Str>(); constexpr auto name = getModelTypeName<T, Str>();
static_assert(ox::StringView{name}.size(), "Type lacks required TypeName"); static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
return name; return name;
} }
@@ -159,7 +159,7 @@ constexpr auto ModelTypeId_v = [] {
constexpr auto name = ModelTypeName_v<T, ox::StringView>; constexpr auto name = ModelTypeName_v<T, ox::StringView>;
constexpr auto version = ModelTypeVersion_v<T>; constexpr auto version = ModelTypeVersion_v<T>;
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version); constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr); return ox::sfmt<ox::IString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr);
}(); }();
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,8 +15,8 @@
namespace ox { namespace ox {
void panic(Error const &err, StringViewCR panicMsg, std::source_location const &src) noexcept { void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const&err) noexcept {
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", src.file_name(), src.line(), panicMsg); oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
if (err.msg) { if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg); oxErrf("\tError Message:\t{}\n", err.msg);
} }
@@ -26,61 +26,41 @@ void panic(Error const &err, StringViewCR panicMsg, std::source_location const &
} }
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
printStackTrace(2); printStackTrace(2);
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << src.file_name() << ":" << src.line() << ")"; oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
std::abort(); std::abort();
#else #else
while (1); while (1);
#endif #endif
} }
#if __GNUC__ && !_WIN32 void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept {
__attribute__((weak)) panic(StringView{file}, line, StringView{panicMsg}, err);
#endif
void panic(Error const &err, char const*panicMsg, std::source_location const &src) noexcept {
panic(err, StringView{panicMsg}, src);
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(
StringViewCR file,
int const line,
StringViewCR assertTxt, StringViewCR assertTxt,
StringViewCR msg, StringViewCR msg) noexcept {
std::source_location const &src) noexcept {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
auto const st = genStackTrace(2); auto const st = genStackTrace(2);
oxTracef( oxTracef("assert", "Failed assert: {} ({}) [{}:{}]:\n{}", msg, assertTxt, file, line, st);
"assert", "Failed assert: {} ({}) [{}:{}]:\n{}",
msg,
assertTxt,
src.file_name(),
src.line(),
st);
abort(); abort();
#else #else
oxErrf( oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
src.file_name(), constexprPanic(file, line, msg);
src.line(),
msg);
oxTracef(
"assert", "Failed assert: {} ({}) [{}:{}]",
msg,
assertTxt,
src.file_name(),
src.line());
constexprPanic(msg, {}, src);
#endif #endif
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(
[[maybe_unused]] Error const &err, StringViewCR file,
int const line,
[[maybe_unused]] Error const&err,
StringViewCR, StringViewCR,
StringViewCR assertMsg, StringViewCR assertMsg) noexcept {
std::source_location const &src) noexcept {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
auto msg = sfmt( auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n",
src.file_name(),
src.line(),
assertMsg);
if (err.msg) { if (err.msg) {
msg += sfmt("\tError Message:\t{}\n", err.msg); msg += sfmt("\tError Message:\t{}\n", err.msg);
} }
@@ -90,10 +70,10 @@ void assertFailFuncRuntime(
} }
msg += genStackTrace(2); msg += genStackTrace(2);
oxErr(msg); oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, src.file_name(), src.line()); oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
abort(); abort();
#else #else
constexprPanic(assertMsg, {}, src); constexprPanic(file, line, assertMsg);
#endif #endif
} }

View File

@@ -23,49 +23,42 @@
namespace ox { namespace ox {
[[noreturn]] [[noreturn]]
void panic( void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept;
Error const&err,
StringViewCR panicMsg,
std::source_location const &src = std::source_location::current()) noexcept;
[[noreturn]]
inline void panic(
StringViewCR panicMsg,
std::source_location const &src = std::source_location::current()) noexcept {
panic(Error{1}, panicMsg, src);
}
[[noreturn]] [[noreturn]]
constexpr void constexprPanic( constexpr void constexprPanic(
StringViewCR file,
int const line,
StringViewCR panicMsg, StringViewCR panicMsg,
Error const &err = {}, Error const&err = {}) noexcept {
std::source_location const &src = std::source_location::current()) noexcept {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
panic(err, panicMsg, src); panic(file, line, panicMsg, err);
} else { } else {
while (true); while (true);
} }
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(
StringViewCR file,
int line,
StringViewCR assertTxt, StringViewCR assertTxt,
StringViewCR msg, StringViewCR msg) noexcept;
std::source_location const &src = std::source_location::current()) noexcept;
void assertFailFuncRuntime( void assertFailFuncRuntime(
Error const &err, StringViewCR file,
int line,
Error const&err,
StringViewCR, StringViewCR,
StringViewCR assertMsg, StringViewCR assertMsg) noexcept;
std::source_location const &src = std::source_location::current()) noexcept;
constexpr void assertFunc( constexpr void assertFunc(
StringViewCR file,
int const line,
bool const pass, bool const pass,
[[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR assertTxt,
[[maybe_unused]]StringViewCR msg, [[maybe_unused]]StringViewCR msg) noexcept {
std::source_location const &src = std::source_location::current()) noexcept {
if (!pass) { if (!pass) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(assertTxt, msg, src); assertFailFuncRuntime(file, line, assertTxt, msg);
} else { } else {
while (true); while (true);
} }
@@ -73,13 +66,14 @@ constexpr void assertFunc(
} }
constexpr void assertFunc( constexpr void assertFunc(
Error const &err, StringViewCR file,
int const line,
Error const&err,
StringViewCR, StringViewCR,
StringViewCR assertMsg, StringViewCR assertMsg) noexcept {
std::source_location const &src = std::source_location::current()) noexcept {
if (err) { if (err) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
assertFailFuncRuntime(err, {}, assertMsg, src); assertFailFuncRuntime(file, line, err, {}, assertMsg);
} else { } else {
while (true); while (true);
} }
@@ -87,31 +81,20 @@ constexpr void assertFunc(
} }
constexpr void expect( constexpr void expect(
auto const &actual, StringViewCR file,
auto const &expected, int const line,
std::source_location const &src = std::source_location::current()) noexcept { auto const&actual,
auto const&expected) noexcept {
if (actual != expected) { if (actual != expected) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
oxErrf( oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, "Value incorrect");
"\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", oxErrf("expected: {}\nactual: {}\n", detail::toStringView<true>(expected), detail::toStringView<true>(actual));
src.file_name(),
src.line(),
"Value incorrect");
oxErrf(
"expected: {}\nactual: {}\n",
detail::toStringView<true>(expected),
detail::toStringView<true>(actual));
printStackTrace(2); printStackTrace(2);
oxTracef( oxTracef("assert.expect", "Failed assert: {} == {} [{}:{}]", detail::toStringView<true>(actual), detail::toStringView<true>(expected), file, line);
"assert.expect", "Failed assert: {} == {} [{}:{}]",
detail::toStringView<true>(actual),
detail::toStringView<true>(expected),
src.file_name(),
src.line());
std::abort(); std::abort();
#else #else
constexprPanic("Comparison failed", {}, src); constexprPanic(file, line, "Comparison failed");
#endif #endif
} else { } else {
while (true); while (true);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,7 @@ class exception {
virtual ~exception() = default; virtual ~exception() = default;
[[nodiscard]] [[nodiscard]]
virtual char const *what() const noexcept { virtual char const*what() const noexcept {
return ""; return "";
} }
}; };
@@ -44,7 +44,7 @@ struct [[nodiscard]] Error {
explicit constexpr Error( explicit constexpr Error(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const &src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, src{src},
errCode{errCode} errCode{errCode}
{} {}
@@ -52,7 +52,7 @@ struct [[nodiscard]] Error {
explicit constexpr Error( explicit constexpr Error(
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, ox::CString msg,
std::source_location const &src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, src{src},
msg{msg}, msg{msg},
errCode{errCode} errCode{errCode}
@@ -65,13 +65,13 @@ struct [[nodiscard]] Error {
}; };
[[nodiscard]] [[nodiscard]]
constexpr auto errCode(Error const &err) noexcept { constexpr auto errCode(Error const&err) noexcept {
return err.errCode; return err.errCode;
} }
template<typename T = char const*> template<typename T = char const*>
[[nodiscard]] [[nodiscard]]
constexpr auto toStr(Error const &err) noexcept { constexpr auto toStr(Error const&err) noexcept {
return err.msg ? T{err.msg} : ""; return err.msg ? T{err.msg} : "";
} }
@@ -82,19 +82,19 @@ struct Exception: public std::exception {
explicit Exception( explicit Exception(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const &src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, src{src},
errCode{errCode} {} errCode{errCode} {}
explicit Exception( explicit Exception(
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, ox::CString msg,
std::source_location const &src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, src{src},
msg{msg}, msg{msg},
errCode{errCode} {} errCode{errCode} {}
explicit Exception(Error const &err) noexcept: explicit Exception(Error const&err) noexcept:
src{err.src}, src{err.src},
msg{err.msg ? err.msg : ""}, msg{err.msg ? err.msg : ""},
errCode{err.errCode} {} errCode{err.errCode} {}
@@ -104,16 +104,13 @@ struct Exception: public std::exception {
} }
[[nodiscard]] [[nodiscard]]
char const *what() const noexcept override { char const*what() const noexcept override {
return msg; return msg;
} }
}; };
[[noreturn]] [[noreturn]]
void panic( void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
Error const &err,
char const *panicMsg,
std::source_location const &src = std::source_location::current()) noexcept;
template<typename T> template<typename T>
struct [[nodiscard]] Result { struct [[nodiscard]] Result {
@@ -127,25 +124,25 @@ struct [[nodiscard]] Result {
} }
template<typename U> template<typename U>
constexpr Result(Result<U> const &other) noexcept: value(other.value), error(other.error) { constexpr Result(Result<U> const&other) noexcept: value(other.value), error(other.error) {
} }
template<typename U> template<typename U>
constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) { constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
} }
constexpr Result(Error const &error) noexcept: value(), error(error) { constexpr Result(Error const&error) noexcept: value(), error(error) {
} }
constexpr Result(type const &value, Error const &error = {}) noexcept: value(value), error(error) { constexpr Result(type const&value, Error const&error = {}) noexcept: value(value), error(error) {
} }
constexpr Result(type &&value, Error const &error = {}) noexcept: value(std::move(value)), error(error) { constexpr Result(type &&value, Error const&error = {}) noexcept: value(std::move(value)), error(error) {
} }
constexpr ~Result() noexcept = default; constexpr ~Result() noexcept = default;
explicit constexpr operator type const &() const noexcept { explicit constexpr operator type const&() const noexcept {
return value; return value;
} }
@@ -159,7 +156,7 @@ struct [[nodiscard]] Result {
} }
template<typename U> template<typename U>
constexpr Error copyTo(U &val) const & noexcept { constexpr Error copyTo(U &val) const& noexcept {
if (!error) [[likely]] { if (!error) [[likely]] {
val = value; val = value;
} }
@@ -185,7 +182,7 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &unwrap() & noexcept { constexpr T &unwrap() & noexcept {
if (error) { if (error) {
ox::panic(error, "Failed unwrap"); oxPanic(error, "Failed unwrap");
} }
return value; return value;
} }
@@ -193,15 +190,15 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &&unwrap() && noexcept { constexpr T &&unwrap() && noexcept {
if (error) { if (error) {
ox::panic(error, "Failed unwrap"); oxPanic(error, "Failed unwrap");
} }
return std::move(value); return std::move(value);
} }
[[nodiscard]] [[nodiscard]]
constexpr T const &unwrap() const & noexcept { constexpr T const&unwrap() const & noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
ox::panic(error, "Failed unwrap"); oxPanic(error, "Failed unwrap");
} }
return value; return value;
} }
@@ -223,7 +220,7 @@ struct [[nodiscard]] Result {
} }
[[nodiscard]] [[nodiscard]]
constexpr T const &unwrapThrow() const & { constexpr T const&unwrapThrow() const & {
if (error) { if (error) {
throw ox::Exception(error); throw ox::Exception(error);
} }
@@ -247,7 +244,7 @@ struct [[nodiscard]] Result {
} }
template<typename U = T> template<typename U = T>
constexpr ox::Result<U> to(auto const &f) & noexcept { constexpr ox::Result<U> to(auto const&f) & noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
return error; return error;
} }
@@ -255,7 +252,7 @@ struct [[nodiscard]] Result {
} }
template<typename U = T> template<typename U = T>
constexpr ox::Result<U> to(auto const &f) && noexcept { constexpr ox::Result<U> to(auto const&f) && noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
return error; return error;
} }
@@ -267,7 +264,7 @@ struct [[nodiscard]] Result {
* @param alt * @param alt
* @return value of Result or alt * @return value of Result or alt
*/ */
constexpr T or_value(T &&alt) const & noexcept { constexpr T or_value(T &&alt) const& noexcept {
if (error) { if (error) {
return std::move(alt); return std::move(alt);
} }
@@ -291,7 +288,7 @@ struct [[nodiscard]] Result {
* @param alt * @param alt
* @return value of Result or alt * @return value of Result or alt
*/ */
constexpr T or_value(T const &alt) const & noexcept { constexpr T or_value(T const&alt) const& noexcept {
if (error) { if (error) {
return alt; return alt;
} }
@@ -303,54 +300,45 @@ struct [[nodiscard]] Result {
* @param alt * @param alt
* @return value of Result or alt * @return value of Result or alt
*/ */
constexpr T or_value(T const &alt) && noexcept { constexpr T or_value(T const&alt) && noexcept {
if (error) { if (error) {
return alt; return alt;
} }
return std::move(value); return std::move(value);
} }
constexpr Result transformError(ErrorCode const ec, CString const msg) && {
if (error) {
error = Error{ec, msg};
}
return *this;
}
}; };
namespace detail { namespace detail {
constexpr Error toError(Error const &e) noexcept { constexpr Error toError(Error const&e) noexcept {
return e; return e;
} }
template<typename T> template<typename T>
constexpr Error toError(Result<T> const &r) noexcept { constexpr Error toError(Result<T> const&r) noexcept {
return r.error; return r.error;
} }
} }
constexpr void primitiveAssert( constexpr void primitiveAssert(char const*file, int line, bool pass, char const*msg) noexcept {
bool const pass,
char const *msg,
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(ox::defines::Debug) { if constexpr(ox::defines::Debug) {
if (!pass) [[unlikely]] { if (!pass) [[unlikely]] {
panic(ox::Error{1}, msg, src); panic(file, line, msg, ox::Error(1));
} }
} }
} }
constexpr void boundsCheck( constexpr void boundsCheck(
char const*file,
int const line,
size_t const i, size_t const i,
size_t const sz, size_t const sz,
char const *msg, char const*msg) noexcept {
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(defines::CheckBounds) { if constexpr(defines::CheckBounds) {
if (i >= sz) [[unlikely]] { if (i >= sz) [[unlikely]] {
panic(ox::Error{1}, msg, src); panic(file, line, msg, ox::Error{1});
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -47,7 +47,7 @@ class Span {
} }
template<std::size_t sz> template<std::size_t sz>
constexpr Span(std::array<ox::remove_const_t<T>, sz> const &a) noexcept: constexpr Span(std::array<ox::remove_const_t<T>, sz> const&a) noexcept:
m_items(a.data()), m_items(a.data()),
m_size(a.size()) { m_size(a.size()) {
} }
@@ -60,7 +60,7 @@ class Span {
} }
template<std::size_t sz> template<std::size_t sz>
constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const &a) noexcept: constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const&a) noexcept:
m_items(a.data()), m_items(a.data()),
m_size(a.size()) { m_size(a.size()) {
} }
@@ -72,7 +72,7 @@ class Span {
} }
template<std::size_t sz, typename Allocator> template<std::size_t sz, typename Allocator>
constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const &v) noexcept: constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const&v) noexcept:
m_items(v.data()), m_items(v.data()),
m_size(v.size()) { m_size(v.size()) {
} }
@@ -147,40 +147,22 @@ class Span {
} }
constexpr T &operator[](std::size_t i) const noexcept { constexpr T &operator[](std::size_t i) const noexcept {
boundsCheck(i, size(), "Span access overflow"); boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow");
return m_items[i]; return m_items[i];
} }
constexpr Span operator+(size_t i) const noexcept { constexpr Span operator+(size_t i) const noexcept {
boundsCheck(i, size(), "Span access overflow"); boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow");
return {m_items + i, m_size - i}; return {m_items + i, m_size - i};
} }
constexpr Span operator+=(size_t i) noexcept { constexpr Span operator+=(size_t i) noexcept {
boundsCheck(i, size(), "Span access overflow"); boundsCheck(__FILE__, __LINE__, i, size(), "Span access overflow");
m_items += i; m_items += i;
m_size -= i; m_size -= i;
return *this; return *this;
} }
constexpr Span operator++(int) noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
constexpr Span operator++() noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
[[nodiscard]] [[nodiscard]]
constexpr auto data() const noexcept { constexpr auto data() const noexcept {
return m_items; return m_items;

View File

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

View File

@@ -139,7 +139,7 @@ class BasicString {
constexpr BasicString &operator+=(Integer_c auto i) noexcept; constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringViewCR src) noexcept; constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(BasicString const&src) noexcept; constexpr BasicString &operator+=(BasicString const&src) noexcept;
@@ -176,7 +176,7 @@ class BasicString {
constexpr char &operator[](std::size_t i) noexcept; constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept { constexpr Error append(const char *str, std::size_t strLen) noexcept {
auto currentLen = size(); auto currentLen = len();
m_buff.resize(m_buff.size() + strLen); m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&m_buff[currentLen], str, strLen); ox::listcpy(&m_buff[currentLen], str, strLen);
// make sure last element is a null terminator // make sure last element is a null terminator
@@ -185,8 +185,8 @@ class BasicString {
return {}; return {};
} }
constexpr Error append(StringViewCR sv) noexcept { constexpr Error append(ox::StringView sv) noexcept {
return append(sv.data(), sv.size()); return append(sv.data(), sv.len());
} }
[[nodiscard]] [[nodiscard]]
@@ -237,7 +237,7 @@ class BasicString {
* Returns the number of characters in this string. * Returns the number of characters in this string.
*/ */
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept; constexpr std::size_t len() const noexcept;
/** /**
* Returns the number of bytes used for this string. * Returns the number of bytes used for this string.
@@ -277,7 +277,7 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept: constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept:
BasicString(StringView{str.data(), str.size()}) { BasicString(StringView{str.data(), str.len()}) {
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
@@ -376,7 +376,7 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringViewCR s) noexcept { constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes(); std::size_t strLen = s.bytes();
std::ignore = append(s.data(), strLen); std::ignore = append(s.data(), strLen);
return *this; return *this;
@@ -384,14 +384,14 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept { constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
std::ignore = append(src.c_str(), src.size()); std::ignore = append(src.c_str(), src.len());
return *this; return *this;
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox::strlen(str); const std::size_t strLen = ox::strlen(str);
const auto currentLen = size(); const auto currentLen = len();
BasicString<SmallStringSize_v> cpy; BasicString<SmallStringSize_v> cpy;
cpy.m_buff.resize(m_buff.size() + strLen); cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen); ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -420,8 +420,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(StringViewCR src) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(StringViewCR src) const noexcept {
const std::size_t strLen = src.size(); const std::size_t strLen = src.len();
const auto currentLen = size(); const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen); BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen); cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen); ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -432,8 +432,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept { constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
const std::size_t strLen = src.size(); const std::size_t strLen = src.len();
const auto currentLen = size(); const auto currentLen = len();
BasicString<SmallStringSize_v> cpy(currentLen + strLen); BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen); cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen); ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -456,7 +456,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) con
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept { constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return StringView(*this) == StringView(other); return ox::StringView(*this) == ox::StringView(other);
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
@@ -521,7 +521,7 @@ constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
} }
template<std::size_t SmallStringSize_v> template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::size() const noexcept { constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
return m_buff.size() - 1; return m_buff.size() - 1;
} }
@@ -548,28 +548,28 @@ using StringCR = String const&;
[[nodiscard]] [[nodiscard]]
constexpr String toString(StringViewCR sv) noexcept { constexpr ox::String toString(ox::StringViewCR sv) noexcept {
return ox::String(sv); return ox::String(sv);
} }
template<typename PlatSpec, std::size_t SmallStringSize_v> template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]] [[nodiscard]]
constexpr auto sizeOf(BasicString<SmallStringSize_v> const*) noexcept { constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v}; VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v); return sizeOf<PlatSpec>(&v);
} }
template<typename PlatSpec, std::size_t SmallStringSize_v> template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]] [[nodiscard]]
constexpr auto alignOf(BasicString<SmallStringSize_v> const&) noexcept { constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v}; VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v); return alignOf<PlatSpec>(&v);
} }
template<size_t sz> template<size_t sz>
struct MaybeView<BasicString<sz>> { struct MaybeView<ox::BasicString<sz>> {
using type = StringView; using type = ox::StringView;
}; };
} }

View File

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

View File

@@ -8,7 +8,6 @@
#pragma once #pragma once
#include "cstringview.hpp"
#include "string.hpp" #include "string.hpp"
namespace ox { namespace ox {

View File

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

View File

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

View File

@@ -28,4 +28,3 @@ add_test("[ox/std] FromHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "FromHex")
add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex") add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex")
add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID") add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID")
add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate") add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")
add_test("[ox/std] intToStr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "intToStr")

View File

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

View File

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

View File

@@ -63,6 +63,25 @@ namespace ox {
using CString = char const*; using CString = char const*;
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<const T*>(this);
}
};
template<std::size_t sz> template<std::size_t sz>
struct SignedType { struct SignedType {
}; };

View File

@@ -180,6 +180,20 @@ struct is_same<T, T>: true_type {};
template<typename T, typename U> template<typename T, typename U>
constexpr auto is_same_v = is_same<T, U>::value; constexpr auto is_same_v = is_same<T, U>::value;
// enable_if ///////////////////////////////////////////////////////////////////
template<bool B, class T = void>
struct enable_if {
};
template<class T>
struct enable_if<true, T> {
using type = T;
};
template<bool B, typename T>
using enable_if_t = typename enable_if<B, T>::type;
template<typename T> template<typename T>
struct is_pointer { struct is_pointer {
static constexpr bool value = false; static constexpr bool value = false;
@@ -223,9 +237,6 @@ struct remove_pointer<T* const volatile> {
using type = T; using type = T;
}; };
template<typename T>
using remove_pointer_t = typename remove_pointer<T>::type;
template<typename T> template<typename T>
struct remove_reference { struct remove_reference {

View File

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

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {}; ox::Array<AllocAlias<T>, Size> m_data = {};
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default; constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept { constexpr void allocate(T **items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) { if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
@@ -49,31 +49,45 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T **items, T **items,
VectorAllocator *src, VectorAllocator *src,
std::size_t const count, const std::size_t count,
std::size_t const cap) noexcept { const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later // try removing it later
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) { if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) { for (auto i = 0u; i < count; ++i) {
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i])); const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
new (&m_data[i]) T(std::move(*srcItem)); const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
} std::construct_at<T>(dstItem, std::move(*srcItem));
if (count) {
*items = std::launder(reinterpret_cast<T*>(m_data.data()));
} else {
*items = reinterpret_cast<T*>(m_data.data());
} }
*items = reinterpret_cast<T*>(m_data.data());
} }
} }
} }
constexpr void deallocate(T *const items, std::size_t const cap) noexcept { constexpr void moveItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (std::size_t i = 0; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
*dstItem = std::move(*srcItem);
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
if (items) { Allocator{}.deallocate(items, cap);
Allocator{}.deallocate(items, cap);
}
} else { } else {
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) { if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
@@ -87,10 +101,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> { struct VectorAllocator<T, Allocator, 0> {
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default; constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept { constexpr void allocate(T **items, std::size_t cap) noexcept {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
} }
@@ -98,15 +112,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T**, T**,
VectorAllocator*, VectorAllocator*,
std::size_t const, const std::size_t,
std::size_t const) noexcept { const std::size_t) noexcept {
} }
[[maybe_unused]] [[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, std::size_t const, std::size_t const) noexcept { constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
} }
constexpr void deallocate(T *const items, std::size_t const cap) noexcept { constexpr void deallocate(T *items, std::size_t cap) noexcept {
if (items) { if (items) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
} }
@@ -247,8 +261,6 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr void resize(std::size_t size) noexcept(useNoexcept); constexpr void resize(std::size_t size) noexcept(useNoexcept);
constexpr void reserveResize(std::size_t size) noexcept(useNoexcept);
[[nodiscard]] [[nodiscard]]
constexpr T *data() noexcept { constexpr T *data() noexcept {
return m_items; return m_items;
@@ -263,7 +275,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr bool contains(MaybeView_t<T> const&) const noexcept; constexpr bool contains(MaybeView_t<T> const&) const noexcept;
constexpr iterator<T&, T*, false> insert( constexpr iterator<T&, T*, false> insert(
std::size_t pos, std::size_t cnt, T const &val) noexcept(useNoexcept); std::size_t pos, std::size_t cnt, T const&val) noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept); constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept);
@@ -273,9 +285,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args> template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept); constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T const &item) noexcept(useNoexcept); constexpr void push_back(T item) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept); constexpr void pop_back() noexcept(useNoexcept);
@@ -409,7 +419,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
m_items = other.m_items; m_items = other.m_items;
this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap); this->moveItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0; other.m_size = 0;
other.m_cap = 0; other.m_cap = 0;
other.m_items = nullptr; other.m_items = nullptr;
@@ -419,13 +429,13 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept { constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept {
boundsCheck(i, size(), "Vector access overflow"); boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept { constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept {
boundsCheck(i, size(), "Vector access overflow"); boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
@@ -520,13 +530,7 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(std::size_t const size) noexcept(useNoexcept) { constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
reserve(size);
resize(size);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const &v) const noexcept {
for (std::size_t i = 0; i < m_size; ++i) { for (std::size_t i = 0; i < m_size; ++i) {
if (m_items[i] == v) { if (m_items[i] == v) {
return true; return true;
@@ -538,7 +542,7 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> co
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false> constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert( Vector<T, SmallVectorSize, Allocator>::insert(
std::size_t pos, std::size_t cnt, T const &val) noexcept(useNoexcept) { std::size_t pos, std::size_t cnt, T const&val) noexcept(useNoexcept) {
if (m_size + cnt > m_cap) { if (m_size + cnt > m_cap) {
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt); reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
} }
@@ -611,16 +615,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], item);
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
} }

View File

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

View File

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

View File

@@ -26,7 +26,7 @@ extern void (*__preinit_array_end[]) (void);
extern void (*__init_array_start[]) (void); extern void (*__init_array_start[]) (void);
extern void (*__init_array_end[]) (void); extern void (*__init_array_end[]) (void);
int main(int argc, char const **argv); int main(int argc, const char **argv);
extern "C" { extern "C" {
@@ -50,7 +50,7 @@ void __libc_init_array() {
} }
int c_start() { int c_start() {
char const *args[2] = {"", "rom.oxfs"}; const char *args[2] = {"", "rom.oxfs"};
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END); ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
mgba::initConsole(); mgba::initConsole();
#pragma GCC diagnostic push #pragma GCC diagnostic push

View File

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

View File

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

View File

@@ -1,9 +1,3 @@
# d2025.07.0
* Add sub-command for exporting TileSheets as PNG files.
* Add 'Reload Project' menu item under File.
* Fix opening a project to mark an unopenable file as closed in the config file on startup.
# d2025.06.0 # d2025.06.0
* Add ability to remember recent projects in config * Add ability to remember recent projects in config

View File

@@ -19,10 +19,10 @@ using Color32 = uint32_t;
[[nodiscard]] [[nodiscard]]
constexpr Color32 toColor32(Color16 nc) noexcept { constexpr Color32 toColor32(Color16 nc) noexcept {
auto const r = static_cast<Color32>(((nc & 0b0000000000011111) >> 0) * 8); const auto r = static_cast<Color32>(((nc & 0b0000000000011111) >> 0) * 8);
auto const g = static_cast<Color32>(((nc & 0b0000001111100000) >> 5) * 8); const auto g = static_cast<Color32>(((nc & 0b0000001111100000) >> 5) * 8);
auto const b = static_cast<Color32>(((nc & 0b0111110000000000) >> 10) * 8); const auto b = static_cast<Color32>(((nc & 0b0111110000000000) >> 10) * 8);
auto const a = static_cast<Color32>(255); const auto a = static_cast<Color32>(255);
return r | (g << 8) | (b << 16) | (a << 24); return r | (g << 8) | (b << 16) | (a << 24);
} }

View File

@@ -12,37 +12,8 @@ constexpr auto TileWidth = 8;
constexpr auto TileHeight = 8; constexpr auto TileHeight = 8;
constexpr auto PixelsPerTile = TileWidth * TileHeight; constexpr auto PixelsPerTile = TileWidth * TileHeight;
constexpr ox::StringLiteral FileExt_ng{"ng"}; constexpr ox::StringLiteral FileExt_ng("ng");
constexpr ox::StringLiteral FileExt_nts{"nts"}; constexpr ox::StringLiteral FileExt_nts("nts");
constexpr ox::StringLiteral FileExt_npal{"npal"}; constexpr ox::StringLiteral FileExt_npal("npal");
constexpr ox::Array<ox::StringLiteral, 2> FileExts_TileSheet{
FileExt_nts,
FileExt_ng,
};
constexpr ox::Array<ox::StringLiteral, 2> FileExts_Palette{
FileExt_npal,
};
[[nodiscard]]
constexpr bool isTileSheet(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_TileSheet.begin(),
FileExts_TileSheet.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
[[nodiscard]]
constexpr bool isPalette(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_Palette.begin(),
FileExts_Palette.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
} }

View File

@@ -111,23 +111,23 @@ struct InitParams {
uint_t glBlocksPerSprite = 64; uint_t glBlocksPerSprite = 64;
}; };
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params = {}) noexcept; ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params = {}) noexcept;
[[nodiscard]] [[nodiscard]]
int tileColumns(Context const&) noexcept; int tileColumns(Context&) noexcept;
[[nodiscard]] [[nodiscard]]
int tileRows(Context const&) noexcept; int tileRows(Context&) noexcept;
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t palBank,
CompactPalette const &palette, CompactPalette const&palette,
size_t page = 0) noexcept; size_t page = 0) noexcept;
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
CompactPalette const &palette, CompactPalette const&palette,
size_t page = 0) noexcept; size_t page = 0) noexcept;
ox::Error loadBgPalette( ox::Error loadBgPalette(
@@ -138,7 +138,7 @@ ox::Error loadBgPalette(
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t palBank, size_t palBank,
ox::FileAddress const &paletteAddr) noexcept; ox::FileAddress const&paletteAddr) noexcept;
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
@@ -146,12 +146,12 @@ ox::Error loadSpritePalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
ox::FileAddress const &paletteAddr) noexcept; ox::FileAddress const&paletteAddr) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
TileSheetSet const &set) noexcept; TileSheetSet const&set) noexcept;
void clearCbb(Context &ctx, unsigned cbb) noexcept; void clearCbb(Context &ctx, unsigned cbb) noexcept;
@@ -160,7 +160,7 @@ void clearCbbs(Context &ctx) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t dstTileIdx, size_t dstTileIdx,
size_t srcTileIdx, size_t srcTileIdx,
size_t tileCnt) noexcept; size_t tileCnt) noexcept;
@@ -176,7 +176,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::FileAddress const &tsAddr, ox::FileAddress const&tsAddr,
size_t dstTileIdx, size_t dstTileIdx,
size_t srcTileIdx, size_t srcTileIdx,
size_t tileCnt) noexcept; size_t tileCnt) noexcept;
@@ -184,24 +184,24 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
CompactTileSheet const &ts, CompactTileSheet const&ts,
ox::Optional<unsigned> const &paletteBank = {}) noexcept; ox::Optional<unsigned> const&paletteBank = {}) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::StringViewCR tilesheetPath, ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const &paletteBank) noexcept; ox::Optional<unsigned> const&paletteBank) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
ox::FileAddress const &tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::Optional<unsigned> const &paletteBank = {}) noexcept; ox::Optional<unsigned> const&paletteBank = {}) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const &ts, CompactTileSheet const&ts,
bool loadDefaultPalette) noexcept; bool loadDefaultPalette) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
@@ -211,16 +211,16 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
ox::FileAddress const &tilesheetAddr, ox::FileAddress const&tilesheetAddr,
bool loadDefaultPalette = false) noexcept; bool loadDefaultPalette = false) noexcept;
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const &set) noexcept; TileSheetSet const&set) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank = 0) noexcept; void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank = 0) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const &tile) noexcept; void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept;
void clearBg(Context &ctx, uint_t bgIdx) noexcept; void clearBg(Context &ctx, uint_t bgIdx) noexcept;
@@ -238,15 +238,11 @@ void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbbIdx) noexcept;
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept; void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept;
void setBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void hideSprite(Context &ctx, unsigned) noexcept; void hideSprite(Context &ctx, unsigned) noexcept;
void showSprite(Context &ctx, unsigned) noexcept; void showSprite(Context &ctx, unsigned) noexcept;
void setSprite(Context &ctx, uint_t idx, Sprite const &sprite) noexcept; void setSprite(Context &ctx, uint_t idx, Sprite const&sprite) noexcept;
[[nodiscard]] [[nodiscard]]
uint_t spriteCount(Context const &ctx) noexcept; uint_t spriteCount(Context const &ctx) noexcept;
@@ -264,8 +260,8 @@ constexpr ox::CStringView GlslVersion = "#version 330";
[[nodiscard]] [[nodiscard]]
ox::Size drawSize(int scale = 5) noexcept; ox::Size drawSize(int scale = 5) noexcept;
void draw(Context &ctx, ox::Size const &renderSz) noexcept; void draw(gfx::Context &ctx, ox::Size const&renderSz) noexcept;
void draw(Context&, int scale = 5) noexcept; void draw(gfx::Context&, int scale = 5) noexcept;
} }

View File

@@ -168,9 +168,9 @@ OX_MODEL_BEGIN(PaletteV3)
OX_MODEL_END() OX_MODEL_END()
[[nodiscard]] [[nodiscard]]
constexpr bool valid(PaletteV3 const &p) noexcept { constexpr bool valid(PaletteV3 const&p) noexcept {
auto const colors = p.colorInfo.size(); auto const colors = p.colorInfo.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](auto const &page) { return ox::all_of(p.pages.begin(), p.pages.end(), [colors](auto const&page) {
return page.size() == colors; return page.size() == colors;
}); });
} }
@@ -198,9 +198,9 @@ OX_MODEL_BEGIN(PaletteV4)
OX_MODEL_END() OX_MODEL_END()
[[nodiscard]] [[nodiscard]]
constexpr bool valid(PaletteV4 const &p) noexcept { constexpr bool valid(PaletteV4 const&p) noexcept {
auto const colors = p.colorNames.size(); auto const colors = p.colorNames.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV1 const &page) { return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV1 const&page) {
return page.colors.size() == colors; return page.colors.size() == colors;
}); });
} }

View File

@@ -11,39 +11,39 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
[[nodiscard]] [[nodiscard]]
constexpr std::size_t ptToIdx(int const x, int const y, int const c, int const scale = 1) noexcept { constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept {
auto const tileWidth = TileWidth * scale; const auto tileWidth = TileWidth * scale;
auto const tileHeight = TileHeight * scale; const auto tileHeight = TileHeight * scale;
auto const pixelsPerTile = tileWidth * tileHeight; const auto pixelsPerTile = tileWidth * tileHeight;
auto const colLength = static_cast<std::size_t>(pixelsPerTile); const auto colLength = static_cast<std::size_t>(pixelsPerTile);
auto const rowLength = static_cast<std::size_t>(static_cast<std::size_t>(c / tileWidth) * colLength); const auto rowLength = static_cast<std::size_t>(static_cast<std::size_t>(c / tileWidth) * colLength);
auto const colStart = static_cast<std::size_t>(colLength * static_cast<std::size_t>(x / tileWidth)); const auto colStart = static_cast<std::size_t>(colLength * static_cast<std::size_t>(x / tileWidth));
auto const rowStart = static_cast<std::size_t>(rowLength * static_cast<std::size_t>(y / tileHeight)); const auto rowStart = static_cast<std::size_t>(rowLength * static_cast<std::size_t>(y / tileHeight));
auto const colOffset = static_cast<std::size_t>(x % tileWidth); const auto colOffset = static_cast<std::size_t>(x % tileWidth);
auto const rowOffset = static_cast<std::size_t>((y % tileHeight) * tileHeight); const auto rowOffset = static_cast<std::size_t>((y % tileHeight) * tileHeight);
return static_cast<std::size_t>(colStart + colOffset + rowStart + rowOffset); return static_cast<std::size_t>(colStart + colOffset + rowStart + rowOffset);
} }
[[nodiscard]] [[nodiscard]]
constexpr std::size_t ptToIdx(ox::Point const &pt, int const c, int const scale = 1) noexcept { constexpr std::size_t ptToIdx(const ox::Point &pt, int c, int scale = 1) noexcept {
return ptToIdx(pt.x, pt.y, c * TileWidth, scale); return ptToIdx(pt.x, pt.y, c * TileWidth, scale);
} }
[[nodiscard]] [[nodiscard]]
constexpr ox::Point idxToPt(int const i, int c, int const scale = 1) noexcept { constexpr ox::Point idxToPt(int i, int c, int scale = 1) noexcept {
auto const tileWidth = TileWidth * scale; const auto tileWidth = TileWidth * scale;
auto const tileHeight = TileHeight * scale; const auto tileHeight = TileHeight * scale;
auto const pixelsPerTile = tileWidth * tileHeight; const auto pixelsPerTile = tileWidth * tileHeight;
// prevent divide by zeros // prevent divide by zeros
if (!c) { if (!c) {
++c; ++c;
} }
auto const t = i / pixelsPerTile; // tile number const auto t = i / pixelsPerTile; // tile number
auto const iti = i % pixelsPerTile; // in tile index const auto iti = i % pixelsPerTile; // in tile index
auto const tc = t % c; // tile column const auto tc = t % c; // tile column
auto const tr = t / c; // tile row const auto tr = t / c; // tile row
auto const itx = iti % tileWidth; // in tile x const auto itx = iti % tileWidth; // in tile x
auto const ity = iti / tileHeight; // in tile y const auto ity = iti / tileHeight; // in tile y
return { return {
itx + tc * tileWidth, itx + tc * tileWidth,
ity + tr * tileHeight, ity + tr * tileHeight,

View File

@@ -6,28 +6,6 @@
#include <studio/studio.hpp> #include <studio/studio.hpp>
#include "tilesheet.hpp" namespace nostalgia::core {
namespace nostalgia::gfx {
inline void navigateToTileSheet(
studio::Context &ctx, ox::StringParam path, SubSheetId const subsheetId) noexcept {
studio::navigateTo(ctx, std::move(path), ox::intToStr(subsheetId));
}
inline void navigateToPalette(studio::Context &ctx, ox::StringParam path) noexcept {
studio::navigateTo(ctx, std::move(path));
}
inline void navigateToPalette(
studio::Context &ctx,
ox::StringParam path,
size_t const colorIdx,
size_t const palPage) noexcept {
studio::navigateTo(
ctx,
std::move(path),
ox::sfmt("{};{}", colorIdx, palPage));
}
} }

View File

@@ -30,7 +30,7 @@ struct TileSheetV1 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV1 const &ts) noexcept { constexpr bool valid(TileSheetV1 const&ts) noexcept {
auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (ts.bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (ts.bpp == 4 ? 2 : 1);
return (ts.bpp == 4 || ts.bpp == 8) && ts.pixels.size() == bytes; return (ts.bpp == 4 || ts.bpp == 8) && ts.pixels.size() == bytes;
} }
@@ -71,16 +71,16 @@ struct TileSheetV2 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV2::SubSheet const &ss, int bpp) noexcept { constexpr bool valid(TileSheetV2::SubSheet const&ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV2::SubSheet const &s) { [bpp, bytes](TileSheetV2::SubSheet const&s) {
return bytes == s.pixels.size() && valid(s, bpp); return bytes == s.pixels.size() && valid(s, bpp);
}); });
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV2 const &ts) noexcept { constexpr bool valid(TileSheetV2 const&ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
} }
@@ -141,16 +141,16 @@ struct TileSheetV3 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV3::SubSheet const &ss, int bpp) noexcept { constexpr bool valid(TileSheetV3::SubSheet const&ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV3::SubSheet const &s) { [bpp, bytes](TileSheetV3::SubSheet const&s) {
return bytes == s.pixels.size() && valid(s, bpp); return bytes == s.pixels.size() && valid(s, bpp);
}); });
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV3 const &ts) noexcept { constexpr bool valid(TileSheetV3 const&ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
} }
@@ -233,18 +233,18 @@ struct TileSheetV4 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV4::SubSheet const &ss, int bpp) noexcept { constexpr bool valid(TileSheetV4::SubSheet const&ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1); auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return return
(ss.pixels.empty() || ss.subsheets.empty()) && (ss.pixels.empty() || ss.subsheets.empty()) &&
ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV4::SubSheet const &s) { [bpp, bytes](TileSheetV4::SubSheet const&s) {
return bytes == s.pixels.size() && valid(s, bpp); return bytes == s.pixels.size() && valid(s, bpp);
}); });
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV4 const &ts) noexcept { constexpr bool valid(TileSheetV4 const&ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
} }
@@ -334,19 +334,19 @@ struct TileSheetV5 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV5::SubSheet const &ss) noexcept { constexpr bool valid(TileSheetV5::SubSheet const&ss) noexcept {
if (ss.subsheets.empty()) { if (ss.subsheets.empty()) {
return std::cmp_equal(ss.columns * ss.rows * PixelsPerTile, ss.pixels.size()); return std::cmp_equal(ss.columns * ss.rows * PixelsPerTile, ss.pixels.size());
} else { } else {
return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(), return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[](TileSheetV5::SubSheet const &s) { [](TileSheetV5::SubSheet const&s) {
return valid(s); return valid(s);
}); });
} }
} }
[[nodiscard]] [[nodiscard]]
constexpr bool valid(TileSheetV5 const &ts) noexcept { constexpr bool valid(TileSheetV5 const&ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet); return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet);
} }
@@ -376,24 +376,24 @@ constexpr ox::Error repair(TileSheetV5 &ts) noexcept {
using TileSheet = TileSheetV5; using TileSheet = TileSheetV5;
[[nodiscard]] [[nodiscard]]
std::size_t idx(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept; std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
[[nodiscard]] [[nodiscard]]
size_t getTileCnt(TileSheet const &ts) noexcept; size_t getTileCnt(TileSheet const&ts) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet const*getSubsheet(TileSheet const &ts, SubSheetId id) noexcept; TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Optional<size_t> getTileIdx(TileSheet const &ts, SubSheetId id) noexcept; ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const &ss, std::size_t idx) noexcept; uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept; uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
void setPixel(TileSheet::SubSheet &ss, ox::Point const &pt, uint8_t palIdx) noexcept; void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t palIdx) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept; ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept;
@@ -406,14 +406,14 @@ void flipY(TileSheet::SubSheet &ss, ox::Point const &a, ox::Point const &b) noex
* @return a count of the pixels in this sheet * @return a count of the pixels in this sheet
*/ */
[[nodiscard]] [[nodiscard]]
unsigned pixelCnt(TileSheet::SubSheet const &ss) noexcept; unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept;
/** /**
* *
* @param ss * @param ss
* @param sz size of Subsheet in tiles (not pixels) * @param sz size of Subsheet in tiles (not pixels)
*/ */
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const &sz) noexcept; ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept;
/** /**
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the * validateSubSheetIdx takes a SubSheetIdx and moves the index to the
@@ -424,21 +424,13 @@ ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const &sz) noexcept;
* @return a valid version of idx * @return a valid version of idx
*/ */
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const &ts, TileSheet::SubSheetIdx idx) noexcept; TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubSheetIdx idx) noexcept;
ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetId pId) noexcept; ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetId pId) noexcept;
ox::Result<TileSheet::SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet &ts) noexcept;
ox::Result<TileSheet::SubSheet const*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet const &ts) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet &getSubSheet( TileSheet::SubSheet &getSubSheet(
ox::SpanView<uint32_t> const &idx, ox::SpanView<uint32_t> const&idx,
std::size_t idxIt, std::size_t idxIt,
TileSheet::SubSheet &pSubsheet) noexcept; TileSheet::SubSheet &pSubsheet) noexcept;
@@ -447,7 +439,7 @@ TileSheet::SubSheet &getSubSheet(
#pragma GCC diagnostic ignored "-Wdangling-reference" #pragma GCC diagnostic ignored "-Wdangling-reference"
#endif #endif
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet const &getSubSheet(TileSheet const &ts, ox::SpanView<uint32_t> const &idx) noexcept; TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, ox::SpanView<uint32_t> const &idx) noexcept;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx) noexcept; TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx) noexcept;
@@ -461,29 +453,27 @@ ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx, TileS
ox::Error rmSubSheet( ox::Error rmSubSheet(
TileSheet &ts, TileSheet &ts,
TileSheet::SubSheetIdx const &idx, TileSheet::SubSheetIdx const&idx,
std::size_t idxIt, std::size_t idxIt,
TileSheet::SubSheet &pSubsheet) noexcept; TileSheet::SubSheet &pSubsheet) noexcept;
ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept; ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel( uint8_t getPixel(
TileSheet const &ts, TileSheet const&ts,
ox::Point const &pt, ox::Point const&pt,
TileSheet::SubSheetIdx const &subsheetIdx) noexcept; TileSheet::SubSheetIdx const&subsheetIdx) noexcept;
ox::Result<SubSheetId> getIdFor(TileSheet const &ts, ox::StringViewCR path) noexcept; ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexcept;
ox::Result<unsigned> getTileOffset(TileSheet const &ts, ox::StringViewCR pNamePath) noexcept; ox::Result<unsigned> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept;
ox::Result<uint32_t> getTileOffset(TileSheet const &ts, SubSheetId pId) noexcept; ox::Result<uint32_t> getTileOffset(TileSheet const&ts, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const &ss, SubSheetId pId) noexcept; ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet &ts, SubSheetId pId) noexcept; ox::Result<ox::StringView> getNameFor(TileSheet const&ts, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet const &ts, SubSheetId pId) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept; ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept;
@@ -499,7 +489,7 @@ struct CompactTileSheetV1 {
}; };
[[nodiscard]] [[nodiscard]]
constexpr bool valid(CompactTileSheetV1 const &ts) noexcept { constexpr bool valid(CompactTileSheetV1 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8; return ts.bpp == 4 || ts.bpp == 8;
} }
@@ -508,22 +498,22 @@ using CompactTileSheet = CompactTileSheetV1;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel4Bpp( uint8_t getPixel4Bpp(
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t idx) noexcept; size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
uint8_t getPixel8Bpp( uint8_t getPixel8Bpp(
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t idx) noexcept; size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Pair<uint8_t> get2Pixels4Bpp( ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t idx) noexcept; size_t idx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Pair<uint8_t> get2Pixels8Bpp( ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t idx) noexcept; size_t idx) noexcept;
OX_MODEL_BEGIN(TileSheetV1) OX_MODEL_BEGIN(TileSheetV1)
@@ -603,8 +593,8 @@ OX_MODEL_BEGIN(CompactTileSheetV1)
OX_MODEL_END() OX_MODEL_END()
ox::Vector<uint32_t> resizeTileSheetData( ox::Vector<uint32_t> resizeTileSheetData(
ox::Vector<uint32_t> const &srcPixels, ox::Vector<uint32_t> const&srcPixels,
ox::Size const &srcSize, ox::Size const&srcSize,
int scale = 2) noexcept; int scale = 2) noexcept;
} }

View File

@@ -23,15 +23,22 @@ struct BgCbbData {
unsigned bpp = 4; unsigned bpp = 4;
}; };
class Context final { class Context {
public: public:
turbine::Context &turbineCtx; turbine::Context &turbineCtx;
ox::Array<BgCbbData, 4> cbbData; ox::Array<BgCbbData, 4> cbbData;
ox::Array<OffsetPair, 4> bgOffsets;
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {} explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
Context(Context const &other) noexcept = delete; Context(Context &other) noexcept = delete;
Context(Context const&other) noexcept = delete;
Context(Context const&&other) noexcept = delete;
virtual ~Context() noexcept = default;
[[nodiscard]]
ox::MemFS const&rom() const noexcept {
return static_cast<ox::MemFS const&>(*turbine::rom(turbineCtx));
}
}; };
@@ -69,12 +76,12 @@ ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&) no
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context&, Context&,
size_t const palBank, size_t const palBank,
CompactPalette const &palette, CompactPalette const&palette,
size_t const page) noexcept { size_t const page) noexcept {
if (palette.pages.empty()) { if (palette.pages.empty()) {
return {}; return {};
} }
auto const paletteMem = ox::Span{MEM_BG_PALETTE} + palBank * 16; auto const paletteMem = MEM_BG_PALETTE + palBank * 16;
for (auto i = 0u; i < colorCnt(palette, page); ++i) { for (auto i = 0u; i < colorCnt(palette, page); ++i) {
paletteMem[i] = color(palette, page, i); paletteMem[i] = color(palette, page, i);
} }
@@ -83,13 +90,14 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context&, Context&,
CompactPalette const &palette, CompactPalette const&palette,
size_t const page) noexcept { size_t const page) noexcept {
if (palette.pages.empty()) { if (palette.pages.empty()) {
return {}; return {};
} }
auto const paletteMem = MEM_SPRITE_PALETTE;
for (auto i = 0u; i < colorCnt(palette, page); ++i) { for (auto i = 0u; i < colorCnt(palette, page); ++i) {
MEM_SPRITE_PALETTE[i] = color(palette, page, i); paletteMem[i] = color(palette, page, i);
} }
return {}; return {};
} }
@@ -110,15 +118,15 @@ void clearCbbs(Context &ctx) noexcept {
static ox::Error loadTileSheetSet( static ox::Error loadTileSheetSet(
Context &ctx, Context &ctx,
ox::Span<uint16_t> tileMapTargetMem, ox::Span<uint16_t> tileMapTargetMem,
TileSheetSet const &set) noexcept { TileSheetSet const&set) noexcept {
size_t tileWriteIdx = 0; size_t tileWriteIdx = 0;
size_t const bppMod = set.bpp == 4; size_t const bppMod = set.bpp == 4;
for (auto const &entry : set.entries) { for (auto const&entry : set.entries) {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), entry.tilesheet)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), entry.tilesheet));
if (set.bpp != ts->bpp && ts->bpp == 8) { if (set.bpp != ts->bpp && ts->bpp == 8) {
return ox::Error(1, "cannot load an 8 BPP tilesheet into a 4 BPP CBB"); return ox::Error(1, "cannot load an 8 BPP tilesheet into a 4 BPP CBB");
} }
for (auto const &s : entry.sections) { for (auto const&s : entry.sections) {
auto const cnt = (static_cast<size_t>(s.tiles) * PixelsPerTile) >> bppMod; auto const cnt = (static_cast<size_t>(s.tiles) * PixelsPerTile) >> bppMod;
for (size_t i = 0; i < cnt; ++i) { for (size_t i = 0; i < cnt; ++i) {
auto const begin = static_cast<size_t>(s.begin) * (PixelsPerTile >> bppMod); auto const begin = static_cast<size_t>(s.begin) * (PixelsPerTile >> bppMod);
@@ -137,7 +145,7 @@ static ox::Error loadTileSheetSet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t const dstTileIdx, size_t const dstTileIdx,
size_t const srcTileIdx, size_t const srcTileIdx,
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
@@ -165,10 +173,10 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
CompactTileSheet const &ts, CompactTileSheet const&ts,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const&paletteBank) noexcept {
auto const cnt = ts.pixels.size() >> (ts.bpp == 4); auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4));
for (size_t i{}; i < cnt; ++i) { for (size_t i = 0; i < cnt; ++i) {
auto const srcIdx = i * 2; auto const srcIdx = i * 2;
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]); auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]); auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
@@ -190,7 +198,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
TileSheetSet const &set) noexcept { TileSheetSet const&set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp); auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_BG_TILES[cbb], set)); OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_BG_TILES[cbb], set));
// update bpp of all bgs with the updated cbb // update bpp of all bgs with the updated cbb
@@ -214,13 +222,12 @@ static void setSpritesBpp(unsigned const bpp) noexcept {
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const &ts, CompactTileSheet const&ts,
bool const loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
for (size_t i{}; i < ts.pixels.size(); i += 2) { for (size_t i = 0; i < ts.pixels.size(); i += 2) {
MEM_SPRITE_TILES[i >> 1] = uint16_t v = ts.pixels[i];
static_cast<uint16_t>( v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8);
ts.pixels[i] | MEM_SPRITE_TILES[i] = v;
(static_cast<uint16_t>(ts.pixels[i + 1]) << 8));
} }
if (loadDefaultPalette && ts.defaultPalette) { if (loadDefaultPalette && ts.defaultPalette) {
OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette)); OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette));
@@ -231,19 +238,15 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const &set) noexcept { TileSheetSet const&set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp); auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set)); OX_RETURN_ERROR(loadTileSheetSet(ctx, {MEM_SPRITE_TILES, 32 * ox::units::KB}, set));
setSpritesBpp(bpp); setSpritesBpp(bpp);
return {}; return {};
} }
void setBgTile( void setBgTile(
Context &ctx, Context &ctx, uint_t const bgIdx, int const column, int const row, BgTile const&tile) noexcept {
uint_t const bgIdx,
int const column,
int const row,
BgTile const &tile) noexcept {
auto const tileIdx = static_cast<std::size_t>(row * tileColumns(ctx) + column); auto const tileIdx = static_cast<std::size_t>(row * tileColumns(ctx) + column);
// see Tonc 9.3 // see Tonc 9.3
MEM_BG_MAP[bgIdx][tileIdx] = MEM_BG_MAP[bgIdx][tileIdx] =
@@ -272,7 +275,7 @@ bool bgStatus(Context&, unsigned const bg) noexcept {
void setBgStatus(Context&, unsigned const bg, bool const status) noexcept { void setBgStatus(Context&, unsigned const bg, bool const status) noexcept {
constexpr auto Bg0Status = 8; constexpr auto Bg0Status = 8;
auto const mask = static_cast<uint32_t>(status) << (Bg0Status + bg); const auto mask = static_cast<uint32_t>(status) << (Bg0Status + bg);
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask); REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
} }
@@ -283,7 +286,7 @@ void setBgBpp(Context&, unsigned const bgIdx, unsigned const bpp) noexcept {
void setBgCbb(Context &ctx, unsigned const bgIdx, unsigned const cbbIdx) noexcept { void setBgCbb(Context &ctx, unsigned const bgIdx, unsigned const cbbIdx) noexcept {
auto &bgCtl = regBgCtl(bgIdx); auto &bgCtl = regBgCtl(bgIdx);
auto const &cbbData = ctx.cbbData[cbbIdx]; const auto &cbbData = ctx.cbbData[cbbIdx];
teagba::bgSetBpp(bgCtl, cbbData.bpp); teagba::bgSetBpp(bgCtl, cbbData.bpp);
teagba::bgSetCbb(bgCtl, cbbIdx); teagba::bgSetCbb(bgCtl, cbbIdx);
} }
@@ -293,18 +296,6 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11); bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
} }
void setBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
ctx.bgOffsets[bg] = {.x = x, .y = y};
teagba::setBgOffset(bg, x, y);
}
void scrollBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = ctx.bgOffsets[bg];
o.x += x;
o.y += y;
teagba::setBgOffset(bg, o.x, o.y);
}
void hideSprite(Context&, unsigned const idx) noexcept { void hideSprite(Context&, unsigned const idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({ teagba::addSpriteUpdate({
@@ -321,28 +312,28 @@ void showSprite(Context&, unsigned const idx) noexcept {
}); });
} }
void setSprite(Context&, uint_t const idx, Sprite const &sprite) noexcept { void setSprite(Context&, uint_t const idx, Sprite const&s) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
uint16_t const eightBpp = sprite.bpp == 8; uint16_t const eightBpp = s.bpp == 8;
teagba::addSpriteUpdate({ teagba::addSpriteUpdate({
.attr0 = static_cast<uint16_t>( .attr0 = static_cast<uint16_t>(
(static_cast<uint16_t>(sprite.y & ox::onMask<uint8_t>(0b111'1111))) (static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
| (static_cast<uint16_t>(1) << 10) // enable alpha | (static_cast<uint16_t>(1) << 10) // enable alpha
| (static_cast<uint16_t>(eightBpp) << 13) | (static_cast<uint16_t>(eightBpp) << 13)
| (static_cast<uint16_t>(sprite.spriteShape) << 14)), | (static_cast<uint16_t>(s.spriteShape) << 14)),
.attr1 = static_cast<uint16_t>( .attr1 = static_cast<uint16_t>(
(static_cast<uint16_t>(sprite.x) & ox::onMask<uint8_t>(8)) (static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
| (static_cast<uint16_t>(sprite.flipX) << 12) | (static_cast<uint16_t>(s.flipX) << 12)
| (static_cast<uint16_t>(sprite.spriteSize) << 14)), | (static_cast<uint16_t>(s.spriteSize) << 14)),
.attr2 = static_cast<uint16_t>( .attr2 = static_cast<uint16_t>(
// double tileIdx if 8 bpp // double tileIdx if 8 bpp
(static_cast<uint16_t>((sprite.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8))) (static_cast<uint16_t>((s.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8)))
| (static_cast<uint16_t>(sprite.priority & 0b11) << 10)), | (static_cast<uint16_t>(s.priority & 0b11) << 10)),
.idx = static_cast<uint16_t>(idx), .idx = static_cast<uint16_t>(idx),
}); });
} }
uint_t spriteCount(Context const &) noexcept { uint_t spriteCount(Context const&) noexcept {
return SpriteCount; return SpriteCount;
} }
@@ -350,13 +341,13 @@ uint_t spriteCount(Context const &) noexcept {
namespace ox { namespace ox {
void panic(char const*panicMsg, Error const&err, std::source_location const &src) noexcept { void panic(const char *file, int line, const char *panicMsg, ox::Error const&err) noexcept {
using namespace nostalgia::gfx; using namespace nostalgia::gfx;
// reset heap to make sure we have enough memory to allocate context data // reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
auto const heapBegin = reinterpret_cast<char*>(MEM_EWRAM.data()); const auto heapBegin = reinterpret_cast<char*>(MEM_EWRAM_BEGIN);
auto const heapSz = MEM_EWRAM.size() / 2; const auto heapSz = (MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2;
auto const heapEnd = reinterpret_cast<char*>(MEM_EWRAM.data() + heapSz); const auto heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz);
ox::heapmgr::initHeap(heapBegin, heapEnd); ox::heapmgr::initHeap(heapBegin, heapEnd);
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap(); auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
@@ -374,7 +365,7 @@ void panic(char const*panicMsg, Error const&err, std::source_location const &src
} }
consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM"); consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
// print to terminal if in mGBA // print to terminal if in mGBA
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", src.file_name(), src.line(), panicMsg); oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
if (err.msg) { if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg); oxErrf("\tError Message:\t{}\n", err.msg);
} }

View File

@@ -87,7 +87,9 @@ class Context {
blocksPerSprite{params.glBlocksPerSprite} { blocksPerSprite{params.glBlocksPerSprite} {
} }
Context(Context const&) = delete; Context(Context const&) = delete;
Context(Context&&) = delete;
Context &operator=(Context const&) = delete; Context &operator=(Context const&) = delete;
Context &operator=(Context&&) = delete;
~Context() noexcept { ~Context() noexcept {
turbine::gl::removeDrawer(turbineCtx, &drawer); turbine::gl::removeDrawer(turbineCtx, &drawer);
} }
@@ -111,7 +113,7 @@ namespace renderer {
static constexpr auto Scale = 1; static constexpr auto Scale = 1;
static constexpr auto PriorityScale = 0.01f; static constexpr auto PriorityScale = 0.01f;
static constexpr ox::StringLiteral bgvshadTmpl{R"glsl( static constexpr ox::CStringView bgvshadTmpl = R"glsl(
{} {}
in vec2 vTexCoord; in vec2 vTexCoord;
in vec3 vPosition; in vec3 vPosition;
@@ -133,9 +135,9 @@ static constexpr ox::StringLiteral bgvshadTmpl{R"glsl(
vTexCoord.x, vTexCoord.x,
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight); vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
fPalOffset = vPalOffset; fPalOffset = vPalOffset;
})glsl"}; })glsl";
static constexpr ox::StringLiteral bgfshadTmpl{R"glsl( static constexpr ox::CStringView bgfshadTmpl = R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in float fPalOffset; in float fPalOffset;
@@ -149,9 +151,9 @@ static constexpr ox::StringLiteral bgfshadTmpl{R"glsl(
if (outColor.a == 0) { if (outColor.a == 0) {
discard; discard;
} }
})glsl"}; })glsl";
static constexpr ox::StringLiteral spritevshadTmpl{R"glsl( static constexpr ox::CStringView spritevshadTmpl = R"glsl(
{} {}
in float vEnabled; in float vEnabled;
in vec3 vPosition; in vec3 vPosition;
@@ -168,9 +170,9 @@ static constexpr ox::StringLiteral spritevshadTmpl{R"glsl(
vPosition.z - 0.004, vPosition.z - 0.004,
1.0) * vEnabled; 1.0) * vEnabled;
fTexCoord = vTexCoord * vec2(1, vTileHeight); fTexCoord = vTexCoord * vec2(1, vTileHeight);
})glsl"}; })glsl";
static constexpr ox::StringLiteral spritefshadTmpl{R"glsl( static constexpr ox::CStringView spritefshadTmpl = R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in vec2 fTexCoord; in vec2 fTexCoord;
@@ -183,7 +185,7 @@ static constexpr ox::StringLiteral spritefshadTmpl{R"glsl(
if (outColor.a == 0) { if (outColor.a == 0) {
discard; discard;
} }
})glsl"}; })glsl";
[[nodiscard]] [[nodiscard]]
static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept { static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept {
@@ -285,7 +287,7 @@ static void initSpriteBufferObjects(Context const &ctx, glutils::BufferSet &bs)
static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept { static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept {
for (auto x = 0u; x < TileColumns; ++x) { for (auto x = 0u; x < TileColumns; ++x) {
for (auto y = 0u; y < TileRows; ++y) { for (auto y = 0u; y < TileRows; ++y) {
auto const i = bgVertexRow(x, y); const auto i = bgVertexRow(x, y);
auto const vbo = ox::Span{bs.vertices} auto const vbo = ox::Span{bs.vertices}
+ i * static_cast<std::size_t>(BgVertexVboLength); + i * static_cast<std::size_t>(BgVertexVboLength);
auto const ebo = ox::Span{bs.elements} auto const ebo = ox::Span{bs.elements}
@@ -385,7 +387,7 @@ static void initBackgroundBufferset(
static glutils::GLTexture createTexture( static glutils::GLTexture createTexture(
GLsizei const w, GLsizei const w,
GLsizei const h, GLsizei const h,
void const *pixels) noexcept { void const*pixels) noexcept {
GLuint texId = 0; GLuint texId = 0;
glGenTextures(1, &texId); glGenTextures(1, &texId);
glutils::GLTexture tex(texId); glutils::GLTexture tex(texId);
@@ -423,22 +425,22 @@ static void drawBackground(CBB &cbb) noexcept {
static void drawBackgrounds( static void drawBackgrounds(
Context &ctx, Context &ctx,
ox::Size const &renderSz) noexcept { ox::Size const&renderSz) noexcept {
// load background shader and its uniforms // load background shader and its uniforms
glUseProgram(ctx.bgShader); glUseProgram(ctx.bgShader);
auto const uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz"); const auto uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz");
auto const uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale")); const auto uniformXScale = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vXScale"));
auto const uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight")); const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vTileHeight"));
auto const uniformBgIdx = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vBgIdx")); const auto uniformBgIdx = static_cast<GLint>(glGetUniformLocation(ctx.bgShader, "vBgIdx"));
auto const [wi, hi] = renderSz; const auto [wi, hi] = renderSz;
auto const wf = static_cast<float>(wi); const auto wf = static_cast<float>(wi);
auto const hf = static_cast<float>(hi); const auto hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf); glUniform1f(uniformXScale, hf / wf);
auto bgIdx = 0.f; auto bgIdx = 0.f;
for (auto const &bg : ctx.backgrounds) { for (const auto &bg : ctx.backgrounds) {
if (bg.enabled) { if (bg.enabled) {
auto &cbb = ctx.cbbs[bg.cbbIdx]; auto &cbb = ctx.cbbs[bg.cbbIdx];
auto const tileRows = cbb.tex.height / (TileHeight * Scale); const auto tileRows = cbb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows)); glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
glUniform2f( glUniform2f(
uniformSrcImgSz, uniformSrcImgSz,
@@ -451,14 +453,14 @@ static void drawBackgrounds(
} }
} }
static void drawSprites(Context &ctx, ox::Size const &renderSz) noexcept { static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
glUseProgram(ctx.spriteShader); glUseProgram(ctx.spriteShader);
auto &sb = ctx.spriteBlocks; auto &sb = ctx.spriteBlocks;
auto const uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale"); const auto uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale");
auto const uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight"); const auto uniformTileHeight = glGetUniformLocation(ctx.spriteShader, "vTileHeight");
auto const [wi, hi] = renderSz; const auto [wi, hi] = renderSz;
auto const wf = static_cast<float>(wi); const auto wf = static_cast<float>(wi);
auto const hf = static_cast<float>(hi); const auto hf = static_cast<float>(hi);
glUniform1f(uniformXScale, hf / wf); glUniform1f(uniformXScale, hf / wf);
// update vbo // update vbo
glBindVertexArray(sb.vao); glBindVertexArray(sb.vao);
@@ -467,7 +469,7 @@ static void drawSprites(Context &ctx, ox::Size const &renderSz) noexcept {
glutils::sendVbo(sb); glutils::sendVbo(sb);
} }
// set vTileHeight uniform // set vTileHeight uniform
auto const tileRows = sb.tex.height / (TileHeight * Scale); const auto tileRows = sb.tex.height / (TileHeight * Scale);
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows)); glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
// draw // draw
glBindTexture(GL_TEXTURE_2D, sb.tex); glBindTexture(GL_TEXTURE_2D, sb.tex);
@@ -479,7 +481,7 @@ static void loadPalette(
ox::Array<GLfloat, 1024> &palette, ox::Array<GLfloat, 1024> &palette,
size_t const palOffset, size_t const palOffset,
GLuint const shaderPgrm, GLuint const shaderPgrm,
CompactPalette const &pal, CompactPalette const&pal,
size_t const page = 0) noexcept { size_t const page = 0) noexcept {
static constexpr std::size_t ColorCnt = 256; static constexpr std::size_t ColorCnt = 256;
for (auto i = palOffset; auto const c : pal.pages[page]) { for (auto i = palOffset; auto const c : pal.pages[page]) {
@@ -491,14 +493,14 @@ static void loadPalette(
// make first color transparent // make first color transparent
palette[palOffset + 3] = 0; palette[palOffset + 3] = 0;
glUseProgram(shaderPgrm); glUseProgram(shaderPgrm);
auto const uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette")); const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
glUniform4fv(uniformPalette, ColorCnt, palette.data()); glUniform4fv(uniformPalette, ColorCnt, palette.data());
} }
static void setSprite( static void setSprite(
Context &ctx, Context &ctx,
uint_t const idx, uint_t const idx,
Sprite const &s) noexcept { Sprite const&s) noexcept {
// Tonc Table 8.4 // Tonc Table 8.4
struct Sz { uint_t x{}, y{}; }; struct Sz { uint_t x{}, y{}; };
static constexpr ox::Array<Sz, 12> dimensions{ static constexpr ox::Array<Sz, 12> dimensions{
@@ -524,12 +526,12 @@ static void setSprite(
auto const uY = static_cast<int>(s.y + 8) % 255 - 8; auto const uY = static_cast<int>(s.y + 8) % 255 - 8;
oxAssert(1 < ctx.spriteBlocks.vertices.size(), "vbo overflow"); oxAssert(1 < ctx.spriteBlocks.vertices.size(), "vbo overflow");
oxAssert(1 < ctx.spriteBlocks.elements.size(), "ebo overflow"); oxAssert(1 < ctx.spriteBlocks.elements.size(), "ebo overflow");
auto const spriteVboSz = ctx.blocksPerSprite * renderer::SpriteVertexVboLength; const auto spriteVboSz = ctx.blocksPerSprite * renderer::SpriteVertexVboLength;
auto const spriteEboSz = ctx.blocksPerSprite * renderer::SpriteVertexEboLength; const auto spriteEboSz = ctx.blocksPerSprite * renderer::SpriteVertexEboLength;
auto const vboBase = spriteVboSz * idx; auto const vboBase = spriteVboSz * idx;
auto const eboBase = spriteEboSz * idx; auto const eboBase = spriteEboSz * idx;
auto i = 0u; auto i = 0u;
auto const set = [&](int xIt, int yIt, bool enabled) { const auto set = [&](int xIt, int yIt, bool enabled) {
auto const fX = static_cast<float>(uX + xIt * 8) / 8; auto const fX = static_cast<float>(uX + xIt * 8) / 8;
auto const fY = static_cast<float>(uY + yIt * 8) / 8; auto const fY = static_cast<float>(uY + yIt * 8) / 8;
auto const vboIdx = vboBase + renderer::SpriteVertexVboLength * i; auto const vboIdx = vboBase + renderer::SpriteVertexVboLength * i;
@@ -572,12 +574,12 @@ static void setSprite(
} }
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params) noexcept { ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params) noexcept {
auto ctx = ox::make_unique<Context>(tctx, params); auto ctx = ox::make_unique<Context>(tctx, params);
auto const bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion); const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
auto const bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion); const auto bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
auto const spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion); const auto spriteVshad = ox::sfmt(renderer::spritevshadTmpl, gl::GlslVersion);
auto const spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion); const auto spriteFshad = ox::sfmt(renderer::spritefshadTmpl, gl::GlslVersion);
OX_RETURN_ERROR(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(ctx->bgShader)); OX_RETURN_ERROR(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(ctx->bgShader));
OX_RETURN_ERROR( OX_RETURN_ERROR(
glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx->spriteShader)); glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx->spriteShader));
@@ -601,12 +603,12 @@ struct TileSheetData {
} }
}; };
static ox::Result<TileSheetData> normalizeTileSheet static ox::Result<TileSheetData> normalizeTileSheet(
(CompactTileSheet const &ts) noexcept { CompactTileSheet const&ts) noexcept {
const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2; const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
auto const tiles = ts.pixels.size() / bytesPerTile; const auto tiles = ts.pixels.size() / bytesPerTile;
constexpr int width = 8; constexpr int width = 8;
int const height = 8 * static_cast<int>(tiles); const int height = 8 * static_cast<int>(tiles);
ox::Vector<uint32_t> pixels; ox::Vector<uint32_t> pixels;
if (bytesPerTile == 64) { // 8 BPP if (bytesPerTile == 64) { // 8 BPP
pixels.resize(ts.pixels.size()); pixels.resize(ts.pixels.size());
@@ -630,7 +632,7 @@ static ox::Result<TileSheetData> normalizeTileSheet
ox::Error loadBgPalette( ox::Error loadBgPalette(
Context &ctx, Context &ctx,
size_t const palBank, size_t const palBank,
CompactPalette const &palette, CompactPalette const&palette,
size_t const page) noexcept { size_t const page) noexcept {
renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, palette, page); renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, palette, page);
return {}; return {};
@@ -638,7 +640,7 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette( ox::Error loadSpritePalette(
Context &ctx, Context &ctx,
CompactPalette const &palette, CompactPalette const&palette,
size_t const page) noexcept { size_t const page) noexcept {
ox::Array<GLfloat, 1024> pal; ox::Array<GLfloat, 1024> pal;
renderer::loadPalette(pal, 0, ctx.spriteShader, palette, page); renderer::loadPalette(pal, 0, ctx.spriteShader, palette, page);
@@ -647,14 +649,14 @@ ox::Error loadSpritePalette(
static ox::Result<TileSheetData> buildSetTsd( static ox::Result<TileSheetData> buildSetTsd(
Context const &ctx, Context const &ctx,
TileSheetSet const &set) noexcept { TileSheetSet const&set) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx); auto &kctx = keelCtx(ctx.turbineCtx);
TileSheetData setTsd; TileSheetData setTsd;
setTsd.width = TileWidth; setTsd.width = TileWidth;
for (auto const &entry : set.entries) { for (auto const&entry : set.entries) {
OX_REQUIRE(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet)); OX_REQUIRE(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet));
OX_REQUIRE(tsd, normalizeTileSheet(*tilesheet)); OX_REQUIRE(tsd, normalizeTileSheet(*tilesheet));
for (auto const &s : entry.sections) { for (auto const&s : entry.sections) {
auto const size = s.tiles * PixelsPerTile; auto const size = s.tiles * PixelsPerTile;
for (auto i = 0; i < size; ++i) { for (auto i = 0; i < size; ++i) {
auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile); auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile);
@@ -667,7 +669,7 @@ static ox::Result<TileSheetData> buildSetTsd(
} }
static void copyPixels( static void copyPixels(
CompactTileSheet const &ts, CompactTileSheet const&ts,
ox::Span<uint32_t> const dst, ox::Span<uint32_t> const dst,
size_t const srcPxIdx, size_t const srcPxIdx,
size_t const pxlCnt) noexcept { size_t const pxlCnt) noexcept {
@@ -702,7 +704,7 @@ void clearCbbs(Context &ctx) noexcept {
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
CompactTileSheet const &ts, CompactTileSheet const&ts,
size_t const dstTileIdx, size_t const dstTileIdx,
size_t const srcTileIdx, size_t const srcTileIdx,
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
@@ -726,8 +728,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
uint_t const cbb, uint_t const cbb,
CompactTileSheet const &ts, CompactTileSheet const&ts,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const&paletteBank) noexcept {
auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4))); auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4)));
auto const tiles = ts.pixels.size() / bytesPerTile; auto const tiles = ts.pixels.size() / bytesPerTile;
OX_RETURN_ERROR(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles)); OX_RETURN_ERROR(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles));
@@ -740,7 +742,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
TileSheetSet const &set) noexcept { TileSheetSet const&set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set)); OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data()); ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {}; return {};
@@ -748,7 +750,7 @@ ox::Error loadBgTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
CompactTileSheet const &ts, CompactTileSheet const&ts,
bool const loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
OX_REQUIRE(tsd, normalizeTileSheet(ts)); OX_REQUIRE(tsd, normalizeTileSheet(ts));
oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height); oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
@@ -761,7 +763,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const &set) noexcept { TileSheetSet const&set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set)); OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data()); ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {}; return {};
@@ -772,18 +774,18 @@ void setBgTile(
uint_t const bgIdx, uint_t const bgIdx,
int const column, int const column,
int const row, int const row,
BgTile const &tile) noexcept { BgTile const&tile) noexcept {
oxTracef( oxTracef(
"nostalgia.gfx.setBgTile", "nostalgia.gfx.setBgTile",
"bgIdx: {}, column: {}, row: {}, tile: {}, palBank: {}", "bgIdx: {}, column: {}, row: {}, tile: {}, palBank: {}",
bgIdx, column, row, tile.tileIdx, tile.palBank); bgIdx, column, row, tile.tileIdx, tile.palBank);
auto const z = static_cast<uint_t>(bgIdx); const auto z = static_cast<uint_t>(bgIdx);
auto const y = static_cast<uint_t>(row); const auto y = static_cast<uint_t>(row);
auto const x = static_cast<uint_t>(column); const auto x = static_cast<uint_t>(column);
auto const i = renderer::bgVertexRow(x, y); const auto i = renderer::bgVertexRow(x, y);
auto &cbb = ctx.cbbs[z]; auto &cbb = ctx.cbbs[z];
auto const vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength; const auto vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
auto const ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength; const auto ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength;
auto &bg = ctx.backgrounds[bgIdx]; auto &bg = ctx.backgrounds[bgIdx];
renderer::setTileBufferObject( renderer::setTileBufferObject(
static_cast<uint_t>(i * renderer::BgVertexVboRows), static_cast<uint_t>(i * renderer::BgVertexVboRows),
@@ -839,12 +841,6 @@ void setBgPriority(Context &ctx, uint_t const bgIdx, uint_t const priority) noex
bg.priority = static_cast<float>(priority & 0b11); bg.priority = static_cast<float>(priority & 0b11);
} }
void setBgOffset(Context&, uint16_t const, int16_t const, int16_t const) noexcept {
}
void scrollBgOffset(Context&, uint16_t const, int16_t const, int16_t const) noexcept {
}
void hideSprite(Context &ctx, uint_t const idx) noexcept { void hideSprite(Context &ctx, uint_t const idx) noexcept {
auto &s = ctx.spriteStates[idx]; auto &s = ctx.spriteStates[idx];
s.enabled = false; s.enabled = false;
@@ -857,7 +853,7 @@ void showSprite(Context &ctx, uint_t const idx) noexcept {
renderer::setSprite(ctx, idx, s); renderer::setSprite(ctx, idx, s);
} }
void setSprite(Context &ctx, uint_t const idx, Sprite const &sprite) noexcept { void setSprite(Context &ctx, uint_t const idx, Sprite const&sprite) noexcept {
auto &s = ctx.spriteStates[idx]; auto &s = ctx.spriteStates[idx];
s = sprite; s = sprite;
renderer::setSprite(ctx, idx, s); renderer::setSprite(ctx, idx, s);
@@ -873,7 +869,7 @@ ox::Size drawSize(int const scale) noexcept {
return {240 * scale, 160 * scale}; return {240 * scale, 160 * scale};
} }
void draw(Context &ctx, ox::Size const &renderSz) noexcept { void draw(Context &ctx, ox::Size const&renderSz) noexcept {
glViewport(0, 0, renderSz.width, renderSz.height); glViewport(0, 0, renderSz.width, renderSz.height);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND); glEnable(GL_BLEND);

View File

@@ -10,11 +10,11 @@ namespace nostalgia::gfx {
constexpr auto GbaTileColumns = 32; constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32; constexpr auto GbaTileRows = 32;
int tileColumns(Context const&) noexcept { int tileColumns(Context&) noexcept {
return GbaTileColumns; return GbaTileColumns;
} }
int tileRows(Context const&) noexcept { int tileRows(Context&) noexcept {
return GbaTileRows; return GbaTileRows;
} }
@@ -51,7 +51,7 @@ ox::Error loadSpritePalette(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
ox::FileAddress const &tsAddr, ox::FileAddress const&tsAddr,
size_t const dstTileIdx, size_t const dstTileIdx,
size_t const srcTileIdx, size_t const srcTileIdx,
size_t const tileCnt) noexcept { size_t const tileCnt) noexcept {
@@ -74,7 +74,7 @@ ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
ox::StringViewCR tilesheetPath, ox::StringViewCR tilesheetPath,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const&paletteBank) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetPath));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank); return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
} }
@@ -82,8 +82,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned const cbb, unsigned const cbb,
ox::FileAddress const &tilesheetAddr, ox::FileAddress const&tilesheetAddr,
ox::Optional<unsigned> const &paletteBank) noexcept { ox::Optional<unsigned> const&paletteBank) noexcept {
OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr)); OX_REQUIRE(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
return loadBgTileSheet(ctx, cbb, *ts, paletteBank); return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
} }
@@ -98,7 +98,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
ox::FileAddress const &tilesheetAddr, ox::FileAddress const&tilesheetAddr,
bool const loadDefaultPalette) noexcept { bool const loadDefaultPalette) noexcept {
OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr)); OX_REQUIRE(ts, readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette); return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
@@ -249,7 +249,7 @@ void setBgTile(
} }
ox::Error initConsole(Context &ctx) noexcept { ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.nts"); constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal"); constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001); setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0); setBgCbb(ctx, 0, 0);

View File

@@ -89,7 +89,7 @@ static class: public keel::Module {
} const mod; } const mod;
keel::Module const *keelModule() noexcept { keel::Module const*keelModule() noexcept {
return &mod; return &mod;
} }

View File

@@ -61,7 +61,7 @@ ox::Error convertPaletteV4ToPaletteV5(
for (auto &s : src.pages) { for (auto &s : src.pages) {
ox::Vector<PaletteColorV2> colors; ox::Vector<PaletteColorV2> colors;
colors.reserve(s.colors.size()); colors.reserve(s.colors.size());
for (auto const &c : s.colors) { for (auto const&c : s.colors) {
colors.emplace_back(c.r, c.g, c.b, c.a); colors.emplace_back(c.r, c.g, c.b, c.a);
} }
dst.pages.emplace_back(PalettePageV2{ dst.pages.emplace_back(PalettePageV2{

View File

@@ -8,6 +8,7 @@
#include <keel/typeconv.hpp> #include <keel/typeconv.hpp>
#include <nostalgia/gfx/context.hpp>
#include <nostalgia/gfx/palette.hpp> #include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp> #include <nostalgia/gfx/tilesheet.hpp>

View File

@@ -26,4 +26,3 @@ install(
add_subdirectory(paletteeditor) add_subdirectory(paletteeditor)
add_subdirectory(tilesheeteditor) add_subdirectory(tilesheeteditor)
add_subdirectory(subcommands)

View File

@@ -72,7 +72,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::Context &sctx, ox::StringParam pa
Editor(sctx, std::move(path)), Editor(sctx, std::move(path)),
m_sctx(sctx), m_sctx(sctx),
m_tctx(sctx.tctx), m_tctx(sctx.tctx),
m_pal(m_sctx.project->loadObj<Palette>(itemPath()).unwrapThrow()) { m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) {
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand); undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage); m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
} }

View File

@@ -20,7 +20,7 @@ class PaletteEditorImGui: public studio::Editor {
bool m_show = false; bool m_show = false;
public: public:
ox::Signal<ox::Error(ox::StringView name)> inputSubmitted; ox::Signal<ox::Error(ox::StringView name)> inputSubmitted;
constexpr void show(ox::StringView const &name) noexcept { constexpr void show(ox::StringView const&name) noexcept {
m_show = true; m_show = true;
m_name = name; m_name = name;
} }

View File

@@ -8,25 +8,10 @@
#include "paletteeditor/paletteeditor-imgui.hpp" #include "paletteeditor/paletteeditor-imgui.hpp"
#include "tilesheeteditor/tilesheeteditor-imgui.hpp" #include "tilesheeteditor/tilesheeteditor-imgui.hpp"
#include "subcommands/export-tilesheet/export-tilesheet.hpp"
namespace nostalgia::gfx { namespace nostalgia::gfx {
static struct: studio::Module { static class: public studio::Module {
ox::String id() const noexcept final {
return ox::String{"net.drinkingtea.nostalgia.gfx"};
}
ox::Vector<studio::Command> commands() const final {
return {
{
"export-tilesheet",
cmdExportTilesheet,
}
};
}
ox::Vector<studio::EditorMaker> editors(studio::Context &ctx) const noexcept final { ox::Vector<studio::EditorMaker> editors(studio::Context &ctx) const noexcept final {
return { return {
studio::editorMaker<TileSheetEditorImGui>(ctx, {FileExt_ng, FileExt_nts}), studio::editorMaker<TileSheetEditorImGui>(ctx, {FileExt_ng, FileExt_nts}),
@@ -43,10 +28,9 @@ static struct: studio::Module {
}, ox::ClawFormat::Organic)); }, ox::ClawFormat::Organic));
return out; return out;
} }
} const mod; } const mod;
studio::Module const *studioModule() noexcept { const studio::Module *studioModule() noexcept {
return &mod; return &mod;
} }

View File

@@ -1,10 +0,0 @@
target_sources(
NostalgiaGfx-Studio PRIVATE
export-tilesheet/export-tilesheet.cpp
)
target_link_libraries(
NostalgiaGfx-Studio PUBLIC
OxClArgs
)

View File

@@ -1,161 +0,0 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <lodepng.h>
#include <ox/clargs/clargs.hpp>
#include <ox/std/trace.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
#include "export-tilesheet.hpp"
#include "nostalgia/gfx/tilesheet.hpp"
#include "studio/context.hpp"
namespace nostalgia::gfx {
static ox::Vector<uint32_t> normalizePixelSizes(
ox::Vector<uint8_t> const &inPixels) noexcept {
ox::Vector<uint32_t> outPixels;
outPixels.reserve(inPixels.size());
outPixels.resize(inPixels.size());
for (size_t i{}; i < inPixels.size(); ++i) {
outPixels[i] = inPixels[i];
}
return outPixels;
}
static ox::Vector<uint32_t> normalizePixelArrangement(
ox::Vector<uint32_t> const &inPixels,
int const cols,
int const scale) {
auto const scalePt = ox::Point{scale, scale};
auto const width = cols * TileWidth;
auto const height = static_cast<int>(inPixels.size()) / width;
auto const dstWidth = width * scale;
ox::Vector<uint32_t> outPixels(static_cast<size_t>((width * scale) * (height * scale)));
for (size_t dstIdx{}; dstIdx < outPixels.size(); ++dstIdx) {
auto const dstPt = ox::Point{
static_cast<int>(dstIdx) % dstWidth,
static_cast<int>(dstIdx) / dstWidth};
auto const srcPt = dstPt / scalePt;
auto const srcIdx = ptToIdx(srcPt, cols);
outPixels[dstIdx] = inPixels[srcIdx];
}
return outPixels;
}
static ox::Error toPngFile(
ox::CStringViewCR path,
ox::Vector<uint32_t> &&pixels,
Palette const &pal,
size_t const page,
unsigned const width,
unsigned const height) noexcept {
for (auto &c : pixels) {
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
}
constexpr auto fmt = LCT_RGBA;
return ox::Error(static_cast<ox::ErrorCode>(
lodepng_encode_file(
path.c_str(),
reinterpret_cast<uint8_t const*>(pixels.data()),
width,
height,
fmt,
8)));
}
ox::Error exportSubsheetToPng(
TileSheet::SubSheet const &s,
Palette const &pal,
size_t const palPage,
ox::CStringViewCR dstPath,
int const scale) noexcept {
// subsheet to png
auto const width = s.columns * TileWidth;
auto const height = s.rows * TileHeight;
auto const err = toPngFile(
dstPath,
normalizePixelArrangement(
normalizePixelSizes(s.pixels),
s.columns,
scale),
pal,
palPage,
static_cast<unsigned>(width * scale),
static_cast<unsigned>(height * scale));
if (err) {
oxErrorf("TileSheet export failed: {}", toStr(err));
return ox::Error{7, "TileSheet export failed"};
}
return {};
}
ox::Error exportSubsheetToPng(
TileSheet const &src,
Palette const &pal,
ox::StringViewCR subsheetPath,
size_t const palPage,
ox::CStringViewCR dstPath,
int const scale) noexcept {
// subsheet to png
auto const [s, ssErr] = getSubSheet(
ox::split(subsheetPath, '.'), src);
if (ssErr) {
return ox::Error{6, "failed to find SubSheet"};
}
return exportSubsheetToPng(
*s,
pal,
palPage,
dstPath,
scale);
}
ox::Error cmdExportTilesheet(studio::Project &project, ox::SpanView<ox::CString> const args) noexcept {
// parse args
ox::ClArgs const clargs{args};
bool showUsage = true;
OX_DEFER [&showUsage] {
if (showUsage) {
oxErr("usage: export-tilesheet "
"-src-path <path> "
"-dst-path <path> "
"[-pal-path <path>] "
"[-subsheet-path <path>] "
"[-scale <int>]\n");
}
};
if (args.empty()) {
return {};
}
OX_REQUIRE(srcPath, clargs.getString("src-path").transformError(1, "no src path specified"));
OX_REQUIRE(dstPath, clargs.getString("dst-path").transformError(2, "no dst path specified"));
auto const palPath = clargs.getString("pal-path", "");
auto const subsheetPath = clargs.getString("subsheet-path").or_value(ox::String{"Root"});
auto const palPage = static_cast<size_t>(clargs.getInt("pal-page", 0));
auto const scale = clargs.getInt("scale", 1);
showUsage = false;
// load objects
auto &kctx = project.kctx();
OX_REQUIRE(ts, keel::readObj<TileSheet>(kctx, srcPath).transformError(4, "could not load TileSheet"));
OX_REQUIRE(pal, keel::readObj<Palette>(kctx, palPath.size() ? palPath : ts->defaultPalette)
.transformError(5, "could not load Palette"));
// export to the destination file
return exportSubsheetToPng(
*ts,
*pal,
subsheetPath,
palPage,
dstPath,
scale);
}
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/error.hpp>
#include <ox/std/span.hpp>
#include <ox/std/stringview.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
namespace nostalgia::gfx {
ox::Error exportSubsheetToPng(
TileSheet::SubSheet const &s,
Palette const &pal,
size_t palPage,
ox::CStringViewCR dstPath,
int scale) noexcept;
ox::Error exportSubsheetToPng(
TileSheet const &src,
Palette const &pal,
ox::StringViewCR subsheetPath,
size_t palPage,
ox::CStringViewCR dstPath,
int scale) noexcept;
ox::Error cmdExportTilesheet(studio::Project& project, ox::SpanView<ox::CString> args) noexcept;
}

View File

@@ -60,7 +60,7 @@ int AddSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::AddSubSheet); return static_cast<int>(CommandId::AddSubSheet);
} }
TileSheet::SubSheetIdx const &AddSubSheetCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const&AddSubSheetCommand::subsheetIdx() const noexcept {
return m_parentIdx; return m_parentIdx;
} }

View File

@@ -25,7 +25,7 @@ class AddSubSheetCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };

View File

@@ -37,7 +37,7 @@ constexpr bool operator==(int i, CommandId c) noexcept {
class TileSheetCommand: public studio::UndoCommand { class TileSheetCommand: public studio::UndoCommand {
public: public:
[[nodiscard]] [[nodiscard]]
virtual TileSheet::SubSheetIdx const &subsheetIdx() const noexcept = 0; virtual TileSheet::SubSheetIdx const&subsheetIdx() const noexcept = 0;
}; };
} }

View File

@@ -48,7 +48,7 @@ CutPasteCommand::CutPasteCommand(
ox::Error CutPasteCommand::redo() noexcept { ox::Error CutPasteCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const &c : m_changes) { for (const auto &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx);
} }
return {}; return {};
@@ -56,7 +56,7 @@ ox::Error CutPasteCommand::redo() noexcept {
ox::Error CutPasteCommand::undo() noexcept { ox::Error CutPasteCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const &c : m_changes) { for (const auto &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
} }
return {}; return {};

View File

@@ -30,10 +30,10 @@ class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> {
ox::Vector<Pixel> m_pixels; ox::Vector<Pixel> m_pixels;
public: public:
void addPixel(ox::Point const &pt, uint16_t colorIdx) noexcept; void addPixel(ox::Point const&pt, uint16_t colorIdx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<Pixel> const &pixels() const noexcept; ox::Vector<Pixel> const&pixels() const noexcept;
}; };
OX_MODEL_BEGIN(TileSheetClipboard::Pixel) OX_MODEL_BEGIN(TileSheetClipboard::Pixel)
@@ -67,9 +67,9 @@ class CutPasteCommand: public TileSheetCommand {
CommandId commandId, CommandId commandId,
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::Point const &dstStart, ox::Point const&dstStart,
ox::Point dstEnd, ox::Point dstEnd,
TileSheetClipboard const &cb); TileSheetClipboard const&cb);
ox::Error redo() noexcept final; ox::Error redo() noexcept final;
@@ -79,7 +79,7 @@ class CutPasteCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };

View File

@@ -66,7 +66,7 @@ int DeleteTilesCommand::commandId() const noexcept {
return static_cast<int>(CommandId::DeleteTile); return static_cast<int>(CommandId::DeleteTile);
} }
TileSheet::SubSheetIdx const &DeleteTilesCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const&DeleteTilesCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

View File

@@ -31,7 +31,7 @@ class DeleteTilesCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };

View File

@@ -74,7 +74,7 @@ DrawCommand::DrawCommand(
DrawCommand::DrawCommand( DrawCommand::DrawCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::SpanView<std::size_t> const &idxList, ox::SpanView<std::size_t> const&idxList,
int const palIdx) noexcept: int const palIdx) noexcept:
m_img(img), m_img(img),
m_subSheetIdx(std::move(subSheetIdx)), m_subSheetIdx(std::move(subSheetIdx)),
@@ -90,7 +90,7 @@ bool DrawCommand::append(std::size_t const idx) noexcept {
if (m_changes.back().value->idx != idx && getPixel(subsheet, idx) != m_palIdx) { if (m_changes.back().value->idx != idx && getPixel(subsheet, idx) != m_palIdx) {
// duplicate entries are bad // duplicate entries are bad
auto existing = find_if( auto existing = find_if(
m_changes.cbegin(), m_changes.cend(), [idx](auto const &c) { m_changes.cbegin(), m_changes.cend(), [idx](auto const&c) {
return c.idx == idx; return c.idx == idx;
}); });
if (existing == m_changes.cend()) { if (existing == m_changes.cend()) {
@@ -102,7 +102,7 @@ bool DrawCommand::append(std::size_t const idx) noexcept {
return false; return false;
} }
bool DrawCommand::append(ox::SpanView<std::size_t> const &idxList) noexcept { bool DrawCommand::append(ox::SpanView<std::size_t> const&idxList) noexcept {
auto out = false; auto out = false;
for (auto idx : idxList) { for (auto idx : idxList) {
out = append(idx) || out; out = append(idx) || out;
@@ -134,7 +134,7 @@ void DrawCommand::lineUpdate(ox::Point a, ox::Point b) noexcept {
ox::Error DrawCommand::redo() noexcept { ox::Error DrawCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const &c : m_changes) { for (auto const&c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(m_palIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(m_palIdx);
} }
return {}; return {};
@@ -142,7 +142,7 @@ ox::Error DrawCommand::redo() noexcept {
ox::Error DrawCommand::undo() noexcept { ox::Error DrawCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const &c : m_changes) { for (auto const&c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx); subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
} }
return {}; return {};
@@ -152,7 +152,7 @@ int DrawCommand::commandId() const noexcept {
return static_cast<int>(CommandId::Draw); return static_cast<int>(CommandId::Draw);
} }
TileSheet::SubSheetIdx const &DrawCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const&DrawCommand::subsheetIdx() const noexcept {
return m_subSheetIdx; return m_subSheetIdx;
} }

View File

@@ -33,12 +33,12 @@ class DrawCommand: public TileSheetCommand {
DrawCommand( DrawCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::SpanView<std::size_t> const &idxList, ox::SpanView<std::size_t> const&idxList,
int palIdx) noexcept; int palIdx) noexcept;
bool append(std::size_t idx) noexcept; bool append(std::size_t idx) noexcept;
bool append(ox::SpanView<std::size_t> const &idxList) noexcept; bool append(ox::SpanView<std::size_t> const&idxList) noexcept;
void lineUpdate(ox::Point a, ox::Point b) noexcept; void lineUpdate(ox::Point a, ox::Point b) noexcept;
@@ -50,7 +50,7 @@ class DrawCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
void finish() noexcept; void finish() noexcept;

View File

@@ -30,7 +30,7 @@ class FlipXCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };
@@ -56,7 +56,7 @@ class FlipYCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };

View File

@@ -62,7 +62,7 @@ int InsertTilesCommand::commandId() const noexcept {
return static_cast<int>(CommandId::InsertTile); return static_cast<int>(CommandId::InsertTile);
} }
TileSheet::SubSheetIdx const &InsertTilesCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const&InsertTilesCommand::subsheetIdx() const noexcept {
return m_idx; return m_idx;
} }

View File

@@ -31,7 +31,7 @@ class InsertTilesCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };

View File

@@ -33,7 +33,7 @@ int MoveSubSheetCommand::commandId() const noexcept {
return static_cast<int>(CommandId::MoveSubSheet); return static_cast<int>(CommandId::MoveSubSheet);
} }
TileSheet::SubSheetIdx const &MoveSubSheetCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const&MoveSubSheetCommand::subsheetIdx() const noexcept {
return *m_active; return *m_active;
} }

View File

@@ -26,7 +26,7 @@ class MoveSubSheetCommand: public TileSheetCommand {
int commandId() const noexcept final; int commandId() const noexcept final;
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const&subsheetIdx() const noexcept override;
}; };

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