[ox] Overhaul serialization/model system and add ModelValue/ModelObject/ModelUnion variant system

This commit is contained in:
Gary Talent 2022-06-21 21:43:49 -05:00
parent bc391b45fc
commit ca64f95be3
47 changed files with 2696 additions and 973 deletions

2
deps/ox/.liccor.yml vendored
View File

@ -6,4 +6,4 @@ copyright_notice: |-
This Source Code Form is subject to the terms of the Mozilla Public 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 License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. file, You can obtain one at https://mozilla.org/MPL/2.0/.

View File

@ -191,6 +191,10 @@ if(JSONCPP_WITH_TESTS)
include(CTest) include(CTest)
endif() endif()
# DrinkingTea - begin
set(CMAKE_CXX_FLAGS "-Wno-everything")
# DrinkingTea - end
# Build the different applications # Build the different applications
add_subdirectory(src) add_subdirectory(src)

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
@ -72,4 +72,34 @@ Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
return stripClawHeader(buff.data(), buff.size()); return stripClawHeader(buff.data(), buff.size());
} }
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
oxRequire(header, readClawHeader(buff));
oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion));
ModelObject obj;
oxReturnError(obj.setType(t));
switch (header.fmt) {
case ClawFormat::Metal:
{
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize);
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
return obj;
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize);
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
return obj;
#else
break;
#endif
}
case ClawFormat::None:
return OxError(1);
}
return OxError(1);
}
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -50,13 +50,14 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
switch (header.fmt) { switch (header.fmt) {
case ClawFormat::Metal: case ClawFormat::Metal:
{ {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), buffLen); MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize);
return model(&reader, val); ModelHandlerInterface handler(&reader);
return model(&handler, val);
} }
case ClawFormat::Organic: case ClawFormat::Organic:
{ {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, buffLen); OrganicClawReader reader(header.data, header.dataSize);
return model(&reader, val); return model(&reader, val);
#else #else
break; break;
@ -85,4 +86,6 @@ Result<T> readClaw(const Buffer &buff) {
return readClaw<T>(buff.data(), buff.size()); return readClaw<T>(buff.data(), buff.size());
} }
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept;
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#undef NDEBUG #undef NDEBUG
@ -25,7 +25,7 @@ union TestUnion {
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool Bool; bool Bool;
uint32_t Int = 5; uint32_t Int = 5;
char String[32]; char *String;
}; };
struct TestStructNest { struct TestStructNest {
@ -49,6 +49,7 @@ struct TestStruct {
int32_t Int6 = 0; int32_t Int6 = 0;
int32_t Int7 = 0; int32_t Int7 = 0;
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::BString<32> String = ""; ox::BString<32> String = "";
uint32_t List[4] = {0, 0, 0, 0}; uint32_t List[4] = {0, 0, 0, 0};
@ -56,21 +57,24 @@ struct TestStruct {
TestStructNest Struct; TestStructNest Struct;
~TestStruct() { ~TestStruct() {
if (unionIdx == 2) {
ox::safeDelete(Union.String);
}
} }
}; };
template<typename T> template<typename T>
constexpr ox::Error model(T *io, TestUnion *obj) { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) {
io->template setTypeInfo<TestUnion>(); io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", ox::SerStr(obj->String))); oxReturnError(io->fieldCString("String", &obj->String));
return OxError(0); return OxError(0);
} }
template<typename T> template<typename T>
constexpr ox::Error model(T *io, TestStructNest *obj) { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) {
io->template setTypeInfo<TestStructNest>(); io->template setTypeInfo<TestStructNest>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
@ -79,7 +83,7 @@ constexpr ox::Error model(T *io, TestStructNest *obj) {
} }
template<typename T> template<typename T>
constexpr ox::Error model(T *io, TestStruct *obj) { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
io->template setTypeInfo<TestStruct>(); io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
@ -91,7 +95,11 @@ constexpr ox::Error model(T *io, TestStruct *obj) {
oxReturnError(io->field("Int6", &obj->Int6)); oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1})); int unionIdx = 0;
if constexpr(ox_strcmp(T::opType(), ox::OpType::Reflect) != 0) {
unionIdx = obj->unionIdx;
}
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, unionIdx}));
oxReturnError(io->field("String", &obj->String)); oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct)); oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
@ -99,7 +107,7 @@ constexpr ox::Error model(T *io, TestStruct *obj) {
return OxError(0); return OxError(0);
} }
std::map<std::string_view, ox::Error(*)()> tests = { static std::map<std::string_view, ox::Error(*)()> tests = {
{ {
{ {
"ClawHeaderReader", "ClawHeaderReader",
@ -153,7 +161,7 @@ std::map<std::string_view, ox::Error(*)()> tests = {
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal); auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal);
oxAssert(err, "writeMC failed"); oxAssert(err, "writeMC failed");
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "writeMC failed"); oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "readMC failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n"; //std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");

View File

@ -82,8 +82,7 @@ Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
} }
template<typename T> Result<Buffer> writeClaw(auto *t, ClawFormat fmt = ClawFormat::Metal) {
Result<Buffer> writeClaw(T *t, ClawFormat fmt = ClawFormat::Metal) {
oxRequire(header, detail::writeClawHeader(t, fmt)); oxRequire(header, detail::writeClawHeader(t, fmt));
oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t)); oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t));
Buffer out(header.len() + data.size()); Buffer out(header.len() + data.size());

View File

@ -3,12 +3,13 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/std/std.hpp> #include <ox/std/std.hpp>
#include <ox/model/def.hpp>
#include <ox/model/typenamecatcher.hpp> #include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp> #include <ox/model/types.hpp>
@ -24,7 +25,7 @@ enum class FileAddressType: int8_t {
class FileAddress { class FileAddress {
template<typename T> template<typename T>
friend constexpr Error model(T*, FileAddress*) noexcept; friend constexpr Error model(T*, CommonPtrWith<FileAddress> auto*) noexcept;
public: public:
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress"; static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
@ -129,22 +130,16 @@ constexpr const char *getModelTypeName<FileAddress>() noexcept {
} }
template<typename T> template<typename T>
constexpr Error model(T *io, FileAddress::Data *obj) noexcept { constexpr Error model(T *io, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
io->template setTypeInfo<FileAddress::Data>(); io->template setTypeInfo<FileAddress::Data>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) { oxReturnError(io->fieldCString("path", &obj->path));
String dummy; oxReturnError(io->fieldCString("constPath", &obj->path));
oxReturnError(io->field("path", &dummy));
oxReturnError(io->field("constPath", &dummy));
} else {
oxReturnError(io->field("path", SerStr(&obj->path)));
oxReturnError(io->field("constPath", SerStr(&obj->path)));
}
oxReturnError(io->field("inode", &obj->inode)); oxReturnError(io->field("inode", &obj->inode));
return OxError(0); return OxError(0);
} }
template<typename T> template<typename T>
constexpr Error model(T *io, FileAddress *fa) noexcept { constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
io->template setTypeInfo<FileAddress>(); io->template setTypeInfo<FileAddress>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) { if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
int8_t type = 0; int8_t type = 0;

View File

@ -64,7 +64,7 @@ template<typename I>
[[nodiscard]] [[nodiscard]]
constexpr McInt encodeInteger(I input) noexcept { constexpr McInt encodeInteger(I input) noexcept {
McInt out; McInt out;
auto inputNegative = is_signed_v<I> && input < 0; const auto inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid // move input to uint64_t to allow consistent bit manipulation, and to avoid
// overflow concerns // overflow concerns
uint64_t val = 0; uint64_t val = 0;
@ -72,7 +72,7 @@ constexpr McInt encodeInteger(I input) noexcept {
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); const auto highBit = inputNegative ? highestBit(~val) : highestBit(val);
const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0); const auto bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
// bytes needed to store value // bytes needed to store value
std::size_t bytes = bits / 8 + (bits % 8 != 0); std::size_t bytes = bits / 8 + (bits % 8 != 0);
@ -84,7 +84,6 @@ constexpr McInt encodeInteger(I input) noexcept {
++bytes; ++bytes;
} }
const auto bytesIndicator = onMask<uint8_t>(bytes - 1); const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
// ensure we are copying from little endian representation // ensure we are copying from little endian representation
LittleEndian<uint64_t> leVal = val; LittleEndian<uint64_t> leVal = val;
if (inputNegative) { if (inputNegative) {
@ -116,7 +115,7 @@ constexpr McInt encodeInteger(I input) noexcept {
[[nodiscard]] [[nodiscard]]
static constexpr std::size_t countBytes(uint8_t b) noexcept { static constexpr std::size_t countBytes(uint8_t b) noexcept {
std::size_t i = 0; std::size_t i = 0;
for (; (b >> i) & 1; i++); while ((b >> i) & 1) ++i;
return i + 1; return i + 1;
} }

View File

@ -3,157 +3,9 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/assert.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>
#include "read.hpp"
namespace ox { namespace ox {
MetalClawReader::MetalClawReader(const uint8_t *buff, std::size_t buffLen, int unionIdx, MetalClawReader *parent) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff),
m_parent(parent) {
}
MetalClawReader::~MetalClawReader() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given";
}
}
Error MetalClawReader::field(const char*, int8_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, int16_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, int32_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, int64_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
}
Error MetalClawReader::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = valErr.value;
oxReturnError(valErr.error);
}
++m_field;
return OxError(0);
}
Error MetalClawReader::field(const char*, SerStr val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
auto data = val.data(size + 1);
// read the string
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} else {
return OxError(MC_OUTBUFFENDED);
}
} else {
auto data = val.data();
if (data) {
data[0] = 0;
}
}
}
++m_field;
return OxError(0);
}
Error MetalClawReader::fieldCString(const char *name, char **val, int len) noexcept {
return field(name, SerStr(val, len));
}
Result<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
if (pass) {
m_buffIt += bytesRead;
}
return out;
}
return OxError(1);
}
[[nodiscard]]
StringLength MetalClawReader::stringLength(const char*) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
return len.value;
}
return 0;
}
MetalClawReader MetalClawReader::child(const char*, int unionIdx) noexcept {
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
}
bool MetalClawReader::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
}
bool MetalClawReader::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
}
void MetalClawReader::nextField() noexcept {
++m_field;
}
} }

View File

@ -3,12 +3,13 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/model/fieldcounter.hpp> #include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp> #include <ox/model/optype.hpp>
#include <ox/model/typenamecatcher.hpp> #include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp> #include <ox/model/types.hpp>
@ -25,7 +26,8 @@
namespace ox { namespace ox {
class MetalClawReader { template<auto HandlerMaker>
class MetalClawReaderTemplate {
private: private:
FieldBitmapReader<const uint8_t*> m_fieldPresence; FieldBitmapReader<const uint8_t*> m_fieldPresence;
@ -35,87 +37,93 @@ class MetalClawReader {
std::size_t m_buffIt = 0; std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0; std::size_t m_buffLen = 0;
const uint8_t *m_buff = nullptr; const uint8_t *m_buff = nullptr;
MetalClawReader *m_parent = nullptr; MetalClawReaderTemplate<HandlerMaker> *m_parent = nullptr;
public: public:
MetalClawReader(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1, MetalClawReader *parent = nullptr) noexcept; constexpr MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1,
MetalClawReaderTemplate<HandlerMaker> *parent = nullptr) noexcept;
~MetalClawReader() noexcept; constexpr ~MetalClawReaderTemplate() noexcept;
Error field(const char*, int8_t *val) noexcept; constexpr Error field(const char*, int8_t *val) noexcept;
Error field(const char*, int16_t *val) noexcept; constexpr Error field(const char*, int16_t *val) noexcept;
Error field(const char*, int32_t *val) noexcept; constexpr Error field(const char*, int32_t *val) noexcept;
Error field(const char*, int64_t *val) noexcept; constexpr Error field(const char*, int64_t *val) noexcept;
Error field(const char*, uint8_t *val) noexcept; constexpr Error field(const char*, uint8_t *val) noexcept;
Error field(const char*, uint16_t *val) noexcept; constexpr Error field(const char*, uint16_t *val) noexcept;
Error field(const char*, uint32_t *val) noexcept; constexpr Error field(const char*, uint32_t *val) noexcept;
Error field(const char*, uint64_t *val) noexcept; constexpr Error field(const char*, uint64_t *val) noexcept;
Error field(const char*, bool *val) noexcept; constexpr Error field(const char*, bool *val) noexcept;
// array handler // array handler
template<typename T> constexpr Error field(const char*, auto *val, std::size_t len) noexcept;
Error field(const char*, T *val, std::size_t len) noexcept;
// map handler // map handler
template<typename T> template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept; constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
// array handler, with callback to allow handling individual elements // array handler, with callback to allow handling individual elements
template<typename T, typename Handler> template<typename T, typename CB>
Error field(const char*, Handler handler) noexcept; constexpr Error field(const char*, CB cb) noexcept;
template<typename T> template<typename T>
Error field(const char*, T *val) noexcept; constexpr Error field(const char*, T *val) noexcept;
template<typename U> template<typename U, bool force>
Error field(const char*, UnionView<U> val) noexcept; constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept; constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L> template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept; constexpr Error field(const char*, BString<L> *val) noexcept;
Error field(const char*, SerStr val) noexcept; constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept; constexpr Error fieldCString(const char*, char **val) noexcept;
constexpr Error fieldCString(const char*, char **val, std::size_t buffLen) noexcept;
/** /**
* Reads an array length from the current location in the buffer. * Reads an array length from the current location in the buffer.
* @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<ArrayLength> arrayLength(const char *name, bool pass = true) noexcept; constexpr Result<ArrayLength> arrayLength(const char *name, 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]]
StringLength stringLength(const char *name) noexcept; constexpr StringLength stringLength(const char *name) noexcept;
template<typename T = std::nullptr_t> template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept; constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
/** /**
* Returns a MetalClawReader to parse a child object. * Returns a MetalClawReader to parse a child object.
*/ */
[[nodiscard]] [[nodiscard]]
MetalClawReader child(const char *name, int unionIdx = -1) noexcept; constexpr MetalClawReaderTemplate<HandlerMaker> child(const char *name, int unionIdx = -1) 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.
*/ */
[[nodiscard]] [[nodiscard]]
bool fieldPresent(const char *name) const noexcept; constexpr bool fieldPresent(const char *name) const noexcept;
/** /**
* Indicates whether or not the given field is present. * Indicates whether or not the given field is present.
*/ */
[[nodiscard]] [[nodiscard]]
bool fieldPresent(int fieldNo) const noexcept; constexpr bool fieldPresent(int fieldNo) const noexcept;
void nextField() noexcept; [[nodiscard]]
constexpr int whichFieldPresent(const char *name, const ModelUnion&) const noexcept;
constexpr void nextField() noexcept;
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
@ -124,12 +132,145 @@ class MetalClawReader {
private: private:
template<typename I> template<typename I>
Error readInteger(I *val) noexcept; constexpr Error readInteger(I *val) noexcept;
}; };
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker>::MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen,
int unionIdx,
MetalClawReaderTemplate *parent) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff),
m_parent(parent) {
}
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker>::~MetalClawReaderTemplate() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given";
}
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int8_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int16_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int32_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int64_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = valErr.value;
oxReturnError(valErr.error);
}
++m_field;
return OxError(0);
}
// array handler
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, auto *val, std::size_t valLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
if (valLen >= len) {
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i]));
}
} else {
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
return OxError(MC_OUTBUFFENDED);
}
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
template<typename T> template<typename T>
Error MetalClawReader::field(const char *name, T *val) noexcept { constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMap<String, T> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = handler.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
oxReturnError(handler.fieldCString("", &wkeyPtr, static_cast<int>(keyLen + 1)));
oxReturnError(handler.field("", &val->operator[](wkey.get())));
}
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
template<typename T>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T *val) noexcept {
if constexpr(isVector_v<T>) { if constexpr(isVector_v<T>) {
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_unionIdx == -1 || 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
@ -142,27 +283,35 @@ Error MetalClawReader::field(const char *name, T *val) noexcept {
++m_field; ++m_field;
return OxError(0); return OxError(0);
} else { } else {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val && m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if ((m_unionIdx == -1 || m_unionIdx == m_field) && val) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child(""); auto reader = child("");
oxReturnError(model(&reader, val)); auto handler = HandlerMaker(&reader);
oxReturnError(model(&handler, val));
}
} }
++m_field; ++m_field;
return OxError(0); return OxError(0);
} }
} }
template<typename U> template<auto HandlerMaker>
Error MetalClawReader::field(const char*, UnionView<U> val) noexcept { template<typename U, bool force>
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get() && m_fieldPresence.get(static_cast<std::size_t>(m_field))) { constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, UnionView<U, force> val) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("", val.idx()); auto reader = child("", val.idx());
oxReturnError(model(&reader, val.get())); auto handler = HandlerMaker(&reader);
oxReturnError(model(&handler, val.get()));
}
} }
++m_field; ++m_field;
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker>
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
Error MetalClawReader::field(const char*, BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
@ -193,13 +342,129 @@ Error MetalClawReader::field(const char*, BasicString<SmallStringSize> *val) noe
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker>
template<std::size_t L> template<std::size_t L>
Error MetalClawReader::field(const char *name, BString<L> *val) noexcept { constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap())); return fieldCString(name, val->data(), val->cap());
} }
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
if (size > buffLen) {
return OxError(MC_OUTBUFFENDED);
}
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small
auto data = val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
auto data = *val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate if too small
if (buffLen < size + 1) {
safeDelete(*val);
*val = new char[size + 1];
buffLen = size + 1;
}
auto data = *val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} else {
auto data = *val;
if (data) {
data[0] = 0;
}
}
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength(const char*, bool pass) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field)) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
if (pass) {
m_buffIt += bytesRead;
}
return out;
}
}
return OxError(1);
}
template<auto HandlerMaker>
template<typename I> template<typename I>
Error MetalClawReader::readInteger(I *val) noexcept { constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
@ -219,65 +484,9 @@ Error MetalClawReader::readInteger(I *val) noexcept {
return OxError(0); return OxError(0);
} }
// array handler template<auto HandlerMaker>
template<typename T> template<typename T, typename CB>
Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) noexcept { constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
if (valLen >= len) {
auto reader = child("");
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(reader.field("", &val[i]));
}
} else {
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
return OxError(MC_OUTBUFFENDED);
}
}
}
++m_field;
return OxError(0);
}
template<typename T>
Error MetalClawReader::field(const char*, HashMap<String, T> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
auto reader = child("");
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = reader.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
oxReturnError(reader.fieldCString("", &wkeyPtr, static_cast<int>(keyLen + 1)));
oxReturnError(reader.field("", &val->operator[](wkey.get())));
}
}
}
++m_field;
return OxError(0);
}
template<typename T, typename Handler>
Error MetalClawReader::field(const char*, Handler handler) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
@ -290,11 +499,12 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
// read the list // read the list
auto reader = child(""); auto reader = child("");
reader.setTypeInfo("List", 0, static_cast<int>(len)); auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) { for (std::size_t i = 0; i < len; ++i) {
T val; T val;
oxReturnError(reader.field("", &val)); oxReturnError(handler.field("", &val));
oxReturnError(handler(i, &val)); oxReturnError(cb(i, &val));
} }
} }
} }
@ -302,18 +512,70 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker>
constexpr StringLength MetalClawReaderTemplate<HandlerMaker>::stringLength(const char*) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field)) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
return len.value;
}
}
return 0;
}
template<auto HandlerMaker>
template<typename T> template<typename T>
constexpr void MetalClawReader::setTypeInfo(const char*, int, int fields) noexcept { constexpr void MetalClawReaderTemplate<HandlerMaker>::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields; m_fields = fields;
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0)); m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
m_fieldPresence.setFields(fields); m_fieldPresence.setFields(fields);
m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt)); m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt));
} }
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker> MetalClawReaderTemplate<HandlerMaker>::child(const char*, int unionIdx) noexcept {
return MetalClawReaderTemplate<HandlerMaker>(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
}
template<auto HandlerMaker>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
}
template<auto HandlerMaker>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
}
template<auto HandlerMaker>
[[nodiscard]]
constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
FieldBitmapReader<const uint8_t*> p(m_buff + m_buffIt, m_buffLen - m_buffIt);
p.setFields(u.fieldCount());
for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) {
return static_cast<int>(i);
}
}
return -1;
}
template<auto HandlerMaker>
constexpr void MetalClawReaderTemplate<HandlerMaker>::nextField() noexcept {
++m_field;
}
using MetalClawReader = MetalClawReaderTemplate<[](auto r) {
return ModelHandlerInterface{r};
}>;
template<typename T> template<typename T>
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept { Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(buff), buffLen); MetalClawReader reader(reinterpret_cast<const uint8_t*>(buff), buffLen);
return model(&reader, val); ModelHandlerInterface handler(&reader);
return model(&handler, val);
} }
template<typename T> template<typename T>

View File

@ -10,6 +10,7 @@ target_link_libraries(
add_test("[ox/mc] McTest Writer" McTest MetalClawWriter) add_test("[ox/mc] McTest Writer" McTest MetalClawWriter)
add_test("[ox/mc] McTest Reader" McTest MetalClawReader) add_test("[ox/mc] McTest Reader" McTest MetalClawReader)
add_test("[ox/mc] McTest MetalClawDef" McTest MetalClawDef) #add_test("[ox/mc] McTest MetalClawDef" McTest MetalClawDef)
add_test("[ox/mc] McTest MetalClawModelValue" McTest MetalClawModelValue)
add_test("[ox/mc] McTest encodeInteger" McTest encodeInteger) add_test("[ox/mc] McTest encodeInteger" McTest encodeInteger)
add_test("[ox/mc] McTest decodeInteger" McTest decodeInteger) add_test("[ox/mc] McTest decodeInteger" McTest decodeInteger)

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#undef NDEBUG #undef NDEBUG
@ -19,7 +19,7 @@ union TestUnion {
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool Bool; bool Bool;
uint32_t Int = 5; uint32_t Int = 5;
char CString[32]; char *CString;
}; };
struct TestStructNest { struct TestStructNest {
@ -43,6 +43,7 @@ struct TestStruct {
int32_t Int6 = 0; int32_t Int6 = 0;
int32_t Int7 = 0; int32_t Int7 = 0;
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::String String = ""; ox::String String = "";
ox::BString<32> BString = ""; ox::BString<32> BString = "";
@ -50,14 +51,19 @@ struct TestStruct {
ox::HashMap<ox::String, int> Map; ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct; TestStructNest EmptyStruct;
TestStructNest Struct; TestStructNest Struct;
constexpr ~TestStruct() noexcept {
if (unionIdx == 2) {
ox::safeDelete(Union.CString);
}
}
}; };
template<typename T> template<typename T>
constexpr ox::Error model(T *io, TestUnion *obj) noexcept { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
io->template setTypeInfo<TestUnion>(); io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("CString", ox::SerStr(obj->CString))); oxReturnError(io->fieldCString("CString", &obj->CString));
return OxError(0); return OxError(0);
} }
@ -68,7 +74,7 @@ oxModelBegin(TestStructNest)
oxModelEnd() oxModelEnd()
template<typename T> template<typename T>
constexpr ox::Error model(T *io, TestStruct *obj) noexcept { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
io->template setTypeInfo<TestStruct>(); io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
@ -80,7 +86,12 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
oxReturnError(io->field("Int6", &obj->Int6)); oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1})); oxReturnError(io->field("unionIdx", &obj->unionIdx));
if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
}
oxReturnError(io->field("String", &obj->String)); oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("BString", &obj->BString)); oxReturnError(io->field("BString", &obj->BString));
oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("List", obj->List, 4));
@ -165,14 +176,15 @@ std::map<ox::String, ox::Error(*)()> tests = {
using ox::MaxValue; using ox::MaxValue;
using ox::mc::McInt; using ox::mc::McInt;
using ox::mc::encodeInteger; using ox::mc::encodeInteger;
static constexpr auto check = [](McInt val, ox::Vector<uint8_t, 9> &&expected) { static constexpr auto check = [](McInt val, const ox::Vector<uint8_t, 9> &expected) {
if (val.length != expected.size()) { if (val.length != expected.size()) {
std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n'; std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n';
return OxError(1); return OxError(1);
} }
for (std::size_t i = 0; i < expected.size(); i++) { for (std::size_t i = 0; i < expected.size(); i++) {
if (expected[i] != val.data[i]) { if (expected[i] != val.data[i]) {
std::cout << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n'; std::cout << "decoded: " << static_cast<uint32_t>(val.data[i]) << ", expected: " << static_cast<uint32_t>(expected[i]) << '\n';
std::cout << "decoded: " << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n';
return OxError(1); return OxError(1);
} }
} }
@ -195,6 +207,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(check(encodeInteger(int64_t(2)), {0b000'0010'0}), "Encode 2 fail"); oxAssert(check(encodeInteger(int64_t(2)), {0b000'0010'0}), "Encode 2 fail");
oxAssert(check(encodeInteger(int64_t(3)), {0b000'0011'0}), "Encode 3 fail"); oxAssert(check(encodeInteger(int64_t(3)), {0b000'0011'0}), "Encode 3 fail");
oxAssert(check(encodeInteger(int64_t(4)), {0b000'0100'0}), "Encode 4 fail"); oxAssert(check(encodeInteger(int64_t(4)), {0b000'0100'0}), "Encode 4 fail");
oxAssert(check(encodeInteger(int64_t(64)), {0b00'0000'01, 0b1}), "Encode 64 fail");
oxAssert(check(encodeInteger(int64_t(128)), {0b00'0000'01, 0b10}), "Encode 128 fail"); oxAssert(check(encodeInteger(int64_t(128)), {0b00'0000'01, 0b10}), "Encode 128 fail");
oxAssert(check(encodeInteger(int64_t(129)), {0b00'0001'01, 0b10}), "Encode 129 fail"); oxAssert(check(encodeInteger(int64_t(129)), {0b00'0001'01, 0b10}), "Encode 129 fail");
oxAssert(check(encodeInteger(int64_t(130)), {0b00'0010'01, 0b10}), "Encode 130 fail"); oxAssert(check(encodeInteger(int64_t(130)), {0b00'0010'01, 0b10}), "Encode 130 fail");
@ -204,6 +217,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(check(encodeInteger( int64_t(-2)), {0b111'1110'0}), "Encode -2 fail"); oxAssert(check(encodeInteger( int64_t(-2)), {0b111'1110'0}), "Encode -2 fail");
oxAssert(check(encodeInteger( int64_t(-3)), {0b111'1101'0}), "Encode -3 fail"); oxAssert(check(encodeInteger( int64_t(-3)), {0b111'1101'0}), "Encode -3 fail");
oxAssert(check(encodeInteger( int64_t(-4)), {0b111'1100'0}), "Encode -4 fail"); oxAssert(check(encodeInteger( int64_t(-4)), {0b111'1100'0}), "Encode -4 fail");
oxAssert(check(encodeInteger( int64_t(-64)), {0b100'0000'0}), "Encode -64 fail");
oxAssert(check(encodeInteger(int64_t(-128)), {0b00'0000'01, 0b11'1111'10}), "Encode -128 fail"); oxAssert(check(encodeInteger(int64_t(-128)), {0b00'0000'01, 0b11'1111'10}), "Encode -128 fail");
oxAssert(check(encodeInteger(int64_t(-129)), {0b11'1111'01, 0b11'1111'01}), "Encode -129 fail"); oxAssert(check(encodeInteger(int64_t(-129)), {0b11'1111'01, 0b11'1111'01}), "Encode -129 fail");
oxAssert(check(encodeInteger(int64_t(-130)), {0b11'1110'01, 0b11'1111'01}), "Encode -130 fail"); oxAssert(check(encodeInteger(int64_t(-130)), {0b11'1110'01, 0b11'1111'01}), "Encode -130 fail");
@ -214,6 +228,7 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail"); oxAssert(check(encodeInteger(uint64_t(2)), {0b0100}), "Encode 2 fail");
oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 fail"); oxAssert(check(encodeInteger(uint64_t(3)), {0b0110}), "Encode 3 fail");
oxAssert(check(encodeInteger(uint64_t(4)), {0b1000}), "Encode 4 fail"); oxAssert(check(encodeInteger(uint64_t(4)), {0b1000}), "Encode 4 fail");
oxAssert(check(encodeInteger(uint64_t(64)), {0b1000'000'0}), "Encode 4 fail");
oxAssert(check(encodeInteger(uint64_t(128)), {0b0001, 0b10}), "Encode 128 fail"); oxAssert(check(encodeInteger(uint64_t(128)), {0b0001, 0b10}), "Encode 128 fail");
oxAssert(check(encodeInteger(uint64_t(129)), {0b0101, 0b10}), "Encode 129 fail"); oxAssert(check(encodeInteger(uint64_t(129)), {0b0101, 0b10}), "Encode 129 fail");
oxAssert(check(encodeInteger(uint64_t(130)), {0b1001, 0b10}), "Encode 130 fail"); oxAssert(check(encodeInteger(uint64_t(130)), {0b1001, 0b10}), "Encode 130 fail");
@ -267,6 +282,58 @@ std::map<ox::String, ox::Error(*)()> tests = {
} }
}, },
{
"MetalClawModelValue",
[] {
static constexpr size_t dataBuffLen = ox::units::MB;
ox::Buffer dataBuff(dataBuffLen);
TestStruct testIn;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), &testIn), "Data generation failed");
ox::TypeStore typeStore;
auto type = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(type.error, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type.value));
oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString failed");
oxAssert(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion["Int"].get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0);
}
},
{ {
"MetalClawDef", "MetalClawDef",
[] { [] {
@ -382,12 +449,11 @@ std::map<ox::String, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
int retval = -1;
if (argc > 0) { if (argc > 0) {
auto testName = args[1]; auto testName = args[1];
if (tests.find(testName) != tests.end()) { if (tests.find(testName) != tests.end()) {
retval = tests[testName](); oxAssert(tests[testName](), "Test failed...");
} }
} }
return retval; return 0;
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/assert.hpp> #include <ox/std/assert.hpp>
@ -15,87 +15,4 @@
namespace ox { namespace ox {
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
}
MetalClawWriter::~MetalClawWriter() noexcept {
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
}
}
Error MetalClawWriter::field(const char*, int8_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int16_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int32_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int64_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint8_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint16_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint32_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint64_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
++m_field;
return OxError(0);
}
Error MetalClawWriter::field(const char*, SerStr val) noexcept {
bool fieldSet = false;
if (val.len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val.len());
if (m_buffIt + strLen.length + static_cast<std::size_t>(val.len()) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val.c_str(), static_cast<std::size_t>(val.len()));
m_buffIt += static_cast<std::size_t>(val.len());
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
Error MetalClawWriter::fieldCString(const char *name, char **val, int len) noexcept {
return field(name, SerStr(val, len));
}
std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
}
} }

View File

@ -3,12 +3,13 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/model/fieldcounter.hpp> #include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp> #include <ox/model/optype.hpp>
#include <ox/model/types.hpp> #include <ox/model/types.hpp>
#include <ox/std/bit.hpp> #include <ox/std/bit.hpp>
@ -38,49 +39,73 @@ class MetalClawWriter {
uint8_t *m_buff = nullptr; uint8_t *m_buff = nullptr;
public: public:
MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept; constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
~MetalClawWriter() noexcept; constexpr ~MetalClawWriter() noexcept;
Error field(const char*, int8_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<int8_t> auto *val) noexcept;
Error field(const char*, int16_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<int16_t> auto *val) noexcept;
Error field(const char*, int32_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<int32_t> auto *val) noexcept;
Error field(const char*, int64_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<int64_t> auto *val) noexcept;
Error field(const char*, uint8_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept;
Error field(const char*, uint16_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept;
Error field(const char*, uint32_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept;
Error field(const char*, uint64_t *val) noexcept; constexpr Error field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept;
Error field(const char*, bool *val) noexcept; constexpr Error field(const char*, CommonPtrWith<bool> auto *val) noexcept;
template<typename T> template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept; constexpr Error field(const char*, T *val, std::size_t len) noexcept;
template<typename T> template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept; constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept;
template<typename T>
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept; constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L> template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept; constexpr Error field(const char*, const BString<L> *val) noexcept;
Error field(const char*, SerStr val) noexcept; template<std::size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept; template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept;
constexpr Error fieldCString(const char *name, const char **val) noexcept;
constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept;
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char**>(val), buffLen);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return fieldCString(name, const_cast<const char**>(val));
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char*>(val), buffLen);
}
template<typename T> template<typename T>
Error field(const char*, T *val) noexcept; constexpr Error field(const char*, T *val) noexcept;
template<typename U> template<typename U, bool force = false>
Error field(const char*, UnionView<U> val) noexcept; constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t> template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept; constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
[[nodiscard]] [[nodiscard]]
std::size_t size() const noexcept; constexpr std::size_t size() const noexcept;
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
@ -88,13 +113,81 @@ class MetalClawWriter {
} }
private: private:
template<typename I> constexpr Error appendInteger(Integer_c auto val) noexcept {
Error appendInteger(I val) noexcept; bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
}; };
constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
}
constexpr MetalClawWriter::~MetalClawWriter() noexcept {
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
}
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
++m_field;
return OxError(0);
}
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawWriter::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length // write the length
@ -116,19 +209,77 @@ Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noe
} }
template<std::size_t L> template<std::size_t L>
Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept { constexpr Error MetalClawWriter::field(const char *name, const BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap())); return fieldCString(name, val->data(), val->cap());
}
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char **val, std::size_t) noexcept {
bool fieldSet = false;
if (m_unionIdx == -1 || m_unionIdx == m_field) {
const auto strLen = *val ? ox_strlen(*val) : 0;
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], *val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept {
return fieldCString(name, val, {});
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
bool fieldSet = false;
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
} }
template<typename T> template<typename T>
Error MetalClawWriter::field(const char*, T *val) noexcept { constexpr Error MetalClawWriter::field(const char*, T *val) noexcept {
if constexpr(isVector_v<T>) { if constexpr(isVector_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 == -1 || m_unionIdx == m_field)) { if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
oxReturnError(model(&writer, val)); ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt; m_buffIt += writer.m_buffIt;
fieldSet = true; fieldSet = true;
@ -140,12 +291,13 @@ Error MetalClawWriter::field(const char*, T *val) noexcept {
} }
} }
template<typename U> template<typename U, bool force>
Error MetalClawWriter::field(const char*, UnionView<U> val) noexcept { constexpr Error MetalClawWriter::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx()); MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
oxReturnError(model(&writer, val.get())); ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt; m_buffIt += writer.m_buffIt;
fieldSet = true; fieldSet = true;
@ -157,7 +309,7 @@ Error MetalClawWriter::field(const char*, UnionView<U> val) noexcept {
} }
template<typename T> template<typename T>
Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept { constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
@ -171,11 +323,12 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
} }
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
writer.setTypeInfo<T>("List", 0, len); ModelHandlerInterface handler{&writer};
handler.setTypeInfo<T>("List", 0, len);
// write the array // write the array
for (std::size_t i = 0; i < len; i++) { for (std::size_t i = 0; i < len; i++) {
oxReturnError(writer.field("", &val[i])); oxReturnError(handler.field("", &val[i]));
} }
m_buffIt += writer.m_buffIt; m_buffIt += writer.m_buffIt;
@ -188,11 +341,10 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
} }
template<typename T> template<typename T>
Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept { constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *val) noexcept {
const auto &keys = val->keys(); const auto &keys = val->keys();
const auto len = keys.size(); const auto len = keys.size();
bool fieldSet = false; bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length // write the length
const auto arrLen = mc::encodeInteger(len); const auto arrLen = mc::encodeInteger(len);
@ -202,69 +354,57 @@ Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept {
} else { } else {
return OxError(MC_BUFFENDED); return OxError(MC_BUFFENDED);
} }
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer};
// double len for both key and value // double len for both key and value
writer.setTypeInfo("Map", 0, len * 2); handler.setTypeInfo("Map", 0, len * 2);
// write the array // write the array
for (std::size_t i = 0; i < len; i++) { for (std::size_t i = 0; i < len; i++) {
const auto &key = keys[i]; const auto &key = keys[i];
const auto keyLen = ox_strlen(key); const auto keyLen = ox_strlen(key);
auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey, key.c_str(), keyLen + 1); memcpy(wkey, key.c_str(), keyLen + 1);
oxReturnError(writer.field("", SerStr(wkey.get(), keyLen))); oxReturnError(handler.fieldCString("", wkey.get(), keyLen));
oxReturnError(writer.field("", &(*val)[key])); oxReturnError(handler.field("", val->at(key).value));
} }
m_buffIt += writer.m_buffIt; m_buffIt += writer.m_buffIt;
fieldSet = true; fieldSet = true;
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<typename I>
Error MetalClawWriter::appendInteger(I val) noexcept {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++; m_field++;
return OxError(0); return OxError(0);
} }
template<typename T> template<typename T>
void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept { constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
}
template<typename T>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields; m_fields = fields;
m_fieldPresence.setFields(fields); m_fieldPresence.setFields(fields);
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen()); m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());
ox_memset(m_buff, 0, m_buffIt); ox_memset(m_buff, 0, m_buffIt);
} }
template<typename T> constexpr std::size_t MetalClawWriter::size() const noexcept {
Result<Buffer> writeMC(T *val) noexcept { return m_buffIt;
}
Result<Buffer> writeMC(auto *val) noexcept {
Buffer buff(10 * units::MB); Buffer buff(10 * units::MB);
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size()); MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size());
oxReturnError(model(&writer, val)); ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
buff.resize(writer.size()); buff.resize(writer.size());
return buff; return buff;
} }
template<typename T> Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept {
Error writeMC(char *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) noexcept {
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen); MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen);
auto err = model(&writer, val); ModelHandlerInterface handler(&writer);
auto err = model(&handler, val);
if (sizeOut) { if (sizeOut) {
*sizeOut = writer.size(); *sizeOut = writer.size();
} }

View File

@ -27,7 +27,9 @@ install(
optype.hpp optype.hpp
metadata.hpp metadata.hpp
model.hpp model.hpp
modelhandleradaptor.hpp
modelops.hpp modelops.hpp
modelvalue.hpp
typenamecatcher.hpp typenamecatcher.hpp
types.hpp types.hpp
typestore.hpp typestore.hpp

View File

@ -3,13 +3,15 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, modelName *o) noexcept { io->template setTypeInfo<modelName>(); #include <ox/std/concepts.hpp>
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept { io->template setTypeInfo<modelName>();
#define oxModelEnd() return OxError(0); } #define oxModelEnd() return OxError(0); }
#define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName)); #define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName));
#define oxModelFieldRename(serFieldName, objFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName)); #define oxModelFieldRename(serFieldName, objFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName));
#define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, modelName*) noexcept #define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, ox::CommonPtrWith<modelName> auto*) noexcept

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -13,8 +13,11 @@
#include <ox/std/hashmap.hpp> #include <ox/std/hashmap.hpp>
#include <ox/std/memory.hpp> #include <ox/std/memory.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/typetraits.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
#include <utility>
#include "optype.hpp"
#include "types.hpp" #include "types.hpp"
namespace ox { namespace ox {
@ -42,15 +45,16 @@ struct DescriptorField {
String fieldName; String fieldName;
int subscriptLevels = 0; int subscriptLevels = 0;
String typeName; // gives reference to type for lookup if type is null String typeName; // gives reference to type for lookup if type is null
bool list = false;
constexpr DescriptorField() noexcept = default; constexpr DescriptorField() noexcept = default;
constexpr DescriptorField(const DescriptorType *pType, String pFieldName, constexpr DescriptorField(const DescriptorType *pType, String pFieldName,
int pSubscriptLevels, String pTypeName) noexcept: int pSubscriptLevels, String pTypeName) noexcept:
type(pType), type(pType),
fieldName(pFieldName), fieldName(std::move(pFieldName)),
subscriptLevels(pSubscriptLevels), subscriptLevels(pSubscriptLevels),
typeName(pTypeName) { typeName(std::move(pTypeName)) {
} }
constexpr DescriptorField(const DescriptorField &other) noexcept: constexpr DescriptorField(const DescriptorField &other) noexcept:
@ -96,7 +100,8 @@ struct DescriptorType {
constexpr DescriptorType() noexcept = default; constexpr DescriptorType() noexcept = default;
constexpr explicit DescriptorType(String tn) noexcept: typeName(std::move(tn)) { constexpr explicit DescriptorType(String tn, int typeVersion) noexcept:
typeName(std::move(tn)), typeVersion(typeVersion) {
} }
constexpr DescriptorType(String tn, PrimitiveType t, int b) noexcept: constexpr DescriptorType(String tn, PrimitiveType t, int b) noexcept:
@ -115,11 +120,11 @@ struct DescriptorType {
template<typename T> template<typename T>
constexpr Error model(T *io, DescriptorType *type) noexcept { constexpr Error model(T *io, CommonPtrWith<DescriptorType> auto *type) noexcept {
io->template setTypeInfo<DescriptorType>(); io->template setTypeInfo<DescriptorType>();
oxReturnError(io->field("typeName", &type->typeName)); oxReturnError(io->field("typeName", &type->typeName));
oxReturnError(io->field("typeVersion", &type->typeVersion)); oxReturnError(io->field("typeVersion", &type->typeVersion));
if constexpr(ox_strcmp(T::opType(), "Reflect") == 0) { if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
uint8_t pt = 0; uint8_t pt = 0;
oxReturnError(io->field("primitiveType", &pt)); oxReturnError(io->field("primitiveType", &pt));
} else { } else {
@ -134,7 +139,7 @@ constexpr Error model(T *io, DescriptorType *type) noexcept {
} }
template<typename T> template<typename T>
constexpr Error model(T *io, DescriptorField *field) noexcept { constexpr Error model(T *io, CommonPtrWith<DescriptorField> auto *field) noexcept {
io->template setTypeInfo<DescriptorField>(); io->template setTypeInfo<DescriptorField>();
oxReturnError(io->field("typeName", &field->typeName)); oxReturnError(io->field("typeName", &field->typeName));
oxReturnError(io->field("fieldName", &field->fieldName)); oxReturnError(io->field("fieldName", &field->fieldName));
@ -149,7 +154,7 @@ template<typename ReaderBase>
class TypeDescReader; class TypeDescReader;
template<typename T> template<typename T>
constexpr Error model(TypeDescReader<T> *io, DescriptorField *field) noexcept { constexpr Error model(TypeDescReader<T> *io, CommonPtrWith<DescriptorField> auto *field) noexcept {
io->template setTypeInfo<DescriptorField>(DescriptorField::TypeName, DescriptorField::TypeVersion, 4); io->template setTypeInfo<DescriptorField>(DescriptorField::TypeName, DescriptorField::TypeVersion, 4);
oxReturnError(io->field("typeName", &field->typeName)); oxReturnError(io->field("typeName", &field->typeName));
auto &typeStore = io->typeStore(); auto &typeStore = io->typeStore();

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/typeinfo.hpp> #include <ox/std/typeinfo.hpp>
@ -33,115 +33,19 @@ static_assert(!preloadable<non_preloadable_type2>::value);
static_assert([] { static_assert([] {
int i = 0; return detail::indirectionLevels_v<int> == 0;
return detail::indirectionLevels(i) == 0;
}(), "indirectionLevels broken: indirectionLevels(int)"); }(), "indirectionLevels broken: indirectionLevels(int)");
static_assert([] { static_assert([] {
int i = 0; return detail::indirectionLevels_v<int*> == 1;
return detail::indirectionLevels(&i) == 1;
}(), "indirectionLevels broken: indirectionLevels(int*)"); }(), "indirectionLevels broken: indirectionLevels(int*)");
static_assert([] { static_assert([] {
int i[2] = {}; return detail::indirectionLevels_v<int[2]> == 1;
return detail::indirectionLevels(i) == 1;
}(), "indirectionLevels broken: indirectionLevels(int[])"); }(), "indirectionLevels broken: indirectionLevels(int[])");
const DescriptorType *TypeDescWriter::type(int8_t*) noexcept { static_assert([] {
constexpr auto String = "B:int8_t"; return detail::indirectionLevels_v<int**> == 2;
constexpr auto PT = PrimitiveType::SignedInteger; }(), "indirectionLevels broken: indirectionLevels(int[])");
constexpr auto Bytes = 1;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(int16_t*) noexcept {
constexpr auto String = "B:int16_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 2;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(int32_t*) noexcept {
constexpr auto String = "B:int32_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 4;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(int64_t*) noexcept {
constexpr auto String = "B:int64_t";
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 8;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint8_t*) noexcept {
constexpr auto String = "B:uint8_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 1;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint16_t*) noexcept {
constexpr auto String = "B:uint16_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 2;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint32_t*) noexcept {
constexpr auto String = "B:uint32_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 4;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(uint64_t*) noexcept {
constexpr auto String = "B:uint64_t";
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 8;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::type(char*) noexcept {
constexpr auto String = "B:string";
constexpr auto PT = PrimitiveType::String;
return getType(String, PT, 0);
}
const DescriptorType *TypeDescWriter::type(SerStr) noexcept {
constexpr auto String = "B:string";
constexpr auto PT = PrimitiveType::String;
return getType(String, PT, 0);
}
const DescriptorType *TypeDescWriter::type(String*) noexcept {
constexpr auto String = "B:string";
constexpr auto PT = PrimitiveType::String;
return getType(String, PT, 0);
}
const DescriptorType *TypeDescWriter::type(bool*) noexcept {
constexpr auto String = "B:bool";
constexpr auto PT = PrimitiveType::Bool;
constexpr auto Bytes = 0;
return getType(String, PT, Bytes);
}
const DescriptorType *TypeDescWriter::getType(const String &tn, PrimitiveType pt, int b) noexcept {
auto t = m_typeStore->get(tn);
if (!t.error) {
auto type = t.value;
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
return type;
} else {
auto dt = ox::make_unique<DescriptorType>(tn);
dt->primitiveType = pt;
dt->length = b;
const auto out = dt.get();
m_typeStore->set(tn, std::move(dt));
return out;
}
}
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -19,6 +19,7 @@
#include "desctypes.hpp" #include "desctypes.hpp"
#include "fieldcounter.hpp" #include "fieldcounter.hpp"
#include "metadata.hpp" #include "metadata.hpp"
#include "modelhandleradaptor.hpp"
#include "optype.hpp" #include "optype.hpp"
#include "typenamecatcher.hpp" #include "typenamecatcher.hpp"
#include "types.hpp" #include "types.hpp"
@ -29,14 +30,13 @@ namespace ox {
namespace detail { namespace detail {
template<typename T> template<typename T>
static constexpr int indirectionLevels(T) noexcept { constexpr int indirectionLevels_v = 0;
return 0;
}
template<typename T> template<typename T>
static constexpr int indirectionLevels(T *t) noexcept { constexpr int indirectionLevels_v<T*> = 1 + indirectionLevels_v<T>;
return 1 + indirectionLevels(*t);
} template<typename T, std::size_t sz>
constexpr int indirectionLevels_v<T[sz]> = 1 + indirectionLevels_v<T>;
} }
@ -49,17 +49,24 @@ class TypeDescWriter {
public: public:
explicit constexpr TypeDescWriter(TypeStore *typeStore = nullptr) noexcept; explicit constexpr TypeDescWriter(TypeStore *typeStore = nullptr) noexcept;
constexpr ~TypeDescWriter() noexcept = default;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName,
int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char *name, T *val, std::size_t valLen) noexcept; constexpr Error field(const char *name, const T *val, std::size_t valLen) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char *name, T val) noexcept; constexpr Error field(const char *name, T val) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char *name, T *val) noexcept; constexpr Error field(const char *name, const T *val) noexcept;
template<typename T = std::nullptr_t> template<typename ...Args>
constexpr void setTypeInfo(const char *name = T::TypeName, int fields = ModelFieldCount_v<T>) noexcept; constexpr Error fieldCString(const char *name, Args&&...) noexcept;
[[nodiscard]] [[nodiscard]]
constexpr DescriptorType *definition() noexcept { constexpr DescriptorType *definition() noexcept {
@ -71,56 +78,79 @@ class TypeDescWriter {
} }
private: private:
const DescriptorType *type(int8_t *val) noexcept; [[nodiscard]]
const DescriptorType *type(int16_t *val) noexcept; constexpr const DescriptorType *type(const int8_t *val) const noexcept;
const DescriptorType *type(int32_t *val) noexcept; [[nodiscard]]
const DescriptorType *type(int64_t *val) noexcept; constexpr const DescriptorType *type(const int16_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int32_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const int64_t *val) const noexcept;
const DescriptorType *type(uint8_t *val) noexcept; [[nodiscard]]
const DescriptorType *type(uint16_t *val) noexcept; constexpr const DescriptorType *type(const uint8_t *val) const noexcept;
const DescriptorType *type(uint32_t *val) noexcept; [[nodiscard]]
const DescriptorType *type(uint64_t *val) noexcept; constexpr const DescriptorType *type(const uint16_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint32_t *val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *type(const uint64_t *val) const noexcept;
const DescriptorType *type(bool *val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(const bool *val) const noexcept;
const DescriptorType *type(char *val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(const char *val) const noexcept;
const DescriptorType *type(SerStr val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(SerStr val) const noexcept;
const DescriptorType *type(String *val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(const String *val) const noexcept;
template<std::size_t sz> template<std::size_t sz>
constexpr const DescriptorType *type(BString<sz> *val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(const BString<sz> *val) const noexcept;
template<typename T> template<typename T>
constexpr const DescriptorType *type(T *val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(const T *val) const noexcept;
template<typename T> template<typename T>
constexpr const DescriptorType *type(Vector<T> *val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(const HashMap<String, T> *val) const noexcept;
template<typename T>
constexpr const DescriptorType *type(HashMap<String, T> *val) noexcept;
template<typename U> template<typename U>
constexpr const DescriptorType *type(UnionView<U> val) noexcept; [[nodiscard]]
constexpr const DescriptorType *type(UnionView<U> val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *getType(const String &tn, int typeVersion, PrimitiveType t, int b) const noexcept;
const DescriptorType *getType(const String &tn, PrimitiveType t, int b) noexcept;
}; };
constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) { constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {
} }
template<typename T>
constexpr void TypeDescWriter::setTypeInfo(const char *typeName, int typeVersion, int) noexcept {
m_type = m_typeStore->getInit(typeName, typeVersion);
if constexpr(is_union_v<T>) {
m_type->primitiveType = PrimitiveType::Union;
} else {
m_type->primitiveType = PrimitiveType::Struct;
}
m_type->preloadable = detail::preloadable<T>::value;
}
// array handler // array handler
template<typename T> template<typename T>
constexpr Error TypeDescWriter::field(const char *name, T *val, std::size_t) noexcept { constexpr Error TypeDescWriter::field(const char *name, const T *val, std::size_t) noexcept {
if (m_type) { if (m_type) {
constexpr typename remove_pointer<decltype(val)>::type *p = nullptr; constexpr typename remove_pointer<decltype(val)>::type *p = nullptr;
const auto t = type(p); const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
if (t == nullptr) { m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v<T> + 1, t->typeName);
type(p);
}
m_type->fieldList.emplace_back(t, name, detail::indirectionLevels(val), t->typeName);
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
@ -138,70 +168,153 @@ constexpr Error TypeDescWriter::field(const char *name, T val) noexcept {
} }
template<typename T> template<typename T>
constexpr Error TypeDescWriter::field(const char *name, T *val) noexcept { constexpr Error TypeDescWriter::field(const char *name, const T *val) noexcept {
if (m_type) { if (m_type) {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(name, val->data(), val->size());
} else {
const auto t = type(val); const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, t->typeName); m_type->fieldList.emplace_back(t, name, 0, t->typeName);
return OxError(0); return OxError(0);
} }
}
return OxError(1); return OxError(1);
} }
template<std::size_t sz> template<typename ...Args>
constexpr const DescriptorType *TypeDescWriter::type(BString<sz> *val) noexcept { constexpr Error TypeDescWriter::fieldCString(const char *name, Args&&...) noexcept {
return type(SerStr(val)); String s;
return field(name, &s);
} }
template<typename T> template<typename T>
constexpr const DescriptorType *TypeDescWriter::type(T *val) noexcept { constexpr const DescriptorType *TypeDescWriter::type(const T *val) const noexcept {
if constexpr(isVector_v<T>) {
return type(val->data());
} else {
auto [t, err] = m_typeStore->template get<T>(); auto [t, err] = m_typeStore->template get<T>();
if (!err) { if (!err) {
return t; return t;
} else { } else {
TypeDescWriter dw(m_typeStore); TypeDescWriter dw(m_typeStore);
oxLogError(model(&dw, val)); const auto reflectErr = model(&dw, val);
oxLogError(reflectErr);
oxAssert(reflectErr, "field(const char *name, T val): Type info could not be generated");
return dw.m_type; return dw.m_type;
} }
} }
template<typename T>
constexpr const DescriptorType *TypeDescWriter::type(Vector<T> *val) noexcept {
return type(val->data());
} }
template<typename T> template<typename T>
constexpr const DescriptorType *TypeDescWriter::type(HashMap<String, T>*) noexcept { constexpr const DescriptorType *TypeDescWriter::type(const HashMap<String, T>*) const noexcept {
return type(static_cast<T*>(nullptr)); return type(static_cast<T*>(nullptr));
} }
template<typename U> template<typename U>
constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val) noexcept { constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val) const noexcept {
return type(val.get()); const auto t = type(val.get());
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
return t;
} }
template<typename T> constexpr const DescriptorType *TypeDescWriter::type(const int8_t*) const noexcept {
constexpr void TypeDescWriter::setTypeInfo(const char *name, int) noexcept { constexpr auto PT = PrimitiveType::SignedInteger;
m_type = m_typeStore->getInit(name); constexpr auto Bytes = 1;
if constexpr(is_union_v<T>) { return getType(types::Int8, 0, PT, Bytes);
m_type->primitiveType = PrimitiveType::Union; }
constexpr const DescriptorType *TypeDescWriter::type(const int16_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 2;
return getType(types::Int16, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int32_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 4;
return getType(types::Int32, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const int64_t*) const noexcept {
constexpr auto PT = PrimitiveType::SignedInteger;
constexpr auto Bytes = 8;
return getType(types::Int64, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint8_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 1;
return getType(types::Uint8, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint16_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 2;
return getType(types::Uint16, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint32_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 4;
return getType(types::Uint32, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const uint64_t*) const noexcept {
constexpr auto PT = PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 8;
return getType(types::Uint64, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const bool*) const noexcept {
constexpr auto PT = PrimitiveType::Bool;
constexpr auto Bytes = 0;
return getType(types::Bool, 0, PT, Bytes);
}
constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::type(SerStr) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::type(const String*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const BString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::getType(const String &tn, int typeVersion, PrimitiveType pt, int b) const noexcept {
auto t = m_typeStore->get(tn, typeVersion);
if (!t.error) {
auto type = t.value;
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
return type;
} else { } else {
m_type->primitiveType = PrimitiveType::Struct; auto dt = ox::make_unique<DescriptorType>(tn, typeVersion);
dt->primitiveType = pt;
dt->length = b;
const auto out = dt.get();
m_typeStore->set(tn, typeVersion, std::move(dt));
return out;
} }
m_type->preloadable = detail::preloadable<T>::value;
} }
template<typename T> template<typename T>
Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept {
TypeDescWriter writer(typeStore); TypeDescWriter writer(typeStore);
oxReturnError(model(&writer, val)); ModelHandlerInterface handler(&writer);
oxReturnError(model(&handler, val));
return writer.definition(); return writer.definition();
} }
auto writeTypeDefOC(auto *val) noexcept {
TypeStore typeStore;
oxRequire(def, buildTypeDef(&typeStore, val));
return writeOC(def.get());
}
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -44,6 +44,11 @@ class FieldCounter {
return OxError(0); return OxError(0);
} }
template<typename ...Args>
constexpr Error fieldCString(Args&&...) noexcept {
return OxError(0);
}
static constexpr auto opType() { static constexpr auto opType() {
return OpType::Reflect; return OpType::Reflect;
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -13,7 +13,9 @@
#include "desctypes.hpp" #include "desctypes.hpp"
#include "descwrite.hpp" #include "descwrite.hpp"
#include "fieldcounter.hpp" #include "fieldcounter.hpp"
#include "modelhandleradaptor.hpp"
#include "modelops.hpp" #include "modelops.hpp"
#include "modelvalue.hpp"
#include "typenamecatcher.hpp" #include "typenamecatcher.hpp"
#include "types.hpp" #include "types.hpp"
#include "typestore.hpp" #include "typestore.hpp"

View File

@ -0,0 +1,155 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/utility.hpp>
#include "modelvalue.hpp"
namespace ox {
template<typename Handler>
class ModelHandlerInterface {
private:
Handler *m_handler = nullptr;
public:
constexpr explicit ModelHandlerInterface(Handler *handler) noexcept: m_handler(handler) {
}
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept {
m_handler->setTypeInfo(name, version, fields);
}
template<std::size_t len>
constexpr Error fieldCString(const char *name, char val[len]) noexcept {
return m_handler->fieldCString(name, &val[0], len);
}
template<std::size_t len>
constexpr Error fieldCString(const char *name, const char val[len]) noexcept {
return m_handler->fieldCString(name, &val[0], len);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return m_handler->fieldCString(name, val);
}
constexpr Error fieldCString(const char *name, const char **val) noexcept {
return m_handler->fieldCString(name, val);
}
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error field(const char *name, CommonPtrWith<ModelValue> auto *v) noexcept {
switch (v->type()) {
case ModelValue::Type::Undefined:
break;
case ModelValue::Type::Bool:
return m_handler->field(name, &v->template get<bool>());
case ModelValue::Type::UnsignedInteger8:
return m_handler->field(name, &v->template get<uint8_t>());
case ModelValue::Type::UnsignedInteger16:
return m_handler->field(name, &v->template get<uint16_t>());
case ModelValue::Type::UnsignedInteger32:
return m_handler->field(name, &v->template get<uint32_t>());
case ModelValue::Type::UnsignedInteger64:
return m_handler->field(name, &v->template get<uint64_t>());
case ModelValue::Type::SignedInteger8:
return m_handler->field(name, &v->template get<int8_t>());
case ModelValue::Type::SignedInteger16:
return m_handler->field(name, &v->template get<int16_t>());
case ModelValue::Type::SignedInteger32:
return m_handler->field(name, &v->template get<int32_t>());
case ModelValue::Type::SignedInteger64:
return m_handler->field(name, &v->template get<int64_t>());
case ModelValue::Type::String:
return m_handler->field(name, &v->template get<String>());
case ModelValue::Type::Object:
return m_handler->field(name, &v->template get<ModelObject>());
case ModelValue::Type::Union:
{
auto &u = v->template get<ModelUnion>();
if constexpr(ox_strcmp(Handler::opType(), OpType::Read) == 0) {
u.setActiveField(m_handler->whichFieldPresent(name, u));
}
return m_handler->field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
}
case ModelValue::Type::Vector:
return m_handler->field(name, &v->template get<ModelValueVector>());
}
oxPanic(OxError(1), "invalid type");
return OxError(1, "invalid type");
}
// array handler, with callback to allow handling individual elements
template<typename T, typename Callback>
constexpr Error field(const char *name, Callback cb) noexcept {
return m_handler->template field<T, Callback>(name, cb);
}
constexpr Error field(const char *name, const auto *v) noexcept {
return m_handler->field(name, v);
}
constexpr Error field(const char *name, auto *v) noexcept {
return m_handler->field(name, v);
}
template<typename U, bool force = false>
constexpr Error field(const char *name, UnionView<U, force> val) noexcept {
return m_handler->field(name, val);
}
constexpr Error field(const char *name, auto *val, std::size_t len) noexcept {
return m_handler->field(name, val, len);
}
/**
* Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length
*/
[[nodiscard]]
constexpr auto arrayLength(const char *name, bool pass = true) noexcept {
return m_handler->arrayLength(name, pass);
}
/**
* Reads an string length from the current location in the buffer.
*/
[[nodiscard]]
constexpr auto stringLength(const char *name) noexcept {
return m_handler->stringLength(name);
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return Handler::opType();
}
[[nodiscard]]
constexpr auto handler() noexcept {
return m_handler;
}
};
}

View File

@ -14,12 +14,36 @@
#include <ox/std/utility.hpp> #include <ox/std/utility.hpp>
#include "fieldcounter.hpp" #include "fieldcounter.hpp"
#include "modelvalue.hpp"
#include "optype.hpp"
#include "types.hpp" #include "types.hpp"
namespace ox { namespace ox {
namespace detail { namespace detail {
class Wrap {
public:
virtual ~Wrap() = default;
};
template<typename T>
class WrapT: public Wrap {
private:
T *m_obj = nullptr;
public:
constexpr WrapT(T *obj) noexcept: m_obj(obj) {
}
constexpr WrapT() = default;
[[nodiscard]]
constexpr auto obj() noexcept {
return m_obj;
}
};
template<std::size_t size> template<std::size_t size>
class MemberList { class MemberList {
@ -27,7 +51,7 @@ class MemberList {
std::size_t m_i = 0; std::size_t m_i = 0;
public: public:
void *vars[size]; Array<void*, size> vars;
template<typename T> template<typename T>
constexpr Error field(const char*, T *v) noexcept { constexpr Error field(const char*, T *v) noexcept {
@ -41,8 +65,8 @@ class MemberList {
return OxError(0); return OxError(0);
} }
template<typename U> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U> u) noexcept { constexpr Error field(const char*, UnionView<U, force> u) noexcept {
vars[m_i++] = static_cast<void*>(u.get()); vars[m_i++] = static_cast<void*>(u.get());
return OxError(0); return OxError(0);
} }
@ -57,7 +81,7 @@ class MemberList {
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return "GetMembers"; return OpType::Reflect;
} }
}; };
@ -97,8 +121,8 @@ class Copier {
return OxError(0); return OxError(0);
} }
template<typename U> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U> u) { constexpr Error field(const char*, UnionView<U, force> u) {
auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]); auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]);
auto &src = *u.get(); auto &src = *u.get();
dst = src; dst = src;
@ -116,7 +140,7 @@ class Copier {
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return "Copy"; return OpType::Read;
} }
}; };
@ -158,8 +182,8 @@ class Mover {
return OxError(0); return OxError(0);
} }
template<typename U> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U> u) noexcept { constexpr Error field(const char*, UnionView<U, force> u) noexcept {
auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]); auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]);
auto &src = *u.get(); auto &src = *u.get();
dst = std::move(src); dst = std::move(src);
@ -177,7 +201,7 @@ class Mover {
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return "Copy"; return OpType::Read;
} }
}; };
@ -222,8 +246,8 @@ class Equals {
return OxError(0); return OxError(0);
} }
template<typename U> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U> u) noexcept { constexpr Error field(const char*, UnionView<U, force> u) noexcept {
const auto &dst = *cbit_cast<U*>(m_other->vars[m_i]); const auto &dst = *cbit_cast<U*>(m_other->vars[m_i]);
const auto &src = *u.get(); const auto &src = *u.get();
++m_i; ++m_i;
@ -253,13 +277,31 @@ class Equals {
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return "Copy"; return OpType::Read;
} }
}; };
} }
template<typename T>
constexpr void moveModel(ModelObject *dst, T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&mover, src));
}
template<typename T>
constexpr void moveModel(T *dst, ModelObject *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&mover, src));
}
template<typename T> template<typename T>
constexpr void moveModel(T *dst, T *src) noexcept { constexpr void moveModel(T *dst, T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>; constexpr auto size = ModelFieldCount_v<T>;
@ -269,6 +311,24 @@ constexpr void moveModel(T *dst, T *src) noexcept {
oxIgnoreError(model(&mover, src)); oxIgnoreError(model(&mover, src));
} }
template<typename T>
constexpr void copyModel(ModelObject *dst, const T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&copier, src));
}
template<typename T>
constexpr void copyModel(T *dst, const ModelObject *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&copier, src));
}
template<typename T> template<typename T>
constexpr void copyModel(T *dst, const T *src) noexcept { constexpr void copyModel(T *dst, const T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>; constexpr auto size = ModelFieldCount_v<T>;

9
deps/ox/src/ox/model/modelvalue.cpp vendored Normal file
View File

@ -0,0 +1,9 @@
/*
* Copyright 2015 - 2022 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 "modelvalue.hpp"

886
deps/ox/src/ox/model/modelvalue.hpp vendored Normal file
View File

@ -0,0 +1,886 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/types.hpp>
#include <ox/std/vector.hpp>
#include "def.hpp"
#include "desctypes.hpp"
#include "fieldcounter.hpp"
#include "metadata.hpp"
#include "optype.hpp"
#include "typenamecatcher.hpp"
#include "types.hpp"
#include "typestore.hpp"
namespace ox {
class ModelObject;
class ModelUnion;
class ModelValue;
class ModelValueVector;
class ModelValue {
public:
enum class Type {
Undefined,
Bool,
UnsignedInteger8,
UnsignedInteger16,
UnsignedInteger32,
UnsignedInteger64,
SignedInteger8,
SignedInteger16,
SignedInteger32,
SignedInteger64,
String,
Object,
Union,
Vector,
};
private:
Type m_type = Type::Undefined;
union {
bool b{};
int8_t i8;
uint8_t ui8;
int16_t i16;
uint16_t ui16;
int32_t i32;
uint32_t ui32;
int64_t i64;
uint64_t ui64;
String *str;
ModelObject *obj;
ModelUnion *uni;
ModelValueVector *vec;
} m_data;
template<typename T>
consteval static Type getType() noexcept {
if constexpr(is_bool_v<T>) {
return Type::Bool;
} else if constexpr(is_integer_v<T>) {
if (!is_signed_v<T> && sizeof(T) == 1) {
return Type::UnsignedInteger8;
} else if constexpr(!is_signed_v<T> && sizeof(T) == 2) {
return Type::UnsignedInteger16;
} else if constexpr(!is_signed_v<T> && sizeof(T) == 4) {
return Type::UnsignedInteger32;
} else if constexpr(!is_signed_v<T> && sizeof(T) == 8) {
return Type::UnsignedInteger64;
} else if constexpr(is_signed_v<T> && sizeof(T) == 1) {
return Type::SignedInteger8;
} else if constexpr(is_signed_v<T> && sizeof(T) == 2) {
return Type::SignedInteger16;
} else if constexpr(is_signed_v<T> && sizeof(T) == 4) {
return Type::SignedInteger32;
} else if constexpr(is_signed_v<T> && sizeof(T) == 8) {
return Type::SignedInteger64;
}
} else if constexpr(is_same_v<T, ModelUnion>) {
return Type::Union;
} else if constexpr(is_same_v<T, ModelObject>) {
return Type::Object;
} else if constexpr(is_same_v<T, String>) {
return Type::String;
} else if constexpr(is_same_v<T, ModelValueVector>) {
return Type::Vector;
} else {
return Type::Undefined;
}
}
template<Type type>
static constexpr auto &getValue(auto &t) noexcept {
if constexpr(type == Type::Bool) {
return t.m_data.b;
} else if constexpr(type == Type::UnsignedInteger8) {
return t.m_data.ui8;
} else if constexpr(type == Type::UnsignedInteger16) {
return t.m_data.ui16;
} else if constexpr(type == Type::UnsignedInteger32) {
return t.m_data.ui32;
} else if constexpr(type == Type::UnsignedInteger64) {
return t.m_data.ui64;
} else if constexpr(type == Type::SignedInteger8) {
return t.m_data.i8;
} else if constexpr(type == Type::SignedInteger16) {
return t.m_data.i16;
} else if constexpr(type == Type::SignedInteger32) {
return t.m_data.i32;
} else if constexpr(type == Type::SignedInteger64) {
return t.m_data.i64;
} else if constexpr(type == Type::String) {
return *t.m_data.str;
} else if constexpr(type == Type::Union) {
return *t.m_data.uni;
} else if constexpr(type == Type::Object) {
return *t.m_data.obj;
} else if constexpr(type == Type::Vector) {
return *t.m_data.vec;
} else {
return t.m_data.i32;
}
}
public:
constexpr ModelValue() noexcept = default;
constexpr ModelValue(const ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &&other) noexcept;
template<typename T>
explicit constexpr ModelValue(const T &val) noexcept;
template<typename T>
explicit constexpr ModelValue(T &&val) noexcept;
constexpr ~ModelValue() noexcept;
template<typename T>
[[nodiscard]]
constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(OxError(1), "invalid cast");
}
return getValue<type>(*this);
}
template<typename T>
[[nodiscard]]
constexpr auto &get() noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(OxError(1), "invalid cast");
}
return getValue<type>(*this);
}
[[nodiscard]]
constexpr Type type() const noexcept;
constexpr Error setType(const DescriptorType *type, int subscriptLevels = 0) noexcept;
template<typename T>
constexpr Error setType() noexcept;
template<typename T>
constexpr Error set(const T &v) noexcept;
template<typename T>
constexpr Error set(T &&v) noexcept;
constexpr ModelValue &operator=(ModelValue &val) noexcept;
constexpr ModelValue &operator=(const ModelValue &val) noexcept;
constexpr ModelValue &operator=(ModelValue &&val) noexcept;
constexpr ModelValue &operator=(const auto &val) noexcept;
constexpr ModelValue &operator=(auto &&val) noexcept;
private:
constexpr void freeResources() noexcept;
};
class ModelValueVector {
private:
Vector<ModelValue> m_vec;
ModelValue m_templateValue;
String m_typeName;
int m_typeVersion = 0;
public:
constexpr ModelValueVector() noexcept = default;
constexpr ModelValueVector(const ModelValueVector &other) noexcept;
constexpr ModelValueVector(ModelValueVector &&other) noexcept;
constexpr ModelValueVector &operator=(const ModelValueVector &other) noexcept;
constexpr ModelValueVector &operator=(ModelValueVector &&other) noexcept;
[[nodiscard]]
constexpr auto data() const noexcept {
return m_vec.data();
}
[[nodiscard]]
constexpr auto data() noexcept {
return m_vec.data();
}
constexpr void resize(std::size_t sz) noexcept {
const auto oldSz = m_vec.size();
m_vec.resize(sz);
if (sz > oldSz) {
for (auto i = oldSz; i < sz; ++i) {
m_vec[i] = m_templateValue;
}
}
}
[[nodiscard]]
constexpr auto &get() noexcept {
return m_vec;
}
[[nodiscard]]
constexpr const auto &get() const noexcept {
return m_vec;
}
constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept {
return m_templateValue.setType(type, subscriptLevels);
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
return m_typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_typeVersion;
}
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return m_vec.size();
}
constexpr auto &operator[](std::size_t i) noexcept {
return m_vec[i];
}
constexpr auto &operator[](std::size_t i) const noexcept {
return m_vec[i];
}
[[nodiscard]]
auto begin() noexcept {
return m_vec.begin();
}
[[nodiscard]]
auto cbegin() const noexcept {
return m_vec.cbegin();
}
[[nodiscard]]
auto rbegin() noexcept {
return m_vec.rbegin();
}
[[nodiscard]]
auto crbegin() const noexcept {
return m_vec.crbegin();
}
[[nodiscard]]
auto end() noexcept {
return m_vec.end();
}
[[nodiscard]]
auto cend() const noexcept {
return m_vec.cend();
}
[[nodiscard]]
auto rend() noexcept {
return m_vec.rend();
}
[[nodiscard]]
auto crend() const noexcept {
return m_vec.crend();
}
};
consteval bool isVector(const ModelValueVector*) noexcept {
return true;
}
class ModelObject {
protected:
struct Field {
String name;
ModelValue value;
};
oxModelFriend(ModelObject);
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields;
String m_typeName;
int m_typeVersion = 0;
public:
constexpr ModelObject() noexcept = default;
constexpr ModelObject(const ModelObject &other) noexcept {
for (const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value});
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelObject(ModelObject &&other) noexcept {
for (auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(std::move(f));
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr auto &operator=(const ModelObject &other) noexcept {
if (&other == this) [[unlikely]] {
return *this;
}
for (const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value});
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr auto &operator=(ModelObject &&other) noexcept {
if (&other == this) [[unlikely]] {
return *this;
}
for (auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(std::move(f));
m_fields[field->name] = &field->value;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr auto &operator[](const std::size_t &i) noexcept {
return *m_fieldsOrder[i];
}
constexpr auto &operator[](const String &k) noexcept {
return *m_fields[k];
}
constexpr auto &operator[](const std::size_t i) noexcept {
return *m_fieldsOrder[i];
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
return m_typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_typeVersion;
}
constexpr Error setType(const DescriptorType *type) noexcept {
if (type->primitiveType != PrimitiveType::Struct && type->primitiveType != PrimitiveType::Union) {
return OxError(1, "Cannot load a non-struct type to ModelObject");
}
m_typeName = type->typeName;
m_typeVersion = type->typeVersion;
for (const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
m_fields[field->name] = &field->value;
m_fieldsOrder.emplace_back(std::move(field));
}
return OxError(0);
}
};
class ModelUnion {
protected:
struct Field {
int idx = -1;
String name;
ModelValue value;
};
oxModelFriend(ModelUnion);
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields;
String m_typeName;
int m_typeVersion = 0;
int m_unionIdx = -1;
private:
constexpr ModelUnion() noexcept = default;
public:
constexpr ModelUnion(const ModelUnion &other) noexcept {
for (auto i = 0; const auto &f : other.m_fieldsOrder) {
auto &field = m_fieldsOrder.emplace_back(new Field{i, f->name, f->value});
m_fields[field->name] = field.get();
++i;
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
m_unionIdx = other.m_unionIdx;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UniquePtr<ModelUnion> out(new ModelUnion);
oxReturnError(out->setType(type));
return out;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UniquePtr<ModelUnion>(new ModelUnion(other));
}
constexpr auto &operator[](const String &k) noexcept {
return m_fields[k]->value;
}
constexpr auto &operator[](const std::size_t i) noexcept {
return m_fieldsOrder[i]->value;
}
constexpr void setActiveField(int i) noexcept {
m_unionIdx = i;
}
constexpr void set(int i, auto val) noexcept {
m_unionIdx = i;
*m_fieldsOrder[i] = val;
}
constexpr void set(std::size_t i, auto val) noexcept {
m_unionIdx = static_cast<int>(i);
*m_fieldsOrder[i] = val;
}
[[nodiscard]]
constexpr ModelValue &get(std::size_t i) noexcept {
return m_fieldsOrder[i]->value;
}
[[nodiscard]]
constexpr ModelValue &get(const String &k) noexcept {
return (*m_fields.at(k).value)->value;
}
[[nodiscard]]
constexpr int getKeyIdx(const auto &k) const noexcept {
for (auto i = 0; const auto &f : m_fieldsOrder) {
if (f->name == k) {
return i;
}
++i;
}
return -1;
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
return m_typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_typeVersion;
}
constexpr Error setType(const DescriptorType *type) noexcept {
if (type->primitiveType != PrimitiveType::Struct && type->primitiveType != PrimitiveType::Union) {
return OxError(1, "Cannot load a non-struct type to ModelUnion");
}
m_fields.clear();
m_fieldsOrder.clear();
m_typeName = type->typeName;
m_typeVersion = type->typeVersion;
for (auto i = 0; const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
field->idx = i;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
m_fields[field->name] = field.get();
m_fieldsOrder.emplace_back(std::move(field));
++i;
}
return OxError(0);
}
[[nodiscard]]
constexpr auto fieldCount() const noexcept {
return m_fields.size();
}
[[nodiscard]]
constexpr auto unionIdx() const noexcept {
return m_unionIdx;
}
};
constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
return OxError(0);
}
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
return OxError(0);
}
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
break;
case Type::Union:
m_data.uni = new ModelUnion(other.get<ModelUnion>());
break;
case Type::Object:
m_data.obj = new ModelObject(other.get<ModelObject>());
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
}
constexpr ModelValue::ModelValue(ModelValue &other) noexcept: ModelValue(const_cast<const ModelValue&>(other)) {
}
constexpr ModelValue::ModelValue(ModelValue &&other) noexcept {
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
ox_memset(&other.m_data, 0, sizeof(m_data));
break;
case Type::String:
m_data.str = other.m_data.str;
other.m_data.str = new String;
break;
case Type::Union:
m_data.uni = new ModelUnion(*other.m_data.uni);
break;
case Type::Object:
m_data.obj = new ModelObject(*other.m_data.obj);
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
}
template<typename T>
constexpr ModelValue::ModelValue(const T &val) noexcept {
set(val);
}
template<typename T>
constexpr ModelValue::ModelValue(T &&val) noexcept {
set(ox::forward(val));
}
constexpr ModelValue::~ModelValue() noexcept {
freeResources();
}
constexpr ModelValue::Type ModelValue::type() const noexcept {
return m_type;
}
constexpr Error ModelValue::setType(const DescriptorType *type, int subscriptLevels) noexcept {
freeResources();
if (subscriptLevels) {
m_type = Type::Vector;
m_data.vec = new ModelValueVector;
return m_data.vec->setType(type, subscriptLevels - 1);
} else if (type->typeName == types::Bool) {
m_type = Type::Bool;
} else if (type->typeName == types::String) {
m_type = Type::String;
m_data.str = new String;
} else if (type->typeName == types::Uint8) {
m_type = Type::UnsignedInteger8;
} else if (type->typeName == types::Uint16) {
m_type = Type::UnsignedInteger16;
} else if (type->typeName == types::Uint32) {
m_type = Type::UnsignedInteger32;
} else if (type->typeName == types::Uint64) {
m_type = Type::UnsignedInteger64;
} else if (type->typeName == types::Int8) {
m_type = Type::SignedInteger8;
} else if (type->typeName == types::Int16) {
m_type = Type::SignedInteger16;
} else if (type->typeName == types::Int32) {
m_type = Type::SignedInteger32;
} else if (type->typeName == types::Int64) {
m_type = Type::SignedInteger64;
} else if (type->primitiveType == PrimitiveType::Struct) {
m_type = Type::Object;
m_data.obj = new ModelObject;
oxReturnError(m_data.obj->setType(type));
} else if (type->primitiveType == PrimitiveType::Union) {
m_type = Type::Union;
oxRequireM(u, ModelUnion::make(type));
m_data.uni = u.release();
oxReturnError(m_data.uni->setType(type));
}
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::setType() noexcept {
constexpr auto type = getType<T>();
return setType(type);
}
template<typename T>
constexpr Error ModelValue::set(const T &v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
value = v;
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::set(T &&v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
type == Type::Union || type == Type::String) {
safeDelete(value);
}
value = ox::forward<T>(v);
return OxError(0);
}
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
return this->operator=(const_cast<const ModelValue&>(other));
}
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
if (this == &other) [[unlikely]] {
return *this;
}
freeResources();
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
break;
case Type::Union:
m_data.uni = new ModelUnion(other.get<ModelUnion>());
break;
case Type::Object:
m_data.obj = new ModelObject(other.get<ModelObject>());
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
return *this;
}
constexpr ModelValue &ModelValue::operator=(ModelValue &&other) noexcept {
if (this == &other) [[unlikely]] {
return *this;
}
freeResources();
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
ox_memset(&other.m_data, 0, sizeof(m_data));
break;
case Type::String:
m_data.str = other.m_data.str;
other.m_data.str = new String;
break;
case Type::Object:
m_data.obj = new ModelObject(*other.m_data.obj);
break;
case Type::Union:
m_data.uni = new ModelUnion(*other.m_data.uni);
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
}
return *this;
}
constexpr ModelValue &ModelValue::operator=(const auto &val) noexcept {
if (this == &val) {
return *this;
}
set(val);
return *this;
}
constexpr ModelValue &ModelValue::operator=(auto &&val) noexcept {
if (this == &val) {
return *this;
}
set(ox::forward(val));
return *this;
}
constexpr void ModelValue::freeResources() noexcept {
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
break;
case Type::String:
safeDelete(m_data.str);
break;
case Type::Object:
safeDelete(m_data.obj);
break;
case Type::Union:
safeDelete(m_data.uni);
break;
case Type::Vector:
safeDelete(m_data.vec);
break;
}
m_type = Type::Undefined;
}
constexpr ModelValueVector::ModelValueVector(const ModelValueVector &other) noexcept {
for (auto &v : other.m_vec) {
m_vec.emplace_back(v);
}
m_templateValue = other.m_templateValue;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
for (auto &v : other.m_vec) {
m_vec.emplace_back(std::move(v));
}
m_templateValue = std::move(other.m_templateValue);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
}
constexpr ModelValueVector &ModelValueVector::operator=(const ModelValueVector &other) noexcept {
if (this == &other) {
return *this;
}
for (auto &v : other.m_vec) {
m_vec.emplace_back(v);
}
m_templateValue = other.m_templateValue;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr ModelValueVector &ModelValueVector::operator=(ModelValueVector &&other) noexcept {
if (this == &other) {
return *this;
}
for (auto &v : other.m_vec) {
m_vec.emplace_back(std::move(v));
}
m_templateValue = std::move(other.m_templateValue);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
return *this;
}
}

View File

@ -3,54 +3,18 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/std/assert.hpp> #include <ox/std/assert.hpp>
#include <ox/std/concepts.hpp>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/strops.hpp> #include <ox/std/strops.hpp>
namespace ox { namespace ox::OpType {
namespace OpType {
constexpr auto Read = "Read"; constexpr auto Read = "Read";
constexpr auto Write = "Write"; constexpr auto Write = "Write";
constexpr auto Reflect = "Reflect"; constexpr auto Reflect = "Reflect";
} }
// empty default implementations of model functions
template<typename T, typename O>
constexpr Error modelRead(T*, O*) noexcept {
oxAssert(OxError(1), "Missing modelRead function");
return OxError(1, "Model: modelRead not implemented");
}
template<typename T, typename O>
constexpr Error modelWrite(T*, O*) noexcept {
oxAssert(OxError(1), "Missing modelWrite function");
return OxError(1, "Model: modelWrite not implemented");
}
template<typename T, typename O>
constexpr Error modelReflect(T*, O*) noexcept {
return OxError(1, "Model: modelReflect not implemented");
}
template<typename T, typename O>
constexpr Error model(T *io, O *obj) noexcept {
if constexpr(ox_strcmp(T::opType(), OpType::Read) == 0) {
return modelRead(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::Write) == 0) {
return modelWrite(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
return modelReflect(io, obj);
} else {
oxAssert(OxError(1), "Missing model function");
return OxError(1);
}
}
}

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -40,8 +40,8 @@ struct TypeNameCatcher {
return OxError(0); return OxError(0);
} }
template<typename T> template<typename ...Args>
constexpr Error fieldCString(const char*, T) noexcept { constexpr Error fieldCString(Args&&...) noexcept {
return OxError(0); return OxError(0);
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -12,10 +12,15 @@
#include <vector> #include <vector>
#endif #endif
#if __has_include(<array>)
#include <array>
#endif
#if __has_include(<QVector>) #if __has_include(<QVector>)
#include <QVector> #include <QVector>
#endif #endif
#include <ox/std/array.hpp>
#include <ox/std/bstring.hpp> #include <ox/std/bstring.hpp>
#include <ox/std/strops.hpp> #include <ox/std/strops.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
@ -24,19 +29,32 @@
namespace ox { namespace ox {
namespace types {
constexpr auto String = "B:string";
constexpr auto Bool = "B:bool";
constexpr auto Uint8 = "B:uint8_t";
constexpr auto Uint16 = "B:uint16_t";
constexpr auto Uint32 = "B:uint32_t";
constexpr auto Uint64 = "B:uint64_t";
constexpr auto Int8 = "B:int8_t";
constexpr auto Int16 = "B:int16_t";
constexpr auto Int32 = "B:int32_t";
constexpr auto Int64 = "B:int64_t";
}
template<typename T> template<typename T>
constexpr bool isVector(const T*) noexcept { consteval bool isVector(const T*) noexcept {
return false; return false;
} }
template<typename T> template<typename T>
constexpr bool isVector(const Vector<T>*) noexcept { consteval bool isVector(const Vector<T>*) noexcept {
return true; return true;
} }
#if __has_include(<vector>) #if __has_include(<vector>)
template<typename T> template<typename T>
constexpr bool isVector(const std::vector<T>*) noexcept { consteval bool isVector(const std::vector<T>*) noexcept {
return true; return true;
} }
#endif #endif
@ -51,6 +69,24 @@ constexpr bool isVector(const QVector<T>*) noexcept {
template<typename T> template<typename T>
constexpr bool isVector_v = isVector(static_cast<const T*>(nullptr)); constexpr bool isVector_v = isVector(static_cast<const T*>(nullptr));
template<typename T>
constexpr bool isArray_v = false;
template<typename T>
constexpr bool isArray_v<T[]> = false;
template<typename T, std::size_t sz>
constexpr bool isArray_v<T[sz]> = false;
template<typename T, std::size_t sz>
constexpr bool isArray_v<Array<T, sz>> = false;
#if __has_include(<array>)
template<typename T, std::size_t sz>
constexpr bool isArray_v<std::array<T, sz>> = false;
#endif
class SerStr { class SerStr {
protected: protected:
@ -121,12 +157,12 @@ class SerStr {
}; };
template<typename Union> template<typename Union, bool force = false>
class UnionView { class UnionView {
protected: protected:
int m_idx = -1; int m_idx = -1;
typename enable_if<is_union_v<Union>, Union>::type *m_union = nullptr; typename enable_if<is_union_v<Union> || force, Union>::type *m_union = nullptr;
public: public:
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) { constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -13,6 +13,7 @@
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/typetraits.hpp> #include <ox/std/typetraits.hpp>
#include "ox/std/fmt.hpp"
#include "typenamecatcher.hpp" #include "typenamecatcher.hpp"
#include "desctypes.hpp" #include "desctypes.hpp"
@ -22,29 +23,37 @@ class TypeStore {
private: private:
HashMap<String, UniquePtr<DescriptorType>> m_cache; HashMap<String, UniquePtr<DescriptorType>> m_cache;
static constexpr auto buildTypeId(const auto &name, auto version) noexcept {
return ox::sfmt("{};{}", name, version);
}
public: public:
constexpr TypeStore() noexcept = default; constexpr TypeStore() noexcept = default;
constexpr virtual ~TypeStore() noexcept = default; constexpr virtual ~TypeStore() noexcept = default;
constexpr Result<DescriptorType*> get(const auto &name) const noexcept { constexpr Result<DescriptorType*> get(const auto &name, int typeVersion) const noexcept {
oxRequire(out, m_cache.at(name)); const auto typeId = buildTypeId(name, typeVersion);
oxRequire(out, m_cache.at(typeId));
return out->get(); return out->get();
} }
template<typename T> template<typename T>
constexpr Result<DescriptorType*> get() const noexcept { constexpr Result<DescriptorType*> get() const noexcept {
constexpr auto name = requireModelTypeName<T>(); constexpr auto typeName = requireModelTypeName<T>();
oxRequire(out, m_cache.at(name)); constexpr auto typeVersion = requireModelTypeVersion<T>();
const auto typeId = buildTypeId(typeName, typeVersion);
oxRequire(out, m_cache.at(typeId));
return out->get(); return out->get();
} }
constexpr DescriptorType *getInit(const auto &name) noexcept { constexpr DescriptorType *getInit(const auto &typeName, int typeVersion) noexcept {
auto [out, err] = m_cache.at(name); const auto typeId = buildTypeId(typeName, typeVersion);
auto [out, err] = m_cache.at(typeId);
if (err) { if (err) {
auto &out = m_cache[name]; out = &m_cache[typeId];
out = ox::make_unique<DescriptorType>(name); *out = ox::make_unique<DescriptorType>(typeName, typeVersion);
return out.get(); return out->get();
} }
return out->get(); return out->get();
} }
@ -55,15 +64,13 @@ class TypeStore {
return getInit(name); return getInit(name);
} }
template<typename T> constexpr Result<DescriptorType*> getLoad(const auto &typeName, auto typeVersion) noexcept {
constexpr Result<DescriptorType*> getLoad() noexcept { const auto typeId = buildTypeId(typeName, typeVersion);
constexpr auto nameCstr = requireModelTypeName<T>(); auto [val, err] = m_cache.at(typeId);
const String name = nameCstr;
auto [val, err] = m_cache.at(name);
if (err) { if (err) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
oxRequireM(dt, loadDescriptor(name)); oxRequireM(dt, loadDescriptor(typeName, typeVersion));
auto &out = m_cache[name]; auto &out = m_cache[typeId];
out = std::move(dt); out = std::move(dt);
return out.get(); return out.get();
} else { } else {
@ -73,12 +80,21 @@ class TypeStore {
return val->get(); return val->get();
} }
constexpr void set(const String &name, UniquePtr<DescriptorType> dt) noexcept { template<typename T>
m_cache[name] = std::move(dt); constexpr Result<DescriptorType*> getLoad() noexcept {
constexpr auto typeName = requireModelTypeName<T>();
constexpr auto typeVersion = requireModelTypeVersion<T>();
return getLoad(typeName, typeVersion);
} }
constexpr void set(const String &name, DescriptorType *dt) noexcept { constexpr void set(const auto &typeName, auto typeVersion, UniquePtr<DescriptorType> dt) noexcept {
m_cache[name] = UniquePtr<DescriptorType>(dt); const auto typeId = buildTypeId(typeName, typeVersion);
m_cache[typeId] = std::move(dt);
}
constexpr void set(const auto &typeName, auto typeVersion, DescriptorType *dt) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
m_cache[typeId] = UniquePtr<DescriptorType>(dt);
} }
[[nodiscard]] [[nodiscard]]
@ -92,7 +108,7 @@ class TypeStore {
} }
protected: protected:
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(const ox::String&) noexcept { virtual Result<UniquePtr<DescriptorType>> loadDescriptor(const ox::String&, int) noexcept {
return OxError(1); return OxError(1);
} }

View File

@ -3,10 +3,11 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/bit.hpp> #include <ox/std/bit.hpp>
#include <utility>
#include "read.hpp" #include "read.hpp"
@ -18,7 +19,7 @@ OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t 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 OxError(1, "Could not parse JSON"); throw OxException(1, "Could not parse JSON");
} }
} }
@ -26,12 +27,12 @@ OrganicClawReader::OrganicClawReader(const char *json, std::size_t jsonLen) {
Json::CharReaderBuilder parserBuilder; Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader()); auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) { if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw OxError(1, "Could not parse JSON"); throw OxException(1, "Could not parse JSON");
} }
} }
OrganicClawReader::OrganicClawReader(const Json::Value &json, int unionIdx) noexcept: OrganicClawReader::OrganicClawReader(Json::Value json, int unionIdx) noexcept:
m_json(json), m_json(std::move(json)),
m_unionIdx(unionIdx) { m_unionIdx(unionIdx) {
} }
@ -208,6 +209,87 @@ Error OrganicClawReader::field(const char *key, SerStr val) noexcept {
return err; return err;
} }
Error OrganicClawReader::fieldCString(const char *key, char *val, std::size_t buffLen) noexcept {
auto err = OxError(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (targetValid()) {
if (jv.empty()) {
auto data = val;
if (data) {
data[0] = 0;
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<std::size_t>(end - begin);
auto data = val;
if (strSize >= buffLen) {
err = OxError(2, "String size exceeds capacity of destination");
} else {
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
}
} else {
err = OxError(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(const char *key, char **val) noexcept {
auto err = OxError(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
auto &data = *val;
if (targetValid()) {
if (jv.empty()) {
if (data) {
data[0] = 0;
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<std::size_t>(end - begin);
safeDelete(*val);
*val = new char[strSize + 1];
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
} else {
err = OxError(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Error OrganicClawReader::fieldCString(const char *key, char **val, std::size_t buffLen) noexcept {
auto err = OxError(0);
const char *begin = nullptr, *end = nullptr;
const auto &jv = value(key);
if (targetValid()) {
if (jv.empty()) {
auto data = val;
if (data) {
data[0] = 0;
}
} else if (jv.isString()) {
jv.getString(&begin, &end);
const auto strSize = static_cast<std::size_t>(end - begin);
auto data = val;
if (strSize >= buffLen) {
safeDelete(*val);
*val = new char[strSize + 1];
}
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
data[strSize] = 0;
} else {
err = OxError(1, "Type mismatch");
}
}
++m_fieldIt;
return err;
}
Result<std::size_t> OrganicClawReader::arrayLength(const char *key, bool) noexcept { Result<std::size_t> OrganicClawReader::arrayLength(const char *key, bool) noexcept {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty()) { if (jv.empty()) {
@ -234,13 +316,25 @@ std::size_t OrganicClawReader::stringLength(const char *key) noexcept {
} }
OrganicClawReader OrganicClawReader::child(const char *key, int unionIdx) noexcept { OrganicClawReader OrganicClawReader::child(const char *key, int unionIdx) noexcept {
return OrganicClawReader(m_json[key], unionIdx); return OrganicClawReader(value(key), unionIdx);
} }
bool OrganicClawReader::fieldPresent(const char *key) noexcept { bool OrganicClawReader::fieldPresent(const char *key) noexcept {
return !m_json[key].empty(); return !m_json[key].empty();
} }
int OrganicClawReader::whichFieldPresent(const char *name, const ModelUnion &u) const noexcept {
const auto &obj = m_json[name];
if (!obj.isObject()) {
return -1;
}
const auto &keys = obj.getMemberNames();
if (keys.size() != 1) {
return -1;
}
return u.getKeyIdx(keys.front().c_str());
}
Json::Value &OrganicClawReader::value(const char *key) noexcept { Json::Value &OrganicClawReader::value(const char *key) noexcept {
if (m_json.isArray()) { if (m_json.isArray()) {
return m_json[m_fieldIt]; return m_json[m_fieldIt];
@ -249,7 +343,7 @@ Json::Value &OrganicClawReader::value(const char *key) noexcept {
} }
} }
bool OrganicClawReader::targetValid() noexcept { bool OrganicClawReader::targetValid() const noexcept {
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1; return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -11,6 +11,7 @@
#include <json/json.h> #include <json/json.h>
#include <ox/model/fieldcounter.hpp> #include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp> #include <ox/model/optype.hpp>
#include <ox/model/typenamecatcher.hpp> #include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp> #include <ox/model/types.hpp>
@ -37,7 +38,7 @@ class OrganicClawReader {
OrganicClawReader(const char *json, std::size_t buffSize); OrganicClawReader(const char *json, std::size_t buffSize);
explicit OrganicClawReader(const Json::Value &json, int unionIdx = -1) noexcept; explicit OrganicClawReader(Json::Value json, int unionIdx = -1) noexcept;
Error field(const char *key, int8_t *val) noexcept; Error field(const char *key, int8_t *val) noexcept;
Error field(const char *key, int16_t *val) noexcept; Error field(const char *key, int16_t *val) noexcept;
@ -61,8 +62,8 @@ class OrganicClawReader {
template<typename T> template<typename T>
Error field(const char *key, T *val) noexcept; Error field(const char *key, T *val) noexcept;
template<typename U> template<typename U, bool force = false>
Error field(const char *key, UnionView<U> val) noexcept; Error field(const char *key, UnionView<U, force> val) noexcept;
template<std::size_t L> template<std::size_t L>
Error field(const char *key, BasicString<L> *val) noexcept; Error field(const char *key, BasicString<L> *val) noexcept;
@ -72,6 +73,12 @@ class OrganicClawReader {
Error field(const char *key, SerStr val) noexcept; Error field(const char *key, SerStr val) noexcept;
Error fieldCString(const char *key, char *val, std::size_t buffLen) noexcept;
Error fieldCString(const char *key, char **val) noexcept;
Error fieldCString(const char *key, char **val, std::size_t buffLen) noexcept;
/** /**
* Reads an array length from the current location in the buffer. * Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length * @param pass indicates that the parsing should iterate past the array length
@ -109,16 +116,23 @@ class OrganicClawReader {
// compatibility stub // compatibility stub
constexpr void nextField() noexcept {} constexpr void nextField() noexcept {}
[[nodiscard]]
bool fieldPresent(const char *key) noexcept; bool fieldPresent(const char *key) noexcept;
[[nodiscard]]
int whichFieldPresent(const char *name, const ModelUnion &u) const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return OpType::Read; return OpType::Read;
} }
private: private:
[[nodiscard]]
Json::Value &value(const char *key) noexcept; Json::Value &value(const char *key) noexcept;
bool targetValid() noexcept; [[nodiscard]]
bool targetValid() const noexcept;
}; };
@ -134,7 +148,8 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty() || jv.isObject()) { if (jv.empty() || jv.isObject()) {
auto reader = child(key); auto reader = child(key);
return model(&reader, val); ModelHandlerInterface handler(&reader);
return model(&handler, val);
} else { } else {
err = OxError(1, "Type mismatch"); err = OxError(1, "Type mismatch");
} }
@ -143,14 +158,15 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
return err; return err;
} }
template<typename U> template<typename U, bool force>
Error OrganicClawReader::field(const char *key, UnionView<U> val) noexcept { Error OrganicClawReader::field(const char *key, UnionView<U, force> val) noexcept {
auto err = OxError(0); auto err = OxError(0);
if (targetValid()) { if (targetValid()) {
const auto &jv = value(key); const auto &jv = value(key);
if (jv.empty() || jv.isObject()) { if (jv.empty() || jv.isObject()) {
auto reader = child(key, val.idx()); auto reader = child(key, val.idx());
err = model(&reader, val.get()); ModelHandlerInterface handler(&reader);
err = model(&handler, val.get());
} else { } else {
err = OxError(1, "Type mismatch"); err = OxError(1, "Type mismatch");
} }
@ -185,13 +201,17 @@ Error OrganicClawReader::field(const char *key, BString<L> *val) noexcept {
template<typename T> template<typename T>
Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noexcept { Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noexcept {
const auto &srcVal = value(key); const auto &srcVal = value(key);
if (!srcVal.isNull() && !srcVal.isArray()) {
return OxError(1, "Type mismatch");
}
auto srcSize = srcVal.size(); auto srcSize = srcVal.size();
if (srcSize > valLen) { if (srcSize > valLen) {
return OxError(1); return OxError(1);
} }
OrganicClawReader r(srcVal); OrganicClawReader r(srcVal);
ModelHandlerInterface handler{&r};
for (decltype(srcSize) i = 0; i < srcSize; ++i) { for (decltype(srcSize) i = 0; i < srcSize; ++i) {
oxReturnError(r.field("", &val[i])); oxReturnError(handler.field("", &val[i]));
} }
return OxError(0); return OxError(0);
} }
@ -199,28 +219,32 @@ Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noex
template<typename T> template<typename T>
Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcept { Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcept {
const auto &srcVal = value(key); const auto &srcVal = value(key);
if (!srcVal.isObject()) {
return OxError(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};
for (decltype(srcSize) i = 0; i < srcSize; ++i) { for (decltype(srcSize) i = 0; i < srcSize; ++i) {
const auto k = keys[i].c_str(); const auto k = keys[i].c_str();
oxReturnError(r.field(k, &val->operator[](k))); oxReturnError(handler.field(k, &val->operator[](k)));
} }
return OxError(0); return OxError(0);
} }
template<typename T> Error readOC(const char *buff, std::size_t buffSize, auto *val) noexcept {
Error readOC(const char *json, std::size_t jsonSize, T *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;
Json::CharReaderBuilder parserBuilder; Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader()); auto parser = UniquePtr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonSize, &doc, nullptr)) { if (!parser->parse(buff, buff + buffSize, &doc, nullptr)) {
return OxError(1, "Could not parse JSON"); return OxError(1, "Could not parse JSON");
} }
OrganicClawReader reader(json, jsonSize); OrganicClawReader reader(buff, buffSize);
return model(&reader, val); ModelHandlerInterface handler(&reader);
return model(&handler, val);
} catch (const Error &err) { } catch (const Error &err) {
return err; return err;
} catch (...) { } catch (...) {

View File

@ -10,4 +10,5 @@ target_link_libraries(
add_test("[ox/oc] OcTest Writer" OcTest OrganicClawWriter) add_test("[ox/oc] OcTest Writer" OcTest OrganicClawWriter)
add_test("[ox/oc] OcTest Reader" OcTest OrganicClawReader) add_test("[ox/oc] OcTest Reader" OcTest OrganicClawReader)
add_test("[ox/oc] OcTest OrganicClawModelValue" OcTest OrganicClawModelValue)
add_test("[ox/oc] OcTest OrganicClawDef" OcTest OrganicClawDef) add_test("[ox/oc] OcTest OrganicClawDef" OcTest OrganicClawDef)

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#undef NDEBUG #undef NDEBUG
@ -19,7 +19,7 @@ union TestUnion {
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool Bool; bool Bool;
uint32_t Int = 5; uint32_t Int = 5;
char String[32]; char *String;
}; };
struct TestStructNest { struct TestStructNest {
@ -43,8 +43,9 @@ struct TestStruct {
int32_t Int6 = 0; int32_t Int6 = 0;
int32_t Int7 = 0; int32_t Int7 = 0;
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::BString<32> String = ""; ox::String String = "";
uint32_t List[4] = {0, 0, 0, 0}; uint32_t List[4] = {0, 0, 0, 0};
ox::HashMap<ox::String, int> Map; ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct; TestStructNest EmptyStruct;
@ -55,23 +56,24 @@ struct TestStruct {
TestStruct(TestStruct &&other) noexcept; TestStruct(TestStruct &&other) noexcept;
constexpr ~TestStruct() noexcept { constexpr ~TestStruct() noexcept {
if (unionIdx == 2) {
ox::safeDelete(Union.String);
}
} }
constexpr TestStruct &operator=(TestStruct&&) noexcept; constexpr TestStruct &operator=(TestStruct&&) noexcept;
}; };
template<typename T> constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
constexpr ox::Error model(T *io, TestUnion *obj) noexcept {
io->template setTypeInfo<TestUnion>(); io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", ox::SerStr(obj->String))); oxReturnError(io->fieldCString("String", &obj->String));
return OxError(0); return OxError(0);
} }
template<typename T> constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStructNest> auto *obj) noexcept {
constexpr ox::Error model(T *io, TestStructNest *obj) noexcept {
io->template setTypeInfo<TestStructNest>(); io->template setTypeInfo<TestStructNest>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
@ -79,8 +81,7 @@ constexpr ox::Error model(T *io, TestStructNest *obj) noexcept {
return OxError(0); return OxError(0);
} }
template<typename T> constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
io->template setTypeInfo<TestStruct>(); io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
@ -92,7 +93,12 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
oxReturnError(io->field("Int6", &obj->Int6)); oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1})); oxReturnError(io->field("unionIdx", &obj->unionIdx));
if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
}
oxReturnError(io->field("String", &obj->String)); oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("Map", &obj->Map)); oxReturnError(io->field("Map", &obj->Map));
@ -173,6 +179,57 @@ const std::map<std::string_view, ox::Error(*)()> tests = {
return OxError(0); return OxError(0);
} }
}, },
{
"OrganicClawModelValue",
[] {
ox::Buffer dataBuff;
TestStruct testIn;
testIn.Bool = true;
testIn.Int = 42;
testIn.String = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
oxAssert(ox::writeOC(&testIn).moveTo(&dataBuff), "Data generation failed");
ox::TypeStore typeStore;
auto type = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(type.error, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type.value));
oxAssert(ox::readOC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct["String"].get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String failed");
oxAssert(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion["Int"].get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy["String"].get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0);
}
},
{ {
"OrganicClawDef", "OrganicClawDef",
[] { [] {

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "write.hpp" #include "write.hpp"
@ -18,87 +18,6 @@ OrganicClawWriter::OrganicClawWriter(Json::Value json, int unionIdx) noexcept:
m_unionIdx(unionIdx) { m_unionIdx(unionIdx) {
} }
Error OrganicClawWriter::field(const char *key, int8_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, int16_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, int32_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, int64_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint8_t *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint16_t *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint32_t *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, uint64_t *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, bool *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, String *val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::field(const char *key, SerStr val) noexcept { Error OrganicClawWriter::field(const char *key, SerStr val) noexcept {
if (targetValid() && val.len()) { if (targetValid() && val.len()) {
value(key) = val.c_str(); value(key) = val.c_str();
@ -107,6 +26,26 @@ Error OrganicClawWriter::field(const char *key, SerStr val) noexcept {
return OxError(0); return OxError(0);
} }
Error OrganicClawWriter::fieldCString(const char *key, const char **val, int len) noexcept {
if (targetValid() && len) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error OrganicClawWriter::fieldCString(const char *key, char **val, int len) noexcept {
return fieldCString(key, const_cast<const char**>(val), len);
}
Error OrganicClawWriter::fieldCString(const char *key, const char **val) noexcept {
return fieldCString(key, const_cast<const char**>(val), {});
}
Error OrganicClawWriter::fieldCString(const char *key, char **val) noexcept {
return fieldCString(key, const_cast<const char**>(val), {});
}
Json::Value &OrganicClawWriter::value(const char *key) noexcept { Json::Value &OrganicClawWriter::value(const char *key) noexcept {
if (m_json.isArray()) { if (m_json.isArray()) {
return m_json[m_fieldIt]; return m_json[m_fieldIt];

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -11,6 +11,7 @@
#include <json/json.h> #include <json/json.h>
#include <ox/model/fieldcounter.hpp> #include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp> #include <ox/model/optype.hpp>
#include <ox/model/types.hpp> #include <ox/model/types.hpp>
#include <ox/model/typenamecatcher.hpp> #include <ox/model/typenamecatcher.hpp>
@ -22,8 +23,7 @@ namespace ox {
class OrganicClawWriter { class OrganicClawWriter {
template<typename T> friend Result<Buffer> writeOC(auto *val) noexcept;
friend Result<Buffer> writeOC(T *val) noexcept;
protected: protected:
Json::Value m_json; Json::Value m_json;
@ -35,36 +35,140 @@ class OrganicClawWriter {
explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept; explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept;
Error field(const char*, int8_t *val) noexcept; Error field(const char *key, CommonPtrWith<int8_t> auto *val) noexcept {
Error field(const char*, int16_t *val) noexcept; if (*val) {
Error field(const char*, int32_t *val) noexcept; value(key) = *val;
Error field(const char*, int64_t *val) noexcept; }
++m_fieldIt;
return OxError(0);
}
Error field(const char*, uint8_t *val) noexcept; Error field(const char *key, CommonPtrWith<int16_t> auto *val) noexcept {
Error field(const char*, uint16_t *val) noexcept; if (*val) {
Error field(const char*, uint32_t *val) noexcept; value(key) = *val;
Error field(const char*, uint64_t *val) noexcept; }
++m_fieldIt;
return OxError(0);
}
Error field(const char*, bool *val) noexcept; Error field(const char *key, CommonPtrWith<int32_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<int64_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint8_t> auto *val) noexcept {
if (*val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint16_t> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint32_t> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<uint64_t> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
Error field(const char *key, CommonPtrWith<bool> auto *val) noexcept {
if (targetValid() && *val) {
value(key) = *val;
}
++m_fieldIt;
return OxError(0);
}
template<typename T> template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept; Error field(const char*, T *val, std::size_t len) noexcept;
template<typename U> template<typename U, bool force = true>
Error field(const char*, UnionView<U> val) noexcept; Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T> template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept; Error field(const char *key, const HashMap<String, T> *val) noexcept {
if (targetValid()) {
const auto &keys = val->keys();
OrganicClawWriter w;
ModelHandlerInterface handler{&w};
for (std::size_t i = 0; i < keys.size(); ++i) {
const auto k = keys[i].c_str();
oxReturnError(handler.field(k, val->at(k).value));
}
value(key) = w.m_json;
}
++m_fieldIt;
return OxError(0);
}
template<typename T>
Error field(const char *key, HashMap<String, T> *val) noexcept {
return field(key, const_cast<const HashMap<String, T>*>(val));
}
template<std::size_t L> template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept; Error field(const char *key, const BString<L> *val) noexcept {
return field(key, SerStr(val->data(), val->cap()));
}
Error field(const char*, String *val) noexcept; template<std::size_t L>
Error field(const char *key, BString<L> *val) noexcept {
return field(key, SerStr(val->data(), val->cap()));
}
template<std::size_t L>
Error field(const char *key, const BasicString<L> *val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}
++m_fieldIt;
return OxError(0);
}
template<std::size_t L>
Error field(const char *key, BasicString<L> *val) noexcept {
return field(key, const_cast<const BasicString<L>*>(val));
}
Error field(const char*, SerStr val) noexcept; Error field(const char*, SerStr val) noexcept;
Error fieldCString(const char*, const char **val, int len) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept; Error fieldCString(const char *name, char **val, int len) noexcept;
Error fieldCString(const char *name, const char **val) noexcept;
Error fieldCString(const char *name, char **val) noexcept;
template<typename T> template<typename T>
Error field(const char*, T *val) noexcept; Error field(const char*, T *val) noexcept;
@ -91,8 +195,9 @@ template<typename T>
Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcept { Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcept {
if (targetValid() && len) { if (targetValid() && len) {
OrganicClawWriter w((Json::Value(Json::arrayValue))); OrganicClawWriter w((Json::Value(Json::arrayValue)));
ModelHandlerInterface handler{&w};
for (std::size_t i = 0; i < len; ++i) { for (std::size_t i = 0; i < len; ++i) {
oxReturnError(w.field("", &val[i])); oxReturnError(handler.field("", &val[i]));
} }
value(key) = w.m_json; value(key) = w.m_json;
} }
@ -100,18 +205,14 @@ Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcep
return OxError(0); return OxError(0);
} }
template<std::size_t L>
Error OrganicClawWriter::field(const char *key, BString<L> *val) noexcept {
return field(key, SerStr(val->data(), val->cap()));
}
template<typename T> template<typename T>
Error OrganicClawWriter::field(const char *key, T *val) noexcept { Error OrganicClawWriter::field(const char *key, T *val) noexcept {
if constexpr(isVector_v<T>) { if constexpr(isVector_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;
oxReturnError(model(&w, val)); ModelHandlerInterface handler{&w};
oxReturnError(model(&handler, val));
if (!w.m_json.isNull()) { if (!w.m_json.isNull()) {
value(key) = w.m_json; value(key) = w.m_json;
} }
@ -120,11 +221,12 @@ Error OrganicClawWriter::field(const char *key, T *val) noexcept {
return OxError(0); return OxError(0);
} }
template<typename U> template<typename U, bool force>
Error OrganicClawWriter::field(const char *key, UnionView<U> val) noexcept { Error OrganicClawWriter::field(const char *key, UnionView<U, force> val) noexcept {
if (targetValid()) { if (targetValid()) {
OrganicClawWriter w(val.idx()); OrganicClawWriter w(val.idx());
oxReturnError(model(&w, val.get())); ModelHandlerInterface handler{&w};
oxReturnError(model(&handler, val.get()));
if (!w.m_json.isNull()) { if (!w.m_json.isNull()) {
value(key) = w.m_json; value(key) = w.m_json;
} }
@ -133,25 +235,10 @@ Error OrganicClawWriter::field(const char *key, UnionView<U> val) noexcept {
return OxError(0); return OxError(0);
} }
template<typename T> Result<Buffer> writeOC(auto *val) noexcept {
Error OrganicClawWriter::field(const char *key, HashMap<String, T> *val) noexcept {
if (targetValid()) {
const auto &keys = val->keys();
OrganicClawWriter w;
for (std::size_t i = 0; i < keys.size(); ++i) {
const auto k = keys[i].c_str();
oxReturnError(w.field(k, &val->operator[](k)));
}
value(key) = w.m_json;
}
++m_fieldIt;
return OxError(0);
}
template<typename T>
Result<Buffer> writeOC(T *val) noexcept {
OrganicClawWriter writer; OrganicClawWriter writer;
oxReturnError(model(&writer, val)); ModelHandlerInterface handler(&writer);
oxReturnError(model(&handler, val));
Json::StreamWriterBuilder jsonBuilder; Json::StreamWriterBuilder jsonBuilder;
const auto str = Json::writeString(jsonBuilder, writer.m_json); const auto str = Json::writeString(jsonBuilder, writer.m_json);
Buffer buff(str.size() + 1); Buffer buff(str.size() + 1);

View File

@ -24,6 +24,7 @@ add_library(
buffer.cpp buffer.cpp
buildinfo.cpp buildinfo.cpp
byteswap.cpp byteswap.cpp
concepts.cpp
fmt.cpp fmt.cpp
heapmgr.cpp heapmgr.cpp
math.cpp math.cpp
@ -73,6 +74,7 @@ install(
buffer.hpp buffer.hpp
buildinfo.hpp buildinfo.hpp
byteswap.hpp byteswap.hpp
concepts.hpp
def.hpp def.hpp
defines.hpp defines.hpp
defer.hpp defer.hpp

23
deps/ox/src/ox/std/concepts.cpp vendored Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright 2015 - 2022 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 "concepts.hpp"
namespace ox::detail::test {
class TestType;
[[nodiscard]] constexpr bool ok(auto*) noexcept { return false; }
[[nodiscard]] constexpr bool ok(CommonPtrWith<TestType> auto*) noexcept { return true; }
static_assert(ok(static_cast<TestType*>(nullptr)));
static_assert(ok(static_cast<const TestType*>(nullptr)));
static_assert(!ok(static_cast<int*>(nullptr)));
static_assert(!ok(static_cast<const int*>(nullptr)));
}

17
deps/ox/src/ox/std/concepts.hpp vendored Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "typetraits.hpp"
namespace ox {
template<typename T, typename U>
concept CommonPtrWith = ox::is_same_v<typename ox::remove_pointer<const T*>::type,
typename ox::remove_pointer<const U*>::type>;
}

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -31,7 +31,7 @@ class exception {
#include "utility.hpp" #include "utility.hpp"
#define OxError(...) ox::Error(__FILE__, __LINE__, __VA_ARGS__) #define OxError(...) ox::Error(__FILE__, __LINE__, __VA_ARGS__)
#define OxException(...) ox::Error(__FILE__, __LINE__, __VA_ARGS__) #define OxException(...) ox::Exception(__FILE__, __LINE__, __VA_ARGS__)
namespace ox { namespace ox {
@ -83,7 +83,7 @@ constexpr auto errCode(const Error &err) noexcept {
template<typename T=const char*> template<typename T=const char*>
[[nodiscard]] [[nodiscard]]
constexpr auto toStr(const Error &err) noexcept { constexpr auto toStr(const Error &err) noexcept {
return T(err.msg); return err.msg ? T(err.msg) : "";
} }
struct Exception: public std::exception { struct Exception: public std::exception {

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -46,21 +46,21 @@ class HashMap {
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr T &operator[](K key); constexpr T &operator[](const K &key);
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr Result<T*> at(K key) noexcept; constexpr Result<T*> at(const K &key) noexcept;
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr Result<const T*> at(K key) const noexcept; constexpr Result<const T*> at(const K &key) const noexcept;
constexpr void erase(const K &key); constexpr void erase(const K &key);
constexpr bool contains(K key) const noexcept; constexpr bool contains(const K &key) const noexcept;
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept; constexpr std::size_t size() const noexcept;
@ -68,6 +68,8 @@ class HashMap {
[[nodiscard]] [[nodiscard]]
constexpr const Vector<K> &keys() const noexcept; constexpr const Vector<K> &keys() const noexcept;
constexpr void clear();
private: private:
constexpr void expand(); constexpr void expand();
@ -79,14 +81,12 @@ class HashMap {
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr Pair *const&access(const Vector<Pair*> &pairs, K key) const; constexpr Pair *const&access(const Vector<Pair*> &pairs, const K &key) const;
/** /**
* K is assumed to be a null terminated string. * K is assumed to be a null terminated string.
*/ */
constexpr Pair *&access(Vector<Pair*> &pairs, K key); constexpr Pair *&access(Vector<Pair*> &pairs, const K &key);
constexpr void clear();
}; };
@ -145,7 +145,7 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](K k) { constexpr T &HashMap<K, T>::operator[](const K &k) {
auto &p = access(m_pairs, k); auto &p = access(m_pairs, k);
if (p == nullptr) { if (p == nullptr) {
if (m_pairs.size() * 0.7 < m_keys.size()) { if (m_pairs.size() * 0.7 < m_keys.size()) {
@ -159,19 +159,19 @@ constexpr T &HashMap<K, T>::operator[](K k) {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Result<T*> HashMap<K, T>::at(K k) noexcept { constexpr Result<T*> HashMap<K, T>::at(const K &k) noexcept {
auto p = access(m_pairs, k); auto p = access(m_pairs, k);
if (!p) { if (!p) {
return {nullptr, OxError(1)}; return {nullptr, OxError(1, "value not found for given key")};
} }
return &p->value; return &p->value;
} }
template<typename K, typename T> template<typename K, typename T>
constexpr Result<const T*> HashMap<K, T>::at(K k) const noexcept { constexpr Result<const T*> HashMap<K, T>::at(const K &k) const noexcept {
auto p = access(m_pairs, k); auto p = access(m_pairs, k);
if (!p) { if (!p) {
return {nullptr, OxError(1)}; return {nullptr, OxError(1, "value not found for given key")};
} }
return &p->value; return &p->value;
} }
@ -196,8 +196,9 @@ constexpr void HashMap<K, T>::erase(const K &k) {
} }
oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k))); oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k)));
} }
template<typename K, typename T> template<typename K, typename T>
constexpr bool HashMap<K, T>::contains(K k) const noexcept { constexpr bool HashMap<K, T>::contains(const K &k) const noexcept {
return access(m_pairs, k) != nullptr; return access(m_pairs, k) != nullptr;
} }
@ -211,12 +212,21 @@ constexpr const Vector<K> &HashMap<K, T>::keys() const noexcept {
return m_keys; return m_keys;
} }
template<typename K, typename T>
constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear();
m_pairs.resize(100);
}
template<typename K, typename T> template<typename K, typename T>
constexpr void HashMap<K, T>::expand() { constexpr void HashMap<K, T>::expand() {
Vector<Pair*> r; Vector<Pair*> r;
for (std::size_t i = 0; i < m_keys.size(); ++i) { for (std::size_t i = 0; i < m_keys.size(); ++i) {
auto k = m_keys[i]; auto k = m_keys[i];
access(r, k) = access(m_pairs, k); access(r, k) = std::move(access(m_pairs, k));
} }
m_pairs = std::move(r); m_pairs = std::move(r);
} }
@ -231,43 +241,29 @@ constexpr uint64_t HashMap<K, T>::hash(K k, int len) noexcept {
} }
template<typename K, typename T> template<typename K, typename T>
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(const Vector<Pair*> &pairs, K k) const { constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(const Vector<Pair*> &pairs, const K &k) const {
auto h = hash(k) % pairs.size(); auto h = hash(k) % pairs.size();
char hashStr[sizeof(h) + 1];
ox_memcpy(hashStr, &h, sizeof(h));
hashStr[sizeof(h)] = 0;
while (true) { while (true) {
const auto &p = pairs[h]; const auto &p = pairs[h];
if (p == nullptr || ox_strcmp(p->key, k) == 0) { if (p == nullptr || ox_strcmp(p->key, k) == 0) {
return p; return p;
} else { } else {
h = hash(hashStr, 8) % pairs.size(); h = (h + 1) % pairs.size();
} }
} }
} }
template<typename K, typename T> template<typename K, typename T>
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, K k) { constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, const K &k) {
auto h = hash(k) % pairs.size(); auto h = hash(k) % pairs.size();
char hashStr[sizeof(h) + 1];
ox_memcpy(hashStr, &h, sizeof(h));
hashStr[sizeof(h)] = 0;
while (true) { while (true) {
auto &p = pairs[h]; auto &p = pairs[h];
if (p == nullptr || ox_strcmp(p->key, k) == 0) { if (p == nullptr || ox_strcmp(p->key, k) == 0) {
return p; return p;
} else { } else {
h = hash(hashStr, 8) % pairs.size(); h = (h + 1) % pairs.size();
} }
} }
} }
template<typename K, typename T>
constexpr void HashMap<K, T>::clear() {
for (std::size_t i = 0; i < m_pairs.size(); i++) {
delete m_pairs[i];
}
m_pairs.clear();
}
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -14,6 +14,8 @@
#else #else
#include "utility.hpp"
namespace std { namespace std {
template<class T> template<class T>

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -47,43 +47,43 @@ class MallocaPtr {
T *m_val = nullptr; T *m_val = nullptr;
public: public:
inline MallocaPtr() noexcept = default; constexpr MallocaPtr() noexcept = default;
inline MallocaPtr(MallocaPtr &other) = delete; constexpr MallocaPtr(MallocaPtr &other) = delete;
inline MallocaPtr(const MallocaPtr &other) = delete; constexpr MallocaPtr(const MallocaPtr &other) = delete;
inline MallocaPtr(MallocaPtr &&other) noexcept { constexpr MallocaPtr(MallocaPtr &&other) noexcept {
m_onHeap = other.m_onHeap; m_onHeap = other.m_onHeap;
m_val = other.m_val; m_val = other.m_val;
other.m_onHeap = false; other.m_onHeap = false;
other.m_val = nullptr; other.m_val = nullptr;
} }
inline MallocaPtr(bool onHeap, T *val) noexcept { constexpr MallocaPtr(bool onHeap, T *val) noexcept {
m_onHeap = onHeap; m_onHeap = onHeap;
m_val = val; m_val = val;
} }
inline ~MallocaPtr() noexcept { constexpr ~MallocaPtr() noexcept {
if (m_onHeap && m_val) { if (m_onHeap && m_val) {
delete[] reinterpret_cast<uint8_t*>(m_val); delete[] reinterpret_cast<uint8_t*>(m_val);
} }
} }
inline const T *get() const noexcept { constexpr const T *get() const noexcept {
return reinterpret_cast<T*>(m_val); return reinterpret_cast<T*>(m_val);
} }
inline T *get() noexcept { constexpr T *get() noexcept {
return reinterpret_cast<T*>(m_val); return reinterpret_cast<T*>(m_val);
} }
inline const T &operator=(MallocaPtr &other) = delete; constexpr const T &operator=(MallocaPtr &other) = delete;
inline const T &operator=(const MallocaPtr &other) = delete; constexpr const T &operator=(const MallocaPtr &other) = delete;
inline const T &operator=(MallocaPtr &&other) noexcept { constexpr const T &operator=(MallocaPtr &&other) noexcept {
if (m_onHeap && m_val) { if (m_onHeap && m_val) {
delete[] reinterpret_cast<uint8_t*>(m_val); delete[] reinterpret_cast<uint8_t*>(m_val);
} }
@ -93,35 +93,35 @@ class MallocaPtr {
other.m_val = nullptr; other.m_val = nullptr;
} }
inline const T *operator->() const noexcept { constexpr const T *operator->() const noexcept {
return reinterpret_cast<T*>(m_val); return reinterpret_cast<T*>(m_val);
} }
inline T *operator->() noexcept { constexpr T *operator->() noexcept {
return reinterpret_cast<T*>(m_val); return reinterpret_cast<T*>(m_val);
} }
inline operator const T*() const noexcept { constexpr operator const T*() const noexcept {
return reinterpret_cast<T*>(m_val); return reinterpret_cast<T*>(m_val);
} }
inline operator T*() noexcept { constexpr operator T*() noexcept {
return reinterpret_cast<T*>(m_val); return reinterpret_cast<T*>(m_val);
} }
inline const T &operator*() const noexcept { constexpr const T &operator*() const noexcept {
return *reinterpret_cast<T*>(m_val); return *reinterpret_cast<T*>(m_val);
} }
inline T &operator*() noexcept { constexpr T &operator*() noexcept {
return *reinterpret_cast<T*>(m_val); return *reinterpret_cast<T*>(m_val);
} }
inline bool operator==(const MallocaPtr<T> &other) const noexcept { constexpr bool operator==(const MallocaPtr<T> &other) const noexcept {
return m_val == other.m_val && m_onHeap == other.m_onHeap; return m_val == other.m_val && m_onHeap == other.m_onHeap;
} }
inline bool operator!=(const MallocaPtr<T> &other) const noexcept { constexpr bool operator!=(const MallocaPtr<T> &other) const noexcept {
return m_val != other.m_val || m_onHeap != other.m_onHeap; return m_val != other.m_val || m_onHeap != other.m_onHeap;
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -26,10 +26,10 @@ class Optional {
public: public:
constexpr Optional() noexcept = default; constexpr Optional() noexcept = default;
template<typename ...Args>
constexpr Optional(Args &&... args);
constexpr Optional(const Optional &other) { constexpr Optional(const Optional &other) {
if (m_ptr) {
m_ptr->~T();
}
if (other.m_ptr) { if (other.m_ptr) {
m_ptr = new(m_data) T(*other.m_ptr); m_ptr = new(m_data) T(*other.m_ptr);
} else { } else {
@ -149,4 +149,10 @@ class Optional {
}; };
template<typename T, std::size_t buffSize>
template<typename... Args>
constexpr Optional<T, buffSize>::Optional(Args &&... args) {
emplace(ox::forward<Args>(args)...);
}
} }

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -13,6 +13,7 @@
#include "bit.hpp" #include "bit.hpp"
#include "bstring.hpp" #include "bstring.hpp"
#include "byteswap.hpp" #include "byteswap.hpp"
#include "concepts.hpp"
#include "defer.hpp" #include "defer.hpp"
#include "def.hpp" #include "def.hpp"
#include "defines.hpp" #include "defines.hpp"

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -134,8 +134,12 @@ class BasicString {
constexpr BasicString operator+(const BasicString &src) const noexcept; constexpr BasicString operator+(const BasicString &src) const noexcept;
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const BasicString &other) const noexcept; constexpr bool operator==(const BasicString &other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const BasicString &other) const noexcept; constexpr bool operator!=(const BasicString &other) const noexcept;
constexpr bool operator<(const BasicString &other) const noexcept; constexpr bool operator<(const BasicString &other) const noexcept;
@ -404,8 +408,23 @@ constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(c
return cpy; return cpy;
} }
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator==(const char *other) const noexcept {
bool retval = true;
for (auto i = 0u; i < m_buff.size() && (m_buff[i] || other[i]); ++i) {
if (m_buff[i] != other[i]) {
retval = false;
break;
}
}
return retval;
}
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other) const noexcept { constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other) const noexcept {
if (len() != other.len()) {
return false;
}
bool retval = true; bool retval = true;
std::size_t i = 0; std::size_t i = 0;
while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) { while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) {
@ -418,6 +437,11 @@ constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other
return retval; return retval;
} }
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator!=(const BasicString &other) const noexcept { constexpr bool BasicString<SmallStringSize>::operator!=(const BasicString &other) const noexcept {
return !operator==(other); return !operator==(other);

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -54,7 +54,7 @@ constexpr auto ox_strlen(T str1) noexcept {
template<typename T1, typename T2> template<typename T1, typename T2>
[[nodiscard]] [[nodiscard]]
constexpr int ox_strcmp(T1 str1, T2 str2) noexcept { constexpr int ox_strcmp(const T1 &str1, const T2 &str2) noexcept {
auto retval = 0; auto retval = 0;
auto i = 0u; auto i = 0u;
while (str1[i] || str2[i]) { while (str1[i] || str2[i]) {

View File

@ -3,7 +3,7 @@
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -138,6 +138,21 @@ constexpr bool is_class_v = is_class<T>();
template<typename T> template<typename T>
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value; constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
template<typename T, std::size_t bits>
concept Signed_c = is_signed_v<T> && sizeof(T) == 8 * bits;
template<typename T, std::size_t bits>
concept Unsigned_c = !is_signed_v<T> && sizeof(T) == 8 * bits;
template<typename T, typename U>
struct is_same: false_type {};
template<typename T>
struct is_same<T, T>: true_type {};
template<typename T, typename U>
constexpr auto is_same_v = is_same<T, U>::value;
// enable_if /////////////////////////////////////////////////////////////////// // enable_if ///////////////////////////////////////////////////////////////////
template<bool B, class T = void> template<bool B, class T = void>