Compare commits

..

1 Commits

Author SHA1 Message Date
870fb9c6e3 [nostalgia/studio] Set version to d2025.07.0
All checks were successful
Build / build (push) Successful in 1m17s
2025-07-31 22:07:22 -05:00
75 changed files with 1063 additions and 1384 deletions

View File

@@ -14,7 +14,7 @@ endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.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}
.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/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run
run: build-player
${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio
run-studio: build-studio
run-studio: build
${PROJECT_STUDIO}
.PHONY: gba-run
gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug
debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba
configure-gba:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}

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

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

View File

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

View File

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

View File

@@ -135,7 +135,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
ox::expect(actual, expected);
oxExpect(actual, expected);
return ox::Error{};
}
},

View File

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

View File

@@ -74,9 +74,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
ox::PathIterator it(path);
ox::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error");
ox::expect(buff, "usr");
oxExpect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error");
ox::expect(buff, "share");
oxExpect(buff, "share");
return ox::Error(0);
}
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -133,17 +133,17 @@ struct SpanIterator {
}
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];
}
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];
}
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];
}

View File

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

View File

@@ -47,7 +47,7 @@ class Span {
}
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_size(a.size()) {
}
@@ -60,7 +60,7 @@ class Span {
}
template<std::size_t sz>
constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const &a) noexcept:
constexpr Span(ox::Array<ox::remove_const_t<T>, sz> const&a) noexcept:
m_items(a.data()),
m_size(a.size()) {
}
@@ -72,7 +72,7 @@ class Span {
}
template<std::size_t sz, typename Allocator>
constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const &v) noexcept:
constexpr Span(ox::Vector<ox::remove_const_t<T>, sz, Allocator> const&v) noexcept:
m_items(v.data()),
m_size(v.size()) {
}
@@ -147,17 +147,17 @@ class Span {
}
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];
}
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};
}
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_size -= i;
return *this;

View File

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

View File

@@ -23,12 +23,12 @@ class StringLiteral: public detail::BaseStringView {
constexpr StringLiteral(StringLiteral const &sv) noexcept = default;
consteval StringLiteral(std::nullptr_t) noexcept {}
consteval explicit StringLiteral(std::nullptr_t) noexcept {}
consteval StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {}
consteval explicit StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
consteval StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
consteval explicit StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
OX_ALLOW_UNSAFE_BUFFERS_END
constexpr StringLiteral &operator=(StringLiteral const &other) noexcept {

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] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID")
add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")
add_test("[ox/std] intToStr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "intToStr")

View File

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

View File

@@ -268,7 +268,7 @@ using TraceStream = NullStream;
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox.error");
TraceStream trc(file, line, "ox::error");
if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
} 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 {
if (err) {
TraceStream trc(file, line, "ox.error");
TraceStream trc(file, line, "ox::error");
trc << "Error:" << err;
if (err.src.file_name() != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";

View File

@@ -63,6 +63,25 @@ namespace ox {
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>
struct SignedType {
};

View File

@@ -180,6 +180,20 @@ struct is_same<T, T>: true_type {};
template<typename T, typename U>
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>
struct is_pointer {
static constexpr bool value = false;
@@ -223,9 +237,6 @@ struct remove_pointer<T* const volatile> {
using type = T;
};
template<typename T>
using remove_pointer_t = typename remove_pointer<T>::type;
template<typename T>
struct remove_reference {

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {};
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(const 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
if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap);
@@ -49,26 +49,42 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom(
T **items,
VectorAllocator *src,
std::size_t const count,
std::size_t const cap) noexcept {
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 (auto i = 0u; i < count; ++i) {
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
new (&m_data[i]) T(std::move(*srcItem));
}
if (count) {
*items = std::launder(reinterpret_cast<T*>(m_data.data()));
} else {
*items = reinterpret_cast<T*>(m_data.data());
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
std::construct_at<T>(dstItem, std::move(*srcItem));
}
*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
if (std::is_constant_evaluated()) {
if (items) {
@@ -87,10 +103,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> {
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(const 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);
}
@@ -98,15 +114,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom(
T**,
VectorAllocator*,
std::size_t const,
std::size_t const) noexcept {
const std::size_t,
const std::size_t) noexcept {
}
[[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) {
Allocator{}.deallocate(items, cap);
}
@@ -247,8 +263,6 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr void resize(std::size_t size) noexcept(useNoexcept);
constexpr void reserveResize(std::size_t size) noexcept(useNoexcept);
[[nodiscard]]
constexpr T *data() noexcept {
return m_items;
@@ -263,7 +277,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr bool contains(MaybeView_t<T> const&) const noexcept;
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);
@@ -273,9 +287,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args>
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);
@@ -409,7 +421,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size;
m_cap = other.m_cap;
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_cap = 0;
other.m_items = nullptr;
@@ -419,13 +431,13 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
template<typename T, std::size_t SmallVectorSize, typename Allocator>
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];
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
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];
}
@@ -520,13 +532,7 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(std::size_t const size) noexcept(useNoexcept) {
reserve(size);
resize(size);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const &v) const noexcept {
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
for (std::size_t i = 0; i < m_size; ++i) {
if (m_items[i] == v) {
return true;
@@ -538,7 +544,7 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> co
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
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) {
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
}
@@ -611,16 +617,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &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) {
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}

View File

@@ -99,23 +99,23 @@ volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
/////////////////////////////////////////////////////////////////
// Memory Addresses
#define MEM_EWRAM (*(reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000)))
#define MEM_EWRAM (*reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000))
#define MEM_IWRAM (*(reinterpret_cast<ox::Array<uint8_t, 0x0300'7FFF - 0x0300'0000>*>(0x0300'0000)))
#define MEM_IWRAM (*reinterpret_cast<ox::Array<uint8_t, 0x0300'7FFF - 0x0300'0000>*>(0x0300'0000))
#define REG_BLNDCTL (*reinterpret_cast<uint16_t*>(0x0400'0050))
using Palette = ox::Array<uint16_t, 128>;
#define MEM_BG_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0000)))
#define MEM_SPRITE_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0200)))
#define MEM_BG_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0000))
#define MEM_SPRITE_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0200))
using BgMapTile = ox::Array<uint16_t, 8192>;
#define MEM_BG_TILES (*(reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000)))
#define MEM_BG_MAP (*(reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000)))
#define MEM_BG_TILES (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000))
#define MEM_BG_MAP (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000))
#define MEM_SPRITE_TILES (*(reinterpret_cast<ox::Array<uint16_t, 32 * ox::units::KB>*>(0x0601'0000)))
#define MEM_OAM (*(reinterpret_cast<ox::Array<uint64_t, 64>*>(0x0700'0000)))
#define MEM_SPRITE_TILES (*reinterpret_cast<ox::Array<uint16_t, 32 * ox::units::KB>*>(0x0601'0000))
#define MEM_OAM (*reinterpret_cast<ox::Array<uint64_t, 64>*>(0x0700'0000))
#define MEM_ROM (*(reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000)))
#define MEM_ROM (*reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000))
#define MEM_SRAM (*(reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000)))
#define MEM_SRAM (*reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000))

View File

@@ -43,4 +43,6 @@ void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
}

View File

@@ -18,7 +18,7 @@ GbaSpriteAttrUpdate &spriteAttr(size_t const i) noexcept {
void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept {
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;
REG_IE = ie; // enable vblank interrupt handler
}
@@ -35,4 +35,10 @@ void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
o.y = y;
}
void scrollBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = o.x + x;
o.y = o.y + y;
}
}

View File

@@ -27,9 +27,9 @@ All components have a platform indicator next to them:
* opengl - OpenGL implementation (P-)
* studio - studio plugin for core (P-)
* keel - keel plugin for core (PG)
* sound - sound system for Nostalgia (PG)
* studio - studio plugin for sound (P-)
* keel - keel plugin for sound (PG)
* scene - defines & processes map data (PG)
* studio - studio plugin for scene (P-)
* keel - keel plugin for scene (PG)
* player - plays the games (PG)
* studio - makes the games (P-)
* tools - command line tools (P-)
@@ -48,7 +48,7 @@ All components have a platform indicator next to them:
Not really that external... (PG)
* GlUtils - OpenGL helpers (P-)
* 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
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
reason, but there are reasons for many of these duplications of functionality.
The C++ language designers aren't stupid.
Question them, but don't ignore them.
The C++ language designers aren't stupid. Question them, but don't ignore them.
#### Casting
@@ -164,11 +163,10 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling
Instead of throwing exceptions, generally try to use
[ox::Error](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
convert them to ```ox::Error``` as soon as possible.
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting,
but exceptions may be used where they make sense.
Exceptions should generally just use ```ox::Exception```, which is basically an
Exceptions should generally just use ```OxException```, which is bascially an
exception form of ```ox::Error```.
### File I/O

View File

@@ -23,15 +23,17 @@ struct BgCbbData {
unsigned bpp = 4;
};
class Context final {
class Context {
public:
turbine::Context &turbineCtx;
ox::Array<BgCbbData, 4> cbbData;
ox::Array<OffsetPair, 4> bgOffsets;
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
Context(Context &other) noexcept = delete;
Context(Context const &other) noexcept = delete;
Context(Context const &&other) noexcept = delete;
virtual ~Context() noexcept = default;
};
@@ -293,16 +295,12 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
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};
void setBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
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 scrollBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::scrollBgOffset(bg, x, y);
}
void hideSprite(Context&, unsigned const idx) noexcept {
@@ -321,23 +319,23 @@ 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");
uint16_t const eightBpp = sprite.bpp == 8;
uint16_t const eightBpp = s.bpp == 8;
teagba::addSpriteUpdate({
.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>(eightBpp) << 13)
| (static_cast<uint16_t>(sprite.spriteShape) << 14)),
| (static_cast<uint16_t>(s.spriteShape) << 14)),
.attr1 = static_cast<uint16_t>(
(static_cast<uint16_t>(sprite.x) & ox::onMask<uint8_t>(8))
| (static_cast<uint16_t>(sprite.flipX) << 12)
| (static_cast<uint16_t>(sprite.spriteSize) << 14)),
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
| (static_cast<uint16_t>(s.flipX) << 12)
| (static_cast<uint16_t>(s.spriteSize) << 14)),
.attr2 = static_cast<uint16_t>(
// double tileIdx if 8 bpp
(static_cast<uint16_t>((sprite.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8)))
| (static_cast<uint16_t>(sprite.priority & 0b11) << 10)),
(static_cast<uint16_t>((s.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8)))
| (static_cast<uint16_t>(s.priority & 0b11) << 10)),
.idx = static_cast<uint16_t>(idx),
});
}
@@ -350,7 +348,7 @@ uint_t spriteCount(Context const &) noexcept {
namespace ox {
void panic(char const*panicMsg, Error const&err, std::source_location const &src) noexcept {
void panic(char const *file, int line, char const *panicMsg, ox::Error const &err) noexcept {
using namespace nostalgia::gfx;
// reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
@@ -374,7 +372,7 @@ void panic(char const*panicMsg, Error const&err, std::source_location const &src
}
consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
// 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) {
oxErrf("\tError Message:\t{}\n", err.msg);
}

View File

@@ -87,7 +87,9 @@ class Context {
blocksPerSprite{params.glBlocksPerSprite} {
}
Context(Context const&) = delete;
Context(Context&&) = delete;
Context &operator=(Context const&) = delete;
Context &operator=(Context&&) = delete;
~Context() noexcept {
turbine::gl::removeDrawer(turbineCtx, &drawer);
}
@@ -111,7 +113,7 @@ namespace renderer {
static constexpr auto Scale = 1;
static constexpr auto PriorityScale = 0.01f;
static constexpr ox::StringLiteral bgvshadTmpl{R"glsl(
static constexpr ox::CStringView bgvshadTmpl = R"glsl(
{}
in vec2 vTexCoord;
in vec3 vPosition;
@@ -133,9 +135,9 @@ static constexpr ox::StringLiteral bgvshadTmpl{R"glsl(
vTexCoord.x,
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
fPalOffset = vPalOffset;
})glsl"};
})glsl";
static constexpr ox::StringLiteral bgfshadTmpl{R"glsl(
static constexpr ox::CStringView bgfshadTmpl = R"glsl(
{}
out vec4 outColor;
in float fPalOffset;
@@ -149,9 +151,9 @@ static constexpr ox::StringLiteral bgfshadTmpl{R"glsl(
if (outColor.a == 0) {
discard;
}
})glsl"};
})glsl";
static constexpr ox::StringLiteral spritevshadTmpl{R"glsl(
static constexpr ox::CStringView spritevshadTmpl = R"glsl(
{}
in float vEnabled;
in vec3 vPosition;
@@ -168,9 +170,9 @@ static constexpr ox::StringLiteral spritevshadTmpl{R"glsl(
vPosition.z - 0.004,
1.0) * vEnabled;
fTexCoord = vTexCoord * vec2(1, vTileHeight);
})glsl"};
})glsl";
static constexpr ox::StringLiteral spritefshadTmpl{R"glsl(
static constexpr ox::CStringView spritefshadTmpl = R"glsl(
{}
out vec4 outColor;
in vec2 fTexCoord;
@@ -183,7 +185,7 @@ static constexpr ox::StringLiteral spritefshadTmpl{R"glsl(
if (outColor.a == 0) {
discard;
}
})glsl"};
})glsl";
[[nodiscard]]
static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept {
@@ -839,12 +841,6 @@ void setBgPriority(Context &ctx, uint_t const bgIdx, uint_t const priority) noex
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 {
auto &s = ctx.spriteStates[idx];
s.enabled = false;

View File

@@ -5,13 +5,6 @@
#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 {

View File

@@ -3,6 +3,7 @@
*/
#include <imgui.h>
#include <lodepng.h>
#include <ox/std/point.hpp>
#include <keel/media.hpp>

View File

@@ -57,6 +57,7 @@ class TileSheetEditorImGui: public studio::Editor {
ox::Vec2 m_prevMouseDownPos;
TileSheetTool m_tool = TileSheetTool::Draw;
bool m_palPathFocused{};
ox::Vector<ox::UPtr<studio::UndoCommand>, 1> m_deferredCmds;
public:
TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path);

View File

@@ -69,7 +69,7 @@ void TileSheetGrid::update(ox::Vec2 const &paneSize, TileSheet::SubSheet const &
glBindVertexArray(m_bufferSet.vao);
setBufferObjects(paneSize, subsheet);
glutils::sendVbo(m_bufferSet);
//glutils::sendEbo(m_bufferSet);
glutils::sendEbo(m_bufferSet);
}
void TileSheetGrid::setBufferObject(
@@ -89,6 +89,7 @@ void TileSheetGrid::setBufferObject(
void TileSheetGrid::setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept {
if (subsheet.columns < 1 || subsheet.rows < 1) {
m_bufferSet.elements.clear();
m_bufferSet.vertices.clear();
return;
}

View File

@@ -8,4 +8,4 @@ target_link_libraries(
NostalgiaGfx
)
add_test("[nostalgia/gfx] readWriteTileSheet" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/NostalgiaGfxTest readWriteTileSheet)
add_test("[NostalgiaGfx] readWriteTileSheet" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/NostalgiaGfxTest readWriteTileSheet)

View File

@@ -18,7 +18,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
gfx::TileSheet const in;
OX_REQUIRE(buff, ox::writeMC(in));
OX_REQUIRE(out, ox::readMC<gfx::TileSheet>(buff));
ox::expect(in.subsheet.name, out.subsheet.name);
oxAssert(in.subsheet.name == out.subsheet.name, "subsheet.name serialization broken");
return {};
}
},

View File

@@ -15,7 +15,7 @@ target_link_libraries(
target_compile_definitions(
NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="dev build"
OLYMPIC_APP_VERSION="d2025.07.0"
)
install(

View File

@@ -18,7 +18,7 @@
<string>APPL</string>
<key>CFBundleVersion</key>
<string>dev build</string>
<string>d2025.07.0</string>
<key>LSMinimumSystemVersion</key>
<string>12.0.0</string>

View File

@@ -13,11 +13,11 @@ namespace keel {
constexpr auto K1HdrSz = 40;
ox::Result<ox::UUID> readUuidHeader(ox::BufferView const &buff) noexcept;
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept;
ox::Result<ox::UUID> regenerateUuidHeader(ox::Buffer &buff) noexcept;
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const &uuid) noexcept {
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexcept {
OX_RETURN_ERROR(write(writer, "K1;"));
OX_RETURN_ERROR(uuid.toString(writer));
return writer.put(';');
@@ -35,15 +35,15 @@ ox::Result<T> readAsset(ox::BufferView buff) noexcept {
return out;
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView const &buff) noexcept;
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept;
struct AssetHdr {
ox::UUID uuid;
ox::ClawHeader clawHdr;
};
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const &buff) noexcept;
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView buff) noexcept;
ox::Result<AssetHdr> readAssetHeader(ox::BufferView const &buff) noexcept;
ox::Result<AssetHdr> readAssetHeader(ox::BufferView buff) noexcept;
}

View File

@@ -351,23 +351,23 @@ class AssetManager {
template<typename T>
class AssetRef {
private:
T const *m_obj = nullptr;
T const* m_obj = nullptr;
public:
constexpr AssetRef() noexcept = default;
explicit constexpr AssetRef(T const *obj) noexcept: m_obj(obj) {
explicit constexpr AssetRef(T const*obj) noexcept: m_obj(obj) {
}
constexpr T const *get() const noexcept {
constexpr T const*get() const noexcept {
return m_obj;
}
constexpr T const &operator*() const & noexcept {
constexpr T const&operator*() const & noexcept {
return *m_obj;
}
constexpr T const *operator->() const noexcept {
constexpr T const*operator->() const noexcept {
return m_obj;
}

View File

@@ -35,7 +35,7 @@ class Context {
};
constexpr ox::SpanView<PackTransform> packTransforms(
[[maybe_unused]] Context const &ctx) noexcept {
[[maybe_unused]] Context const&ctx) noexcept {
#ifndef OX_BARE_METAL
return ctx.packTransforms;
#else
@@ -44,7 +44,7 @@ constexpr ox::SpanView<PackTransform> packTransforms(
}
constexpr ox::SpanView<Converter> converters(
[[maybe_unused]] Context const &ctx) noexcept {
[[maybe_unused]] Context const&ctx) noexcept {
#ifndef OX_BARE_METAL
return ctx.converters;
#else

View File

@@ -29,22 +29,22 @@ OX_MODEL_BEGIN(PreloadPtr)
OX_MODEL_FIELD(preloadAddr)
OX_MODEL_END()
ox::Result<std::size_t> getPreloadAddr(Context &ctx, ox::FileAddress const &addr) noexcept;
ox::Result<std::size_t> getPreloadAddr(Context &ctx, ox::FileAddress const&addr) noexcept;
ox::Result<std::size_t> getPreloadAddr(Context &ctx, ox::StringViewCR path) noexcept;
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const &uuid) noexcept;
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const&uuid) noexcept;
// map of UUIDs to paths
using DuplicateSet = ox::HashMap<ox::UUID, ox::Vector<ox::String>>;
ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::StringViewCR path) noexcept;
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const &fileAddr) noexcept;
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept;
ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringViewCR path) noexcept;
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const &fileAddr) noexcept;
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept;
ox::Result<ox::CStringView> getPath(Context &ctx, ox::CStringViewCR fileId) noexcept;
@@ -58,7 +58,7 @@ ox::Result<ox::CStringView> uuidUrlToPath(Context &ctx, ox::StringViewCR uuid) n
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noexcept;
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const &uuid) noexcept;
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
[[nodiscard]]
constexpr bool isUuidUrl(ox::StringViewCR path) noexcept {
@@ -147,7 +147,7 @@ template<typename T>
ox::Result<AssetRef<T>> readObj(
Context &ctx,
ox::StringViewCR assetId,
[[maybe_unused]] bool const forceLoad = false) noexcept {
[[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
return readObjFile<T>(ctx, assetId, forceLoad);
#else
@@ -158,8 +158,8 @@ ox::Result<AssetRef<T>> readObj(
template<typename T>
ox::Result<AssetRef<T>> readObj(
Context &ctx,
ox::FileAddress const &file,
[[maybe_unused]] bool const forceLoad = false) noexcept {
ox::FileAddress const&file,
[[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
OX_REQUIRE(assetId, file.getPath());
return readObj<T>(ctx, ox::StringView(assetId), forceLoad);
@@ -176,9 +176,9 @@ ox::Result<AssetRef<T>> readObj(
template<typename T>
ox::Error writeObj(
Context &ctx,
ox::FileAddress const &file,
T const &obj,
ox::ClawFormat const fmt = ox::ClawFormat::Metal) noexcept {
ox::FileAddress const&file,
T const&obj,
ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
OX_REQUIRE(objBuff, ox::writeClaw(obj, fmt));
return ctx.rom->write(file, objBuff.data(), objBuff.size());
}

View File

@@ -40,6 +40,6 @@ class Module {
void registerModule(Module const*mod) noexcept;
[[nodiscard]]
ox::Vector<keel::Module const*> const &modules() noexcept;
ox::Vector<keel::Module const*> const&modules() noexcept;
}

View File

@@ -125,7 +125,7 @@ ox::Error preloadObj(
OX_RETURN_ERROR(err);
keel::PreloadPtr const p{.preloadAddr = a};
OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff));
auto const &pbufSz = pl.buff().size();
auto const&pbufSz = pl.buff().size();
oxOutf("preloaded {} as a {} @ {} to {} / {}, total size: {}\n",
path, obj.type()->typeName, a, a + size, pbufSz - 1, pbufSz - a);
} else {
@@ -148,7 +148,7 @@ ox::Error preloadDir(
// copy
oxTracef("pack.preload", "path: {}", path);
OX_REQUIRE(fileList, romFs.ls(path));
for (auto const &name : fileList) {
for (auto const&name : fileList) {
auto const filePath = ox::sfmt("{}{}", path, name);
OX_REQUIRE(stat, romFs.stat(filePath));
if (stat.fileType == ox::FileType::Directory) {
@@ -169,7 +169,7 @@ ox::Error preloadDir(
}
template<typename PlatSpec>
ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const &fsBuff, ox::Preloader<PlatSpec> &pl) noexcept {
ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const&fsBuff, ox::Preloader<PlatSpec> &pl) noexcept {
constexpr auto padbin = [](ox::BufferWriter &w, unsigned factor) noexcept -> ox::Error {
return w.write(nullptr, factor - w.buff().size() % factor);
};
@@ -185,7 +185,7 @@ ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const &fsBuff, ox
OX_RETURN_ERROR(padbin(w, hdrSize));
OX_RETURN_ERROR(w.write(preloadHdr.data(), preloadHdr.bytes()));
OX_RETURN_ERROR(pl.offsetPtrs(binBuff.size()));
auto const &plBuff = pl.buff();
auto const&plBuff = pl.buff();
OX_RETURN_ERROR(w.write(plBuff.data(), plBuff.size()));
return {};
}

View File

@@ -122,7 +122,7 @@ class BaseConverter {
virtual ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
virtual ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
Context &ctx, ox::BufferView const &srcBuff) const noexcept = 0;
Context &ctx, ox::BufferView const&srcBuff) const noexcept = 0;
[[nodiscard]]
constexpr bool matches(
@@ -187,7 +187,7 @@ class ConverterFunc final: public BaseConverter {
}
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
Context &ctx, ox::BufferView const &srcBuff) const noexcept override {
Context &ctx, ox::BufferView const&srcBuff) const noexcept override {
OX_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value)));
@@ -214,13 +214,13 @@ class Converter {
}
[[nodiscard]]
BaseConverter const &converter() const noexcept {
return *std::launder(m_buff.data());
return *m_buff.data();
}
};
ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
ox::BufferView const &srcBuffer,
ox::BufferView const&srcBuffer,
ox::StringViewCR dstTypeName,
int dstTypeVersion) noexcept;
@@ -241,7 +241,7 @@ ox::Result<ox::UPtr<Wrap>> convert(
ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
auto const &src,
auto const&src,
ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept {
auto srcCpy = src;
@@ -258,13 +258,13 @@ ox::Result<DstType> convertObjToObj(
}
template<typename DstType>
ox::Result<DstType> convert(Context &ctx, ox::BufferView const &src) noexcept {
ox::Result<DstType> convert(Context &ctx, ox::BufferView const&src) noexcept {
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
return std::move(wrapCast<DstType>(*out));
}
template<typename DstType>
ox::Error convert(Context &ctx, ox::BufferView const &buff, DstType &outObj) noexcept {
ox::Error convert(Context &ctx, ox::BufferView const&buff, DstType &outObj) noexcept {
OX_REQUIRE(out, convert(ctx, buff, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
outObj = std::move(wrapCast<DstType>(*out));
return {};
@@ -279,7 +279,7 @@ ox::Error convertObjToObj(Context &ctx, auto &src, DstType &outObj) noexcept {
template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff(
Context &ctx, ox::BufferView const &src, ox::ClawFormat const fmt) noexcept {
Context &ctx, ox::BufferView const&src, ox::ClawFormat const fmt) noexcept {
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
}

View File

@@ -16,7 +16,7 @@ class TypeStore: public ox::TypeStore {
ox::String m_descPath;
public:
explicit TypeStore(ox::FileSystem &fs, ox::StringViewCR descPath) noexcept;
explicit TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept;
protected:
ox::Result<ox::UPtr<ox::DescriptorType>> loadDescriptor(ox::StringView typeId) noexcept override;

View File

@@ -6,7 +6,7 @@
namespace keel {
ox::Result<ox::UUID> readUuidHeader(ox::BufferView const &buff) noexcept {
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept {
if (buff.size() < K1HdrSz) [[unlikely]] {
return ox::Error{1, "Insufficient data to contain complete Keel header"};
}
@@ -27,15 +27,16 @@ ox::Result<ox::UUID> regenerateUuidHeader(ox::Buffer &buff) noexcept {
return id;
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView const &buff) noexcept {
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept {
std::size_t offset = 0;
if (!readUuidHeader(buff).error) {
offset = K1HdrSz;
}
return ox::readClaw(ts, buff + offset);
buff += offset;
return ox::readClaw(ts, buff);
}
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const &buff) noexcept {
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const buff) noexcept {
auto const err = readUuidHeader(buff).error;
auto const offset = err ? 0u : K1HdrSz;
if (offset >= buff.size()) [[unlikely]] {
@@ -44,14 +45,15 @@ ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const &buff) noexcept
return ox::readClawTypeId(buff + offset);
}
ox::Result<AssetHdr> readAssetHeader(ox::BufferView const &buff) noexcept {
ox::Result<AssetHdr> readAssetHeader(ox::BufferView buff) noexcept {
ox::Result<AssetHdr> out;
auto const err = readUuidHeader(buff).moveTo(out.value.uuid);
auto const offset = err ? 0u : K1HdrSz;
if (offset >= buff.size()) [[unlikely]] {
return ox::Error(1, "Buffer too small for expected data");
}
OX_RETURN_ERROR(ox::readClawHeader(buff + offset).moveTo(out.value.clawHdr));
buff += offset;
OX_RETURN_ERROR(ox::readClawHeader(buff).moveTo(out.value.clawHdr));
return out;
}

View File

@@ -16,7 +16,7 @@ static ox::Error init(
setRomFs(ctx, std::move(fs), *duplicateSet) :
setRomFs(ctx, std::move(fs));
#ifndef OX_BARE_METAL
auto const &mods = modules();
auto const&mods = modules();
for (auto &mod : mods) {
// register type converters
for (auto const c : mod->converters()) {

View File

@@ -24,10 +24,10 @@ ox::Result<char*> loadRom(ox::StringViewCR path) noexcept {
auto buff = new char[static_cast<std::size_t>(size)];
file.read(buff, size);
return buff;
} catch (std::ios_base::failure const &e) {
} catch (std::ios_base::failure const&e) {
oxErrorf("Could not read ROM file due to file IO failure: {}", e.what());
return ox::Error(2, "Could not read ROM file");
} catch (std::bad_alloc const &e) {
} catch (std::bad_alloc const&e) {
oxErrorf("Could not read ROM file due to new failure: {}", e.what());
return ox::Error(2, "Could not allocate memory for ROM file");
}
@@ -42,14 +42,14 @@ static void clearUuidMap(Context &ctx) noexcept {
ctx.pathToUuid.clear();
}
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const &uuid) noexcept {
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const&uuid) noexcept {
ctx.pathToUuid[filePath] = uuid;
ctx.uuidToPath[uuid.toString()] = filePath;
}
static ox::Error buildUuidMap(Context &ctx, ox::StringViewCR path, DuplicateSet *duplicates) noexcept {
OX_REQUIRE(files, ctx.rom->ls(path));
for (auto const &f : files) {
for (auto const&f : files) {
OX_REQUIRE_M(filePath, ox::join("/", ox::Array<ox::StringView, 2>{path, f}));
OX_REQUIRE(stat, ctx.rom->stat(filePath));
if (stat.fileType == ox::FileType::NormalFile) {
@@ -97,7 +97,7 @@ ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::StringViewCR path) noexcept {
#endif
}
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const &fileAddr) noexcept {
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
OX_REQUIRE(path, fileAddr.getPath());
return getUuid(ctx, path);
}
@@ -111,7 +111,7 @@ ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringViewCR path) noexcept {
}
}
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const &fileAddr) noexcept {
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
OX_REQUIRE(path, fileAddr.getPath());
if (beginsWith(path, "uuid://")) {
auto const uuid = substr(path, 7);
@@ -173,7 +173,7 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noex
#endif
}
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const &uuid) noexcept {
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept {
#ifndef OX_BARE_METAL
OX_REQUIRE_M(out, ctx.uuidToPath.at(uuid.toString()));
return ox::CStringView(*out);
@@ -240,7 +240,7 @@ ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::StringViewCR path
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
}
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const &addr) noexcept {
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const&addr) noexcept {
OX_REQUIRE(stat, ctx.rom->stat(addr));
OX_REQUIRE(buff, static_cast<ox::MemFS&>(*ctx.rom).directAccess(addr));
PreloadPtr p;

View File

@@ -8,14 +8,14 @@ namespace keel {
static ox::Vector<Module const*> mods;
void registerModule(Module const *mod) noexcept {
void registerModule(Module const*mod) noexcept {
if (mod) {
mods.emplace_back(mod);
}
}
[[nodiscard]]
ox::Vector<Module const*> const &modules() noexcept {
ox::Vector<Module const*> const&modules() noexcept {
return mods;
}

View File

@@ -32,7 +32,7 @@ static ox::Result<ox::Buffer> readFileBuff(ox::StringViewCR path) noexcept {
file.seekg(0, std::ios::beg);
file.read(buff.data(), static_cast<std::streamsize>(buff.size()));
return buff;
} catch (std::ios_base::failure const &e) {
} catch (std::ios_base::failure const&e) {
oxErrorf("Could not read OxFS file: {}", e.what());
return ox::Error(2, "Could not read OxFS file");
}

View File

@@ -144,7 +144,7 @@ static ox::Error transformClaw(
// copy
oxTracef("pack.transformClaw", "path: {}", path);
OX_REQUIRE(fileList, dest.ls(path));
for (auto const &name : fileList) {
for (auto const&name : fileList) {
auto const filePath = ox::sfmt("{}{}", path, name);
OX_REQUIRE(stat, dest.stat(filePath));
if (stat.fileType == ox::FileType::Directory) {
@@ -171,7 +171,7 @@ static ox::Error copy(
auto const childLogPrefix = ox::sfmt("{}\t", logPrefix);
// copy
OX_REQUIRE(fileList, src.ls(path));
for (auto const &name : fileList) {
for (auto const&name : fileList) {
auto const currentFile = ox::sfmt("{}{}", path, name);
if (beginsWith(name, ".")) {
continue;
@@ -187,7 +187,7 @@ static ox::Error copy(
OX_DEFER [&status] {
oxOutf(" {}\n", status);
};
OX_REQUIRE(buff, src.read(currentFile));
OX_REQUIRE_M(buff, src.read(currentFile));
// write file to dest
OX_RETURN_ERROR(dest.write(currentFile, buff));
status = "OK";

View File

@@ -9,12 +9,12 @@
namespace keel {
static ox::Result<BaseConverter const*> findConverter(
ox::SpanView<Converter> const &converters,
ox::SpanView<Converter> const&converters,
ox::StringViewCR srcTypeName,
int const srcTypeVersion,
ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept {
for (auto const &c : converters) {
for (auto const&c : converters) {
if (c.converter().matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
return &c.converter();
}
@@ -22,17 +22,17 @@ static ox::Result<BaseConverter const*> findConverter(
return ox::Error{1, "Could not find converter"};
};
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const &c, Context &ctx, ox::BufferView const &src) noexcept {
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const&c, Context &ctx, ox::BufferView const&src) noexcept {
return c.convertBuffToPtr(ctx, src);
}
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const &c, Context &ctx, Wrap &src) noexcept {
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const&c, Context &ctx, Wrap &src) noexcept {
return c.convertPtrToPtr(ctx, src);
}
static ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
ox::SpanView<Converter> const &converters,
ox::SpanView<Converter> const&converters,
auto &src,
ox::StringViewCR srcTypeName,
int const srcTypeVersion,
@@ -45,7 +45,7 @@ static ox::Result<ox::UPtr<Wrap>> convert(
return convert(*c, ctx, src);
}
// try to chain multiple converters
for (auto const &subConverter : converters) {
for (auto const&subConverter : converters) {
if (!subConverter.converter().dstMatches(dstTypeName, dstTypeVersion)) {
continue;
}
@@ -61,7 +61,7 @@ static ox::Result<ox::UPtr<Wrap>> convert(
ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
ox::BufferView const &srcBuffer,
ox::BufferView const&srcBuffer,
ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept {
OX_REQUIRE(hdr, readAssetHeader(srcBuffer));

View File

@@ -6,7 +6,7 @@
namespace keel {
TypeStore::TypeStore(ox::FileSystem &fs, ox::StringViewCR descPath) noexcept:
TypeStore::TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept:
m_fs(fs),
m_descPath(descPath) {
}

View File

@@ -19,13 +19,13 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
ox::Array<char, hdr.size()> buff;
ox::CharBuffWriter bw(buff);
OX_RETURN_ERROR(keel::writeUuidHeader(bw, uuid));
ox::expect(ox::StringView(buff.data(), buff.size()), hdr);
oxExpect(ox::StringView(buff.data(), buff.size()), hdr);
return {};
}
},
};
int main(int const argc, char const **argv) {
int main(int argc, char const **argv) {
int retval = -1;
if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)};

View File

@@ -31,7 +31,7 @@ ox::Result<T> getDragDropPayload(ox::CStringViewCR name) noexcept {
return ox::Error(1, "No drag/drop payload");
}
return ox::readClaw<T>({
std::launder(reinterpret_cast<char const*>(payload->Data)),
reinterpret_cast<char const*>(payload->Data),
static_cast<size_t>(payload->DataSize)});
}

View File

@@ -8,18 +8,13 @@ namespace studio {
void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept {
ox::String path = std::move(filePath);
if (keel::isUuidUrl(path)) {
if (beginsWith(path, "uuid://")) {
auto const [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path);
if (err) {
return;
}
path = p;
}
//if (
// auto const [np, err] = ctx.navStack.back();
// !err && np->filePath == path && np->navArgs == navArgs.view()) {
// return;
//}
ctx.navStack.resize(ctx.navIdx + 1);
ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()});
try {
@@ -54,9 +49,8 @@ void navigateBack(Context &ctx) noexcept {
}
void navigateForward(Context &ctx) noexcept {
auto const nextIdx = ctx.navIdx + 1;
while (nextIdx < ctx.navStack.size()) {
auto const &n = ctx.navStack[nextIdx];
while (ctx.navIdx < ctx.navStack.size()) {
auto const &n = ctx.navStack[ctx.navIdx];
try {
ctx.navCallback(n.filePath, n.navArgs);
} catch (std::exception const &e) {
@@ -64,7 +58,7 @@ void navigateForward(Context &ctx) noexcept {
oxErrf("navigateForward failed: {}", e.what());
}
if (!ctx.project->exists(n.filePath)) {
std::ignore = ctx.navStack.erase(nextIdx);
std::ignore = ctx.navStack.erase(ctx.navIdx);
continue;
}
++ctx.navIdx;

View File

@@ -285,11 +285,11 @@ static void handleKeyPress(Context &ctx, int const key, bool const down) noexcep
map[GLFW_KEY_ESCAPE] = Key::Escape;
return map;
}();
auto const eventHandler = keyEventHandler(ctx);
auto const keyIdx = static_cast<std::size_t>(key);
if (keyIdx < keyMap.size()) {
auto const k = keyMap[keyIdx];
setKeyDownStatus(ctx, k, down);
auto const eventHandler = keyEventHandler(ctx);
if (eventHandler) {
eventHandler(ctx, k, down);
}
@@ -306,9 +306,7 @@ static void handleGlfwMouseButtonEvent(
int) noexcept {
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
setMandatoryRefreshPeriod(ctx, ticksMs(ctx) + config::MandatoryRefreshPeriod);
if (ctx.mouseButtonEventHandler) {
ctx.mouseButtonEventHandler(ctx, btn, action == 1);
}
ctx.mouseButtonEventHandler(ctx, btn, action == 1);
}
static void handleGlfwKeyEvent(GLFWwindow *window, int const key, int, int const action, int) noexcept {