From ca64f95be30cfb9a5df4b651d9d2e1f733a9c6fb Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 21 Jun 2022 21:43:49 -0500 Subject: [PATCH] [ox] Overhaul serialization/model system and add ModelValue/ModelObject/ModelUnion variant system --- deps/ox/.liccor.yml | 2 +- deps/ox/deps/jsoncpp/CMakeLists.txt | 4 + deps/ox/src/ox/claw/read.cpp | 32 +- deps/ox/src/ox/claw/read.hpp | 11 +- deps/ox/src/ox/claw/test/tests.cpp | 26 +- deps/ox/src/ox/claw/write.hpp | 3 +- deps/ox/src/ox/fs/filesystem/filelocation.hpp | 19 +- deps/ox/src/ox/mc/intops.hpp | 7 +- deps/ox/src/ox/mc/read.cpp | 150 +-- deps/ox/src/ox/mc/read.hpp | 484 +++++++--- deps/ox/src/ox/mc/test/CMakeLists.txt | 3 +- deps/ox/src/ox/mc/test/tests.cpp | 106 ++- deps/ox/src/ox/mc/write.cpp | 85 +- deps/ox/src/ox/mc/write.hpp | 280 ++++-- deps/ox/src/ox/model/CMakeLists.txt | 2 + deps/ox/src/ox/model/def.hpp | 8 +- deps/ox/src/ox/model/desctypes.hpp | 21 +- deps/ox/src/ox/model/descwrite.cpp | 110 +-- deps/ox/src/ox/model/descwrite.hpp | 261 ++++-- deps/ox/src/ox/model/fieldcounter.hpp | 7 +- deps/ox/src/ox/model/model.hpp | 4 +- deps/ox/src/ox/model/modelhandleradaptor.hpp | 155 +++ deps/ox/src/ox/model/modelops.hpp | 86 +- deps/ox/src/ox/model/modelvalue.cpp | 9 + deps/ox/src/ox/model/modelvalue.hpp | 886 ++++++++++++++++++ deps/ox/src/ox/model/optype.hpp | 48 +- deps/ox/src/ox/model/typenamecatcher.hpp | 6 +- deps/ox/src/ox/model/types.hpp | 48 +- deps/ox/src/ox/model/typestore.hpp | 60 +- deps/ox/src/ox/oc/read.cpp | 108 ++- deps/ox/src/ox/oc/read.hpp | 58 +- deps/ox/src/ox/oc/test/CMakeLists.txt | 1 + deps/ox/src/ox/oc/test/tests.cpp | 79 +- deps/ox/src/ox/oc/write.cpp | 103 +- deps/ox/src/ox/oc/write.hpp | 177 +++- deps/ox/src/ox/std/CMakeLists.txt | 2 + deps/ox/src/ox/std/concepts.cpp | 23 + deps/ox/src/ox/std/concepts.hpp | 17 + deps/ox/src/ox/std/error.hpp | 6 +- deps/ox/src/ox/std/hashmap.hpp | 64 +- deps/ox/src/ox/std/memory.hpp | 4 +- deps/ox/src/ox/std/new.hpp | 40 +- deps/ox/src/ox/std/optional.hpp | 14 +- deps/ox/src/ox/std/std.hpp | 3 +- deps/ox/src/ox/std/string.hpp | 26 +- deps/ox/src/ox/std/strops.hpp | 4 +- deps/ox/src/ox/std/typetraits.hpp | 17 +- 47 files changed, 2696 insertions(+), 973 deletions(-) create mode 100644 deps/ox/src/ox/model/modelhandleradaptor.hpp create mode 100644 deps/ox/src/ox/model/modelvalue.cpp create mode 100644 deps/ox/src/ox/model/modelvalue.hpp create mode 100644 deps/ox/src/ox/std/concepts.cpp create mode 100644 deps/ox/src/ox/std/concepts.hpp diff --git a/deps/ox/.liccor.yml b/deps/ox/.liccor.yml index bec59a77..c911b893 100644 --- a/deps/ox/.liccor.yml +++ b/deps/ox/.liccor.yml @@ -6,4 +6,4 @@ copyright_notice: |- 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 http://mozilla.org/MPL/2.0/. + file, You can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/deps/ox/deps/jsoncpp/CMakeLists.txt b/deps/ox/deps/jsoncpp/CMakeLists.txt index 0d90626e..8e2c7174 100644 --- a/deps/ox/deps/jsoncpp/CMakeLists.txt +++ b/deps/ox/deps/jsoncpp/CMakeLists.txt @@ -191,6 +191,10 @@ if(JSONCPP_WITH_TESTS) include(CTest) endif() +# DrinkingTea - begin +set(CMAKE_CXX_FLAGS "-Wno-everything") +# DrinkingTea - end + # Build the different applications add_subdirectory(src) diff --git a/deps/ox/src/ox/claw/read.cpp b/deps/ox/src/ox/claw/read.cpp index 13d9768c..cee5f8af 100644 --- a/deps/ox/src/ox/claw/read.cpp +++ b/deps/ox/src/ox/claw/read.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include @@ -72,4 +72,34 @@ Result stripClawHeader(const ox::Buffer &buff) noexcept { return stripClawHeader(buff.data(), buff.size()); } +Result 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(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); +} + } diff --git a/deps/ox/src/ox/claw/read.hpp b/deps/ox/src/ox/claw/read.hpp index b5f7fa71..7864a029 100644 --- a/deps/ox/src/ox/claw/read.hpp +++ b/deps/ox/src/ox/claw/read.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -50,13 +50,14 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) { switch (header.fmt) { case ClawFormat::Metal: { - MetalClawReader reader(reinterpret_cast(header.data), buffLen); - return model(&reader, val); + MetalClawReader reader(reinterpret_cast(header.data), header.dataSize); + ModelHandlerInterface handler(&reader); + return model(&handler, val); } case ClawFormat::Organic: { #ifdef OX_USE_STDLIB - OrganicClawReader reader(header.data, buffLen); + OrganicClawReader reader(header.data, header.dataSize); return model(&reader, val); #else break; @@ -85,4 +86,6 @@ Result readClaw(const Buffer &buff) { return readClaw(buff.data(), buff.size()); } +Result readClaw(TypeStore *ts, const Buffer &buff) noexcept; + } diff --git a/deps/ox/src/ox/claw/test/tests.cpp b/deps/ox/src/ox/claw/test/tests.cpp index e57eb249..8771522b 100644 --- a/deps/ox/src/ox/claw/test/tests.cpp +++ b/deps/ox/src/ox/claw/test/tests.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #undef NDEBUG @@ -25,7 +25,7 @@ union TestUnion { static constexpr auto TypeVersion = 1; bool Bool; uint32_t Int = 5; - char String[32]; + char *String; }; struct TestStructNest { @@ -49,6 +49,7 @@ struct TestStruct { int32_t Int6 = 0; int32_t Int7 = 0; int32_t Int8 = 0; + int unionIdx = 1; TestUnion Union; ox::BString<32> String = ""; uint32_t List[4] = {0, 0, 0, 0}; @@ -56,21 +57,24 @@ struct TestStruct { TestStructNest Struct; ~TestStruct() { + if (unionIdx == 2) { + ox::safeDelete(Union.String); + } } }; template -constexpr ox::Error model(T *io, TestUnion *obj) { +constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Int", &obj->Int)); - oxReturnError(io->field("String", ox::SerStr(obj->String))); + oxReturnError(io->fieldCString("String", &obj->String)); return OxError(0); } template -constexpr ox::Error model(T *io, TestStructNest *obj) { +constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Int", &obj->Int)); @@ -79,7 +83,7 @@ constexpr ox::Error model(T *io, TestStructNest *obj) { } template -constexpr ox::Error model(T *io, TestStruct *obj) { +constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); 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("Int7", &obj->Int7)); 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("List", obj->List, 4)); oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct)); @@ -99,7 +107,7 @@ constexpr ox::Error model(T *io, TestStruct *obj) { return OxError(0); } -std::map tests = { +static std::map tests = { { { "ClawHeaderReader", @@ -153,7 +161,7 @@ std::map tests = { auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal); 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"; oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); diff --git a/deps/ox/src/ox/claw/write.hpp b/deps/ox/src/ox/claw/write.hpp index 48e8a65c..55e36d43 100644 --- a/deps/ox/src/ox/claw/write.hpp +++ b/deps/ox/src/ox/claw/write.hpp @@ -82,8 +82,7 @@ Result writeClawHeader(T *t, ClawFormat fmt) noexcept { } -template -Result writeClaw(T *t, ClawFormat fmt = ClawFormat::Metal) { +Result writeClaw(auto *t, ClawFormat fmt = ClawFormat::Metal) { oxRequire(header, detail::writeClawHeader(t, fmt)); oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t)); Buffer out(header.len() + data.size()); diff --git a/deps/ox/src/ox/fs/filesystem/filelocation.hpp b/deps/ox/src/ox/fs/filesystem/filelocation.hpp index 6eb76d5d..878d5043 100644 --- a/deps/ox/src/ox/fs/filesystem/filelocation.hpp +++ b/deps/ox/src/ox/fs/filesystem/filelocation.hpp @@ -3,12 +3,13 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include +#include #include #include @@ -24,7 +25,7 @@ enum class FileAddressType: int8_t { class FileAddress { template - friend constexpr Error model(T*, FileAddress*) noexcept; + friend constexpr Error model(T*, CommonPtrWith auto*) noexcept; public: static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress"; @@ -129,22 +130,16 @@ constexpr const char *getModelTypeName() noexcept { } template -constexpr Error model(T *io, FileAddress::Data *obj) noexcept { +constexpr Error model(T *io, CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); - if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) { - String dummy; - 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->fieldCString("path", &obj->path)); + oxReturnError(io->fieldCString("constPath", &obj->path)); oxReturnError(io->field("inode", &obj->inode)); return OxError(0); } template -constexpr Error model(T *io, FileAddress *fa) noexcept { +constexpr Error model(T *io, CommonPtrWith auto *fa) noexcept { io->template setTypeInfo(); if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) { int8_t type = 0; diff --git a/deps/ox/src/ox/mc/intops.hpp b/deps/ox/src/ox/mc/intops.hpp index 1d6d4099..d2da8255 100644 --- a/deps/ox/src/ox/mc/intops.hpp +++ b/deps/ox/src/ox/mc/intops.hpp @@ -64,7 +64,7 @@ template [[nodiscard]] constexpr McInt encodeInteger(I input) noexcept { McInt out; - auto inputNegative = is_signed_v && input < 0; + const auto inputNegative = is_signed_v && input < 0; // move input to uint64_t to allow consistent bit manipulation, and to avoid // overflow concerns uint64_t val = 0; @@ -72,7 +72,7 @@ constexpr McInt encodeInteger(I input) noexcept { if (val) { // bits needed to represent number factoring in space possibly // needed for signed bit - const auto highBit = inputNegative ? (highestBit(~val)) : highestBit(val); + const auto highBit = inputNegative ? highestBit(~val) : highestBit(val); const auto bits = highBit + 1 + (is_signed_v ? 1 : 0); // bytes needed to store value std::size_t bytes = bits / 8 + (bits % 8 != 0); @@ -84,7 +84,6 @@ constexpr McInt encodeInteger(I input) noexcept { ++bytes; } const auto bytesIndicator = onMask(bytes - 1); - // ensure we are copying from little endian representation LittleEndian leVal = val; if (inputNegative) { @@ -116,7 +115,7 @@ constexpr McInt encodeInteger(I input) noexcept { [[nodiscard]] static constexpr std::size_t countBytes(uint8_t b) noexcept { std::size_t i = 0; - for (; (b >> i) & 1; i++); + while ((b >> i) & 1) ++i; return i + 1; } diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp index 56119894..303087c8 100644 --- a/deps/ox/src/ox/mc/read.cpp +++ b/deps/ox/src/ox/mc/read.cpp @@ -3,157 +3,9 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#include -#include -#include - -#include "read.hpp" - 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(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(m_field))) { - // read the length - if (m_buffIt >= m_buffLen) { - return OxError(MC_BUFFENDED); - } - std::size_t bytesRead = 0; - auto [size, err] = mc::decodeInteger(&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(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 MetalClawReader::arrayLength(const char*, bool pass) noexcept { - if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast(m_field))) { - // read the length - if (m_buffIt >= m_buffLen) { - return OxError(MC_BUFFENDED); - } - std::size_t bytesRead = 0; - auto out = mc::decodeInteger(&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(m_field))) { - // read the length - std::size_t bytesRead = 0; - auto len = mc::decodeInteger(&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(m_field)).value; -} - -bool MetalClawReader::fieldPresent(int fieldNo) const noexcept { - return m_fieldPresence.get(static_cast(fieldNo)).value; -} - -void MetalClawReader::nextField() noexcept { - ++m_field; -} - } diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index b986f9b3..65a5b972 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -3,12 +3,13 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include +#include #include #include #include @@ -25,7 +26,8 @@ namespace ox { -class MetalClawReader { +template +class MetalClawReaderTemplate { private: FieldBitmapReader m_fieldPresence; @@ -35,87 +37,93 @@ class MetalClawReader { std::size_t m_buffIt = 0; std::size_t m_buffLen = 0; const uint8_t *m_buff = nullptr; - MetalClawReader *m_parent = nullptr; + MetalClawReaderTemplate *m_parent = nullptr; 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 *parent = nullptr) noexcept; - ~MetalClawReader() noexcept; + constexpr ~MetalClawReaderTemplate() noexcept; - Error field(const char*, int8_t *val) noexcept; - Error field(const char*, int16_t *val) noexcept; - Error field(const char*, int32_t *val) noexcept; - Error field(const char*, int64_t *val) noexcept; + constexpr Error field(const char*, int8_t *val) noexcept; + constexpr Error field(const char*, int16_t *val) noexcept; + constexpr Error field(const char*, int32_t *val) noexcept; + constexpr Error field(const char*, int64_t *val) noexcept; - Error field(const char*, uint8_t *val) noexcept; - Error field(const char*, uint16_t *val) noexcept; - Error field(const char*, uint32_t *val) noexcept; - Error field(const char*, uint64_t *val) noexcept; + constexpr Error field(const char*, uint8_t *val) noexcept; + constexpr Error field(const char*, uint16_t *val) noexcept; + constexpr Error field(const char*, uint32_t *val) noexcept; + constexpr Error field(const char*, uint64_t *val) noexcept; - Error field(const char*, bool *val) noexcept; + constexpr Error field(const char*, bool *val) noexcept; // array handler - template - Error field(const char*, T *val, std::size_t len) noexcept; + constexpr Error field(const char*, auto *val, std::size_t len) noexcept; // map handler template - Error field(const char*, HashMap *val) noexcept; + constexpr Error field(const char*, HashMap *val) noexcept; // array handler, with callback to allow handling individual elements - template - Error field(const char*, Handler handler) noexcept; + template + constexpr Error field(const char*, CB cb) noexcept; template - Error field(const char*, T *val) noexcept; + constexpr Error field(const char*, T *val) noexcept; - template - Error field(const char*, UnionView val) noexcept; + template + constexpr Error field(const char*, UnionView val) noexcept; template - Error field(const char*, BasicString *val) noexcept; + constexpr Error field(const char*, BasicString *val) noexcept; template - Error field(const char*, BString *val) noexcept; + constexpr Error field(const char*, BString *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. * @param pass indicates that the parsing should iterate past the array length */ - Result arrayLength(const char *name, bool pass = true) noexcept; + constexpr Result arrayLength(const char *name, bool pass = true) noexcept; /** * Reads an string length from the current location in the buffer. */ [[nodiscard]] - StringLength stringLength(const char *name) noexcept; + constexpr StringLength stringLength(const char *name) noexcept; template - constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v) noexcept; + constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, + int fields = ModelFieldCount_v) noexcept; /** * Returns a MetalClawReader to parse a child object. */ [[nodiscard]] - MetalClawReader child(const char *name, int unionIdx = -1) noexcept; + constexpr MetalClawReaderTemplate child(const char *name, int unionIdx = -1) noexcept; /** * Indicates whether or not the next field to be read is present. */ [[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. */ [[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]] static constexpr auto opType() noexcept { @@ -124,12 +132,145 @@ class MetalClawReader { private: template - Error readInteger(I *val) noexcept; + constexpr Error readInteger(I *val) noexcept; }; +template +constexpr MetalClawReaderTemplate::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 +constexpr MetalClawReaderTemplate::~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 +constexpr Error MetalClawReaderTemplate::field(const char*, int8_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, int16_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, int32_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, int64_t *val) noexcept { + return readInteger(val); +} + + +template +constexpr Error MetalClawReaderTemplate::field(const char*, uint8_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, uint16_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, uint32_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, uint64_t *val) noexcept { + return readInteger(val); +} + +template +constexpr Error MetalClawReaderTemplate::field(const char*, bool *val) noexcept { + if (m_unionIdx == -1 || m_unionIdx == m_field) { + auto valErr = m_fieldPresence.get(static_cast(m_field)); + *val = valErr.value; + oxReturnError(valErr.error); + } + ++m_field; + return OxError(0); +} + +// array handler +template +constexpr Error MetalClawReaderTemplate::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(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + oxRequire(len, mc::decodeInteger(&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(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 template -Error MetalClawReader::field(const char *name, T *val) noexcept { +constexpr Error MetalClawReaderTemplate::field(const char*, HashMap *val) noexcept { + if (m_unionIdx == -1 || m_unionIdx == m_field) { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + oxRequire(len, mc::decodeInteger(&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(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(keyLen + 1))); + oxReturnError(handler.field("", &val->operator[](wkey.get()))); + } + } + } + ++m_field; + return OxError(0); +} + +template +template +constexpr Error MetalClawReaderTemplate::field(const char *name, T *val) noexcept { if constexpr(isVector_v) { if (m_unionIdx == -1 || m_unionIdx == m_field) { // 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; return OxError(0); } else { - if ((m_unionIdx == -1 || m_unionIdx == m_field) && val && m_fieldPresence.get(static_cast(m_field))) { - auto reader = child(""); - oxReturnError(model(&reader, val)); + if ((m_unionIdx == -1 || m_unionIdx == m_field) && val) { + if (m_fieldPresence.get(static_cast(m_field))) { + auto reader = child(""); + auto handler = HandlerMaker(&reader); + oxReturnError(model(&handler, val)); + } } ++m_field; return OxError(0); } } -template -Error MetalClawReader::field(const char*, UnionView val) noexcept { - if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get() && m_fieldPresence.get(static_cast(m_field))) { - auto reader = child("", val.idx()); - oxReturnError(model(&reader, val.get())); +template +template +constexpr Error MetalClawReaderTemplate::field(const char*, UnionView val) noexcept { + if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get()) { + if (m_fieldPresence.get(static_cast(m_field))) { + auto reader = child("", val.idx()); + auto handler = HandlerMaker(&reader); + oxReturnError(model(&handler, val.get())); + } } ++m_field; return OxError(0); } +template template -Error MetalClawReader::field(const char*, BasicString *val) noexcept { +constexpr Error MetalClawReaderTemplate::field(const char*, BasicString *val) noexcept { if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_fieldPresence.get(static_cast(m_field))) { // read the length @@ -193,13 +342,129 @@ Error MetalClawReader::field(const char*, BasicString *val) noe return OxError(0); } +template template -Error MetalClawReader::field(const char *name, BString *val) noexcept { - return field(name, SerStr(val->data(), val->cap())); +constexpr Error MetalClawReaderTemplate::field(const char *name, BString *val) noexcept { + return fieldCString(name, val->data(), val->cap()); } +template +constexpr Error MetalClawReaderTemplate::fieldCString(const char*, char *val, std::size_t buffLen) noexcept { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + auto [size, err] = mc::decodeInteger(&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 +constexpr Error MetalClawReaderTemplate::fieldCString(const char*, char **val) noexcept { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + auto [size, err] = mc::decodeInteger(&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 +constexpr Error MetalClawReaderTemplate::fieldCString(const char*, char **val, std::size_t buffLen) noexcept { + if (m_unionIdx == -1 || m_unionIdx == m_field) { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + auto [size, err] = mc::decodeInteger(&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 +constexpr Result MetalClawReaderTemplate::arrayLength(const char*, bool pass) noexcept { + if ((m_unionIdx == -1 || m_unionIdx == m_field)) { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + auto out = mc::decodeInteger(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value; + if (pass) { + m_buffIt += bytesRead; + } + return out; + } + } + return OxError(1); +} + +template template -Error MetalClawReader::readInteger(I *val) noexcept { +constexpr Error MetalClawReaderTemplate::readInteger(I *val) noexcept { if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_fieldPresence.get(static_cast(m_field))) { std::size_t bytesRead = 0; @@ -219,65 +484,9 @@ Error MetalClawReader::readInteger(I *val) noexcept { return OxError(0); } -// array handler -template -Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) noexcept { - if (m_unionIdx == -1 || m_unionIdx == m_field) { - if (m_fieldPresence.get(static_cast(m_field))) { - // read the length - if (m_buffIt >= m_buffLen) { - return OxError(MC_BUFFENDED); - } - std::size_t bytesRead = 0; - oxRequire(len, mc::decodeInteger(&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(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 -Error MetalClawReader::field(const char*, HashMap *val) noexcept { - if (m_unionIdx == -1 || m_unionIdx == m_field) { - if (m_fieldPresence.get(static_cast(m_field))) { - // read the length - if (m_buffIt >= m_buffLen) { - return OxError(MC_BUFFENDED); - } - std::size_t bytesRead = 0; - oxRequire(len, mc::decodeInteger(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); - m_buffIt += bytesRead; - // read the list - auto reader = child(""); - reader.setTypeInfo("List", 0, static_cast(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(keyLen + 1))); - oxReturnError(reader.field("", &val->operator[](wkey.get()))); - } - } - } - ++m_field; - return OxError(0); -} - -template -Error MetalClawReader::field(const char*, Handler handler) noexcept { +template +template +constexpr Error MetalClawReaderTemplate::field(const char*, CB cb) noexcept { if (m_unionIdx == -1 || m_unionIdx == m_field) { if (m_fieldPresence.get(static_cast(m_field))) { // read the length @@ -290,11 +499,12 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept { // read the list auto reader = child(""); - reader.setTypeInfo("List", 0, static_cast(len)); + auto handler = HandlerMaker(&reader); + handler.setTypeInfo("List", 0, static_cast(len)); for (std::size_t i = 0; i < len; ++i) { T val; - oxReturnError(reader.field("", &val)); - oxReturnError(handler(i, &val)); + oxReturnError(handler.field("", &val)); + oxReturnError(cb(i, &val)); } } } @@ -302,18 +512,70 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept { return OxError(0); } +template +constexpr StringLength MetalClawReaderTemplate::stringLength(const char*) noexcept { + if ((m_unionIdx == -1 || m_unionIdx == m_field)) { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + std::size_t bytesRead = 0; + auto len = mc::decodeInteger(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead); + return len.value; + } + } + return 0; +} + +template template -constexpr void MetalClawReader::setTypeInfo(const char*, int, int fields) noexcept { +constexpr void MetalClawReaderTemplate::setTypeInfo(const char*, int, int fields) noexcept { m_fields = fields; m_buffIt = static_cast((fields / 8 + 1) - (fields % 8 == 0)); m_fieldPresence.setFields(fields); m_fieldPresence.setMaxLen(static_cast(m_buffIt)); } +template +constexpr MetalClawReaderTemplate MetalClawReaderTemplate::child(const char*, int unionIdx) noexcept { + return MetalClawReaderTemplate(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this); +} + +template +constexpr bool MetalClawReaderTemplate::fieldPresent(const char*) const noexcept { + return m_fieldPresence.get(static_cast(m_field)).value; +} + +template +constexpr bool MetalClawReaderTemplate::fieldPresent(int fieldNo) const noexcept { + return m_fieldPresence.get(static_cast(fieldNo)).value; +} + +template +[[nodiscard]] +constexpr int MetalClawReaderTemplate::whichFieldPresent(const char*, const ModelUnion &u) const noexcept { + FieldBitmapReader 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(i); + } + } + return -1; +} + +template +constexpr void MetalClawReaderTemplate::nextField() noexcept { + ++m_field; +} + +using MetalClawReader = MetalClawReaderTemplate<[](auto r) { + return ModelHandlerInterface{r}; +}>; + template Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept { MetalClawReader reader(reinterpret_cast(buff), buffLen); - return model(&reader, val); + ModelHandlerInterface handler(&reader); + return model(&handler, val); } template diff --git a/deps/ox/src/ox/mc/test/CMakeLists.txt b/deps/ox/src/ox/mc/test/CMakeLists.txt index 5e7602d2..a1f4d5f0 100644 --- a/deps/ox/src/ox/mc/test/CMakeLists.txt +++ b/deps/ox/src/ox/mc/test/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries( add_test("[ox/mc] McTest Writer" McTest MetalClawWriter) 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 decodeInteger" McTest decodeInteger) diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index 2a22df29..df800c77 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #undef NDEBUG @@ -19,7 +19,7 @@ union TestUnion { static constexpr auto TypeVersion = 1; bool Bool; uint32_t Int = 5; - char CString[32]; + char *CString; }; struct TestStructNest { @@ -43,6 +43,7 @@ struct TestStruct { int32_t Int6 = 0; int32_t Int7 = 0; int32_t Int8 = 0; + int unionIdx = 1; TestUnion Union; ox::String String = ""; ox::BString<32> BString = ""; @@ -50,14 +51,19 @@ struct TestStruct { ox::HashMap Map; TestStructNest EmptyStruct; TestStructNest Struct; + constexpr ~TestStruct() noexcept { + if (unionIdx == 2) { + ox::safeDelete(Union.CString); + } + } }; template -constexpr ox::Error model(T *io, TestUnion *obj) noexcept { +constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Int", &obj->Int)); - oxReturnError(io->field("CString", ox::SerStr(obj->CString))); + oxReturnError(io->fieldCString("CString", &obj->CString)); return OxError(0); } @@ -68,7 +74,7 @@ oxModelBegin(TestStructNest) oxModelEnd() template -constexpr ox::Error model(T *io, TestStruct *obj) noexcept { +constexpr ox::Error model(T *io, ox::CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); 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("Int7", &obj->Int7)); 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("BString", &obj->BString)); oxReturnError(io->field("List", obj->List, 4)); @@ -165,14 +176,15 @@ std::map tests = { using ox::MaxValue; using ox::mc::McInt; using ox::mc::encodeInteger; - static constexpr auto check = [](McInt val, ox::Vector &&expected) { + static constexpr auto check = [](McInt val, const ox::Vector &expected) { if (val.length != expected.size()) { std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n'; return OxError(1); } for (std::size_t i = 0; i < expected.size(); i++) { if (expected[i] != val.data[i]) { - std::cout << i << ": " << static_cast(val.data[i]) << '\n'; + std::cout << "decoded: " << static_cast(val.data[i]) << ", expected: " << static_cast(expected[i]) << '\n'; + std::cout << "decoded: " << i << ": " << static_cast(val.data[i]) << '\n'; return OxError(1); } } @@ -195,6 +207,7 @@ std::map tests = { 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(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(129)), {0b00'0001'01, 0b10}), "Encode 129 fail"); oxAssert(check(encodeInteger(int64_t(130)), {0b00'0010'01, 0b10}), "Encode 130 fail"); @@ -204,6 +217,7 @@ std::map tests = { 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(-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(-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"); @@ -214,6 +228,7 @@ std::map tests = { 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(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(129)), {0b0101, 0b10}), "Encode 129 fail"); oxAssert(check(encodeInteger(uint64_t(130)), {0b1001, 0b10}), "Encode 130 fail"); @@ -267,14 +282,13 @@ std::map tests = { } }, + { - "MetalClawDef", + "MetalClawModelValue", [] { - //constexpr size_t descBuffLen = 1024; - //uint8_t descBuff[descBuffLen]; static constexpr size_t dataBuffLen = ox::units::MB; - char dataBuff[dataBuffLen]; - TestStruct testIn, testOut; + ox::Buffer dataBuff(dataBuffLen); + TestStruct testIn; testIn.Bool = true; testIn.Int = 42; testIn.BString = "Test String 1"; @@ -285,18 +299,71 @@ std::map tests = { testIn.Struct.Bool = false; testIn.Struct.Int = 300; testIn.Struct.BString = "Test String 2"; - oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); + 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"); - oxReturnError(ox::walkModel(type.value, dataBuff, dataBuffLen, + ox::ModelObject testOut; + oxReturnError(testOut.setType(type.value)); + oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed"); + oxAssert(testOut["Int"].get() == testIn.Int, "testOut.Int failed"); + oxAssert(testOut["Bool"].get() == testIn.Bool, "testOut.Bool failed"); + oxAssert(testOut["String"].get() == testIn.String, "testOut.String failed"); + auto &testOutStruct = testOut["Struct"].get(); + auto &testOutUnion = testOut["Union"].get(); + auto &testOutList = testOut["List"].get(); + auto testOutStructCopy = testOut["Struct"].get(); + auto testOutUnionCopy = testOut["Union"].get(); + auto testOutListCopy = testOut["List"].get(); + oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed"); + oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed"); + oxAssert(testOutStruct["Bool"].get() == testIn.Struct.Bool, "testOut.Struct.Bool failed"); + oxAssert(testOutStruct["BString"].get() == testIn.Struct.BString.c_str(), "testOut.Struct.BString failed"); + oxAssert(testOut["unionIdx"].get() == testIn.unionIdx, "testOut.unionIdx failed"); + oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong"); + oxAssert(testOutUnion["Int"].get() == testIn.Union.Int, "testOut.Union.Int failed"); + oxAssert(testOutList[0].get() == testIn.List[0], "testOut.List[0] failed"); + oxAssert(testOutList[1].get() == testIn.List[1], "testOut.Struct.List[1] failed"); + oxAssert(testOutStructCopy["Bool"].get() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed"); + oxAssert(testOutStructCopy["BString"].get() == testIn.Struct.BString.c_str(), "testOut.Struct.BString (copy) failed"); + oxAssert(testOutListCopy[0].get() == testIn.List[0], "testOut.Struct.List[0] (copy) failed"); + oxAssert(testOutListCopy[1].get() == testIn.List[1], "testOut.Struct.List[1] (copy) failed"); + return OxError(0); + } + }, + + { + "MetalClawDef", + [] { + //constexpr size_t descBuffLen = 1024; + //uint8_t descBuff[descBuffLen]; + static constexpr size_t dataBuffLen = ox::units::MB; + char dataBuff[dataBuffLen]; + TestStruct testIn, testOut; + 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"; + oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); + ox::TypeStore typeStore; + auto type = ox::buildTypeDef(&typeStore, &testIn); + oxAssert(type.error, "Descriptor write failed"); + oxReturnError(ox::walkModel(type.value, dataBuff, dataBuffLen, [](const ox::Vector&, const ox::Vector&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error { //std::cout << f.fieldName.c_str() << '\n'; auto fieldName = f.fieldName.c_str(); switch (f.type->primitiveType) { case ox::PrimitiveType::UnsignedInteger: - std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t"; - switch (f.type->length) { + std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t"; + switch (f.type->length) { case 1: { uint8_t i = {}; oxAssert(rdr->field(fieldName, &i), "Walking model failed."); @@ -382,12 +449,11 @@ std::map tests = { }; int main(int argc, const char **args) { - int retval = -1; if (argc > 0) { auto testName = args[1]; if (tests.find(testName) != tests.end()) { - retval = tests[testName](); + oxAssert(tests[testName](), "Test failed..."); } } - return retval; + return 0; } diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp index dc1af3ad..698623a1 100644 --- a/deps/ox/src/ox/mc/write.cpp +++ b/deps/ox/src/ox/mc/write.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include @@ -15,87 +15,4 @@ 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(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(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(val.len())); - m_buffIt += static_cast(val.len()); - fieldSet = true; - } else { - return OxError(MC_BUFFENDED); - } - } - oxReturnError(m_fieldPresence.set(static_cast(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; -} - } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index 893c8d6b..5fa8adb1 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -3,12 +3,13 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include +#include #include #include #include @@ -38,49 +39,73 @@ class MetalClawWriter { uint8_t *m_buff = nullptr; 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; - Error field(const char*, int16_t *val) noexcept; - Error field(const char*, int32_t *val) noexcept; - Error field(const char*, int64_t *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; - Error field(const char*, uint8_t *val) noexcept; - Error field(const char*, uint16_t *val) noexcept; - Error field(const char*, uint32_t *val) noexcept; - Error field(const char*, uint64_t *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; - Error field(const char*, bool *val) noexcept; + constexpr Error field(const char*, CommonPtrWith auto *val) noexcept; template - Error field(const char*, T *val, std::size_t len) noexcept; + constexpr Error field(const char*, T *val, std::size_t len) noexcept; template - Error field(const char*, HashMap *val) noexcept; + constexpr Error field(const char *name, const HashMap *val) noexcept; + + template + constexpr Error field(const char*, HashMap *val) noexcept; template - Error field(const char*, BasicString *val) noexcept; + constexpr Error field(const char*, const BasicString *val) noexcept; template - Error field(const char*, BString *val) noexcept; + constexpr Error field(const char*, const BString *val) noexcept; - Error field(const char*, SerStr val) noexcept; + template + constexpr Error field(const char*, BasicString *val) noexcept; - Error fieldCString(const char *name, char **val, int len) noexcept; + template + constexpr Error field(const char*, BString *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(val), buffLen); + } + + constexpr Error fieldCString(const char *name, char **val) noexcept { + return fieldCString(name, const_cast(val)); + } + + constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept { + return fieldCString(name, const_cast(val), buffLen); + } template - Error field(const char*, T *val) noexcept; + constexpr Error field(const char*, T *val) noexcept; - template - Error field(const char*, UnionView val) noexcept; + template + constexpr Error field(const char*, UnionView val) noexcept; template - void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v) noexcept; + constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, + int fields = ModelFieldCount_v) noexcept; [[nodiscard]] - std::size_t size() const noexcept; + constexpr std::size_t size() const noexcept; [[nodiscard]] static constexpr auto opType() noexcept { @@ -88,13 +113,81 @@ class MetalClawWriter { } private: - template - Error appendInteger(I val) noexcept; + constexpr Error appendInteger(Integer_c auto 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(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 auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + return appendInteger(*val); +} + +constexpr Error MetalClawWriter::field(const char*, CommonPtrWith auto *val) noexcept { + if (m_unionIdx == -1 || m_unionIdx == m_field) { + oxReturnError(m_fieldPresence.set(static_cast(m_field), *val)); + } + ++m_field; + return OxError(0); +} + template -Error MetalClawWriter::field(const char*, BasicString *val) noexcept { +constexpr Error MetalClawWriter::field(const char*, const BasicString *val) noexcept { bool fieldSet = false; if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) { // write the length @@ -116,19 +209,77 @@ Error MetalClawWriter::field(const char*, BasicString *val) noe } template -Error MetalClawWriter::field(const char *name, BString *val) noexcept { - return field(name, SerStr(val->data(), val->cap())); +constexpr Error MetalClawWriter::field(const char *name, const BString *val) noexcept { + return fieldCString(name, val->data(), val->cap()); +} + +template +constexpr Error MetalClawWriter::field(const char *name, BasicString *val) noexcept { + return field(name, const_cast*>(val)); +} + +template +constexpr Error MetalClawWriter::field(const char *name, BString *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(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(strLen)); + m_buffIt += static_cast(strLen); + fieldSet = true; + } else { + return OxError(MC_BUFFENDED); + } + } + oxReturnError(m_fieldPresence.set(static_cast(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(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(strLen)); + m_buffIt += static_cast(strLen); + fieldSet = true; + } else { + return OxError(MC_BUFFENDED); + } + } + oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); + ++m_field; + return OxError(0); } template -Error MetalClawWriter::field(const char*, T *val) noexcept { +constexpr Error MetalClawWriter::field(const char*, T *val) noexcept { if constexpr(isVector_v) { return field(nullptr, val->data(), val->size()); } else { bool fieldSet = false; if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) { MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); - oxReturnError(model(&writer, val)); + ModelHandlerInterface handler{&writer}; + oxReturnError(model(&handler, val)); if (static_cast(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { m_buffIt += writer.m_buffIt; fieldSet = true; @@ -140,12 +291,13 @@ Error MetalClawWriter::field(const char*, T *val) noexcept { } } -template -Error MetalClawWriter::field(const char*, UnionView val) noexcept { +template +constexpr Error MetalClawWriter::field(const char*, UnionView val) noexcept { bool fieldSet = false; if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) { 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(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { m_buffIt += writer.m_buffIt; fieldSet = true; @@ -157,7 +309,7 @@ Error MetalClawWriter::field(const char*, UnionView val) noexcept { } template -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; 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); - writer.setTypeInfo("List", 0, len); + ModelHandlerInterface handler{&writer}; + handler.setTypeInfo("List", 0, len); // write the array for (std::size_t i = 0; i < len; i++) { - oxReturnError(writer.field("", &val[i])); + oxReturnError(handler.field("", &val[i])); } m_buffIt += writer.m_buffIt; @@ -188,11 +341,10 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept { } template -Error MetalClawWriter::field(const char*, HashMap *val) noexcept { +constexpr Error MetalClawWriter::field(const char*, const HashMap *val) noexcept { const auto &keys = val->keys(); const auto len = keys.size(); bool fieldSet = false; - if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { // write the length const auto arrLen = mc::encodeInteger(len); @@ -202,69 +354,57 @@ Error MetalClawWriter::field(const char*, HashMap *val) noexcept { } else { return OxError(MC_BUFFENDED); } - MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); + ModelHandlerInterface handler{&writer}; // double len for both key and value - writer.setTypeInfo("Map", 0, len * 2); - + handler.setTypeInfo("Map", 0, len * 2); // write the array for (std::size_t i = 0; i < len; i++) { const auto &key = keys[i]; const auto keyLen = ox_strlen(key); auto wkey = ox_malloca(keyLen + 1, char, 0); memcpy(wkey, key.c_str(), keyLen + 1); - oxReturnError(writer.field("", SerStr(wkey.get(), keyLen))); - oxReturnError(writer.field("", &(*val)[key])); + oxReturnError(handler.fieldCString("", wkey.get(), keyLen)); + oxReturnError(handler.field("", val->at(key).value)); } - m_buffIt += writer.m_buffIt; fieldSet = true; } - - oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); - m_field++; - return OxError(0); -} - -template -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(m_field), fieldSet)); m_field++; return OxError(0); } template -void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept { +constexpr Error MetalClawWriter::field(const char *name, HashMap *val) noexcept { + return field(name, const_cast*>(val)); +} + +template +constexpr void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept { m_fields = fields; m_fieldPresence.setFields(fields); m_buffIt = static_cast(m_fieldPresence.getMaxLen()); ox_memset(m_buff, 0, m_buffIt); } -template -Result writeMC(T *val) noexcept { +constexpr std::size_t MetalClawWriter::size() const noexcept { + return m_buffIt; +} + +Result writeMC(auto *val) noexcept { Buffer buff(10 * units::MB); MetalClawWriter writer(reinterpret_cast(buff.data()), buff.size()); - oxReturnError(model(&writer, val)); + ModelHandlerInterface handler{&writer}; + oxReturnError(model(&handler, val)); buff.resize(writer.size()); return buff; } -template -Error writeMC(char *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) noexcept { +Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept { MetalClawWriter writer(reinterpret_cast(buff), buffLen); - auto err = model(&writer, val); + ModelHandlerInterface handler(&writer); + auto err = model(&handler, val); if (sizeOut) { *sizeOut = writer.size(); } diff --git a/deps/ox/src/ox/model/CMakeLists.txt b/deps/ox/src/ox/model/CMakeLists.txt index 8c0897e8..121e285d 100644 --- a/deps/ox/src/ox/model/CMakeLists.txt +++ b/deps/ox/src/ox/model/CMakeLists.txt @@ -27,7 +27,9 @@ install( optype.hpp metadata.hpp model.hpp + modelhandleradaptor.hpp modelops.hpp + modelvalue.hpp typenamecatcher.hpp types.hpp typestore.hpp diff --git a/deps/ox/src/ox/model/def.hpp b/deps/ox/src/ox/model/def.hpp index fa1ce0aa..e2b20125 100644 --- a/deps/ox/src/ox/model/def.hpp +++ b/deps/ox/src/ox/model/def.hpp @@ -3,13 +3,15 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once -#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, modelName *o) noexcept { io->template setTypeInfo(); +#include + +#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *o) noexcept { io->template setTypeInfo(); #define oxModelEnd() return OxError(0); } #define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName)); #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 auto*) noexcept diff --git a/deps/ox/src/ox/model/desctypes.hpp b/deps/ox/src/ox/model/desctypes.hpp index ec6d150a..6ecaf9d7 100644 --- a/deps/ox/src/ox/model/desctypes.hpp +++ b/deps/ox/src/ox/model/desctypes.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -13,8 +13,11 @@ #include #include #include +#include #include +#include +#include "optype.hpp" #include "types.hpp" namespace ox { @@ -42,15 +45,16 @@ struct DescriptorField { String fieldName; int subscriptLevels = 0; String typeName; // gives reference to type for lookup if type is null + bool list = false; constexpr DescriptorField() noexcept = default; constexpr DescriptorField(const DescriptorType *pType, String pFieldName, int pSubscriptLevels, String pTypeName) noexcept: type(pType), - fieldName(pFieldName), + fieldName(std::move(pFieldName)), subscriptLevels(pSubscriptLevels), - typeName(pTypeName) { + typeName(std::move(pTypeName)) { } constexpr DescriptorField(const DescriptorField &other) noexcept: @@ -96,7 +100,8 @@ struct DescriptorType { 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: @@ -115,11 +120,11 @@ struct DescriptorType { template -constexpr Error model(T *io, DescriptorType *type) noexcept { +constexpr Error model(T *io, CommonPtrWith auto *type) noexcept { io->template setTypeInfo(); oxReturnError(io->field("typeName", &type->typeName)); 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; oxReturnError(io->field("primitiveType", &pt)); } else { @@ -134,7 +139,7 @@ constexpr Error model(T *io, DescriptorType *type) noexcept { } template -constexpr Error model(T *io, DescriptorField *field) noexcept { +constexpr Error model(T *io, CommonPtrWith auto *field) noexcept { io->template setTypeInfo(); oxReturnError(io->field("typeName", &field->typeName)); oxReturnError(io->field("fieldName", &field->fieldName)); @@ -149,7 +154,7 @@ template class TypeDescReader; template -constexpr Error model(TypeDescReader *io, DescriptorField *field) noexcept { +constexpr Error model(TypeDescReader *io, CommonPtrWith auto *field) noexcept { io->template setTypeInfo(DescriptorField::TypeName, DescriptorField::TypeVersion, 4); oxReturnError(io->field("typeName", &field->typeName)); auto &typeStore = io->typeStore(); diff --git a/deps/ox/src/ox/model/descwrite.cpp b/deps/ox/src/ox/model/descwrite.cpp index 93de2a32..b8f32e9e 100644 --- a/deps/ox/src/ox/model/descwrite.cpp +++ b/deps/ox/src/ox/model/descwrite.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include @@ -33,115 +33,19 @@ static_assert(!preloadable::value); static_assert([] { - int i = 0; - return detail::indirectionLevels(i) == 0; + return detail::indirectionLevels_v == 0; }(), "indirectionLevels broken: indirectionLevels(int)"); static_assert([] { - int i = 0; - return detail::indirectionLevels(&i) == 1; + return detail::indirectionLevels_v == 1; }(), "indirectionLevels broken: indirectionLevels(int*)"); static_assert([] { - int i[2] = {}; - return detail::indirectionLevels(i) == 1; + return detail::indirectionLevels_v == 1; }(), "indirectionLevels broken: indirectionLevels(int[])"); -const DescriptorType *TypeDescWriter::type(int8_t*) noexcept { - constexpr auto String = "B:int8_t"; - constexpr auto PT = PrimitiveType::SignedInteger; - 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(tn); - dt->primitiveType = pt; - dt->length = b; - const auto out = dt.get(); - m_typeStore->set(tn, std::move(dt)); - return out; - } -} +static_assert([] { + return detail::indirectionLevels_v == 2; +}(), "indirectionLevels broken: indirectionLevels(int[])"); } diff --git a/deps/ox/src/ox/model/descwrite.hpp b/deps/ox/src/ox/model/descwrite.hpp index 8bf23c03..7d913f68 100644 --- a/deps/ox/src/ox/model/descwrite.hpp +++ b/deps/ox/src/ox/model/descwrite.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -19,6 +19,7 @@ #include "desctypes.hpp" #include "fieldcounter.hpp" #include "metadata.hpp" +#include "modelhandleradaptor.hpp" #include "optype.hpp" #include "typenamecatcher.hpp" #include "types.hpp" @@ -29,14 +30,13 @@ namespace ox { namespace detail { template -static constexpr int indirectionLevels(T) noexcept { - return 0; -} +constexpr int indirectionLevels_v = 0; template -static constexpr int indirectionLevels(T *t) noexcept { - return 1 + indirectionLevels(*t); -} +constexpr int indirectionLevels_v = 1 + indirectionLevels_v; + +template +constexpr int indirectionLevels_v = 1 + indirectionLevels_v; } @@ -49,17 +49,24 @@ class TypeDescWriter { public: explicit constexpr TypeDescWriter(TypeStore *typeStore = nullptr) noexcept; + constexpr ~TypeDescWriter() noexcept = default; + + template + constexpr void setTypeInfo(const char *name = T::TypeName, + int version = T::TypeVersion, + int fields = ModelFieldCount_v) noexcept; + template - 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 constexpr Error field(const char *name, T val) noexcept; template - constexpr Error field(const char *name, T *val) noexcept; + constexpr Error field(const char *name, const T *val) noexcept; - template - constexpr void setTypeInfo(const char *name = T::TypeName, int fields = ModelFieldCount_v) noexcept; + template + constexpr Error fieldCString(const char *name, Args&&...) noexcept; [[nodiscard]] constexpr DescriptorType *definition() noexcept { @@ -71,56 +78,79 @@ class TypeDescWriter { } private: - const DescriptorType *type(int8_t *val) noexcept; - const DescriptorType *type(int16_t *val) noexcept; - const DescriptorType *type(int32_t *val) noexcept; - const DescriptorType *type(int64_t *val) noexcept; + [[nodiscard]] + constexpr const DescriptorType *type(const int8_t *val) const noexcept; + [[nodiscard]] + 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; - const DescriptorType *type(uint16_t *val) noexcept; - const DescriptorType *type(uint32_t *val) noexcept; - const DescriptorType *type(uint64_t *val) noexcept; + [[nodiscard]] + constexpr const DescriptorType *type(const uint8_t *val) const noexcept; + [[nodiscard]] + 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 - constexpr const DescriptorType *type(BString *val) noexcept; + [[nodiscard]] + constexpr const DescriptorType *type(const BString *val) const noexcept; template - constexpr const DescriptorType *type(T *val) noexcept; + [[nodiscard]] + constexpr const DescriptorType *type(const T *val) const noexcept; template - constexpr const DescriptorType *type(Vector *val) noexcept; - - template - constexpr const DescriptorType *type(HashMap *val) noexcept; + [[nodiscard]] + constexpr const DescriptorType *type(const HashMap *val) const noexcept; template - constexpr const DescriptorType *type(UnionView val) noexcept; + [[nodiscard]] + constexpr const DescriptorType *type(UnionView 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) { } +template +constexpr void TypeDescWriter::setTypeInfo(const char *typeName, int typeVersion, int) noexcept { + m_type = m_typeStore->getInit(typeName, typeVersion); + if constexpr(is_union_v) { + m_type->primitiveType = PrimitiveType::Union; + } else { + m_type->primitiveType = PrimitiveType::Struct; + } + m_type->preloadable = detail::preloadable::value; +} + // array handler template -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) { constexpr typename remove_pointer::type *p = nullptr; const auto t = type(p); oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); - if (t == nullptr) { - type(p); - } - m_type->fieldList.emplace_back(t, name, detail::indirectionLevels(val), t->typeName); + m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v + 1, t->typeName); return OxError(0); } return OxError(1); @@ -138,70 +168,153 @@ constexpr Error TypeDescWriter::field(const char *name, T val) noexcept { } template -constexpr Error TypeDescWriter::field(const char *name, T *val) noexcept { +constexpr Error TypeDescWriter::field(const char *name, const T *val) noexcept { if (m_type) { - const auto t = type(val); - oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated"); - m_type->fieldList.emplace_back(t, name, 0, t->typeName); - return OxError(0); + if constexpr(isVector_v || isArray_v) { + return field(name, val->data(), val->size()); + } else { + const auto t = type(val); + oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated"); + m_type->fieldList.emplace_back(t, name, 0, t->typeName); + return OxError(0); + } } return OxError(1); } -template -constexpr const DescriptorType *TypeDescWriter::type(BString *val) noexcept { - return type(SerStr(val)); +template +constexpr Error TypeDescWriter::fieldCString(const char *name, Args&&...) noexcept { + String s; + return field(name, &s); } template -constexpr const DescriptorType *TypeDescWriter::type(T *val) noexcept { - auto [t, err] = m_typeStore->template get(); - if (!err) { - return t; +constexpr const DescriptorType *TypeDescWriter::type(const T *val) const noexcept { + if constexpr(isVector_v) { + return type(val->data()); } else { - TypeDescWriter dw(m_typeStore); - oxLogError(model(&dw, val)); - return dw.m_type; + auto [t, err] = m_typeStore->template get(); + if (!err) { + return t; + } else { + TypeDescWriter dw(m_typeStore); + 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; + } } } template -constexpr const DescriptorType *TypeDescWriter::type(Vector *val) noexcept { - return type(val->data()); -} - -template -constexpr const DescriptorType *TypeDescWriter::type(HashMap*) noexcept { +constexpr const DescriptorType *TypeDescWriter::type(const HashMap*) const noexcept { return type(static_cast(nullptr)); } template -constexpr const DescriptorType *TypeDescWriter::type(UnionView val) noexcept { - return type(val.get()); +constexpr const DescriptorType *TypeDescWriter::type(UnionView val) const noexcept { + const auto t = type(val.get()); + oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); + return t; } -template -constexpr void TypeDescWriter::setTypeInfo(const char *name, int) noexcept { - m_type = m_typeStore->getInit(name); - if constexpr(is_union_v) { - m_type->primitiveType = PrimitiveType::Union; +constexpr const DescriptorType *TypeDescWriter::type(const int8_t*) const noexcept { + constexpr auto PT = PrimitiveType::SignedInteger; + constexpr auto Bytes = 1; + return getType(types::Int8, 0, PT, Bytes); +} + +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 +constexpr const DescriptorType *TypeDescWriter::type(const BString*) 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 { - m_type->primitiveType = PrimitiveType::Struct; + auto dt = ox::make_unique(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::value; } template -Result buildTypeDef(TypeStore *typeStore, T *val) noexcept { +constexpr Result buildTypeDef(TypeStore *typeStore, T *val) noexcept { TypeDescWriter writer(typeStore); - oxReturnError(model(&writer, val)); + ModelHandlerInterface handler(&writer); + oxReturnError(model(&handler, val)); return writer.definition(); } -auto writeTypeDefOC(auto *val) noexcept { - TypeStore typeStore; - oxRequire(def, buildTypeDef(&typeStore, val)); - return writeOC(def.get()); -} - } diff --git a/deps/ox/src/ox/model/fieldcounter.hpp b/deps/ox/src/ox/model/fieldcounter.hpp index 9f302b1c..d67b7dba 100644 --- a/deps/ox/src/ox/model/fieldcounter.hpp +++ b/deps/ox/src/ox/model/fieldcounter.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -44,6 +44,11 @@ class FieldCounter { return OxError(0); } + template + constexpr Error fieldCString(Args&&...) noexcept { + return OxError(0); + } + static constexpr auto opType() { return OpType::Reflect; } diff --git a/deps/ox/src/ox/model/model.hpp b/deps/ox/src/ox/model/model.hpp index 6c407da0..7a97fe62 100644 --- a/deps/ox/src/ox/model/model.hpp +++ b/deps/ox/src/ox/model/model.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -13,7 +13,9 @@ #include "desctypes.hpp" #include "descwrite.hpp" #include "fieldcounter.hpp" +#include "modelhandleradaptor.hpp" #include "modelops.hpp" +#include "modelvalue.hpp" #include "typenamecatcher.hpp" #include "types.hpp" #include "typestore.hpp" diff --git a/deps/ox/src/ox/model/modelhandleradaptor.hpp b/deps/ox/src/ox/model/modelhandleradaptor.hpp new file mode 100644 index 00000000..1499176b --- /dev/null +++ b/deps/ox/src/ox/model/modelhandleradaptor.hpp @@ -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 + +#include "modelvalue.hpp" + +namespace ox { + +template +class ModelHandlerInterface { + private: + Handler *m_handler = nullptr; + + public: + constexpr explicit ModelHandlerInterface(Handler *handler) noexcept: m_handler(handler) { + } + + template + constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, + int fields = ModelFieldCount_v) noexcept { + m_handler->setTypeInfo(name, version, fields); + } + + template + constexpr Error fieldCString(const char *name, char val[len]) noexcept { + return m_handler->fieldCString(name, &val[0], len); + } + + template + 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 auto *v) noexcept { + switch (v->type()) { + case ModelValue::Type::Undefined: + break; + case ModelValue::Type::Bool: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::UnsignedInteger8: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::UnsignedInteger16: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::UnsignedInteger32: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::UnsignedInteger64: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::SignedInteger8: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::SignedInteger16: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::SignedInteger32: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::SignedInteger64: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::String: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::Object: + return m_handler->field(name, &v->template get()); + case ModelValue::Type::Union: + { + auto &u = v->template get(); + if constexpr(ox_strcmp(Handler::opType(), OpType::Read) == 0) { + u.setActiveField(m_handler->whichFieldPresent(name, u)); + } + return m_handler->field(name, UnionView(&u, u.unionIdx())); + } + case ModelValue::Type::Vector: + return m_handler->field(name, &v->template get()); + } + oxPanic(OxError(1), "invalid type"); + return OxError(1, "invalid type"); + } + + // array handler, with callback to allow handling individual elements + template + constexpr Error field(const char *name, Callback cb) noexcept { + return m_handler->template field(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 + constexpr Error field(const char *name, UnionView 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; + } + +}; + +} diff --git a/deps/ox/src/ox/model/modelops.hpp b/deps/ox/src/ox/model/modelops.hpp index 98bbb5a0..9fe92835 100644 --- a/deps/ox/src/ox/model/modelops.hpp +++ b/deps/ox/src/ox/model/modelops.hpp @@ -14,12 +14,36 @@ #include #include "fieldcounter.hpp" +#include "modelvalue.hpp" +#include "optype.hpp" #include "types.hpp" namespace ox { namespace detail { +class Wrap { + public: + virtual ~Wrap() = default; +}; + +template +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 class MemberList { @@ -27,7 +51,7 @@ class MemberList { std::size_t m_i = 0; public: - void *vars[size]; + Array vars; template constexpr Error field(const char*, T *v) noexcept { @@ -41,8 +65,8 @@ class MemberList { return OxError(0); } - template - constexpr Error field(const char*, UnionView u) noexcept { + template + constexpr Error field(const char*, UnionView u) noexcept { vars[m_i++] = static_cast(u.get()); return OxError(0); } @@ -57,7 +81,7 @@ class MemberList { [[nodiscard]] static constexpr auto opType() noexcept { - return "GetMembers"; + return OpType::Reflect; } }; @@ -97,8 +121,8 @@ class Copier { return OxError(0); } - template - constexpr Error field(const char*, UnionView u) { + template + constexpr Error field(const char*, UnionView u) { auto &dst = *cbit_cast(m_dst->vars[m_i]); auto &src = *u.get(); dst = src; @@ -116,7 +140,7 @@ class Copier { [[nodiscard]] static constexpr auto opType() noexcept { - return "Copy"; + return OpType::Read; } }; @@ -158,8 +182,8 @@ class Mover { return OxError(0); } - template - constexpr Error field(const char*, UnionView u) noexcept { + template + constexpr Error field(const char*, UnionView u) noexcept { auto &dst = *cbit_cast(m_dst->vars[m_i]); auto &src = *u.get(); dst = std::move(src); @@ -177,7 +201,7 @@ class Mover { [[nodiscard]] static constexpr auto opType() noexcept { - return "Copy"; + return OpType::Read; } }; @@ -222,8 +246,8 @@ class Equals { return OxError(0); } - template - constexpr Error field(const char*, UnionView u) noexcept { + template + constexpr Error field(const char*, UnionView u) noexcept { const auto &dst = *cbit_cast(m_other->vars[m_i]); const auto &src = *u.get(); ++m_i; @@ -253,13 +277,31 @@ class Equals { [[nodiscard]] static constexpr auto opType() noexcept { - return "Copy"; + return OpType::Read; } }; } +template +constexpr void moveModel(ModelObject *dst, T *src) noexcept { + constexpr auto size = ModelFieldCount_v; + detail::MemberList dstFields; + detail::Mover mover(&dstFields); + oxIgnoreError(model(&dstFields, dst)); + oxIgnoreError(model(&mover, src)); +} + +template +constexpr void moveModel(T *dst, ModelObject *src) noexcept { + constexpr auto size = ModelFieldCount_v; + detail::MemberList dstFields; + detail::Mover mover(&dstFields); + oxIgnoreError(model(&dstFields, dst)); + oxIgnoreError(model(&mover, src)); +} + template constexpr void moveModel(T *dst, T *src) noexcept { constexpr auto size = ModelFieldCount_v; @@ -269,6 +311,24 @@ constexpr void moveModel(T *dst, T *src) noexcept { oxIgnoreError(model(&mover, src)); } +template +constexpr void copyModel(ModelObject *dst, const T *src) noexcept { + constexpr auto size = ModelFieldCount_v; + detail::MemberList dstFields; + detail::Copier copier(&dstFields); + oxIgnoreError(model(&dstFields, dst)); + oxIgnoreError(model(&copier, src)); +} + +template +constexpr void copyModel(T *dst, const ModelObject *src) noexcept { + constexpr auto size = ModelFieldCount_v; + detail::MemberList dstFields; + detail::Copier copier(&dstFields); + oxIgnoreError(model(&dstFields, dst)); + oxIgnoreError(model(&copier, src)); +} + template constexpr void copyModel(T *dst, const T *src) noexcept { constexpr auto size = ModelFieldCount_v; diff --git a/deps/ox/src/ox/model/modelvalue.cpp b/deps/ox/src/ox/model/modelvalue.cpp new file mode 100644 index 00000000..62611763 --- /dev/null +++ b/deps/ox/src/ox/model/modelvalue.cpp @@ -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" diff --git a/deps/ox/src/ox/model/modelvalue.hpp b/deps/ox/src/ox/model/modelvalue.hpp new file mode 100644 index 00000000..ac040cf7 --- /dev/null +++ b/deps/ox/src/ox/model/modelvalue.hpp @@ -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 +#include +#include +#include +#include + +#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 + consteval static Type getType() noexcept { + if constexpr(is_bool_v) { + return Type::Bool; + } else if constexpr(is_integer_v) { + if (!is_signed_v && sizeof(T) == 1) { + return Type::UnsignedInteger8; + } else if constexpr(!is_signed_v && sizeof(T) == 2) { + return Type::UnsignedInteger16; + } else if constexpr(!is_signed_v && sizeof(T) == 4) { + return Type::UnsignedInteger32; + } else if constexpr(!is_signed_v && sizeof(T) == 8) { + return Type::UnsignedInteger64; + } else if constexpr(is_signed_v && sizeof(T) == 1) { + return Type::SignedInteger8; + } else if constexpr(is_signed_v && sizeof(T) == 2) { + return Type::SignedInteger16; + } else if constexpr(is_signed_v && sizeof(T) == 4) { + return Type::SignedInteger32; + } else if constexpr(is_signed_v && sizeof(T) == 8) { + return Type::SignedInteger64; + } + } else if constexpr(is_same_v) { + return Type::Union; + } else if constexpr(is_same_v) { + return Type::Object; + } else if constexpr(is_same_v) { + return Type::String; + } else if constexpr(is_same_v) { + return Type::Vector; + } else { + return Type::Undefined; + } + } + + template + 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 + explicit constexpr ModelValue(const T &val) noexcept; + + template + explicit constexpr ModelValue(T &&val) noexcept; + + constexpr ~ModelValue() noexcept; + + template + [[nodiscard]] + constexpr const auto &get() const noexcept { + constexpr auto type = getType(); + if (m_type != type) [[unlikely]] { + oxPanic(OxError(1), "invalid cast"); + } + return getValue(*this); + } + + template + [[nodiscard]] + constexpr auto &get() noexcept { + constexpr auto type = getType(); + if (m_type != type) [[unlikely]] { + oxPanic(OxError(1), "invalid cast"); + } + return getValue(*this); + } + + [[nodiscard]] + constexpr Type type() const noexcept; + + constexpr Error setType(const DescriptorType *type, int subscriptLevels = 0) noexcept; + + template + constexpr Error setType() noexcept; + + template + constexpr Error set(const T &v) noexcept; + + template + 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 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> m_fieldsOrder; + HashMap 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->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> m_fieldsOrder; + HashMap 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> make(const DescriptorType *type) noexcept { + UniquePtr out(new ModelUnion); + oxReturnError(out->setType(type)); + return out; + } + + static constexpr Result> make(const ModelUnion &other) noexcept { + return UniquePtr(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(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->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 auto *obj) noexcept { + h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast(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 auto *obj) noexcept { + h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast(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()); + break; + case Type::Union: + m_data.uni = new ModelUnion(other.get()); + break; + case Type::Object: + m_data.obj = new ModelObject(other.get()); + break; + case Type::Vector: + m_data.vec = new ModelValueVector(*other.m_data.vec); + break; + } +} + +constexpr ModelValue::ModelValue(ModelValue &other) noexcept: ModelValue(const_cast(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 +constexpr ModelValue::ModelValue(const T &val) noexcept { + set(val); +} + +template +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 +constexpr Error ModelValue::setType() noexcept { + constexpr auto type = getType(); + return setType(type); +} + +template +constexpr Error ModelValue::set(const T &v) noexcept { + constexpr auto type = getType(); + if (m_type != type) [[unlikely]] { + return OxError(1, "type mismatch"); + } + auto &value = getValue(*this); + value = v; + return OxError(0); +} + +template +constexpr Error ModelValue::set(T &&v) noexcept { + constexpr auto type = getType(); + if (m_type != type) [[unlikely]] { + return OxError(1, "type mismatch"); + } + auto &value = getValue(*this); + if constexpr(type == Type::Vector || type == Type::Object || + type == Type::Union || type == Type::String) { + safeDelete(value); + } + value = ox::forward(v); + return OxError(0); +} + +constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept { + return this->operator=(const_cast(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()); + break; + case Type::Union: + m_data.uni = new ModelUnion(other.get()); + break; + case Type::Object: + m_data.obj = new ModelObject(other.get()); + 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; +} + +} diff --git a/deps/ox/src/ox/model/optype.hpp b/deps/ox/src/ox/model/optype.hpp index e06409ab..3ed29b70 100644 --- a/deps/ox/src/ox/model/optype.hpp +++ b/deps/ox/src/ox/model/optype.hpp @@ -3,54 +3,18 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include +#include #include #include -namespace ox { - -namespace OpType { - constexpr auto Read = "Read"; - constexpr auto Write = "Write"; - constexpr auto Reflect = "Reflect"; -} - -// empty default implementations of model functions - -template -constexpr Error modelRead(T*, O*) noexcept { - oxAssert(OxError(1), "Missing modelRead function"); - return OxError(1, "Model: modelRead not implemented"); -} - -template -constexpr Error modelWrite(T*, O*) noexcept { - oxAssert(OxError(1), "Missing modelWrite function"); - return OxError(1, "Model: modelWrite not implemented"); -} - -template -constexpr Error modelReflect(T*, O*) noexcept { - return OxError(1, "Model: modelReflect not implemented"); -} - -template -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); - } -} - +namespace ox::OpType { +constexpr auto Read = "Read"; +constexpr auto Write = "Write"; +constexpr auto Reflect = "Reflect"; } diff --git a/deps/ox/src/ox/model/typenamecatcher.hpp b/deps/ox/src/ox/model/typenamecatcher.hpp index 10a693d1..bf1ec3fc 100644 --- a/deps/ox/src/ox/model/typenamecatcher.hpp +++ b/deps/ox/src/ox/model/typenamecatcher.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -40,8 +40,8 @@ struct TypeNameCatcher { return OxError(0); } - template - constexpr Error fieldCString(const char*, T) noexcept { + template + constexpr Error fieldCString(Args&&...) noexcept { return OxError(0); } diff --git a/deps/ox/src/ox/model/types.hpp b/deps/ox/src/ox/model/types.hpp index 537c6fa7..62dadccf 100644 --- a/deps/ox/src/ox/model/types.hpp +++ b/deps/ox/src/ox/model/types.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -12,10 +12,15 @@ #include #endif +#if __has_include() +#include +#endif + #if __has_include() #include #endif +#include #include #include #include @@ -24,19 +29,32 @@ 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 -constexpr bool isVector(const T*) noexcept { +consteval bool isVector(const T*) noexcept { return false; } template -constexpr bool isVector(const Vector*) noexcept { +consteval bool isVector(const Vector*) noexcept { return true; } #if __has_include() template -constexpr bool isVector(const std::vector*) noexcept { +consteval bool isVector(const std::vector*) noexcept { return true; } #endif @@ -51,6 +69,24 @@ constexpr bool isVector(const QVector*) noexcept { template constexpr bool isVector_v = isVector(static_cast(nullptr)); +template +constexpr bool isArray_v = false; + +template +constexpr bool isArray_v = false; + +template +constexpr bool isArray_v = false; + +template +constexpr bool isArray_v> = false; + +#if __has_include() +template +constexpr bool isArray_v> = false; +#endif + + class SerStr { protected: @@ -121,12 +157,12 @@ class SerStr { }; -template +template class UnionView { protected: int m_idx = -1; - typename enable_if, Union>::type *m_union = nullptr; + typename enable_if || force, Union>::type *m_union = nullptr; public: constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) { diff --git a/deps/ox/src/ox/model/typestore.hpp b/deps/ox/src/ox/model/typestore.hpp index d2ec47f4..05128d43 100644 --- a/deps/ox/src/ox/model/typestore.hpp +++ b/deps/ox/src/ox/model/typestore.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -13,6 +13,7 @@ #include #include +#include "ox/std/fmt.hpp" #include "typenamecatcher.hpp" #include "desctypes.hpp" @@ -22,29 +23,37 @@ class TypeStore { private: HashMap> m_cache; + static constexpr auto buildTypeId(const auto &name, auto version) noexcept { + return ox::sfmt("{};{}", name, version); + } + public: constexpr TypeStore() noexcept = default; constexpr virtual ~TypeStore() noexcept = default; - constexpr Result get(const auto &name) const noexcept { - oxRequire(out, m_cache.at(name)); + constexpr Result get(const auto &name, int typeVersion) const noexcept { + const auto typeId = buildTypeId(name, typeVersion); + oxRequire(out, m_cache.at(typeId)); return out->get(); } template constexpr Result get() const noexcept { - constexpr auto name = requireModelTypeName(); - oxRequire(out, m_cache.at(name)); + constexpr auto typeName = requireModelTypeName(); + constexpr auto typeVersion = requireModelTypeVersion(); + const auto typeId = buildTypeId(typeName, typeVersion); + oxRequire(out, m_cache.at(typeId)); return out->get(); } - constexpr DescriptorType *getInit(const auto &name) noexcept { - auto [out, err] = m_cache.at(name); + constexpr DescriptorType *getInit(const auto &typeName, int typeVersion) noexcept { + const auto typeId = buildTypeId(typeName, typeVersion); + auto [out, err] = m_cache.at(typeId); if (err) { - auto &out = m_cache[name]; - out = ox::make_unique(name); - return out.get(); + out = &m_cache[typeId]; + *out = ox::make_unique(typeName, typeVersion); + return out->get(); } return out->get(); } @@ -55,15 +64,13 @@ class TypeStore { return getInit(name); } - template - constexpr Result getLoad() noexcept { - constexpr auto nameCstr = requireModelTypeName(); - const String name = nameCstr; - auto [val, err] = m_cache.at(name); + constexpr Result getLoad(const auto &typeName, auto typeVersion) noexcept { + const auto typeId = buildTypeId(typeName, typeVersion); + auto [val, err] = m_cache.at(typeId); if (err) { if (!std::is_constant_evaluated()) { - oxRequireM(dt, loadDescriptor(name)); - auto &out = m_cache[name]; + oxRequireM(dt, loadDescriptor(typeName, typeVersion)); + auto &out = m_cache[typeId]; out = std::move(dt); return out.get(); } else { @@ -73,12 +80,21 @@ class TypeStore { return val->get(); } - constexpr void set(const String &name, UniquePtr dt) noexcept { - m_cache[name] = std::move(dt); + template + constexpr Result getLoad() noexcept { + constexpr auto typeName = requireModelTypeName(); + constexpr auto typeVersion = requireModelTypeVersion(); + return getLoad(typeName, typeVersion); } - constexpr void set(const String &name, DescriptorType *dt) noexcept { - m_cache[name] = UniquePtr(dt); + constexpr void set(const auto &typeName, auto typeVersion, UniquePtr dt) noexcept { + 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(dt); } [[nodiscard]] @@ -92,7 +108,7 @@ class TypeStore { } protected: - virtual Result> loadDescriptor(const ox::String&) noexcept { + virtual Result> loadDescriptor(const ox::String&, int) noexcept { return OxError(1); } diff --git a/deps/ox/src/ox/oc/read.cpp b/deps/ox/src/ox/oc/read.cpp index 00fefebd..8fbd922e 100644 --- a/deps/ox/src/ox/oc/read.cpp +++ b/deps/ox/src/ox/oc/read.cpp @@ -3,10 +3,11 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include +#include #include "read.hpp" @@ -18,7 +19,7 @@ OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) Json::CharReaderBuilder parserBuilder; auto parser = std::unique_ptr(parserBuilder.newCharReader()); 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; auto parser = std::unique_ptr(parserBuilder.newCharReader()); 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: - m_json(json), +OrganicClawReader::OrganicClawReader(Json::Value json, int unionIdx) noexcept: + m_json(std::move(json)), m_unionIdx(unionIdx) { } @@ -208,6 +209,87 @@ Error OrganicClawReader::field(const char *key, SerStr val) noexcept { 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(end - begin); + auto data = val; + if (strSize >= buffLen) { + err = OxError(2, "String size exceeds capacity of destination"); + } else { + ox_memcpy(data, begin, static_cast(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(end - begin); + safeDelete(*val); + *val = new char[strSize + 1]; + ox_memcpy(data, begin, static_cast(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(end - begin); + auto data = val; + if (strSize >= buffLen) { + safeDelete(*val); + *val = new char[strSize + 1]; + } + ox_memcpy(data, begin, static_cast(strSize)); + data[strSize] = 0; + } else { + err = OxError(1, "Type mismatch"); + } + } + ++m_fieldIt; + return err; +} + Result OrganicClawReader::arrayLength(const char *key, bool) noexcept { const auto &jv = value(key); 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 { - return OrganicClawReader(m_json[key], unionIdx); + return OrganicClawReader(value(key), unionIdx); } bool OrganicClawReader::fieldPresent(const char *key) noexcept { 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 { if (m_json.isArray()) { 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(m_fieldIt) == m_unionIdx || m_unionIdx == -1; } diff --git a/deps/ox/src/ox/oc/read.hpp b/deps/ox/src/ox/oc/read.hpp index a491420b..3b170418 100644 --- a/deps/ox/src/ox/oc/read.hpp +++ b/deps/ox/src/ox/oc/read.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -37,7 +38,7 @@ class OrganicClawReader { 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, int16_t *val) noexcept; @@ -61,8 +62,8 @@ class OrganicClawReader { template Error field(const char *key, T *val) noexcept; - template - Error field(const char *key, UnionView val) noexcept; + template + Error field(const char *key, UnionView val) noexcept; template Error field(const char *key, BasicString *val) noexcept; @@ -72,6 +73,12 @@ class OrganicClawReader { 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. * @param pass indicates that the parsing should iterate past the array length @@ -109,16 +116,23 @@ class OrganicClawReader { // compatibility stub constexpr void nextField() noexcept {} + [[nodiscard]] bool fieldPresent(const char *key) noexcept; + [[nodiscard]] + int whichFieldPresent(const char *name, const ModelUnion &u) const noexcept; + + [[nodiscard]] static constexpr auto opType() noexcept { return OpType::Read; } private: + [[nodiscard]] 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); if (jv.empty() || jv.isObject()) { auto reader = child(key); - return model(&reader, val); + ModelHandlerInterface handler(&reader); + return model(&handler, val); } else { err = OxError(1, "Type mismatch"); } @@ -143,14 +158,15 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept { return err; } -template -Error OrganicClawReader::field(const char *key, UnionView val) noexcept { +template +Error OrganicClawReader::field(const char *key, UnionView val) noexcept { auto err = OxError(0); if (targetValid()) { const auto &jv = value(key); if (jv.empty() || jv.isObject()) { auto reader = child(key, val.idx()); - err = model(&reader, val.get()); + ModelHandlerInterface handler(&reader); + err = model(&handler, val.get()); } else { err = OxError(1, "Type mismatch"); } @@ -185,13 +201,17 @@ Error OrganicClawReader::field(const char *key, BString *val) noexcept { template Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noexcept { const auto &srcVal = value(key); + if (!srcVal.isNull() && !srcVal.isArray()) { + return OxError(1, "Type mismatch"); + } auto srcSize = srcVal.size(); if (srcSize > valLen) { return OxError(1); } OrganicClawReader r(srcVal); + ModelHandlerInterface handler{&r}; for (decltype(srcSize) i = 0; i < srcSize; ++i) { - oxReturnError(r.field("", &val[i])); + oxReturnError(handler.field("", &val[i])); } return OxError(0); } @@ -199,28 +219,32 @@ Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) noex template Error OrganicClawReader::field(const char *key, HashMap *val) noexcept { const auto &srcVal = value(key); + if (!srcVal.isObject()) { + return OxError(1, "Type mismatch"); + } auto keys = srcVal.getMemberNames(); auto srcSize = srcVal.size(); OrganicClawReader r(srcVal); + ModelHandlerInterface handler{&r}; for (decltype(srcSize) i = 0; i < srcSize; ++i) { const auto k = keys[i].c_str(); - oxReturnError(r.field(k, &val->operator[](k))); + oxReturnError(handler.field(k, &val->operator[](k))); } return OxError(0); } -template -Error readOC(const char *json, std::size_t jsonSize, T *val) noexcept { +Error readOC(const char *buff, std::size_t buffSize, auto *val) noexcept { // OrganicClawReader constructor can throw, but readOC should return its errors. try { Json::Value doc; Json::CharReaderBuilder parserBuilder; - auto parser = std::unique_ptr(parserBuilder.newCharReader()); - if (!parser->parse(json, json + jsonSize, &doc, nullptr)) { + auto parser = UniquePtr(parserBuilder.newCharReader()); + if (!parser->parse(buff, buff + buffSize, &doc, nullptr)) { return OxError(1, "Could not parse JSON"); } - OrganicClawReader reader(json, jsonSize); - return model(&reader, val); + OrganicClawReader reader(buff, buffSize); + ModelHandlerInterface handler(&reader); + return model(&handler, val); } catch (const Error &err) { return err; } catch (...) { diff --git a/deps/ox/src/ox/oc/test/CMakeLists.txt b/deps/ox/src/ox/oc/test/CMakeLists.txt index 33b35f04..0f435d73 100644 --- a/deps/ox/src/ox/oc/test/CMakeLists.txt +++ b/deps/ox/src/ox/oc/test/CMakeLists.txt @@ -10,4 +10,5 @@ target_link_libraries( add_test("[ox/oc] OcTest Writer" OcTest OrganicClawWriter) add_test("[ox/oc] OcTest Reader" OcTest OrganicClawReader) +add_test("[ox/oc] OcTest OrganicClawModelValue" OcTest OrganicClawModelValue) add_test("[ox/oc] OcTest OrganicClawDef" OcTest OrganicClawDef) diff --git a/deps/ox/src/ox/oc/test/tests.cpp b/deps/ox/src/ox/oc/test/tests.cpp index 540b9059..ff6f94eb 100644 --- a/deps/ox/src/ox/oc/test/tests.cpp +++ b/deps/ox/src/ox/oc/test/tests.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #undef NDEBUG @@ -19,7 +19,7 @@ union TestUnion { static constexpr auto TypeVersion = 1; bool Bool; uint32_t Int = 5; - char String[32]; + char *String; }; struct TestStructNest { @@ -43,8 +43,9 @@ struct TestStruct { int32_t Int6 = 0; int32_t Int7 = 0; int32_t Int8 = 0; + int unionIdx = 1; TestUnion Union; - ox::BString<32> String = ""; + ox::String String = ""; uint32_t List[4] = {0, 0, 0, 0}; ox::HashMap Map; TestStructNest EmptyStruct; @@ -55,23 +56,24 @@ struct TestStruct { TestStruct(TestStruct &&other) noexcept; constexpr ~TestStruct() noexcept { + if (unionIdx == 2) { + ox::safeDelete(Union.String); + } } constexpr TestStruct &operator=(TestStruct&&) noexcept; }; -template -constexpr ox::Error model(T *io, TestUnion *obj) noexcept { +constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Int", &obj->Int)); - oxReturnError(io->field("String", ox::SerStr(obj->String))); + oxReturnError(io->fieldCString("String", &obj->String)); return OxError(0); } -template -constexpr ox::Error model(T *io, TestStructNest *obj) noexcept { +constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Int", &obj->Int)); @@ -79,8 +81,7 @@ constexpr ox::Error model(T *io, TestStructNest *obj) noexcept { return OxError(0); } -template -constexpr ox::Error model(T *io, TestStruct *obj) noexcept { +constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *obj) noexcept { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); 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("Int7", &obj->Int7)); 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("List", obj->List, 4)); oxReturnError(io->field("Map", &obj->Map)); @@ -173,6 +179,57 @@ const std::map tests = { 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() == testIn.Int, "testOut.Int failed"); + oxAssert(testOut["Bool"].get() == testIn.Bool, "testOut.Bool failed"); + oxAssert(testOut["String"].get() == testIn.String, "testOut.String failed"); + auto &testOutStruct = testOut["Struct"].get(); + auto &testOutUnion = testOut["Union"].get(); + auto &testOutList = testOut["List"].get(); + auto testOutStructCopy = testOut["Struct"].get(); + auto testOutUnionCopy = testOut["Union"].get(); + auto testOutListCopy = testOut["List"].get(); + oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed"); + oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed"); + oxAssert(testOutStruct["Bool"].get() == testIn.Struct.Bool, "testOut.Struct.Bool failed"); + oxAssert(testOutStruct["String"].get() == testIn.Struct.String.c_str(), "testOut.Struct.String failed"); + oxAssert(testOut["unionIdx"].get() == testIn.unionIdx, "testOut.unionIdx failed"); + oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong"); + oxAssert(testOutUnion["Int"].get() == testIn.Union.Int, "testOut.Union.Int failed"); + oxAssert(testOutList[0].get() == testIn.List[0], "testOut.List[0] failed"); + oxAssert(testOutList[1].get() == testIn.List[1], "testOut.Struct.List[1] failed"); + oxAssert(testOutStructCopy["Bool"].get() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed"); + oxAssert(testOutStructCopy["String"].get() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed"); + oxAssert(testOutListCopy[0].get() == testIn.List[0], "testOut.Struct.List[0] (copy) failed"); + oxAssert(testOutListCopy[1].get() == testIn.List[1], "testOut.Struct.List[1] (copy) failed"); + return OxError(0); + } + }, + { "OrganicClawDef", [] { diff --git a/deps/ox/src/ox/oc/write.cpp b/deps/ox/src/ox/oc/write.cpp index 6a72e98e..2b8af429 100644 --- a/deps/ox/src/ox/oc/write.cpp +++ b/deps/ox/src/ox/oc/write.cpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "write.hpp" @@ -18,87 +18,6 @@ OrganicClawWriter::OrganicClawWriter(Json::Value json, int unionIdx) noexcept: 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 { if (targetValid() && val.len()) { value(key) = val.c_str(); @@ -107,6 +26,26 @@ Error OrganicClawWriter::field(const char *key, SerStr val) noexcept { 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(val), len); +} + +Error OrganicClawWriter::fieldCString(const char *key, const char **val) noexcept { + return fieldCString(key, const_cast(val), {}); +} + +Error OrganicClawWriter::fieldCString(const char *key, char **val) noexcept { + return fieldCString(key, const_cast(val), {}); +} + Json::Value &OrganicClawWriter::value(const char *key) noexcept { if (m_json.isArray()) { return m_json[m_fieldIt]; diff --git a/deps/ox/src/ox/oc/write.hpp b/deps/ox/src/ox/oc/write.hpp index 6a26c40f..182ea4b8 100644 --- a/deps/ox/src/ox/oc/write.hpp +++ b/deps/ox/src/ox/oc/write.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -22,8 +23,7 @@ namespace ox { class OrganicClawWriter { - template - friend Result writeOC(T *val) noexcept; + friend Result writeOC(auto *val) noexcept; protected: Json::Value m_json; @@ -35,36 +35,140 @@ class OrganicClawWriter { explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept; - Error field(const char*, int8_t *val) noexcept; - Error field(const char*, int16_t *val) noexcept; - Error field(const char*, int32_t *val) noexcept; - Error field(const char*, int64_t *val) noexcept; + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (*val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } - Error field(const char*, uint8_t *val) noexcept; - Error field(const char*, uint16_t *val) noexcept; - Error field(const char*, uint32_t *val) noexcept; - Error field(const char*, uint64_t *val) noexcept; + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (*val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } - Error field(const char*, bool *val) noexcept; + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (*val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } + + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (*val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } + + + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (*val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } + + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (targetValid() && *val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } + + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (targetValid() && *val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } + + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (targetValid() && *val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } + + Error field(const char *key, CommonPtrWith auto *val) noexcept { + if (targetValid() && *val) { + value(key) = *val; + } + ++m_fieldIt; + return OxError(0); + } template Error field(const char*, T *val, std::size_t len) noexcept; - template - Error field(const char*, UnionView val) noexcept; + template + Error field(const char*, UnionView val) noexcept; template - Error field(const char*, HashMap *val) noexcept; + Error field(const char *key, const HashMap *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 + Error field(const char *key, HashMap *val) noexcept { + return field(key, const_cast*>(val)); + } template - Error field(const char*, BString *val) noexcept; + Error field(const char *key, const BString *val) noexcept { + return field(key, SerStr(val->data(), val->cap())); + } - Error field(const char*, String *val) noexcept; + template + Error field(const char *key, BString *val) noexcept { + return field(key, SerStr(val->data(), val->cap())); + } + + template + Error field(const char *key, const BasicString *val) noexcept { + if (targetValid() && val->len()) { + value(key) = val->c_str(); + } + ++m_fieldIt; + return OxError(0); + } + + template + Error field(const char *key, BasicString *val) noexcept { + return field(key, const_cast*>(val)); + } 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, const char **val) noexcept; + + Error fieldCString(const char *name, char **val) noexcept; + template Error field(const char*, T *val) noexcept; @@ -91,8 +195,9 @@ template Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) noexcept { if (targetValid() && len) { OrganicClawWriter w((Json::Value(Json::arrayValue))); + ModelHandlerInterface handler{&w}; for (std::size_t i = 0; i < len; ++i) { - oxReturnError(w.field("", &val[i])); + oxReturnError(handler.field("", &val[i])); } 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); } -template -Error OrganicClawWriter::field(const char *key, BString *val) noexcept { - return field(key, SerStr(val->data(), val->cap())); -} - template Error OrganicClawWriter::field(const char *key, T *val) noexcept { if constexpr(isVector_v) { return field(key, val->data(), val->size()); } else if (val && targetValid()) { OrganicClawWriter w; - oxReturnError(model(&w, val)); + ModelHandlerInterface handler{&w}; + oxReturnError(model(&handler, val)); if (!w.m_json.isNull()) { value(key) = w.m_json; } @@ -120,11 +221,12 @@ Error OrganicClawWriter::field(const char *key, T *val) noexcept { return OxError(0); } -template -Error OrganicClawWriter::field(const char *key, UnionView val) noexcept { +template +Error OrganicClawWriter::field(const char *key, UnionView val) noexcept { if (targetValid()) { OrganicClawWriter w(val.idx()); - oxReturnError(model(&w, val.get())); + ModelHandlerInterface handler{&w}; + oxReturnError(model(&handler, val.get())); if (!w.m_json.isNull()) { value(key) = w.m_json; } @@ -133,25 +235,10 @@ Error OrganicClawWriter::field(const char *key, UnionView val) noexcept { return OxError(0); } -template -Error OrganicClawWriter::field(const char *key, HashMap *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 -Result writeOC(T *val) noexcept { +Result writeOC(auto *val) noexcept { OrganicClawWriter writer; - oxReturnError(model(&writer, val)); + ModelHandlerInterface handler(&writer); + oxReturnError(model(&handler, val)); Json::StreamWriterBuilder jsonBuilder; const auto str = Json::writeString(jsonBuilder, writer.m_json); Buffer buff(str.size() + 1); diff --git a/deps/ox/src/ox/std/CMakeLists.txt b/deps/ox/src/ox/std/CMakeLists.txt index 1008f652..2d1c5115 100644 --- a/deps/ox/src/ox/std/CMakeLists.txt +++ b/deps/ox/src/ox/std/CMakeLists.txt @@ -24,6 +24,7 @@ add_library( buffer.cpp buildinfo.cpp byteswap.cpp + concepts.cpp fmt.cpp heapmgr.cpp math.cpp @@ -73,6 +74,7 @@ install( buffer.hpp buildinfo.hpp byteswap.hpp + concepts.hpp def.hpp defines.hpp defer.hpp diff --git a/deps/ox/src/ox/std/concepts.cpp b/deps/ox/src/ox/std/concepts.cpp new file mode 100644 index 00000000..54198ceb --- /dev/null +++ b/deps/ox/src/ox/std/concepts.cpp @@ -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 auto*) noexcept { return true; } + +static_assert(ok(static_cast(nullptr))); +static_assert(ok(static_cast(nullptr))); +static_assert(!ok(static_cast(nullptr))); +static_assert(!ok(static_cast(nullptr))); + +} \ No newline at end of file diff --git a/deps/ox/src/ox/std/concepts.hpp b/deps/ox/src/ox/std/concepts.hpp new file mode 100644 index 00000000..8c8c14a3 --- /dev/null +++ b/deps/ox/src/ox/std/concepts.hpp @@ -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 +concept CommonPtrWith = ox::is_same_v::type, + typename ox::remove_pointer::type>; +} \ No newline at end of file diff --git a/deps/ox/src/ox/std/error.hpp b/deps/ox/src/ox/std/error.hpp index 0478121a..8635dc13 100644 --- a/deps/ox/src/ox/std/error.hpp +++ b/deps/ox/src/ox/std/error.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -31,7 +31,7 @@ class exception { #include "utility.hpp" #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 { @@ -83,7 +83,7 @@ constexpr auto errCode(const Error &err) noexcept { template [[nodiscard]] constexpr auto toStr(const Error &err) noexcept { - return T(err.msg); + return err.msg ? T(err.msg) : ""; } struct Exception: public std::exception { diff --git a/deps/ox/src/ox/std/hashmap.hpp b/deps/ox/src/ox/std/hashmap.hpp index ac2b1f23..1b7c1877 100644 --- a/deps/ox/src/ox/std/hashmap.hpp +++ b/deps/ox/src/ox/std/hashmap.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -46,21 +46,21 @@ class HashMap { /** * 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. */ - constexpr Result at(K key) noexcept; + constexpr Result at(const K &key) noexcept; /** * K is assumed to be a null terminated string. */ - constexpr Result at(K key) const noexcept; + constexpr Result at(const K &key) const noexcept; constexpr void erase(const K &key); - constexpr bool contains(K key) const noexcept; + constexpr bool contains(const K &key) const noexcept; [[nodiscard]] constexpr std::size_t size() const noexcept; @@ -68,6 +68,8 @@ class HashMap { [[nodiscard]] constexpr const Vector &keys() const noexcept; + constexpr void clear(); + private: constexpr void expand(); @@ -79,14 +81,12 @@ class HashMap { /** * K is assumed to be a null terminated string. */ - constexpr Pair *const&access(const Vector &pairs, K key) const; + constexpr Pair *const&access(const Vector &pairs, const K &key) const; /** * K is assumed to be a null terminated string. */ - constexpr Pair *&access(Vector &pairs, K key); - - constexpr void clear(); + constexpr Pair *&access(Vector &pairs, const K &key); }; @@ -145,7 +145,7 @@ constexpr HashMap &HashMap::operator=(HashMap &&other) { } template -constexpr T &HashMap::operator[](K k) { +constexpr T &HashMap::operator[](const K &k) { auto &p = access(m_pairs, k); if (p == nullptr) { if (m_pairs.size() * 0.7 < m_keys.size()) { @@ -159,19 +159,19 @@ constexpr T &HashMap::operator[](K k) { } template -constexpr Result HashMap::at(K k) noexcept { +constexpr Result HashMap::at(const K &k) noexcept { auto p = access(m_pairs, k); if (!p) { - return {nullptr, OxError(1)}; + return {nullptr, OxError(1, "value not found for given key")}; } return &p->value; } template -constexpr Result HashMap::at(K k) const noexcept { +constexpr Result HashMap::at(const K &k) const noexcept { auto p = access(m_pairs, k); if (!p) { - return {nullptr, OxError(1)}; + return {nullptr, OxError(1, "value not found for given key")}; } return &p->value; } @@ -196,8 +196,9 @@ constexpr void HashMap::erase(const K &k) { } oxIgnoreError(m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k))); } + template -constexpr bool HashMap::contains(K k) const noexcept { +constexpr bool HashMap::contains(const K &k) const noexcept { return access(m_pairs, k) != nullptr; } @@ -211,12 +212,21 @@ constexpr const Vector &HashMap::keys() const noexcept { return m_keys; } +template +constexpr void HashMap::clear() { + for (std::size_t i = 0; i < m_pairs.size(); i++) { + delete m_pairs[i]; + } + m_pairs.clear(); + m_pairs.resize(100); +} + template constexpr void HashMap::expand() { Vector r; for (std::size_t i = 0; i < m_keys.size(); ++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); } @@ -231,43 +241,29 @@ constexpr uint64_t HashMap::hash(K k, int len) noexcept { } template -constexpr typename HashMap::Pair *const&HashMap::access(const Vector &pairs, K k) const { +constexpr typename HashMap::Pair *const&HashMap::access(const Vector &pairs, const K &k) const { auto h = hash(k) % pairs.size(); - char hashStr[sizeof(h) + 1]; - ox_memcpy(hashStr, &h, sizeof(h)); - hashStr[sizeof(h)] = 0; while (true) { const auto &p = pairs[h]; if (p == nullptr || ox_strcmp(p->key, k) == 0) { return p; } else { - h = hash(hashStr, 8) % pairs.size(); + h = (h + 1) % pairs.size(); } } } template -constexpr typename HashMap::Pair *&HashMap::access(Vector &pairs, K k) { +constexpr typename HashMap::Pair *&HashMap::access(Vector &pairs, const K &k) { auto h = hash(k) % pairs.size(); - char hashStr[sizeof(h) + 1]; - ox_memcpy(hashStr, &h, sizeof(h)); - hashStr[sizeof(h)] = 0; while (true) { auto &p = pairs[h]; if (p == nullptr || ox_strcmp(p->key, k) == 0) { return p; } else { - h = hash(hashStr, 8) % pairs.size(); + h = (h + 1) % pairs.size(); } } } -template -constexpr void HashMap::clear() { - for (std::size_t i = 0; i < m_pairs.size(); i++) { - delete m_pairs[i]; - } - m_pairs.clear(); -} - } diff --git a/deps/ox/src/ox/std/memory.hpp b/deps/ox/src/ox/std/memory.hpp index 4231f9fb..a30fe874 100644 --- a/deps/ox/src/ox/std/memory.hpp +++ b/deps/ox/src/ox/std/memory.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -14,6 +14,8 @@ #else +#include "utility.hpp" + namespace std { template diff --git a/deps/ox/src/ox/std/new.hpp b/deps/ox/src/ox/std/new.hpp index a0fb6eae..85a7b466 100644 --- a/deps/ox/src/ox/std/new.hpp +++ b/deps/ox/src/ox/std/new.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -47,43 +47,43 @@ class MallocaPtr { T *m_val = nullptr; 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_val = other.m_val; other.m_onHeap = false; other.m_val = nullptr; } - inline MallocaPtr(bool onHeap, T *val) noexcept { + constexpr MallocaPtr(bool onHeap, T *val) noexcept { m_onHeap = onHeap; m_val = val; } - inline ~MallocaPtr() noexcept { + constexpr ~MallocaPtr() noexcept { if (m_onHeap && m_val) { delete[] reinterpret_cast(m_val); } } - inline const T *get() const noexcept { + constexpr const T *get() const noexcept { return reinterpret_cast(m_val); } - inline T *get() noexcept { + constexpr T *get() noexcept { return reinterpret_cast(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) { delete[] reinterpret_cast(m_val); } @@ -93,35 +93,35 @@ class MallocaPtr { other.m_val = nullptr; } - inline const T *operator->() const noexcept { + constexpr const T *operator->() const noexcept { return reinterpret_cast(m_val); } - inline T *operator->() noexcept { + constexpr T *operator->() noexcept { return reinterpret_cast(m_val); } - inline operator const T*() const noexcept { + constexpr operator const T*() const noexcept { return reinterpret_cast(m_val); } - inline operator T*() noexcept { + constexpr operator T*() noexcept { return reinterpret_cast(m_val); } - inline const T &operator*() const noexcept { + constexpr const T &operator*() const noexcept { return *reinterpret_cast(m_val); } - inline T &operator*() noexcept { + constexpr T &operator*() noexcept { return *reinterpret_cast(m_val); } - inline bool operator==(const MallocaPtr &other) const noexcept { + constexpr bool operator==(const MallocaPtr &other) const noexcept { return m_val == other.m_val && m_onHeap == other.m_onHeap; } - inline bool operator!=(const MallocaPtr &other) const noexcept { + constexpr bool operator!=(const MallocaPtr &other) const noexcept { return m_val != other.m_val || m_onHeap != other.m_onHeap; } diff --git a/deps/ox/src/ox/std/optional.hpp b/deps/ox/src/ox/std/optional.hpp index b8383cc0..38da7db4 100644 --- a/deps/ox/src/ox/std/optional.hpp +++ b/deps/ox/src/ox/std/optional.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -26,10 +26,10 @@ class Optional { public: constexpr Optional() noexcept = default; + template + constexpr Optional(Args &&... args); + constexpr Optional(const Optional &other) { - if (m_ptr) { - m_ptr->~T(); - } if (other.m_ptr) { m_ptr = new(m_data) T(*other.m_ptr); } else { @@ -149,4 +149,10 @@ class Optional { }; +template +template +constexpr Optional::Optional(Args &&... args) { + emplace(ox::forward(args)...); +} + } \ No newline at end of file diff --git a/deps/ox/src/ox/std/std.hpp b/deps/ox/src/ox/std/std.hpp index 82e50bdd..f6d6f8f0 100644 --- a/deps/ox/src/ox/std/std.hpp +++ b/deps/ox/src/ox/std/std.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -13,6 +13,7 @@ #include "bit.hpp" #include "bstring.hpp" #include "byteswap.hpp" +#include "concepts.hpp" #include "defer.hpp" #include "def.hpp" #include "defines.hpp" diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index 5cd9d215..ffa82436 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -134,8 +134,12 @@ class BasicString { 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 char *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 BasicString::operator+(c return cpy; } +template +constexpr bool BasicString::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 constexpr bool BasicString::operator==(const BasicString &other) const noexcept { + if (len() != other.len()) { + return false; + } bool retval = true; std::size_t i = 0; while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) { @@ -418,6 +437,11 @@ constexpr bool BasicString::operator==(const BasicString &other return retval; } +template +constexpr bool BasicString::operator!=(const char *other) const noexcept { + return !operator==(other); +} + template constexpr bool BasicString::operator!=(const BasicString &other) const noexcept { return !operator==(other); diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp index d757a776..5dfd91f5 100644 --- a/deps/ox/src/ox/std/strops.hpp +++ b/deps/ox/src/ox/std/strops.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -54,7 +54,7 @@ constexpr auto ox_strlen(T str1) noexcept { template [[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 i = 0u; while (str1[i] || str2[i]) { diff --git a/deps/ox/src/ox/std/typetraits.hpp b/deps/ox/src/ox/std/typetraits.hpp index f3820cc6..ee8ac99b 100644 --- a/deps/ox/src/ox/std/typetraits.hpp +++ b/deps/ox/src/ox/std/typetraits.hpp @@ -3,7 +3,7 @@ * * 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 http://mozilla.org/MPL/2.0/. + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once @@ -138,6 +138,21 @@ constexpr bool is_class_v = is_class(); template constexpr bool is_signed_v = integral_constant::value; +template +concept Signed_c = is_signed_v && sizeof(T) == 8 * bits; + +template +concept Unsigned_c = !is_signed_v && sizeof(T) == 8 * bits; + +template +struct is_same: false_type {}; + +template +struct is_same: true_type {}; + +template +constexpr auto is_same_v = is_same::value; + // enable_if /////////////////////////////////////////////////////////////////// template