Compare commits

..

53 Commits

Author SHA1 Message Date
54d7c706eb [studio] Make FileInfo free resources on close
All checks were successful
Build / build (push) Successful in 1m15s
2026-02-06 21:36:39 -06:00
c9cb186462 [studio] Cleanup useless complexity
All checks were successful
Build / build (push) Successful in 1m16s
2026-02-06 21:28:46 -06:00
f204d01a3d [studio] FileInfo: reset file info when opening
All checks were successful
Build / build (push) Successful in 1m12s
2026-02-05 22:22:07 -06:00
62337bd29e [studio] FileInfo: Rename ID to Asset ID, allow for no value of fields
All checks were successful
Build / build (push) Successful in 1m12s
2026-02-05 22:15:00 -06:00
7b24b33849 [nostalgia] Update release notes
All checks were successful
Build / build (push) Successful in 1m11s
2026-02-05 21:40:10 -06:00
86c2c26d8d [studio] Fix warning
All checks were successful
Build / build (push) Successful in 1m11s
2026-02-05 21:35:39 -06:00
f8b2700ea7 [studio] Add Get Info file dialog
Some checks failed
Build / build (push) Failing after 1m9s
2026-02-05 21:32:36 -06:00
7848cbbbff [nostalgia/gfx/keel] Cleanup
All checks were successful
Build / build (push) Successful in 1m9s
2026-02-03 02:22:58 -06:00
96c5223e44 [ox/std] Fix possible false positive in HashMap::operator==
All checks were successful
Build / build (push) Successful in 1m13s
2026-01-30 21:03:58 -06:00
d19b848427 [ox/std] Reduce AnyPtr to 2/3 the size
All checks were successful
Build / build (push) Successful in 1m13s
2026-01-30 20:54:17 -06:00
c812051ec0 [nostalgia/gfx/studio] Cleanup
All checks were successful
Build / build (push) Successful in 1m11s
2026-01-30 00:31:19 -06:00
3c07eb2df7 [nostalgia/gfx/studio] Cleanup
All checks were successful
Build / build (push) Successful in 1m7s
2026-01-29 19:30:32 -06:00
ca851e1059 [ox] Cleanup some expensive headers
All checks were successful
Build / build (push) Successful in 1m7s
2026-01-28 22:55:26 -06:00
11e75cb6ca [ox/std] Add Error::reoriginate
All checks were successful
Build / build (push) Successful in 1m13s
2026-01-28 00:46:55 -06:00
8c4add57e4 [ox/std] Fix build
All checks were successful
Build / build (push) Successful in 1m17s
2026-01-28 00:45:26 -06:00
5e1698a321 [ox/std] Cleanup serialize code
Some checks failed
Build / build (push) Failing after 52s
2026-01-27 23:15:53 -06:00
3e95bc0842 [ox/model] Update style for ModelHandlerAdaptor 2026-01-27 23:09:53 -06:00
58e19fad48 [ox] Cleanup MetalClawWriter and FieldBitmapWriter 2026-01-27 23:05:03 -06:00
a3a56b24e8 [ox/std] Fix is_integer_v 2026-01-27 23:03:07 -06:00
7681830ca6 [ox] Remove some unnecessary const_casts 2026-01-27 23:01:36 -06:00
46a7331754 [ox/mc] Cleanup, fix possible overflow bug
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-26 00:55:55 -06:00
56c19ad2a6 [ox/std] Add remove_pointer_t alias 2026-01-26 00:46:12 -06:00
c6ecadf9a8 [ox/mc] Cleanup
All checks were successful
Build / build (push) Successful in 1m10s
2026-01-26 00:21:16 -06:00
2ed469f2dd [ox] Cleanup
All checks were successful
Build / build (push) Successful in 1m11s
2026-01-25 23:58:46 -06:00
53aea9731d [ox] Cleanup
All checks were successful
Build / build (push) Successful in 1m9s
2026-01-25 23:46:54 -06:00
0e028ff653 [ox] Cleanup
All checks were successful
Build / build (push) Successful in 1m10s
2026-01-25 22:05:49 -06:00
07688a2c29 [ox] Remove oxExpect macro
All checks were successful
Build / build (push) Successful in 1m9s
2026-01-25 21:52:26 -06:00
9ce4d3f8c7 [keel,nostalgia/gfx] Minor cleanup of tests 2026-01-25 21:51:10 -06:00
4aa8255c55 [ox] Update formatting in recently edited files
All checks were successful
Build / build (push) Successful in 1m11s
2026-01-25 21:26:44 -06:00
bfdfc10425 [nostalgia/gfx] Update panic
All checks were successful
Build / build (push) Successful in 1m11s
2026-01-25 21:11:54 -06:00
cdd574d873 [ox] Change panic and assert to use std::source_location 2026-01-25 21:11:22 -06:00
bc05bd12e5 [ox/model] Rename and fix isBString helpers
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-25 02:06:14 -06:00
b754c66cf5 [ox] Remove enable_if
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-23 01:38:53 -06:00
6a42303239 [ox/std] Slight optimization 2026-01-23 01:38:31 -06:00
7477ede222 [ox/std] Cleanup some enable_ifs
All checks were successful
Build / build (push) Successful in 1m7s
2026-01-21 23:35:19 -06:00
65e3153dda [ox/std] Add Union_c concept 2026-01-21 23:35:02 -06:00
53a224cf8f [ox/std] Cleanup 2026-01-21 23:34:36 -06:00
592e641ba9 [ox/std] Fix writeItoa to work with max length 64 bit ints
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-21 23:28:13 -06:00
689da4a019 [ox] Update docs
All checks were successful
Build / build (push) Successful in 1m10s
2026-01-21 21:04:17 -06:00
bdf7755ee2 [nostalgia/developer-handbook] Update developer handbook 2026-01-21 21:03:47 -06:00
63f627377d [ox/std] Remove excess char from intToStr return
All checks were successful
Build / build (push) Successful in 1m9s
2026-01-20 01:29:37 -06:00
ff9002ad9a [nostalgia/developer-handbook] Update error handling section
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-20 01:22:05 -06:00
4d0da022cf [ox] Update error handling docs
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-20 00:47:51 -06:00
02332d99b5 [ox] Fix issues in String Types section of docs
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-20 00:26:38 -06:00
a566ed2a8b [ox/std] Fix writeItoa to work with negatives
All checks were successful
Build / build (push) Successful in 1m9s
2026-01-19 23:00:16 -06:00
815c3d19bf [ox/std] Make StringLiteral constructors non-explicit
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-19 21:00:58 -06:00
522bb14f18 [ox/std] Fix intToStr to have room for negatives 2026-01-19 21:00:12 -06:00
f40d5515f9 [ox] Add strings section to docs
All checks were successful
Build / build (push) Successful in 1m11s
2026-01-18 19:00:24 -06:00
941d1d90dc [ox/std] Add Vector::reserveResize
All checks were successful
Build / build (push) Successful in 1m15s
2026-01-07 21:48:04 -06:00
3e880dcdcc [nostalgia/gfx/studio] Remove unused EBO management
All checks were successful
Build / build (push) Successful in 1m16s
2026-01-07 21:33:16 -06:00
03328ac10f [turbine/glfw] Fix to handle null click handler
All checks were successful
Build / build (push) Successful in 1m9s
2025-12-03 20:44:01 -06:00
63d0abaa3c [nostalgia/gfx/gba] Remove teagba scroll bg function call
All checks were successful
Build / build (push) Successful in 1m15s
2025-11-22 23:53:18 -06:00
ef2a8cda77 [teagba] Remove bg scroll, cleanup 2025-11-22 23:53:04 -06:00
72 changed files with 2028 additions and 1529 deletions

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

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

View File

@@ -40,7 +40,7 @@ ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
} }
bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept { bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept {
auto const [value, err] = m_bools.at(arg); auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }

View File

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

View File

@@ -52,8 +52,7 @@ Error readClaw(ox::BufferView buff, T &val) {
{ {
ox::BufferReader br({header.data, header.dataSize}); ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br); MetalClawReader reader(br);
ModelHandlerInterface handler(&reader); return model(reader.interface(), &val);
return model(&handler, &val);
} }
case ClawFormat::Organic: 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 hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3"); constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1})); OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
oxExpect(actual, expected); ox::expect(actual, expected);
return ox::Error{}; return ox::Error{};
} }
}, },

View File

@@ -74,9 +74,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
ox::PathIterator it(path); ox::PathIterator it(path);
ox::StringView buff; ox::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error"); oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "usr"); ox::expect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error"); oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "share"); ox::expect(buff, "share");
return ox::Error(0); return ox::Error(0);
} }
}, },
@@ -175,8 +175,8 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen); auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed."); oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
ox::FileStore32 fileStore(list, buffLen); ox::FileStore32 fileStore(list, buffLen);
oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed."); oxAssert(fileStore.write(4, str1, str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed."); oxAssert(fileStore.write(5, str2, str2Len, 1), "FileStore::write 2 failed.");
char str1Read[str1Len]; char str1Read[str1Len];
size_t str1ReadSize = 0; size_t str1ReadSize = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,7 +22,7 @@ class AnyPtrT {
private: private:
struct WrapBase { struct WrapBase {
virtual constexpr ~WrapBase() = default; virtual constexpr ~WrapBase() = default;
virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0; virtual constexpr WrapBase *copyTo(Span<char> s) const noexcept = 0;
virtual constexpr operator bool() const noexcept = 0; virtual constexpr operator bool() const noexcept = 0;
virtual void free() noexcept = 0; virtual void free() noexcept = 0;
}; };
@@ -32,7 +32,7 @@ class AnyPtrT {
T *data{}; T *data{};
explicit constexpr Wrap(T *pData) noexcept: data(pData) { explicit constexpr Wrap(T *pData) noexcept: data(pData) {
} }
constexpr WrapBase *copyTo(ox::Span<char> s) noexcept override { constexpr WrapBase *copyTo(Span<char> s) const noexcept override {
oxAssert(s.size() >= sizeof(Wrap), "too small buffer"); oxAssert(s.size() >= sizeof(Wrap), "too small buffer");
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
return new Wrap(data); return new Wrap(data);
@@ -49,8 +49,10 @@ class AnyPtrT {
} }
}; };
WrapBase *m_wrapPtr{}; union {
ox::Array<char, sizeof(Wrap<void*>)> m_wrapData; WrapBase *m_wrapPtr{};
AllocAlias<Wrap<void*>> m_wrapData;
} m_data;
public: public:
constexpr AnyPtrT() noexcept = default; constexpr AnyPtrT() noexcept = default;
@@ -58,25 +60,25 @@ class AnyPtrT {
template<typename T> template<typename T>
constexpr AnyPtrT(T *ptr) noexcept { constexpr AnyPtrT(T *ptr) noexcept {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
m_wrapPtr = new Wrap<T>(ptr); setWrapPtr(new Wrap<T>(ptr));
} else { } else {
m_wrapPtr = new(m_wrapData.data()) Wrap<T>(ptr); new(m_data.m_wrapData.data()) Wrap<T>(ptr);
} }
} }
constexpr AnyPtrT(AnyPtrT const&other) noexcept requires(!unique) { constexpr AnyPtrT(AnyPtrT const &other) noexcept requires(!unique) {
if (other) { if (other) {
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData); setWrapPtr(other.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
} }
} }
constexpr AnyPtrT(AnyPtrT &&other) noexcept { constexpr AnyPtrT(AnyPtrT &&other) noexcept {
if (other) { if (other) {
m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData); setWrapPtr(other.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_data.m_wrapPtr);
} }
other.m_wrapPtr = {}; m_data.m_wrapData = {};
} }
} }
@@ -85,7 +87,7 @@ class AnyPtrT {
free(); free();
} }
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_data.m_wrapPtr);
} }
} }
@@ -94,25 +96,31 @@ class AnyPtrT {
if constexpr(unique) { if constexpr(unique) {
free(); free();
} else if (std::is_constant_evaluated()) { } else if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_data.m_wrapPtr);
} }
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
m_wrapPtr = new Wrap(ptr); setWrapPtr(new Wrap(ptr));
} else { } else {
m_wrapPtr = new(m_wrapData.data()) Wrap(ptr); new(m_data.m_wrapData.data()) Wrap(ptr);
} }
return *this; return *this;
} }
constexpr AnyPtrT &operator=(AnyPtrT const&ptr) noexcept requires(!unique) { constexpr AnyPtrT &operator=(AnyPtrT const &ptr) noexcept requires(!unique) {
if (this != &ptr) { if (this != &ptr) {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_data.m_wrapPtr);
} }
if (ptr) { if (std::is_constant_evaluated()) {
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData); if (ptr) {
ptr.getWrapPtr()->copyTo(m_data.m_wrapData.buff);
}
} else { } else {
m_wrapPtr = nullptr; if (ptr) {
setWrapPtr(ptr.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
} else {
setWrapPtr(nullptr);
}
} }
} }
return *this; return *this;
@@ -123,43 +131,65 @@ class AnyPtrT {
if constexpr(unique) { if constexpr(unique) {
free(); free();
} else if (std::is_constant_evaluated()) { } else if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_data.m_wrapPtr);
} }
if (ptr) { if (ptr) {
m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData); setWrapPtr(ptr.getWrapPtr()->copyTo(m_data.m_wrapData.buff));
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(ptr.m_wrapPtr); ox::safeDelete(ptr.m_data.m_wrapPtr);
ptr.m_wrapPtr = nullptr; setWrapPtr(nullptr);
} }
} else { } else {
m_wrapPtr = nullptr; m_data = {};
} }
} }
return *this; return *this;
} }
constexpr operator bool() const noexcept { constexpr operator bool() const noexcept {
return m_wrapPtr && *m_wrapPtr; return getWrapPtr() && *getWrapPtr();
} }
constexpr void free() noexcept { constexpr void free() noexcept {
if (m_wrapPtr) { if (auto p = getWrapPtr()) {
m_wrapPtr->free(); p->free();
} }
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
ox::safeDelete(m_wrapPtr); ox::safeDelete(m_data.m_wrapPtr);
} }
m_wrapPtr = nullptr; m_data.m_wrapData = {};
} }
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T *get() const noexcept { constexpr T *get() const noexcept {
#ifdef OX_BARE_METAL if constexpr(defines::HasRTTI) {
return static_cast<Wrap<T>*>(m_wrapPtr)->data; return dynamic_cast<Wrap<T> const*>(getWrapPtr())->data;
#else }
return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data; return static_cast<Wrap<T> const*>(getWrapPtr())->data;
#endif }
private:
constexpr void setWrapPtr(WrapBase *ptr) noexcept {
if (std::is_constant_evaluated()) {
m_data.m_wrapPtr = ptr;
}
}
constexpr WrapBase *getWrapPtr() noexcept {
if (std::is_constant_evaluated()) {
return m_data.m_wrapPtr;
} else {
return std::launder(reinterpret_cast<WrapBase*>(m_data.m_wrapData.data()));
}
}
constexpr WrapBase const *getWrapPtr() const noexcept {
if (std::is_constant_evaluated()) {
return m_data.m_wrapPtr;
} else {
return std::launder(reinterpret_cast<WrapBase const*>(m_data.m_wrapData.data()));
}
} }
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -53,6 +53,12 @@ constexpr auto NDebug = true;
constexpr auto NDebug = false; constexpr auto NDebug = false;
#endif #endif
#if defined(OX_BARE_METAL)
constexpr auto HasRTTI = false;
#else
constexpr auto HasRTTI = true;
#endif
#if defined(__BIG_ENDIAN__) #if defined(__BIG_ENDIAN__)
constexpr auto BigEndian = true; constexpr auto BigEndian = true;
constexpr auto LittleEndian = false; constexpr auto LittleEndian = false;

View File

@@ -17,7 +17,7 @@ class exception {
virtual ~exception() = default; virtual ~exception() = default;
[[nodiscard]] [[nodiscard]]
virtual char const*what() const noexcept { virtual char const *what() const noexcept {
return ""; return "";
} }
}; };
@@ -37,22 +37,22 @@ using ErrorCode = uint16_t;
struct [[nodiscard]] Error { struct [[nodiscard]] Error {
std::source_location src; std::source_location src;
ox::CString msg = nullptr; CString msg = nullptr;
ErrorCode errCode = 0; ErrorCode errCode = 0;
constexpr Error() noexcept = default; constexpr Error() noexcept = default;
explicit constexpr Error( explicit constexpr Error(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const &src = std::source_location::current()) noexcept:
src{src}, src{src},
errCode{errCode} errCode{errCode}
{} {}
explicit constexpr Error( explicit constexpr Error(
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, CString const msg,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const &src = std::source_location::current()) noexcept:
src{src}, src{src},
msg{msg}, msg{msg},
errCode{errCode} errCode{errCode}
@@ -62,39 +62,51 @@ struct [[nodiscard]] Error {
return errCode; return errCode;
} }
constexpr Error reoriginate(
ErrorCode const pErrCode,
CString const pMsg = nullptr,
std::source_location const &pSrc = std::source_location::current()) const noexcept {
return Error{pErrCode, pMsg, pSrc};
}
constexpr Error reoriginate(
std::source_location const &pSrc = std::source_location::current()) const noexcept {
return Error{errCode, msg, pSrc};
}
}; };
[[nodiscard]] [[nodiscard]]
constexpr auto errCode(Error const&err) noexcept { constexpr auto errCode(Error const &err) noexcept {
return err.errCode; return err.errCode;
} }
template<typename T = char const*> template<typename T = char const*>
[[nodiscard]] [[nodiscard]]
constexpr auto toStr(Error const&err) noexcept { constexpr auto toStr(Error const &err) noexcept {
return err.msg ? T{err.msg} : ""; return err.msg ? T{err.msg} : "";
} }
struct Exception: public std::exception { struct Exception: public std::exception {
std::source_location src; std::source_location src;
ox::CString msg = nullptr; CString msg = nullptr;
ErrorCode errCode = 0; ErrorCode errCode = 0;
explicit Exception( explicit Exception(
ErrorCode const errCode, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const &src = std::source_location::current()) noexcept:
src{src}, src{src},
errCode{errCode} {} errCode{errCode} {}
explicit Exception( explicit Exception(
ErrorCode const errCode, ErrorCode const errCode,
ox::CString msg, CString msg,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const &src = std::source_location::current()) noexcept:
src{src}, src{src},
msg{msg}, msg{msg},
errCode{errCode} {} errCode{errCode} {}
explicit Exception(Error const&err) noexcept: explicit Exception(Error const &err) noexcept:
src{err.src}, src{err.src},
msg{err.msg ? err.msg : ""}, msg{err.msg ? err.msg : ""},
errCode{err.errCode} {} errCode{err.errCode} {}
@@ -104,18 +116,21 @@ struct Exception: public std::exception {
} }
[[nodiscard]] [[nodiscard]]
char const*what() const noexcept override { char const *what() const noexcept override {
return msg; return msg;
} }
}; };
[[noreturn]] [[noreturn]]
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept; void panic(
Error const &err,
CString panicMsg,
std::source_location const &src = std::source_location::current()) noexcept;
template<typename T> template<typename T>
struct [[nodiscard]] Result { struct [[nodiscard]] Result {
using type = typename remove_reference<T>::type; using type = remove_reference_t<T>;
T value; T value;
Error error; Error error;
@@ -124,25 +139,25 @@ struct [[nodiscard]] Result {
} }
template<typename U> template<typename U>
constexpr Result(Result<U> const&other) noexcept: value(other.value), error(other.error) { constexpr Result(Result<U> const &other) noexcept: value(other.value), error(other.error) {
} }
template<typename U> template<typename U>
constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) { constexpr Result(Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
} }
constexpr Result(Error const&error) noexcept: value(), error(error) { constexpr Result(Error const &error) noexcept: value(), error(error) {
} }
constexpr Result(type const&value, Error const&error = {}) noexcept: value(value), error(error) { constexpr Result(type const &value, Error const &error = {}) noexcept: value(value), error(error) {
} }
constexpr Result(type &&value, Error const&error = {}) noexcept: value(std::move(value)), error(error) { constexpr Result(type &&value, Error const &error = {}) noexcept: value(std::move(value)), error(error) {
} }
constexpr ~Result() noexcept = default; constexpr ~Result() noexcept = default;
explicit constexpr operator type const&() const noexcept { explicit constexpr operator type const &() const noexcept {
return value; return value;
} }
@@ -156,7 +171,7 @@ struct [[nodiscard]] Result {
} }
template<typename U> template<typename U>
constexpr Error copyTo(U &val) const& noexcept { constexpr Error copyTo(U &val) const & noexcept {
if (!error) [[likely]] { if (!error) [[likely]] {
val = value; val = value;
} }
@@ -182,7 +197,7 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &unwrap() & noexcept { constexpr T &unwrap() & noexcept {
if (error) { if (error) {
oxPanic(error, "Failed unwrap"); ox::panic(error, "Failed unwrap");
} }
return value; return value;
} }
@@ -190,15 +205,15 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &&unwrap() && noexcept { constexpr T &&unwrap() && noexcept {
if (error) { if (error) {
oxPanic(error, "Failed unwrap"); ox::panic(error, "Failed unwrap");
} }
return std::move(value); return std::move(value);
} }
[[nodiscard]] [[nodiscard]]
constexpr T const&unwrap() const & noexcept { constexpr T const &unwrap() const & noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
oxPanic(error, "Failed unwrap"); ox::panic(error, "Failed unwrap");
} }
return value; return value;
} }
@@ -206,7 +221,7 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &unwrapThrow() & { constexpr T &unwrapThrow() & {
if (error) { if (error) {
throw ox::Exception(error); throw Exception(error);
} }
return value; return value;
} }
@@ -214,13 +229,13 @@ struct [[nodiscard]] Result {
[[nodiscard]] [[nodiscard]]
constexpr T &&unwrapThrow() && { constexpr T &&unwrapThrow() && {
if (error) { if (error) {
throw ox::Exception(error); throw Exception(error);
} }
return std::move(value); return std::move(value);
} }
[[nodiscard]] [[nodiscard]]
constexpr T const&unwrapThrow() const & { constexpr T const &unwrapThrow() const & {
if (error) { if (error) {
throw ox::Exception(error); throw ox::Exception(error);
} }
@@ -244,7 +259,7 @@ struct [[nodiscard]] Result {
} }
template<typename U = T> template<typename U = T>
constexpr ox::Result<U> to(auto const&f) & noexcept { constexpr ox::Result<U> to(auto const &f) & noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
return error; return error;
} }
@@ -252,7 +267,7 @@ struct [[nodiscard]] Result {
} }
template<typename U = T> template<typename U = T>
constexpr ox::Result<U> to(auto const&f) && noexcept { constexpr ox::Result<U> to(auto const &f) && noexcept {
if (error) [[unlikely]] { if (error) [[unlikely]] {
return error; return error;
} }
@@ -264,7 +279,7 @@ struct [[nodiscard]] Result {
* @param alt * @param alt
* @return value of Result or alt * @return value of Result or alt
*/ */
constexpr T or_value(T &&alt) const& noexcept { constexpr T or_value(T &&alt) const & noexcept {
if (error) { if (error) {
return std::move(alt); return std::move(alt);
} }
@@ -288,7 +303,7 @@ struct [[nodiscard]] Result {
* @param alt * @param alt
* @return value of Result or alt * @return value of Result or alt
*/ */
constexpr T or_value(T const&alt) const& noexcept { constexpr T or_value(T const &alt) const & noexcept {
if (error) { if (error) {
return alt; return alt;
} }
@@ -300,7 +315,7 @@ struct [[nodiscard]] Result {
* @param alt * @param alt
* @return value of Result or alt * @return value of Result or alt
*/ */
constexpr T or_value(T const&alt) && noexcept { constexpr T or_value(T const &alt) && noexcept {
if (error) { if (error) {
return alt; return alt;
} }
@@ -318,34 +333,36 @@ struct [[nodiscard]] Result {
namespace detail { namespace detail {
constexpr Error toError(Error const&e) noexcept { constexpr Error toError(Error const &e) noexcept {
return e; return e;
} }
template<typename T> template<typename T>
constexpr Error toError(Result<T> const&r) noexcept { constexpr Error toError(Result<T> const &r) noexcept {
return r.error; return r.error;
} }
} }
constexpr void primitiveAssert(char const*file, int line, bool pass, char const*msg) noexcept { constexpr void primitiveAssert(
bool const pass,
char const *msg,
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(ox::defines::Debug) { if constexpr(ox::defines::Debug) {
if (!pass) [[unlikely]] { if (!pass) [[unlikely]] {
panic(file, line, msg, ox::Error(1)); panic(ox::Error{1}, msg, src);
} }
} }
} }
constexpr void boundsCheck( constexpr void boundsCheck(
char const*file,
int const line,
size_t const i, size_t const i,
size_t const sz, size_t const sz,
char const*msg) noexcept { char const *msg,
std::source_location const &src = std::source_location::current()) noexcept {
if constexpr(defines::CheckBounds) { if constexpr(defines::CheckBounds) {
if (i >= sz) [[unlikely]] { if (i >= sz) [[unlikely]] {
panic(file, line, msg, ox::Error{1}); panic(ox::Error{1}, msg, src);
} }
} }
} }

View File

@@ -106,9 +106,12 @@ constexpr bool HashMap<K, T>::operator==(HashMap const &other) const {
if (m_keys != other.m_keys) { if (m_keys != other.m_keys) {
return false; return false;
} }
for (int i = 0; i < m_keys.size(); ++i) { for (auto &k : m_keys) {
auto &k = m_keys[i]; auto const a = at(k).value;
if (at(k) != other.at(k)) { auto const b = other.at(k).value;
if (
a != b && // handle one being null and other not
(a && b && *a != *b)) {
return false; return false;
} }
} }
@@ -196,7 +199,7 @@ constexpr std::size_t HashMap<K, T>::size() const noexcept {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Vector<K> const&HashMap<K, T>::keys() const noexcept { constexpr Vector<K> const &HashMap<K, T>::keys() const noexcept {
return m_keys; return m_keys;
} }
@@ -205,8 +208,8 @@ constexpr Vector<T> HashMap<K, T>::values() const noexcept {
Vector<T> out; Vector<T> out;
out.reserve(m_keys.size()); out.reserve(m_keys.size());
for (auto const &p : m_pairs) { for (auto const &p : m_pairs) {
if (out) { if (p) {
out.emplace_back(p->value); out.emplace_back(*p->value);
} }
} }
return out; return out;

View File

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

77
deps/ox/src/ox/std/istreamreader.cpp vendored Normal file
View File

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

33
deps/ox/src/ox/std/istreamreader.hpp vendored Normal file
View File

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

View File

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

View File

@@ -79,11 +79,11 @@ constexpr U *make(Args &&...args) noexcept {
#ifdef __cpp_exceptions #ifdef __cpp_exceptions
try { try {
return new T(ox::forward<Args>(args)...); return new T(ox::forward<Args>(args)...);
} catch (std::exception const&ex) { } catch (std::exception const &ex) {
oxPanic(ox::Error(1, ex.what()), ex.what()); ox::panic(ox::Error(1, ex.what()), ex.what());
return nullptr; return nullptr;
} catch (...) { } catch (...) {
oxPanic(ox::Error(2, "Allocation or constructor failed"), "Allocation or constructor failed"); ox::panic(ox::Error(2, "Allocation or constructor failed"), "Allocation or constructor failed");
return nullptr; return nullptr;
} }
#else #else

View File

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

View File

@@ -8,10 +8,6 @@
#pragma once #pragma once
#ifdef OX_USE_STDLIB
#include <istream>
#endif
#include "concepts.hpp" #include "concepts.hpp"
#include "error.hpp" #include "error.hpp"
#include "types.hpp" #include "types.hpp"
@@ -63,18 +59,4 @@ class ReaderT: public Reader_v {
} }
}; };
#ifdef OX_USE_STDLIB
class StreamReader: public Reader_v {
private:
std::istream &m_strm;
public:
constexpr explicit StreamReader(std::istream &stream) noexcept: m_strm(stream) {}
ox::Result<char> peek() const noexcept override;
ox::Result<std::size_t> read(char *v, std::size_t cnt) noexcept override;
ox::Error seekg(std::size_t p) noexcept override;
ox::Error seekg(int64_t p, ios_base::seekdir sd) noexcept override;
ox::Result<std::size_t> tellg() noexcept override;
};
#endif
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -34,6 +34,41 @@ inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
namespace ox { namespace ox {
template<typename T>
struct remove_cv {
using type = T;
};
template<typename T>
struct remove_cv<const T> {
using type = T;
};
template<typename T>
struct remove_cv<volatile T> {
using type = T;
};
template<typename T>
struct remove_cv<const volatile T> {
using type = T;
};
template<typename T>
struct remove_const {
using type = T;
};
template<typename T>
struct remove_const<const T> {
using type = T;
};
template<typename T>
using remove_const_t = typename remove_const<T>::type;
template<class T, T v> template<class T, T v>
struct integral_constant { struct integral_constant {
@@ -109,6 +144,12 @@ template<> struct is_integer<int16_t> : true_type {};
template<> struct is_integer<uint16_t>: true_type {}; template<> struct is_integer<uint16_t>: true_type {};
template<> struct is_integer<int32_t> : true_type {}; template<> struct is_integer<int32_t> : true_type {};
template<> struct is_integer<uint32_t>: true_type {}; template<> struct is_integer<uint32_t>: true_type {};
template<> struct is_integer<int8_t const> : true_type {};
template<> struct is_integer<uint8_t const> : true_type {};
template<> struct is_integer<int16_t const> : true_type {};
template<> struct is_integer<uint16_t const>: true_type {};
template<> struct is_integer<int32_t const> : true_type {};
template<> struct is_integer<uint32_t const>: true_type {};
// some of these need to be done with the actual language syntax because no one // some of these need to be done with the actual language syntax because no one
// can agree on what an (u)int64_t is... // can agree on what an (u)int64_t is...
@@ -116,9 +157,13 @@ template<> struct is_integer<long>: true_type {};
template<> struct is_integer<long long>: true_type {}; template<> struct is_integer<long long>: true_type {};
template<> struct is_integer<unsigned long>: true_type {}; template<> struct is_integer<unsigned long>: true_type {};
template<> struct is_integer<unsigned long long>: true_type {}; template<> struct is_integer<unsigned long long>: true_type {};
template<> struct is_integer<long const>: true_type {};
template<> struct is_integer<long long const>: true_type {};
template<> struct is_integer<unsigned long const>: true_type {};
template<> struct is_integer<unsigned long long const>: true_type {};
template<typename T> template<typename T>
constexpr bool is_integer_v = is_integral<T>::value; constexpr bool is_integer_v = is_integer<T>::value;
template<typename T> template<typename T>
concept Integer_c = is_integer<T>::value; concept Integer_c = is_integer<T>::value;
@@ -180,20 +225,6 @@ struct is_same<T, T>: true_type {};
template<typename T, typename U> template<typename T, typename U>
constexpr auto is_same_v = is_same<T, U>::value; constexpr auto is_same_v = is_same<T, U>::value;
// enable_if ///////////////////////////////////////////////////////////////////
template<bool B, class T = void>
struct enable_if {
};
template<class T>
struct enable_if<true, T> {
using type = T;
};
template<bool B, typename T>
using enable_if_t = typename enable_if<B, T>::type;
template<typename T> template<typename T>
struct is_pointer { struct is_pointer {
static constexpr bool value = false; static constexpr bool value = false;
@@ -237,6 +268,9 @@ struct remove_pointer<T* const volatile> {
using type = T; using type = T;
}; };
template<typename T>
using remove_pointer_t = typename remove_pointer<T>::type;
template<typename T> template<typename T>
struct remove_reference { struct remove_reference {
@@ -275,39 +309,23 @@ template<class T>
constexpr bool is_move_constructible_v = detail::is_move_constructible<T>(0); constexpr bool is_move_constructible_v = detail::is_move_constructible<T>(0);
namespace detail {
template<typename T> template<typename T>
struct remove_cv { T const &declvalCopy();
using type = T;
}; template<typename T, typename = decltype(T(declvalCopy<T>()))>
constexpr bool is_copy_constructible(int) {
return true;
}
template<typename T> template<typename T>
struct remove_cv<const T> { constexpr bool is_copy_constructible(bool) {
using type = T; return false;
}; }
}
template<typename T> template<class T>
struct remove_cv<volatile T> { constexpr bool is_copy_constructible_v = detail::is_copy_constructible<T>(0);
using type = T;
};
template<typename T>
struct remove_cv<const volatile T> {
using type = T;
};
template<typename T>
struct remove_const {
using type = T;
};
template<typename T>
struct remove_const<const T> {
using type = T;
};
template<typename T>
using remove_const_t = typename remove_const<T>::type;
// is String? // is String?

View File

@@ -26,7 +26,7 @@ namespace ox {
namespace detail { namespace detail {
template<typename T, typename Allocator, std::size_t Size = 1> template<typename T, typename Allocator, size_t Size = 1>
struct VectorAllocator { struct VectorAllocator {
static_assert(sizeof(AllocAlias<T>) == sizeof(T)); static_assert(sizeof(AllocAlias<T>) == sizeof(T));
static_assert(alignof(AllocAlias<T>) == alignof(T)); static_assert(alignof(AllocAlias<T>) == alignof(T));
@@ -37,7 +37,7 @@ struct VectorAllocator {
constexpr VectorAllocator(VectorAllocator const&) noexcept = default; constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept { constexpr void allocate(T **items, size_t const cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) { if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
@@ -49,8 +49,8 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T **items, T **items,
VectorAllocator *src, VectorAllocator *src,
std::size_t const count, size_t const count,
std::size_t const cap) noexcept { size_t const cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later // try removing it later
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
@@ -68,7 +68,7 @@ struct VectorAllocator {
} }
} }
constexpr void deallocate(T *const items, std::size_t const cap) noexcept { constexpr void deallocate(T *const items, size_t const cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
if (items) { if (items) {
@@ -90,7 +90,7 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr VectorAllocator(VectorAllocator const&) noexcept = default; constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default; constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t const cap) noexcept { constexpr void allocate(T **items, size_t const cap) noexcept {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
} }
@@ -98,15 +98,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T**, T**,
VectorAllocator*, VectorAllocator*,
std::size_t const, size_t const,
std::size_t const) noexcept { size_t const) noexcept {
} }
[[maybe_unused]] [[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, std::size_t const, std::size_t const) noexcept { constexpr void moveItemsFrom(T**, VectorAllocator*, size_t const, size_t const) noexcept {
} }
constexpr void deallocate(T *const items, std::size_t const cap) noexcept { constexpr void deallocate(T *const items, size_t const cap) noexcept {
if (items) { if (items) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
} }
@@ -116,12 +116,12 @@ struct VectorAllocator<T, Allocator, 0> {
} }
template<typename T, std::size_t SmallVectorSize = 0, typename Allocator = std::allocator<T>> template<typename T, size_t SmallVectorSize = 0, typename Allocator = std::allocator<T>>
class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> { class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
public: public:
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = size_t;
template<typename RefType = T&, typename PtrType = T*, bool reverse = false> template<typename RefType = T&, typename PtrType = T*, bool reverse = false>
using iterator = SpanIterator<T, RefType, PtrType, reverse>; using iterator = SpanIterator<T, RefType, PtrType, reverse>;
@@ -129,18 +129,18 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
private: private:
static constexpr auto initialCap = SmallVectorSize > 0 ? SmallVectorSize : 50; static constexpr auto initialCap = SmallVectorSize > 0 ? SmallVectorSize : 50;
static constexpr auto useNoexcept = ox::is_integral_v<T> || ox::is_pointer_v<T>; static constexpr auto useNoexcept = ox::is_integral_v<T> || ox::is_pointer_v<T>;
std::size_t m_size = 0; size_t m_size = 0;
std::size_t m_cap = 0; size_t m_cap = 0;
T *m_items = nullptr; T *m_items = nullptr;
public: public:
constexpr Vector() noexcept = default; constexpr Vector() noexcept = default;
explicit constexpr Vector(std::size_t size) noexcept; explicit constexpr Vector(size_t size) noexcept;
constexpr Vector(std::initializer_list<T> list) noexcept; constexpr Vector(std::initializer_list<T> list) noexcept;
constexpr Vector(const Vector &other) noexcept(useNoexcept); constexpr Vector(Vector const &other) noexcept(useNoexcept);
constexpr Vector(Vector &&other) noexcept; constexpr Vector(Vector &&other) noexcept;
@@ -155,23 +155,23 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*> begin() const noexcept { constexpr iterator<T const&, T const*> begin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size); return iterator<T const&, T const*>(m_items, 0, m_size);
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*> end() const noexcept { constexpr iterator<T const&, T const*> end() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size); return iterator<T const&, T const*>(m_items, m_size, m_size);
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*> cbegin() const noexcept { constexpr iterator<T const&, T const*> cbegin() const noexcept {
return iterator<const T&, const T*>(m_items, 0, m_size); return iterator<T const&, T const*>(m_items, 0, m_size);
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*> cend() const noexcept { constexpr iterator<T const&, T const*> cend() const noexcept {
return iterator<const T&, const T*>(m_items, m_size, m_size); return iterator<T const&, T const*>(m_items, m_size, m_size);
} }
[[nodiscard]] [[nodiscard]]
@@ -185,36 +185,36 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*, true> crbegin() const noexcept { constexpr iterator<T const&, T const*, true> crbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size); return iterator<T const&, T const*, true>(m_items, m_size - 1, m_size);
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*, true> crend() const noexcept { constexpr iterator<T const&, T const*, true> crend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size); return iterator<T const&, T const*, true>(m_items, MaxValue<size_type>, m_size);
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*, true> rbegin() const noexcept { constexpr iterator<T const&, T const*, true> rbegin() const noexcept {
return iterator<const T&, const T*, true>(m_items, m_size - 1, m_size); return iterator<T const&, T const*, true>(m_items, m_size - 1, m_size);
} }
[[nodiscard]] [[nodiscard]]
constexpr iterator<const T&, const T*, true> rend() const noexcept { constexpr iterator<T const&, T const*, true> rend() const noexcept {
return iterator<const T&, const T*, true>(m_items, MaxValue<size_type>, m_size); return iterator<T const&, T const*, true>(m_items, MaxValue<size_type>, m_size);
} }
constexpr bool operator==(const Vector &other) const noexcept(useNoexcept); constexpr bool operator==(Vector const &other) const noexcept(useNoexcept);
constexpr Vector &operator=(const Vector &other) noexcept(useNoexcept); constexpr Vector &operator=(Vector const &other) noexcept(useNoexcept);
constexpr Vector &operator=(Vector &&other) noexcept; constexpr Vector &operator=(Vector &&other) noexcept;
[[nodiscard]] [[nodiscard]]
constexpr T &operator[](std::size_t i) noexcept; constexpr T &operator[](size_t i) noexcept;
[[nodiscard]] [[nodiscard]]
constexpr const T &operator[](std::size_t i) const noexcept; constexpr T const &operator[](size_t i) const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr Result<T*> at(size_t i) noexcept; constexpr Result<T*> at(size_t i) noexcept;
@@ -226,26 +226,28 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr Result<T*> front() noexcept; constexpr Result<T*> front() noexcept;
[[nodiscard]] [[nodiscard]]
constexpr Result<const T*> front() const noexcept; constexpr Result<T const*> front() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr Result<T*> back() noexcept; constexpr Result<T*> back() noexcept;
[[nodiscard]] [[nodiscard]]
constexpr Result<const T*> back() const noexcept; constexpr Result<T const*> back() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr std::size_t capacity() const noexcept; constexpr size_t capacity() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept; constexpr size_t size() const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr bool empty() const noexcept; constexpr bool empty() const noexcept;
constexpr void clear() noexcept(useNoexcept); constexpr void clear() noexcept(useNoexcept);
constexpr void resize(std::size_t size) noexcept(useNoexcept); constexpr void resize(size_t size) noexcept(useNoexcept);
constexpr void reserveResize(size_t size) noexcept(useNoexcept);
[[nodiscard]] [[nodiscard]]
constexpr T *data() noexcept { constexpr T *data() noexcept {
@@ -253,7 +255,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
} }
[[nodiscard]] [[nodiscard]]
constexpr const T *data() const noexcept { constexpr T const *data() const noexcept {
return m_items; return m_items;
} }
@@ -261,12 +263,12 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr bool contains(MaybeView_t<T> const&) const noexcept; constexpr bool contains(MaybeView_t<T> const&) const noexcept;
constexpr iterator<T&, T*, false> insert( constexpr iterator<T&, T*, false> insert(
std::size_t pos, std::size_t cnt, T const&val) noexcept(useNoexcept); size_t pos, size_t cnt, T const &val) noexcept(useNoexcept);
constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept); constexpr iterator<T&, T*, false> insert(size_t pos, T val) noexcept(useNoexcept);
template<typename... Args> template<typename... Args>
constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept); constexpr iterator<T&, T*, false> emplace(size_t pos, Args&&... args) noexcept(useNoexcept);
template<typename... Args> template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept); constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
@@ -282,14 +284,14 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
* @param pos iterator at the point to remove * @param pos iterator at the point to remove
* @return Error if index is out of bounds * @return Error if index is out of bounds
*/ */
constexpr Result<iterator<T&, T*, false>> erase(const iterator<> &pos) noexcept(useNoexcept); constexpr Result<iterator<T&, T*, false>> erase(iterator<> const &pos) noexcept(useNoexcept);
/** /**
* Removes an item from the Vector. * Removes an item from the Vector.
* @param pos position of item to remove * @param pos position of item to remove
* @return Error if index is out of bounds * @return Error if index is out of bounds
*/ */
constexpr Result<iterator<T&, T*, false>> erase(std::size_t pos) noexcept(useNoexcept); constexpr Result<iterator<T&, T*, false>> erase(size_t pos) noexcept(useNoexcept);
/** /**
* Moves the last item in the Vector to position pos and decrements the * Moves the last item in the Vector to position pos and decrements the
@@ -297,59 +299,62 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
* @param pos position of item to remove * @param pos position of item to remove
* @return Error if index is out of bounds * @return Error if index is out of bounds
*/ */
constexpr Error unordered_erase(std::size_t pos) noexcept(useNoexcept); constexpr Error unordered_erase(size_t pos) noexcept(useNoexcept);
constexpr Error remove(MaybeView_t<T> const &val); constexpr Error remove(MaybeView_t<T> const &val);
constexpr void reserve(std::size_t cap) noexcept(useNoexcept); constexpr void reserve(size_t cap) noexcept(useNoexcept);
constexpr void shrink_to_fit() noexcept(useNoexcept); constexpr void shrink_to_fit() noexcept(useNoexcept);
private: private:
constexpr void reserveInsert( constexpr void reserveInsert(
std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept); size_t cap, size_t pos, size_t offset = 1) noexcept(useNoexcept);
}; };
template<typename T, std::size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse> template<typename T, size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse>
using VectorIt = typename Vector<T, SmallVectorSize, Allocator>::template iterator<RefType, reverse>; using VectorIt = typename Vector<T, SmallVectorSize, Allocator>::template iterator<RefType, reverse>;
template<typename T, std::size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse> template<typename T, size_t SmallVectorSize, typename Allocator, typename RefType, bool reverse>
constexpr VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> operator+( constexpr VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> operator+(
std::size_t n, size_t n,
const VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> &a) { VectorIt<T, SmallVectorSize, Allocator, RefType, reverse> const &a) {
return a + n; return a + n;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexcept { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(size_t const size) noexcept {
m_size = size; m_size = size;
m_cap = m_size; m_cap = m_size;
this->allocate(&m_items, m_cap); this->allocate(&m_items, m_cap);
for (std::size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
std::construct_at(&m_items[i]); std::construct_at(&m_items[i]);
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
reserve(list.size()); m_size = list.size();
for (auto &item : list) { m_cap = m_size;
emplace_back(std::move(item)); this->allocate(&m_items, m_cap);
for (size_t i{}; auto &item : list) {
std::construct_at(&m_items[i], std::move(item));
++i;
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(const Vector &other) noexcept(useNoexcept) { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector const &other) noexcept(useNoexcept) {
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
this->allocate(&m_items, other.m_cap); this->allocate(&m_items, other.m_cap);
for (std::size_t i = 0; i < m_size; ++i) { for (size_t i = 0; i < m_size; ++i) {
std::construct_at(&m_items[i], other.m_items[i]); std::construct_at(&m_items[i], other.m_items[i]);
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept { constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept {
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
@@ -360,20 +365,20 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept
other.m_items = nullptr; other.m_items = nullptr;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::~Vector() { constexpr Vector<T, SmallVectorSize, Allocator>::~Vector() {
clear(); clear();
this->deallocate(m_items, m_cap); this->deallocate(m_items, m_cap);
m_items = nullptr; m_items = nullptr;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::operator==( constexpr bool Vector<T, SmallVectorSize, Allocator>::operator==(
const Vector &other) const noexcept(useNoexcept) { Vector const &other) const noexcept(useNoexcept) {
if (m_size != other.m_size) { if (m_size != other.m_size) {
return false; return false;
} }
for (std::size_t i = 0; i < m_size; i++) { for (size_t i = 0; i < m_size; i++) {
if (!(m_items[i] == other.m_items[i])) { if (!(m_items[i] == other.m_items[i])) {
return false; return false;
} }
@@ -381,9 +386,9 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::operator==(
return true; return true;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=( constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(
const Vector &other) noexcept(useNoexcept) { Vector const &other) noexcept(useNoexcept) {
if (this != &other) { if (this != &other) {
clear(); clear();
this->deallocate(m_items, m_cap); this->deallocate(m_items, m_cap);
@@ -391,14 +396,14 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
this->allocate(&m_items, other.m_cap); this->allocate(&m_items, other.m_cap);
for (std::size_t i = 0; i < m_size; i++) { for (size_t i = 0; i < m_size; i++) {
std::construct_at(&m_items[i], other.m_items[i]); std::construct_at(&m_items[i], other.m_items[i]);
} }
} }
return *this; return *this;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=( constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(
Vector &&other) noexcept { Vector &&other) noexcept {
if (this != &other) { if (this != &other) {
@@ -415,35 +420,35 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
return *this; return *this;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) noexcept { constexpr T &Vector<T, SmallVectorSize, Allocator>::operator[](size_t const i) noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow"); boundsCheck(i, size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr const T &Vector<T, SmallVectorSize, Allocator>::operator[](std::size_t i) const noexcept { constexpr T const &Vector<T, SmallVectorSize, Allocator>::operator[](size_t const i) const noexcept {
boundsCheck(__FILE__, __LINE__, i, size(), "Vector access overflow"); boundsCheck(i, size(), "Vector access overflow");
return m_items[i]; return m_items[i];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::at(size_t i) noexcept { constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::at(size_t const i) noexcept {
if (i < size()) [[likely]] { if (i < size()) [[likely]] {
return &operator[](i); return &operator[](i);
} }
return ox::Error(1, "Vector: Invalid index"); return ox::Error(1, "Vector: Invalid index");
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::at(size_t i) const noexcept { constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::at(size_t const i) const noexcept {
if (i < size()) [[likely]] { if (i < size()) [[likely]] {
return &operator[](i); return &operator[](i);
} }
return ox::Error(1, "Vector: Invalid index"); return ox::Error(1, "Vector: Invalid index");
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::front() noexcept { constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::front() noexcept {
if (!m_size) { if (!m_size) {
return {nullptr, ox::Error(1)}; return {nullptr, ox::Error(1)};
@@ -451,15 +456,15 @@ constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::front() noexcept {
return &m_items[0]; return &m_items[0];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<const T*> Vector<T, SmallVectorSize, Allocator>::front() const noexcept { constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::front() const noexcept {
if (!m_size) { if (!m_size) {
return {nullptr, ox::Error(1)}; return {nullptr, ox::Error(1)};
} }
return &m_items[0]; return &m_items[0];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::back() noexcept { constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::back() noexcept {
if (!m_size) { if (!m_size) {
return {nullptr, ox::Error(1)}; return {nullptr, ox::Error(1)};
@@ -467,59 +472,65 @@ constexpr Result<T*> Vector<T, SmallVectorSize, Allocator>::back() noexcept {
return &m_items[m_size - 1]; return &m_items[m_size - 1];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<const T*> Vector<T, SmallVectorSize, Allocator>::back() const noexcept { constexpr Result<T const*> Vector<T, SmallVectorSize, Allocator>::back() const noexcept {
if (!m_size) { if (!m_size) {
return {nullptr, ox::Error(1)}; return {nullptr, ox::Error(1)};
} }
return &m_items[m_size - 1]; return &m_items[m_size - 1];
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr std::size_t Vector<T, SmallVectorSize, Allocator>::capacity() const noexcept { constexpr size_t Vector<T, SmallVectorSize, Allocator>::capacity() const noexcept {
return m_cap; return m_cap;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr std::size_t Vector<T, SmallVectorSize, Allocator>::size() const noexcept { constexpr size_t Vector<T, SmallVectorSize, Allocator>::size() const noexcept {
return m_size; return m_size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::empty() const noexcept { constexpr bool Vector<T, SmallVectorSize, Allocator>::empty() const noexcept {
return !m_size; return !m_size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::clear() noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::clear() noexcept(useNoexcept) {
if constexpr(is_class<T>()) { if constexpr(is_class<T>()) {
for (std::size_t i = 0; i < m_size; ++i) { for (size_t i = 0; i < m_size; ++i) {
m_items[i].~T(); m_items[i].~T();
} }
} }
m_size = 0; m_size = 0;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::resize(size_t const size) noexcept(useNoexcept) {
if (m_cap < size) { if (m_cap < size) {
reserve(size * 2); reserve(size * 2);
} }
if (m_size < size) { if (m_size < size) {
for (std::size_t i = m_size; i < size; i++) { for (size_t i = m_size; i < size; i++) {
std::construct_at(&m_items[i]); std::construct_at(&m_items[i]);
} }
} else { } else {
for (std::size_t i = size; i < m_size; i++) { for (size_t i = size; i < m_size; i++) {
m_items[i].~T(); m_items[i].~T();
} }
} }
m_size = size; m_size = size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept { constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(size_t const size) noexcept(useNoexcept) {
for (std::size_t i = 0; i < m_size; ++i) { reserve(size);
resize(size);
}
template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const &v) const noexcept {
for (size_t i = 0; i < m_size; ++i) {
if (m_items[i] == v) { if (m_items[i] == v) {
return true; return true;
} }
@@ -527,10 +538,10 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> co
return false; return false;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false> constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert( Vector<T, SmallVectorSize, Allocator>::insert(
std::size_t pos, std::size_t cnt, T const&val) noexcept(useNoexcept) { size_t const pos, size_t const cnt, T const &val) noexcept(useNoexcept) {
if (m_size + cnt > m_cap) { if (m_size + cnt > m_cap) {
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt); reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
} }
@@ -550,9 +561,9 @@ Vector<T, SmallVectorSize, Allocator>::insert(
return begin() + pos; return begin() + pos;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false> constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, T val) noexcept(useNoexcept) { Vector<T, SmallVectorSize, Allocator>::insert(size_t pos, T val) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos); reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
} }
@@ -568,10 +579,10 @@ Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, T val) noexcept(u
return begin() + pos; return begin() + pos;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
template<typename... Args> template<typename... Args>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false> constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
Vector<T, SmallVectorSize, Allocator>::emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept) { Vector<T, SmallVectorSize, Allocator>::emplace(size_t pos, Args&&... args) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos); reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
if (pos < m_size) { if (pos < m_size) {
@@ -591,7 +602,7 @@ Vector<T, SmallVectorSize, Allocator>::emplace(std::size_t pos, Args&&... args)
return begin() + pos; return begin() + pos;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
template<typename... Args> template<typename... Args>
constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args) noexcept(useNoexcept) { constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
@@ -602,7 +613,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
return *out; return *out;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
@@ -611,7 +622,7 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) n
++m_size; ++m_size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, 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) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
@@ -620,21 +631,21 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexce
++m_size; ++m_size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) {
--m_size; --m_size;
m_items[m_size].~T(); m_items[m_size].~T();
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>> constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>>
Vector<T, SmallVectorSize, Allocator>::erase(const iterator<> &pos) noexcept(useNoexcept) { Vector<T, SmallVectorSize, Allocator>::erase(iterator<> const &pos) noexcept(useNoexcept) {
return erase(pos.offset()); return erase(pos.offset());
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>> constexpr Result<typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>>
Vector<T, SmallVectorSize, Allocator>::erase(std::size_t pos) noexcept(useNoexcept) { Vector<T, SmallVectorSize, Allocator>::erase(size_t pos) noexcept(useNoexcept) {
if (pos >= m_size) { if (pos >= m_size) {
return ox::Error(1, "Vector::erase failed: pos is greater than Vector size"); return ox::Error(1, "Vector::erase failed: pos is greater than Vector size");
} }
@@ -646,8 +657,8 @@ Vector<T, SmallVectorSize, Allocator>::erase(std::size_t pos) noexcept(useNoexce
return begin() + pos; return begin() + pos;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size_t pos) constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(size_t pos)
noexcept(useNoexcept) { noexcept(useNoexcept) {
if (pos >= m_size) { if (pos >= m_size) {
return ox::Error(1); return ox::Error(1);
@@ -658,7 +669,7 @@ constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size
return {}; return {};
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(MaybeView_t<T> const &val) { constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(MaybeView_t<T> const &val) {
for (size_t i{}; auto const &v : *this) { for (size_t i{}; auto const &v : *this) {
if (v == val) { if (v == val) {
@@ -669,18 +680,18 @@ constexpr ox::Error Vector<T, SmallVectorSize, Allocator>::remove(MaybeView_t<T>
return ox::Error{1, "element not found"}; return ox::Error{1, "element not found"};
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(size_t cap) noexcept(useNoexcept) {
if (cap <= m_cap) { if (cap <= m_cap) {
return; return;
} }
const auto oldItems = m_items; auto const oldItems = m_items;
const auto oldCap = m_cap; auto const oldCap = m_cap;
m_cap = cap; m_cap = cap;
this->allocate(&m_items, cap); this->allocate(&m_items, cap);
if (oldItems) { // move over old items if (oldItems) { // move over old items
const auto itRange = ox::min(cap, m_size); auto const itRange = ox::min(cap, m_size);
for (std::size_t i = 0; i < itRange; ++i) { for (size_t i = 0; i < itRange; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i])); std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T(); oldItems[i].~T();
} }
@@ -688,17 +699,17 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) n
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(useNoexcept) { constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(useNoexcept) {
if (m_size == m_cap) { if (m_size == m_cap) {
return; return;
} }
const auto oldItems = m_items; auto const oldItems = m_items;
const auto oldCap = m_cap; auto const oldCap = m_cap;
m_cap = m_size; m_cap = m_size;
this->allocate(&m_items, m_size); this->allocate(&m_items, m_size);
if (oldItems) { // move over old items if (oldItems) { // move over old items
for (std::size_t i = 0; i < m_size; ++i) { for (size_t i = 0; i < m_size; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i])); std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T(); oldItems[i].~T();
} }
@@ -706,26 +717,26 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(u
} }
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert( constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
std::size_t cap, size_t cap,
std::size_t pos, size_t pos,
std::size_t offset) noexcept(useNoexcept) { size_t offset) noexcept(useNoexcept) {
if (cap <= m_cap) { if (cap <= m_cap) {
return; return;
} }
const auto oldItems = m_items; auto const oldItems = m_items;
const auto oldCap = m_cap; auto const oldCap = m_cap;
m_cap = cap; m_cap = cap;
this->allocate(&m_items, cap); this->allocate(&m_items, cap);
if (oldItems) { // move over old items if (oldItems) { // move over old items
auto itRange = ox::min(m_size, pos); auto itRange = ox::min(m_size, pos);
for (std::size_t i = 0; i < itRange; ++i) { for (size_t i = 0; i < itRange; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i])); std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T(); oldItems[i].~T();
} }
itRange = m_size; itRange = m_size;
for (std::size_t i = pos; i < itRange; ++i) { for (size_t i = pos; i < itRange; ++i) {
std::construct_at(&m_items[i + offset], std::move(oldItems[i])); std::construct_at(&m_items[i + offset], std::move(oldItems[i]));
oldItems[i].~T(); oldItems[i].~T();
} }
@@ -736,8 +747,8 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
template<typename PlatSpec, typename T> template<typename PlatSpec, typename T>
[[nodiscard]] [[nodiscard]]
constexpr auto alignOf(const Vector<T>&) noexcept { constexpr auto alignOf(Vector<T> const&) noexcept {
const typename PlatSpec::size_t i = 0; typename PlatSpec::size_t const i = 0;
return PlatSpec::alignOf(i); return PlatSpec::alignOf(i);
} }

View File

@@ -99,23 +99,23 @@ volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Memory Addresses // 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)) #define REG_BLNDCTL (*reinterpret_cast<uint16_t*>(0x0400'0050))
using Palette = ox::Array<uint16_t, 128>; using Palette = ox::Array<uint16_t, 128>;
#define MEM_BG_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0000)) #define MEM_BG_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0000)))
#define MEM_SPRITE_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0200)) #define MEM_SPRITE_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0200)))
using BgMapTile = ox::Array<uint16_t, 8192>; using BgMapTile = ox::Array<uint16_t, 8192>;
#define MEM_BG_TILES (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000)) #define MEM_BG_TILES (*(reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000)))
#define MEM_BG_MAP (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000)) #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_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_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,6 +43,4 @@ void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) 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 { void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept {
const auto ie = REG_IE; // disable vblank interrupt handler const auto ie = REG_IE; // disable vblank interrupt handler
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler REG_IE = REG_IE & static_cast<uint16_t>(~Int_vblank); // disable vblank interrupt handler
g_spriteBuffer[upd.idx] = upd; g_spriteBuffer[upd.idx] = upd;
REG_IE = ie; // enable vblank interrupt handler REG_IE = ie; // enable vblank interrupt handler
} }
@@ -35,10 +35,4 @@ void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
o.y = y; 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-) * opengl - OpenGL implementation (P-)
* studio - studio plugin for core (P-) * studio - studio plugin for core (P-)
* keel - keel plugin for core (PG) * keel - keel plugin for core (PG)
* scene - defines & processes map data (PG) * sound - sound system for Nostalgia (PG)
* studio - studio plugin for scene (P-) * studio - studio plugin for sound (P-)
* keel - keel plugin for scene (PG) * keel - keel plugin for sound (PG)
* player - plays the games (PG) * player - plays the games (PG)
* studio - makes the games (P-) * studio - makes the games (P-)
* tools - command line tools (P-) * tools - command line tools (P-)
@@ -48,7 +48,7 @@ All components have a platform indicator next to them:
Not really that external... (PG) Not really that external... (PG)
* GlUtils - OpenGL helpers (P-) * GlUtils - OpenGL helpers (P-)
* teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL * teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL
2.0), and custom GBA hardware interop code (-G) 2.0), and custom GBA hardware interop code (-G)
Most GBA code is built on PC because it is small and helps to work on both Most GBA code is built on PC because it is small and helps to work on both
projects with the same CMake build dir, but GBA code is never linked with any projects with the same CMake build dir, but GBA code is never linked with any
@@ -89,7 +89,8 @@ The GBA has two major resources for learning about its hardware:
On the surface, it seems like C++ changes the way we do things from C for no On the surface, it seems like C++ changes the way we do things from C for no
reason, but there are reasons for many of these duplications of functionality. reason, but there are reasons for many of these duplications of functionality.
The C++ language designers aren't stupid. Question them, but don't ignore them. The C++ language designers aren't stupid.
Question them, but don't ignore them.
#### Casting #### Casting
@@ -163,10 +164,11 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling ### Error Handling
Instead of throwing exceptions, generally try to use Instead of throwing exceptions, generally try to use
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting, [ox::Error](deps/ox/ox-docs.md#error-handling) for error reporting.
but exceptions may be used where they make sense. Exceptions may be used where errors-as-values will not work, but catch them and
convert them to ```ox::Error``` as soon as possible.
Exceptions should generally just use ```OxException```, which is bascially an Exceptions should generally just use ```ox::Exception```, which is basically an
exception form of ```ox::Error```. exception form of ```ox::Error```.
### File I/O ### File I/O

View File

@@ -1,3 +1,7 @@
# NEXT
* Add Get Info file dialog option in project explorer
# d2025.07.0 # d2025.07.0
* Add sub-command for exporting TileSheets as PNG files. * Add sub-command for exporting TileSheets as PNG files.

View File

@@ -23,17 +23,15 @@ struct BgCbbData {
unsigned bpp = 4; unsigned bpp = 4;
}; };
class Context { class Context final {
public: public:
turbine::Context &turbineCtx; turbine::Context &turbineCtx;
ox::Array<BgCbbData, 4> cbbData; ox::Array<BgCbbData, 4> cbbData;
ox::Array<OffsetPair, 4> bgOffsets;
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {} explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
Context(Context &other) noexcept = delete;
Context(Context const &other) noexcept = delete; Context(Context const &other) noexcept = delete;
Context(Context const &&other) noexcept = delete;
virtual ~Context() noexcept = default;
}; };
@@ -295,12 +293,16 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11); bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
} }
void setBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept { void setBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
ctx.bgOffsets[bg] = {.x = x, .y = y};
teagba::setBgOffset(bg, x, y); teagba::setBgOffset(bg, x, y);
} }
void scrollBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept { void scrollBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::scrollBgOffset(bg, x, y); auto &o = ctx.bgOffsets[bg];
o.x += x;
o.y += y;
teagba::setBgOffset(bg, o.x, o.y);
} }
void hideSprite(Context&, unsigned const idx) noexcept { void hideSprite(Context&, unsigned const idx) noexcept {
@@ -319,23 +321,23 @@ void showSprite(Context&, unsigned const idx) noexcept {
}); });
} }
void setSprite(Context&, uint_t const idx, Sprite const &s) noexcept { void setSprite(Context&, uint_t const idx, Sprite const &sprite) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
uint16_t const eightBpp = s.bpp == 8; uint16_t const eightBpp = sprite.bpp == 8;
teagba::addSpriteUpdate({ teagba::addSpriteUpdate({
.attr0 = static_cast<uint16_t>( .attr0 = static_cast<uint16_t>(
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111))) (static_cast<uint16_t>(sprite.y & ox::onMask<uint8_t>(0b111'1111)))
| (static_cast<uint16_t>(1) << 10) // enable alpha | (static_cast<uint16_t>(1) << 10) // enable alpha
| (static_cast<uint16_t>(eightBpp) << 13) | (static_cast<uint16_t>(eightBpp) << 13)
| (static_cast<uint16_t>(s.spriteShape) << 14)), | (static_cast<uint16_t>(sprite.spriteShape) << 14)),
.attr1 = static_cast<uint16_t>( .attr1 = static_cast<uint16_t>(
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8)) (static_cast<uint16_t>(sprite.x) & ox::onMask<uint8_t>(8))
| (static_cast<uint16_t>(s.flipX) << 12) | (static_cast<uint16_t>(sprite.flipX) << 12)
| (static_cast<uint16_t>(s.spriteSize) << 14)), | (static_cast<uint16_t>(sprite.spriteSize) << 14)),
.attr2 = static_cast<uint16_t>( .attr2 = static_cast<uint16_t>(
// double tileIdx if 8 bpp // double tileIdx if 8 bpp
(static_cast<uint16_t>((s.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8))) (static_cast<uint16_t>((sprite.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8)))
| (static_cast<uint16_t>(s.priority & 0b11) << 10)), | (static_cast<uint16_t>(sprite.priority & 0b11) << 10)),
.idx = static_cast<uint16_t>(idx), .idx = static_cast<uint16_t>(idx),
}); });
} }
@@ -348,7 +350,7 @@ uint_t spriteCount(Context const &) noexcept {
namespace ox { namespace ox {
void panic(char const *file, int line, char const *panicMsg, ox::Error const &err) noexcept { void panic(char const*panicMsg, Error const&err, std::source_location const &src) noexcept {
using namespace nostalgia::gfx; using namespace nostalgia::gfx;
// reset heap to make sure we have enough memory to allocate context data // reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
@@ -372,7 +374,7 @@ void panic(char const *file, int line, char const *panicMsg, ox::Error const &er
} }
consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM"); consoleWrite(*ctx, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
// print to terminal if in mGBA // print to terminal if in mGBA
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg); oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", src.file_name(), src.line(), panicMsg);
if (err.msg) { if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg); oxErrf("\tError Message:\t{}\n", err.msg);
} }

View File

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

View File

@@ -13,79 +13,66 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
static class: public keel::Module { static struct: keel::Module {
public:
[[nodiscard]]
ox::String id() const noexcept override {
return ox::String{"net.drinkingtea.nostalgia.gfx"};
}
[[nodiscard]] [[nodiscard]]
ox::Vector<keel::TypeDescGenerator> types() const noexcept final { ox::String id() const noexcept override {
return { return ox::String{"net.drinkingtea.nostalgia.gfx"};
keel::generateTypeDesc<TileSheetV1>, }
keel::generateTypeDesc<TileSheetV2>,
keel::generateTypeDesc<TileSheetV3>,
keel::generateTypeDesc<TileSheetV4>,
keel::generateTypeDesc<TileSheetV5>,
keel::generateTypeDesc<CompactTileSheetV1>,
keel::generateTypeDesc<PaletteV1>,
keel::generateTypeDesc<PaletteV2>,
keel::generateTypeDesc<PaletteV3>,
keel::generateTypeDesc<PaletteV4>,
keel::generateTypeDesc<PaletteV5>,
keel::generateTypeDesc<CompactPaletteV1>,
};
}
[[nodiscard]] [[nodiscard]]
ox::Vector<keel::Converter> converters() const noexcept final { ox::Vector<keel::TypeDescGenerator> types() const noexcept final {
return { return {
keel::Converter::make<convertNostalgiaPaletteToPaletteV1>(), keel::generateTypeDesc<TileSheetV1>,
keel::Converter::make<convertPaletteV1ToPaletteV2>(), keel::generateTypeDesc<TileSheetV2>,
keel::Converter::make<convertPaletteV2ToPaletteV3>(), keel::generateTypeDesc<TileSheetV3>,
keel::Converter::make<convertPaletteV3ToPaletteV4>(), keel::generateTypeDesc<TileSheetV4>,
keel::Converter::make<convertPaletteV4ToPaletteV5>(), keel::generateTypeDesc<TileSheetV5>,
keel::Converter::make<convertPaletteToCompactPalette>(), keel::generateTypeDesc<CompactTileSheetV1>,
keel::Converter::make<convertTileSheetV1ToTileSheetV2>(), keel::generateTypeDesc<PaletteV1>,
keel::Converter::make<convertTileSheetV2ToTileSheetV3>(), keel::generateTypeDesc<PaletteV2>,
keel::Converter::make<convertTileSheetV3ToTileSheetV4>(), keel::generateTypeDesc<PaletteV3>,
keel::Converter::make<convertTileSheetV4ToTileSheetV5>(), keel::generateTypeDesc<PaletteV4>,
keel::Converter::make<convertTileSheetToCompactTileSheet>(), keel::generateTypeDesc<PaletteV5>,
}; keel::generateTypeDesc<CompactPaletteV1>,
} };
}
[[nodiscard]] [[nodiscard]]
ox::Vector<keel::PackTransform> packTransforms() const noexcept final { ox::Vector<keel::Converter> converters() const noexcept final {
return { return {
// convert tilesheets to CompactTileSheets keel::Converter::make<convertNostalgiaPaletteToPaletteV1>(),
[](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> { keel::Converter::make<convertPaletteV1ToPaletteV2>(),
if (typeId == ox::ModelTypeId_v<TileSheetV1> || keel::Converter::make<convertPaletteV2ToPaletteV3>(),
typeId == ox::ModelTypeId_v<TileSheetV2> || keel::Converter::make<convertPaletteV3ToPaletteV4>(),
typeId == ox::ModelTypeId_v<TileSheetV3> || keel::Converter::make<convertPaletteV4ToPaletteV5>(),
typeId == ox::ModelTypeId_v<TileSheetV4> || keel::Converter::make<convertPaletteToCompactPalette>(),
typeId == ox::ModelTypeId_v<TileSheetV5>) { keel::Converter::make<convertTileSheetV1ToTileSheetV2>(),
OX_RETURN_ERROR(keel::convertBuffToBuff<CompactTileSheet>( keel::Converter::make<convertTileSheetV2ToTileSheetV3>(),
ctx, buff, ox::ClawFormat::Metal).moveTo(buff)); keel::Converter::make<convertTileSheetV3ToTileSheetV4>(),
return true; keel::Converter::make<convertTileSheetV4ToTileSheetV5>(),
} keel::Converter::make<convertTileSheetToCompactTileSheet>(),
return false; };
}, }
[](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> || [[nodiscard]]
typeId == ox::ModelTypeId_v<PaletteV1> || ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
typeId == ox::ModelTypeId_v<PaletteV2> || return {
typeId == ox::ModelTypeId_v<PaletteV3> || // convert tilesheets to CompactTileSheets
typeId == ox::ModelTypeId_v<PaletteV4> || keel::transformRule<TileSheetV1, CompactTileSheet>,
typeId == ox::ModelTypeId_v<PaletteV5>) { keel::transformRule<TileSheetV2, CompactTileSheet>,
OX_RETURN_ERROR(keel::convertBuffToBuff<CompactPalette>( keel::transformRule<TileSheetV3, CompactTileSheet>,
ctx, buff, ox::ClawFormat::Metal).moveTo(buff)); keel::transformRule<TileSheetV4, CompactTileSheet>,
return true; keel::transformRule<TileSheetV5, CompactTileSheet>,
} // convert palettes to CompactPalettes
return false; keel::transformRule<NostalgiaPalette, CompactPalette>,
}, keel::transformRule<PaletteV1, CompactPalette>,
}; keel::transformRule<PaletteV2, CompactPalette>,
} keel::transformRule<PaletteV3, CompactPalette>,
keel::transformRule<PaletteV4, CompactPalette>,
keel::transformRule<PaletteV5, CompactPalette>,
};
}
} const mod; } const mod;

View File

@@ -109,8 +109,8 @@ static void convertSubsheet(
dst.rows = src.rows; dst.rows = src.rows;
dst.pixels = std::move(src.pixels); dst.pixels = std::move(src.pixels);
++idIt; ++idIt;
dst.subsheets.resize(src.subsheets.size()); dst.subsheets.reserveResize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) { for (size_t i{}; i < src.subsheets.size(); ++i) {
convertSubsheet(src.subsheets[i], dst.subsheets[i], idIt); convertSubsheet(src.subsheets[i], dst.subsheets[i], idIt);
} }
} }
@@ -136,8 +136,8 @@ static void convertSubsheet(
dst.rows = src.rows; dst.rows = src.rows;
dst.pixels = std::move(src.pixels); dst.pixels = std::move(src.pixels);
++idIt; ++idIt;
dst.subsheets.resize(src.subsheets.size()); dst.subsheets.reserveResize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) { for (size_t i{}; i < src.subsheets.size(); ++i) {
convertSubsheet(src.subsheets[i], dst.subsheets[i], idIt); convertSubsheet(src.subsheets[i], dst.subsheets[i], idIt);
} }
} }
@@ -173,8 +173,8 @@ static void convertSubsheet(
} else { } else {
dst.pixels = std::move(src.pixels); dst.pixels = std::move(src.pixels);
} }
dst.subsheets.resize(src.subsheets.size()); dst.subsheets.reserveResize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) { for (size_t i{}; i < src.subsheets.size(); ++i) {
convertSubsheet(bpp, src.subsheets[i], dst.subsheets[i]); convertSubsheet(bpp, src.subsheets[i], dst.subsheets[i]);
} }
} }

View File

@@ -6,13 +6,14 @@
namespace nostalgia::gfx { namespace nostalgia::gfx {
TileSheetClipboard::Pixel::Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept { TileSheetClipboard::Pixel::Pixel(
colorIdx = pColorIdx; uint8_t const pColorIdx,
pt = pPt; ox::Point const pPt) noexcept:
} colorIdx(pColorIdx),
pt(pPt) {}
void TileSheetClipboard::addPixel(ox::Point const&pt, uint16_t colorIdx) noexcept { void TileSheetClipboard::addPixel(ox::Point const &pt, uint8_t colorIdx) noexcept {
m_pixels.emplace_back(colorIdx, pt); m_pixels.emplace_back(colorIdx, pt);
} }
@@ -22,43 +23,37 @@ const ox::Vector<TileSheetClipboard::Pixel> &TileSheetClipboard::pixels() const
CutPasteCommand::CutPasteCommand( CutPasteCommand::CutPasteCommand(
CommandId commandId, CommandId const commandId,
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx subSheetIdx, TileSheet::SubSheetIdx subSheetIdx,
ox::Point const&dstStart, ox::Point const &dstStart,
ox::Point dstEnd, ox::Point dstEnd,
TileSheetClipboard const&cb): TileSheetClipboard const &cb):
m_commandId(commandId), m_commandId(commandId),
m_img(img), m_img(img),
m_subSheetIdx(std::move(subSheetIdx)) { m_subSheetIdx(std::move(subSheetIdx)) {
auto const&ss = getSubSheet(m_img, m_subSheetIdx); auto const &ss = getSubSheet(m_img, m_subSheetIdx);
if (dstStart.x >= ss.columns * TileWidth || dstStart.y >= ss.rows * TileHeight) { if (dstStart.x >= ss.columns * TileWidth || dstStart.y >= ss.rows * TileHeight) {
throw ox::Exception{1, "paste starts beyond the bounds of target"}; throw ox::Exception{1, "paste starts beyond the bounds of target"};
} }
dstEnd.x = std::min(ss.columns * TileWidth - 1, dstEnd.x); dstEnd.x = std::min(ss.columns * TileWidth - 1, dstEnd.x);
dstEnd.y = std::min(ss.rows * TileHeight - 1, dstEnd.y); dstEnd.y = std::min(ss.rows * TileHeight - 1, dstEnd.y);
for (auto const&p : cb.pixels()) { for (auto const &p : cb.pixels()) {
auto const dstPt = p.pt + dstStart; auto const dstPt = p.pt + dstStart;
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) { if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
auto const idx = gfx::idx(ss, dstPt); auto const idx = gfx::idx(ss, dstPt);
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(ss, idx)); m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx);
} }
} }
} }
ox::Error CutPasteCommand::redo() noexcept { ox::Error CutPasteCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); swap();
for (auto const &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx);
}
return {}; return {};
} }
ox::Error CutPasteCommand::undo() noexcept { ox::Error CutPasteCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx); swap();
for (auto const &c : m_changes) {
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
}
return {}; return {};
} }
@@ -66,8 +61,15 @@ int CutPasteCommand::commandId() const noexcept {
return static_cast<int>(m_commandId); return static_cast<int>(m_commandId);
} }
TileSheet::SubSheetIdx const&CutPasteCommand::subsheetIdx() const noexcept { TileSheet::SubSheetIdx const &CutPasteCommand::subsheetIdx() const noexcept {
return m_subSheetIdx; return m_subSheetIdx;
} }
void CutPasteCommand::swap() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto &c : m_changes) {
std::swap(subsheet.pixels[c.idx], c.palIdx);
}
}
} }

View File

@@ -22,15 +22,15 @@ class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> {
struct Pixel { struct Pixel {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetClipboard.Pixel"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.studio.TileSheetClipboard.Pixel";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
uint16_t colorIdx = 0; uint8_t colorIdx = 0;
ox::Point pt; ox::Point pt;
Pixel(uint16_t pColorIdx, ox::Point pPt) noexcept; Pixel(uint8_t pColorIdx, ox::Point pPt) noexcept;
}; };
protected: protected:
ox::Vector<Pixel> m_pixels; ox::Vector<Pixel> m_pixels;
public: public:
void addPixel(ox::Point const &pt, uint16_t colorIdx) noexcept; void addPixel(ox::Point const &pt, uint8_t colorIdx) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<Pixel> const &pixels() const noexcept; ox::Vector<Pixel> const &pixels() const noexcept;
@@ -49,12 +49,10 @@ class CutPasteCommand: public TileSheetCommand {
private: private:
struct Change { struct Change {
uint32_t idx = 0; uint32_t idx = 0;
uint16_t newPalIdx = 0; uint8_t palIdx = 0;
uint16_t oldPalIdx = 0; constexpr Change(uint32_t const pIdx, uint8_t const pPalIdx) noexcept {
constexpr Change(uint32_t pIdx, uint16_t pNewPalIdx, uint16_t pOldPalIdx) noexcept {
idx = pIdx; idx = pIdx;
newPalIdx = pNewPalIdx; palIdx = pPalIdx;
oldPalIdx = pOldPalIdx;
} }
}; };
CommandId m_commandId; CommandId m_commandId;
@@ -81,6 +79,9 @@ class CutPasteCommand: public TileSheetCommand {
[[nodiscard]] [[nodiscard]]
TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override; TileSheet::SubSheetIdx const &subsheetIdx() const noexcept override;
private:
void swap() noexcept;
}; };
} }

View File

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

View File

@@ -8,4 +8,4 @@ target_link_libraries(
NostalgiaGfx NostalgiaGfx
) )
add_test("[NostalgiaGfx] readWriteTileSheet" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/NostalgiaGfxTest readWriteTileSheet) add_test("[nostalgia/gfx] 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; gfx::TileSheet const in;
OX_REQUIRE(buff, ox::writeMC(in)); OX_REQUIRE(buff, ox::writeMC(in));
OX_REQUIRE(out, ox::readMC<gfx::TileSheet>(buff)); OX_REQUIRE(out, ox::readMC<gfx::TileSheet>(buff));
oxAssert(in.subsheet.name == out.subsheet.name, "subsheet.name serialization broken"); ox::expect(in.subsheet.name, out.subsheet.name);
return {}; return {};
} }
}, },

View File

@@ -19,7 +19,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
ox::Array<char, hdr.size()> buff; ox::Array<char, hdr.size()> buff;
ox::CharBuffWriter bw(buff); ox::CharBuffWriter bw(buff);
OX_RETURN_ERROR(keel::writeUuidHeader(bw, uuid)); OX_RETURN_ERROR(keel::writeUuidHeader(bw, uuid));
oxExpect(ox::StringView(buff.data(), buff.size()), hdr); ox::expect(ox::StringView(buff.data(), buff.size()), hdr);
return {}; return {};
} }
}, },

View File

@@ -6,6 +6,7 @@ add_library(
font.cpp font.cpp
popups/about.cpp popups/about.cpp
popups/deleteconfirmation.cpp popups/deleteconfirmation.cpp
popups/fileinfo.cpp
popups/makecopy.cpp popups/makecopy.cpp
popups/newdir.cpp popups/newdir.cpp
popups/newmenu.cpp popups/newmenu.cpp

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "fileinfo.hpp"
namespace studio {
FileInfo::FileInfo(Context &sctx) noexcept:
Popup("File Info"),
m_sctx(sctx) {}
ox::Error FileInfo::open(ox::StringParam filePath) noexcept {
m_filePath = std::move(filePath);
auto &fs = m_sctx.project->romFs();
OX_REQUIRE(fileBuff, fs.read(m_filePath));
auto [hdr, err] = keel::readAssetHeader(fileBuff);
if (!err) {
m_fileInfo.emplace(Info{
.assetId = hdr.uuid.toString(),
.typeName = std::move(hdr.clawHdr.typeName),
.typeVersion = hdr.clawHdr.typeVersion,
.format = [&hdr] {
switch (hdr.clawHdr.fmt) {
case ox::ClawFormat::Metal:
return ox::StringLiteral{"Metal Claw"};
case ox::ClawFormat::Organic:
return ox::StringLiteral{"Organic Claw"};
default:
return ox::StringLiteral{"Other"};
}
}(),
.dataSize = hdr.clawHdr.dataSize,
});
}
Popup::open();
return {};
}
void FileInfo::draw(Context &sctx) noexcept {
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
close();
return;
}
switch (m_stage) {
case Stage::Closed:
break;
case Stage::Opening:
ImGui::OpenPopup(m_title.c_str());
m_stage = Stage::Open;
[[fallthrough]];
case Stage::Open: {
constexpr auto modalFlags =
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
ig::centerNextWindow(sctx.tctx);
auto open = true;
if (ImGui::BeginPopupModal(m_title.c_str(), &open, modalFlags)) {
drawTable();
switch (auto const r = ig::PopupControlsOk(m_open, "Close")) {
case ig::PopupResponse::None:
break;
case ig::PopupResponse::OK:
response.emit(r);
m_fileInfo.reset();
m_filePath = ox::String{};
close();
break;
case ig::PopupResponse::Cancel:
break;
}
ImGui::EndPopup();
}
if (!open) {
m_stage = Stage::Closed;
}
break;
}
}
}
void FileInfo::drawTable() const noexcept {
ig::IDStackItem const idStackItem{"FileInfo"};
ImGui::Text("%s", m_filePath.c_str());
if (m_fileInfo && ImGui::BeginTable(
"Table", 2,
ImGuiTableFlags_Borders |
ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Field", ImGuiTableColumnFlags_WidthFixed, 70);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_NoHide);
// asset id
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Asset ID:");
ImGui::TableSetColumnIndex(1);
ImGui::Text("%s", m_fileInfo->assetId.c_str());
// typeName
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Type Name:");
ImGui::TableSetColumnIndex(1);
ImGui::Text("%s", m_fileInfo->typeName.c_str());
// typeVersion
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Type Version:");
ImGui::TableSetColumnIndex(1);
ImGui::Text("%d", m_fileInfo->typeVersion);
// format
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Format:");
ImGui::TableSetColumnIndex(1);
ImGui::Text("%s", m_fileInfo->format.c_str());
// size
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Data Size:");
ImGui::TableSetColumnIndex(1);
ImGui::Text("%lluB", m_fileInfo->dataSize);
ImGui::EndTable();
} else {
ImGui::Text("No information available");
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/string.hpp>
#include <studio/context.hpp>
#include <studio/imguiutil.hpp>
namespace studio {
class FileInfo: public ig::Popup {
private:
Context &m_sctx;
ox::String m_filePath;
struct Info {
ox::UUIDStr assetId;
ox::String typeName;
int typeVersion{};
ox::StringLiteral format;
// use manual sizing to work with %ull
unsigned long long dataSize{};
};
ox::Optional<Info> m_fileInfo;
public:
explicit FileInfo(Context &sctx) noexcept;
ox::Error open(ox::StringParam filePath) noexcept;
void draw(Context &sctx) noexcept override;
private:
void drawTable() const noexcept;
};
}

View File

@@ -36,6 +36,13 @@ void ProjectExplorer::dirMoved(ox::StringViewCR src, ox::StringViewCR dst) const
void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept { void ProjectExplorer::fileContextMenu(ox::StringViewCR path) const noexcept {
if (ImGui::BeginPopupContextItem("FileMenu", ImGuiPopupFlags_MouseButtonRight)) { if (ImGui::BeginPopupContextItem("FileMenu", ImGuiPopupFlags_MouseButtonRight)) {
if (ImGui::MenuItem("Open")) {
fileChosen.emit(path);
}
if (ImGui::MenuItem("Get Info")) {
getInfo.emit(path);
}
ImGui::Separator();
if (ImGui::MenuItem("Delete")) { if (ImGui::MenuItem("Delete")) {
deleteItem.emit(path); deleteItem.emit(path);
} }

View File

@@ -21,6 +21,7 @@ class ProjectExplorer final: public FileExplorer {
ox::Signal<ox::Error(ox::StringViewCR)> deleteItem; ox::Signal<ox::Error(ox::StringViewCR)> deleteItem;
ox::Signal<ox::Error(ox::StringViewCR)> renameItem; ox::Signal<ox::Error(ox::StringViewCR)> renameItem;
ox::Signal<ox::Error(ox::StringViewCR)> makeCopy; ox::Signal<ox::Error(ox::StringViewCR)> makeCopy;
ox::Signal<ox::Error(ox::StringViewCR)> getInfo;
ox::Signal<ox::Error(ox::StringViewCR src, ox::StringViewCR dst)> moveDir; ox::Signal<ox::Error(ox::StringViewCR src, ox::StringViewCR dst)> moveDir;
ox::Signal<ox::Error(ox::StringViewCR src, ox::StringViewCR dst)> moveItem; ox::Signal<ox::Error(ox::StringViewCR src, ox::StringViewCR dst)> moveItem;

View File

@@ -146,6 +146,7 @@ StudioUI::StudioUI(turbine::Context &tctx, ox::StringParam projectDataDir) noexc
m_projectExplorer.addDir.connect(this, &StudioUI::addDir); m_projectExplorer.addDir.connect(this, &StudioUI::addDir);
m_projectExplorer.addItem.connect(this, &StudioUI::addFile); m_projectExplorer.addItem.connect(this, &StudioUI::addFile);
m_projectExplorer.deleteItem.connect(this, &StudioUI::deleteFile); m_projectExplorer.deleteItem.connect(this, &StudioUI::deleteFile);
m_projectExplorer.getInfo.connect(this, &StudioUI::getFileInfo);
m_projectExplorer.renameItem.connect(this, &StudioUI::renameFile); m_projectExplorer.renameItem.connect(this, &StudioUI::renameFile);
m_projectExplorer.makeCopy.connect(this, &StudioUI::makeCopyDlg); m_projectExplorer.makeCopy.connect(this, &StudioUI::makeCopyDlg);
m_projectExplorer.moveDir.connect(this, &StudioUI::queueDirMove); m_projectExplorer.moveDir.connect(this, &StudioUI::queueDirMove);
@@ -569,6 +570,10 @@ ox::Error StudioUI::deleteFile(ox::StringViewCR path) noexcept {
return {}; return {};
} }
ox::Error StudioUI::getFileInfo(ox::StringViewCR path) noexcept {
return m_fileInfo.open(path);
}
ox::Error StudioUI::renameFile(ox::StringViewCR path) noexcept { ox::Error StudioUI::renameFile(ox::StringViewCR path) noexcept {
return m_renameFile.openPath(path); return m_renameFile.openPath(path);
} }

View File

@@ -21,6 +21,7 @@
#include "popups/newmenu.hpp" #include "popups/newmenu.hpp"
#include "popups/newproject.hpp" #include "popups/newproject.hpp"
#include "projectexplorer.hpp" #include "projectexplorer.hpp"
#include "popups/fileinfo.hpp"
#include "popups/renamefile.hpp" #include "popups/renamefile.hpp"
namespace studio { namespace studio {
@@ -48,6 +49,7 @@ class StudioUI final: public ox::SignalHandler {
NewMenu m_newMenu{keelCtx(m_tctx)}; NewMenu m_newMenu{keelCtx(m_tctx)};
AboutPopup m_aboutPopup{m_tctx}; AboutPopup m_aboutPopup{m_tctx};
DeleteConfirmation m_deleteConfirmation; DeleteConfirmation m_deleteConfirmation;
FileInfo m_fileInfo{m_sctx};
NewDir m_newDirDialog; NewDir m_newDirDialog;
ig::QuestionPopup m_closeFileConfirm{"Close File?", "This file has unsaved changes. Close?"}; ig::QuestionPopup m_closeFileConfirm{"Close File?", "This file has unsaved changes. Close?"};
ig::QuestionPopup m_closeAppConfirm{ ig::QuestionPopup m_closeAppConfirm{
@@ -62,10 +64,11 @@ class StudioUI final: public ox::SignalHandler {
ig::QuestionPopup dlg{"Remove From Recents?", "Unable to load project. Remove from recent projects?"}; ig::QuestionPopup dlg{"Remove From Recents?", "Unable to load project. Remove from recent projects?"};
size_t idx{}; size_t idx{};
} m_removeRecentProject; } m_removeRecentProject;
ox::Array<Widget*, 11> const m_widgets { ox::Array<Widget*, 12> const m_widgets {
&m_closeFileConfirm, &m_closeFileConfirm,
&m_closeAppConfirm, &m_closeAppConfirm,
&m_copyFilePopup, &m_copyFilePopup,
&m_fileInfo,
&m_newMenu, &m_newMenu,
&m_newProject, &m_newProject,
&m_aboutPopup, &m_aboutPopup,
@@ -130,6 +133,8 @@ class StudioUI final: public ox::SignalHandler {
ox::Error deleteFile(ox::StringViewCR path) noexcept; ox::Error deleteFile(ox::StringViewCR path) noexcept;
ox::Error getFileInfo(ox::StringViewCR path) noexcept;
ox::Error renameFile(ox::StringViewCR path) noexcept; ox::Error renameFile(ox::StringViewCR path) noexcept;
ox::Error handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const &id) noexcept; ox::Error handleMoveFile(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const &id) noexcept;

View File

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