diff --git a/src/ox/claw/read.hpp b/src/ox/claw/read.hpp index 68acc4df5..8a016c152 100644 --- a/src/ox/claw/read.hpp +++ b/src/ox/claw/read.hpp @@ -72,7 +72,7 @@ template Result readClaw(const char *buff, std::size_t buffLen) { T val; oxReturnError(readClaw(buff, buffLen, &val)); - return std::move(val); + return val; } template diff --git a/src/ox/mc/test/tests.cpp b/src/ox/mc/test/tests.cpp index 3043ed7ae..299d080bc 100644 --- a/src/ox/mc/test/tests.cpp +++ b/src/ox/mc/test/tests.cpp @@ -16,7 +16,6 @@ union TestUnion { static constexpr auto TypeName = "TestUnion"; - static constexpr auto Fields = 3; bool Bool; uint32_t Int = 5; char CString[32]; @@ -24,7 +23,6 @@ union TestUnion { struct TestStructNest { static constexpr auto TypeName = "TestStructNest"; - static constexpr auto Fields = 3; bool Bool = false; uint32_t Int = 0; ox::BString<32> BString = ""; @@ -32,7 +30,6 @@ struct TestStructNest { struct TestStruct { static constexpr auto TypeName = "TestStruct"; - static constexpr auto Fields = 16; bool Bool = false; int32_t Int = 0; int32_t Int1 = 0; @@ -272,7 +269,7 @@ std::map tests = { [] { //constexpr size_t descBuffLen = 1024; //uint8_t descBuff[descBuffLen]; - static constexpr size_t dataBuffLen = 1024; + static constexpr size_t dataBuffLen = ox::units::MB; char dataBuff[dataBuffLen]; TestStruct testIn, testOut; testIn.Bool = true; @@ -286,10 +283,11 @@ std::map tests = { testIn.Struct.Int = 300; testIn.Struct.BString = "Test String 2"; oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); - auto type = ox::buildTypeDef(&testIn); + ox::TypeStore typeStore; + auto type = ox::buildTypeDef(&typeStore, &testIn); oxAssert(type.error, "Descriptor write failed"); - oxReturnError(ox::walkModel(type.value.get(), dataBuff, dataBuffLen, - [](const ox::Vector&, const ox::Vector&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error { + 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) { @@ -360,10 +358,10 @@ std::map tests = { break; } case ox::PrimitiveType::String: { - ox::Vector v(rdr->stringLength(fieldName) + 1); + ox::String s; //std::cout << rdr->stringLength() << '\n'; - oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed."); - std::cout << fieldName << ":\t" << "string:\t\t" << v.data() << '\n'; + oxAssert(rdr->field(fieldName, &s), "Walking model failed."); + oxOutf("{}:\tstring:\t\t{}\n", fieldName, s); break; } case ox::PrimitiveType::Struct: diff --git a/src/ox/model/CMakeLists.txt b/src/ox/model/CMakeLists.txt index b2c59eb2b..8c0897e80 100644 --- a/src/ox/model/CMakeLists.txt +++ b/src/ox/model/CMakeLists.txt @@ -30,6 +30,7 @@ install( modelops.hpp typenamecatcher.hpp types.hpp + typestore.hpp walk.hpp DESTINATION include/ox/model diff --git a/src/ox/model/descread.hpp b/src/ox/model/descread.hpp index 703f1feac..8006c063c 100644 --- a/src/ox/model/descread.hpp +++ b/src/ox/model/descread.hpp @@ -8,6 +8,7 @@ #pragma once +#include "typestore.hpp" #include "desctypes.hpp" namespace ox { @@ -18,24 +19,25 @@ class TypeDescReader: public ReaderBase { TypeStore m_typeStore; public: - TypeDescReader(const uint8_t *buff, std::size_t buffLen) noexcept; + constexpr TypeDescReader(const uint8_t *buff, std::size_t buffLen) noexcept; [[nodiscard]] - const TypeStore &typeStore() const noexcept; + constexpr const auto &typeStore() const noexcept; }; template -TypeDescReader::TypeDescReader(const uint8_t *buff, std::size_t buffLen) noexcept: ReaderBase(buff, buffLen) { +constexpr TypeDescReader::TypeDescReader(const uint8_t *buff, std::size_t buffLen) noexcept: + ReaderBase(buff, buffLen) { } template -const TypeStore &TypeDescReader::typeStore() const noexcept { +constexpr const auto &TypeDescReader::typeStore() const noexcept { return m_typeStore; } template -int readMCDef(const uint8_t *buff, std::size_t buffLen, T *val) noexcept { +constexpr int readMCDef(const uint8_t *buff, std::size_t buffLen, T *val) noexcept { TypeDescReader reader(buff, buffLen); return model(&reader, val); } diff --git a/src/ox/model/desctypes.cpp b/src/ox/model/desctypes.cpp index b3434bb94..29c239150 100644 --- a/src/ox/model/desctypes.cpp +++ b/src/ox/model/desctypes.cpp @@ -10,10 +10,4 @@ namespace ox { -DescriptorField::~DescriptorField() { - if (ownsType) { - safeDelete(type); - } -} - } diff --git a/src/ox/model/desctypes.hpp b/src/ox/model/desctypes.hpp index 092576f26..382ed8228 100644 --- a/src/ox/model/desctypes.hpp +++ b/src/ox/model/desctypes.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,6 @@ namespace ox { using FieldName = String; -using TypeName = String; enum class PrimitiveType: uint8_t { UnsignedInteger = 0, @@ -34,82 +34,57 @@ enum class PrimitiveType: uint8_t { struct DescriptorField { // order of fields matters + static constexpr auto TypeName = "net.drinkingtea.ox.DescriptorField"; static constexpr auto TypeVersion = 1; - // only serialize type name if type has already been serialized - struct DescriptorType *type = nullptr; + // do not serialize type + const struct DescriptorType *type = nullptr; String fieldName; int subscriptLevels = 0; - - // do not serialize the following - TypeName typeName; // gives reference to type for lookup if type is null - bool ownsType = false; + String typeName; // gives reference to type for lookup if type is null constexpr DescriptorField() noexcept = default; - /** - * Allow for explicit copying. - */ - constexpr DescriptorField(const DescriptorField &other) noexcept { - type = other.type; - fieldName = other.fieldName; - subscriptLevels = other.subscriptLevels; - typeName = other.typeName; - ownsType = false; // is copy, only owns type if move + constexpr DescriptorField(const DescriptorType *pType, String pFieldName, + int pSubscriptLevels, String pTypeName) noexcept: + type(pType), + fieldName(pFieldName), + subscriptLevels(pSubscriptLevels), + typeName(pTypeName) { } - constexpr DescriptorField(DescriptorType *type, const String &fieldName, int subscriptLevels, const TypeName &typeName, bool ownsType) noexcept { - this->type = type; - this->fieldName = fieldName; - this->subscriptLevels = subscriptLevels; - this->typeName = typeName; - this->ownsType = ownsType; + constexpr DescriptorField(const DescriptorField &other) noexcept: + type(other.type), + fieldName(other.fieldName), + subscriptLevels(other.subscriptLevels), + typeName(other.typeName) { } - constexpr DescriptorField(DescriptorField &&other) noexcept { - type = other.type; - fieldName = other.fieldName; - subscriptLevels = other.subscriptLevels; - typeName = other.typeName; - ownsType = other.ownsType; - + constexpr DescriptorField(DescriptorField &&other) noexcept: + type(other.type), + fieldName(other.fieldName), + subscriptLevels(other.subscriptLevels), + typeName(std::move(other.typeName)) { other.type = {}; - other.fieldName = ""; other.subscriptLevels = {}; - other.typeName = ""; - other.ownsType = {}; } - ~DescriptorField(); + constexpr ~DescriptorField() noexcept = default; - const DescriptorField &operator=(const DescriptorField &other) noexcept { - type = other.type; - fieldName = other.fieldName; - subscriptLevels = other.subscriptLevels; - typeName = other.typeName; - ownsType = other.ownsType; - return *this; - } + constexpr DescriptorField &operator=(const DescriptorField &other) noexcept = delete; - const DescriptorField &operator=(DescriptorField &&other) noexcept { - type = std::move(other.type); - other.type = {}; - fieldName = std::move(other.fieldName); - subscriptLevels = std::move(other.subscriptLevels); - other.subscriptLevels = {}; - typeName = std::move(other.typeName); - ownsType = std::move(other.ownsType); - other.ownsType = {}; - return *this; - } + constexpr DescriptorField &operator=(DescriptorField &&other) noexcept = delete; }; using FieldList = Vector; struct DescriptorType { + + static constexpr auto TypeName = "net.drinkingtea.ox.DescriptorType"; static constexpr auto TypeVersion = 1; - TypeName typeName = ""; + + String typeName; PrimitiveType primitiveType = PrimitiveType::UnsignedInteger; // fieldList only applies to structs FieldList fieldList; @@ -118,23 +93,33 @@ struct DescriptorType { int64_t length = 0; bool preloadable = false; - DescriptorType() = default; + constexpr DescriptorType() noexcept = default; - DescriptorType(const TypeName &tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) { + constexpr explicit DescriptorType(String tn) noexcept: typeName(std::move(tn)) { } - DescriptorType(const TypeName &tn, PrimitiveType t, const FieldList &fl): typeName(tn), primitiveType(t), fieldList(fl) { + constexpr DescriptorType(String tn, PrimitiveType t, int b) noexcept: + typeName(std::move(tn)), + primitiveType(t), + length(b) { } + + constexpr DescriptorType(String tn, PrimitiveType t, FieldList fl) noexcept: + typeName(std::move(tn)), + primitiveType(t), + fieldList(std::move(fl)) { + } + }; template constexpr Error model(T *io, DescriptorType *type) noexcept { - io->template setTypeInfo("net.drinkingtea.ox.DescriptorType", 5); + io->template setTypeInfo(); oxReturnError(io->field("typeName", &type->typeName)); - auto pt = std::bit_cast(type->primitiveType); + auto pt = static_cast(type->primitiveType); oxReturnError(io->field("primitiveType", &pt)); - type->primitiveType = std::bit_cast(pt); + type->primitiveType = static_cast(pt); oxReturnError(io->field("fieldList", &type->fieldList)); oxReturnError(io->field("length", &type->length)); oxReturnError(io->field("preloadable", &type->preloadable)); @@ -142,47 +127,34 @@ constexpr Error model(T *io, DescriptorType *type) noexcept { } template -Error modelWrite(T *io, DescriptorField *field) noexcept { - io->setTypeInfo("ox::DescriptorField", 4); - if (field->ownsType) { - String empty = ""; - oxReturnError(io->field("typeName", &empty)); - oxReturnError(io->field("type", field->type)); - } else { - oxReturnError(io->field("typeName", &field->type->typeName)); - oxReturnError(io->field("type", static_casttype)>(nullptr))); - } +constexpr Error model(T *io, DescriptorField *field) noexcept { + io->template setTypeInfo(DescriptorField::TypeName, 4); + oxReturnError(io->field("typeName", &field->typeName)); oxReturnError(io->field("fieldName", &field->fieldName)); + oxReturnError(io->field("subscriptLevels", &field->subscriptLevels)); // defaultValue is unused now, but leave placeholder for backwards compatibility - int DefaultValue = 0; - oxReturnError(io->field("defaultValue", &DefaultValue)); + int defaultValue = 0; + oxReturnError(io->field("defaultValue", &defaultValue)); return OxError(0); } +template +class TypeDescReader; + template -Error modelRead(T *io, DescriptorField *field) noexcept { - auto &typeStore = io->typeStore(); - io->setTypeInfo("ox::DescriptorField", 4); +constexpr Error model(TypeDescReader *io, DescriptorField *field) noexcept { + io->template setTypeInfo(DescriptorField::TypeName, 4); oxReturnError(io->field("typeName", &field->typeName)); - if (field->typeName == "") { - field->ownsType = true; - if (field->type == nullptr) { - field->type = new DescriptorType; - } - oxReturnError(io->field("type", field->type)); - typeStore[field->type->typeName] = field->type; - } else { - // should be empty, so discard - DescriptorType t; - oxReturnError(io->field("type", &t)); - field->type = typeStore[field->typeName]; - } + auto &typeStore = io->typeStore(); + auto &[type, err] = typeStore->at(field->typeName).value; + oxReturnError(err); + field->type = type.get(); oxReturnError(io->field("fieldName", &field->fieldName)); + oxReturnError(io->field("subscriptLevels", &field->subscriptLevels)); // defaultValue is unused now, but placeholder for backwards compatibility - oxReturnError(io->field("defaultValue", nullptr)); + int defaultValue = 0; + oxReturnError(io->field("defaultValue", &defaultValue)); return OxError(0); } -using TypeStore = HashMap; - } diff --git a/src/ox/model/descwrite.cpp b/src/ox/model/descwrite.cpp index 538ef4eb1..6889b81ab 100644 --- a/src/ox/model/descwrite.cpp +++ b/src/ox/model/descwrite.cpp @@ -47,116 +47,102 @@ static_assert([] { return detail::indirectionLevels(i) == 1; }(), "indirectionLevels broken: indirectionLevels(int[])"); -TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept { - if (!typeStore) { - m_typeStoreOwnerRef = new TypeStore; - typeStore = m_typeStoreOwnerRef; - } - m_typeStore = typeStore; -} - -TypeDescWriter::~TypeDescWriter() noexcept { - // does not own it's elements - safeDelete(m_typeStoreOwnerRef); -} - -DescriptorType *TypeDescWriter::type(int8_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:int8_t"; +const DescriptorType *TypeDescWriter::type(int8_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:int8_t"; constexpr auto PT = PrimitiveType::SignedInteger; constexpr auto Bytes = 1; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(int16_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:int16_t"; +const DescriptorType *TypeDescWriter::type(int16_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:int16_t"; constexpr auto PT = PrimitiveType::SignedInteger; constexpr auto Bytes = 2; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(int32_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:int32_t"; +const DescriptorType *TypeDescWriter::type(int32_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:int32_t"; constexpr auto PT = PrimitiveType::SignedInteger; constexpr auto Bytes = 4; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(int64_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:int64_t"; +const DescriptorType *TypeDescWriter::type(int64_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:int64_t"; constexpr auto PT = PrimitiveType::SignedInteger; constexpr auto Bytes = 8; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(uint8_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:uint8_t"; +const DescriptorType *TypeDescWriter::type(uint8_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:uint8_t"; constexpr auto PT = PrimitiveType::UnsignedInteger; constexpr auto Bytes = 1; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(uint16_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:uint16_t"; +const DescriptorType *TypeDescWriter::type(uint16_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:uint16_t"; constexpr auto PT = PrimitiveType::UnsignedInteger; constexpr auto Bytes = 2; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(uint32_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:uint32_t"; +const DescriptorType *TypeDescWriter::type(uint32_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:uint32_t"; constexpr auto PT = PrimitiveType::UnsignedInteger; constexpr auto Bytes = 4; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(uint64_t*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:uint64_t"; +const DescriptorType *TypeDescWriter::type(uint64_t*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:uint64_t"; constexpr auto PT = PrimitiveType::UnsignedInteger; constexpr auto Bytes = 8; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::type(char*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:string"; +const DescriptorType *TypeDescWriter::type(char*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:string"; constexpr auto PT = PrimitiveType::String; - return getType(TypeName, PT, 0, alreadyExisted); + return getType(String, PT, 0, alreadyExisted); } -DescriptorType *TypeDescWriter::type(SerStr, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:string"; +const DescriptorType *TypeDescWriter::type(SerStr, bool *alreadyExisted) noexcept { + constexpr auto String = "B:string"; constexpr auto PT = PrimitiveType::String; - return getType(TypeName, PT, 0, alreadyExisted); + return getType(String, PT, 0, alreadyExisted); } -DescriptorType *TypeDescWriter::type(String*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:string"; +const DescriptorType *TypeDescWriter::type(String*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:string"; constexpr auto PT = PrimitiveType::String; - return getType(TypeName, PT, 0, alreadyExisted); + return getType(String, PT, 0, alreadyExisted); } -DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) noexcept { - constexpr auto TypeName = "B:bool"; +const DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) noexcept { + constexpr auto String = "B:bool"; constexpr auto PT = PrimitiveType::Bool; constexpr auto Bytes = 0; - return getType(TypeName, PT, Bytes, alreadyExisted); + return getType(String, PT, Bytes, alreadyExisted); } -DescriptorType *TypeDescWriter::getType(const TypeName &tn, PrimitiveType pt, int b, bool *alreadyExisted) noexcept { - if (m_typeStore->contains(tn)) { +const DescriptorType *TypeDescWriter::getType(const String &tn, PrimitiveType pt, int b, bool *alreadyExisted) noexcept { + auto t = m_typeStore->get(tn); + if (!t.error) { *alreadyExisted = true; - auto type = m_typeStore->operator[](tn); + auto type = t.value; oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType"); return type; } else { *alreadyExisted = false; - auto &t = m_typeStore->operator[](tn); - if (!t) { - t = new DescriptorType; - } - t->typeName = tn; - t->primitiveType = pt; - t->length = b; - return t; + 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; } } diff --git a/src/ox/model/descwrite.hpp b/src/ox/model/descwrite.hpp index 6dd7193db..e8666296d 100644 --- a/src/ox/model/descwrite.hpp +++ b/src/ox/model/descwrite.hpp @@ -22,6 +22,7 @@ #include "optype.hpp" #include "typenamecatcher.hpp" #include "types.hpp" +#include "typestore.hpp" namespace ox { @@ -42,28 +43,26 @@ static constexpr int indirectionLevels(T *t) noexcept { class TypeDescWriter { private: - TypeStore *m_typeStoreOwnerRef = nullptr; TypeStore *m_typeStore = nullptr; DescriptorType *m_type = nullptr; public: - explicit TypeDescWriter(TypeStore *typeStore = nullptr) noexcept; - - ~TypeDescWriter() noexcept; + explicit constexpr TypeDescWriter(TypeStore *typeStore = nullptr) noexcept; template - Error field(const char *name, T *val, std::size_t valLen) noexcept; + constexpr Error field(const char *name, T *val, std::size_t valLen) noexcept; template - Error field(const char *name, T val) noexcept; + constexpr Error field(const char *name, T val) noexcept; template - Error field(const char *name, T *val) noexcept; + constexpr Error field(const char *name, T *val) noexcept; template - void setTypeInfo(const char *name = T::TypeName, int fields = countFields()) noexcept; + constexpr void setTypeInfo(const char *name = T::TypeName, int fields = countFields()) noexcept; - [[nodiscard]] DescriptorType *definition() noexcept { + [[nodiscard]] + constexpr DescriptorType *definition() noexcept { return m_type; } @@ -72,45 +71,48 @@ class TypeDescWriter { } private: - DescriptorType *type(int8_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(int16_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(int32_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(int64_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(int8_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(int16_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(int32_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(int64_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(uint8_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(uint16_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(uint32_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(uint64_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(uint8_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(uint16_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(uint32_t *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(uint64_t *val, bool *alreadyExisted) noexcept; - DescriptorType *type(bool *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(bool *val, bool *alreadyExisted) noexcept; - DescriptorType *type(char *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(char *val, bool *alreadyExisted) noexcept; - DescriptorType *type(SerStr val, bool *alreadyExisted) noexcept; + const DescriptorType *type(SerStr val, bool *alreadyExisted) noexcept; - DescriptorType *type(String *val, bool *alreadyExisted) noexcept; + const DescriptorType *type(String *val, bool *alreadyExisted) noexcept; template - DescriptorType *type(BString *val, bool *alreadyExisted) noexcept; + constexpr const DescriptorType *type(BString *val, bool *alreadyExisted) noexcept; template - DescriptorType *type(T *val, bool *alreadyExisted) noexcept; + constexpr const DescriptorType *type(T *val, bool *alreadyExisted) noexcept; template - DescriptorType *type(Vector *val, bool *alreadyExisted) noexcept; + constexpr const DescriptorType *type(Vector *val, bool *alreadyExisted) noexcept; template - DescriptorType *type(HashMap *val, bool *alreadyExisted) noexcept; + constexpr const DescriptorType *type(HashMap *val, bool *alreadyExisted) noexcept; template - DescriptorType *type(UnionView val, bool *alreadyExisted) noexcept; + constexpr const DescriptorType *type(UnionView val, bool *alreadyExisted) noexcept; - DescriptorType *getType(const TypeName &tn, PrimitiveType t, int b, bool *alreadyExisted) noexcept; + const DescriptorType *getType(const String &tn, PrimitiveType t, int b, bool *alreadyExisted) noexcept; }; +constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) { +} + // array handler template -Error TypeDescWriter::field(const char *name, T *val, std::size_t) noexcept { +constexpr Error TypeDescWriter::field(const char *name, T *val, std::size_t) noexcept { if (m_type) { constexpr typename remove_pointer::type *p = nullptr; bool alreadyExisted = false; @@ -119,47 +121,47 @@ Error TypeDescWriter::field(const char *name, T *val, std::size_t) noexcept { if (t == nullptr) { type(p, &alreadyExisted); } - m_type->fieldList.emplace_back(t, name, detail::indirectionLevels(val), alreadyExisted ? t->typeName : "", !alreadyExisted); + m_type->fieldList.emplace_back(t, name, detail::indirectionLevels(val), alreadyExisted ? t->typeName : ""); return OxError(0); } return OxError(1); } template -Error TypeDescWriter::field(const char *name, T val) noexcept { +constexpr Error TypeDescWriter::field(const char *name, T val) noexcept { if (m_type) { bool alreadyExisted = false; const auto t = type(val, &alreadyExisted); oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); - m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted); + m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : ""); return OxError(0); } return OxError(1); } template -Error TypeDescWriter::field(const char *name, T *val) noexcept { +constexpr Error TypeDescWriter::field(const char *name, T *val) noexcept { if (m_type) { bool alreadyExisted = false; const auto t = type(val, &alreadyExisted); oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated"); - m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted); + m_type->fieldList.emplace_back(t, name, 0, t->typeName); return OxError(0); } return OxError(1); } template -DescriptorType *TypeDescWriter::type(BString *val, bool *alreadyExisted) noexcept { +constexpr const DescriptorType *TypeDescWriter::type(BString *val, bool *alreadyExisted) noexcept { return type(SerStr(val), alreadyExisted); } template -DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) noexcept { - const auto name = getModelTypeName(val); - if (m_typeStore->contains(name)) { +constexpr const DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) noexcept { + auto [t, err] = m_typeStore->template get(); + if (!err) { *alreadyExisted = true; - return m_typeStore->operator[](name); + return t; } else { TypeDescWriter dw(m_typeStore); oxLogError(model(&dw, val)); @@ -169,29 +171,24 @@ DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) noexcept { } template -DescriptorType *TypeDescWriter::type(Vector *val, bool *alreadyExisted) noexcept { +constexpr const DescriptorType *TypeDescWriter::type(Vector *val, bool *alreadyExisted) noexcept { return type(val->data(), alreadyExisted); } template -DescriptorType *TypeDescWriter::type(HashMap*, bool *alreadyExisted) noexcept { +constexpr const DescriptorType *TypeDescWriter::type(HashMap*, bool *alreadyExisted) noexcept { return type(static_cast(nullptr), alreadyExisted); } template -DescriptorType *TypeDescWriter::type(UnionView val, bool *alreadyExisted) noexcept { +constexpr const DescriptorType *TypeDescWriter::type(UnionView val, bool *alreadyExisted) noexcept { return type(val.get(), alreadyExisted); } template -void TypeDescWriter::setTypeInfo(const char *name, int) noexcept { - auto &t = m_typeStore->operator[](name); - if (!t) { - t = new DescriptorType; - } - m_type = t; - m_type->typeName = name; - if (is_union_v) { +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; } else { m_type->primitiveType = PrimitiveType::Struct; @@ -200,21 +197,16 @@ void TypeDescWriter::setTypeInfo(const char *name, int) noexcept { } template -Result> buildTypeDef(T *val) noexcept { - TypeDescWriter writer; +Result buildTypeDef(TypeStore *typeStore, T *val) noexcept { + TypeDescWriter writer(typeStore); oxReturnError(model(&writer, val)); - return UniquePtr{writer.definition()}; + return writer.definition(); } -Error writeTypeDef(uint8_t *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept { - oxRequire(def, buildTypeDef(val)); - return writeType(buff, buffLen, def.get(), sizeOut); -} - -Result writeTypeDef(auto *val) noexcept { - Buffer buff(units::MB); - oxReturnError(writeTypeDef(buff.data(), buff.size(), val)); - return std::move(buff); +auto writeTypeDefOC(auto *val) noexcept { + TypeStore typeStore; + oxRequire(def, buildTypeDef(&typeStore, val)); + return writeOC(def.get()); } } diff --git a/src/ox/model/fieldcounter.hpp b/src/ox/model/fieldcounter.hpp index 2fa277a12..5d5bfd65c 100644 --- a/src/ox/model/fieldcounter.hpp +++ b/src/ox/model/fieldcounter.hpp @@ -49,10 +49,19 @@ class FieldCounter { template constexpr int countFields() noexcept { - T t; - FieldCounter c; - oxIgnoreError(model(&c, &t)); - return c.fields; + if (std::is_constant_evaluated()) { + auto a = std::allocator(); + auto t = a.allocate(1); + FieldCounter c; + oxIgnoreError(model(&c, t)); + a.deallocate(t, 1); + return c.fields; + } else { + T t; + FieldCounter c; + oxIgnoreError(model(&c, &t)); + return c.fields; + } } } diff --git a/src/ox/model/model.hpp b/src/ox/model/model.hpp index 1ca0a2b00..6c407da0f 100644 --- a/src/ox/model/model.hpp +++ b/src/ox/model/model.hpp @@ -16,4 +16,5 @@ #include "modelops.hpp" #include "typenamecatcher.hpp" #include "types.hpp" +#include "typestore.hpp" #include "walk.hpp" diff --git a/src/ox/model/modelops.hpp b/src/ox/model/modelops.hpp index 4452a12e9..8d2a420cc 100644 --- a/src/ox/model/modelops.hpp +++ b/src/ox/model/modelops.hpp @@ -13,6 +13,7 @@ #include #include +#include "fieldcounter.hpp" #include "types.hpp" namespace ox { @@ -51,7 +52,7 @@ class MemberList { } template - constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, int = countFields()) noexcept { } [[nodiscard]] @@ -171,7 +172,7 @@ class Mover { } template - constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) noexcept { + constexpr void setTypeInfo(const char* = T::TypeName, int = countFields()) noexcept { } [[nodiscard]] @@ -261,7 +262,7 @@ class Equals { template constexpr void moveModel(T *dst, T *src) noexcept { - constexpr auto size = T::Fields; + constexpr auto size = countFields(); detail::MemberList dstFields; detail::Mover mover(&dstFields); oxIgnoreError(model(&dstFields, dst)); @@ -270,7 +271,7 @@ constexpr void moveModel(T *dst, T *src) noexcept { template constexpr void copyModel(T *dst, const T *src) noexcept { - constexpr auto size = T::Fields; + constexpr auto size = countFields(); detail::MemberList dstFields; detail::Copier copier(&dstFields); oxIgnoreError(model(&dstFields, dst)); diff --git a/src/ox/model/typenamecatcher.hpp b/src/ox/model/typenamecatcher.hpp index 73b3f9c1a..09a9ad10e 100644 --- a/src/ox/model/typenamecatcher.hpp +++ b/src/ox/model/typenamecatcher.hpp @@ -129,7 +129,6 @@ constexpr Str getModelTypeName(T *val) noexcept { template consteval auto requireModelTypeName() noexcept { constexpr auto name = getModelTypeName(); - static_assert(ox_strcmp(name, "") != 0, "TypeName is required"); return name; } diff --git a/src/ox/model/types.hpp b/src/ox/model/types.hpp index 1ff41de09..537c6fa73 100644 --- a/src/ox/model/types.hpp +++ b/src/ox/model/types.hpp @@ -76,6 +76,12 @@ class SerStr { m_cap = cap; } + explicit constexpr SerStr(char *str, char **tgt, int cap = -1) noexcept { + m_tgt = tgt; + m_str = str; + m_cap = cap; + } + template explicit constexpr SerStr(char (&str)[cap]) noexcept { m_str = str; diff --git a/src/ox/model/typestore.hpp b/src/ox/model/typestore.hpp new file mode 100644 index 000000000..249c0c266 --- /dev/null +++ b/src/ox/model/typestore.hpp @@ -0,0 +1,96 @@ +/* + * 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 http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include + +#include "typenamecatcher.hpp" +#include "desctypes.hpp" + +namespace ox { + +class TypeStore { + private: + HashMap> m_cache; + + public: + constexpr TypeStore() noexcept = default; + + constexpr virtual ~TypeStore() noexcept = default; + + constexpr Result get(const auto &name) const noexcept { + oxRequire(out, m_cache.at(name)); + return out->get(); + } + + template + constexpr Result get() const noexcept { + constexpr auto name = requireModelTypeName(); + oxRequire(out, m_cache.at(name)); + return out->get(); + } + + constexpr DescriptorType *getInit(const auto &name) noexcept { + auto [out, err] = m_cache.at(name); + if (err) { + auto &out = m_cache[name]; + out = ox::make_unique(name); + return out.get(); + } + return out->get(); + } + + template + constexpr DescriptorType *getInit() noexcept { + constexpr auto name = requireModelTypeName(); + return getInit(name); + } + + template + constexpr Result getLoad() noexcept { + constexpr auto nameCstr = requireModelTypeName(); + const String name = nameCstr; + auto [val, err] = m_cache.at(name); + if (err) { + oxRequireM(dt, loadDescriptor(name)); + auto &out = m_cache[name]; + out = std::move(dt); + return out.get(); + } + return val->get(); + } + + constexpr void set(const String &name, UniquePtr dt) noexcept { + m_cache[name] = std::move(dt); + } + + constexpr void set(const String &name, DescriptorType *dt) noexcept { + m_cache[name] = UniquePtr(dt); + } + + [[nodiscard]] + constexpr auto typeList() const noexcept { + auto keys = m_cache.keys(); + ox::Vector descs; + for (const auto &k : keys) { + descs.emplace_back(m_cache.at(k).value->get()); + } + return descs; + } + + protected: + constexpr virtual Result> loadDescriptor(const ox::String&) noexcept { + return OxError(1); + } + +}; + +} \ No newline at end of file diff --git a/src/ox/model/walk.hpp b/src/ox/model/walk.hpp index 30bdc3a7d..42ecc95b4 100644 --- a/src/ox/model/walk.hpp +++ b/src/ox/model/walk.hpp @@ -23,7 +23,7 @@ class DataWalker { Vector m_typeStack; T m_fieldHandler; Vector m_path; - Vector m_typePath; + Vector m_typePath; public: DataWalker(DescriptorType *type, T fieldHandler) noexcept; diff --git a/src/ox/oc/test/tests.cpp b/src/ox/oc/test/tests.cpp index 00c454370..70b75c3ce 100644 --- a/src/ox/oc/test/tests.cpp +++ b/src/ox/oc/test/tests.cpp @@ -16,7 +16,6 @@ union TestUnion { static constexpr auto TypeName = "TestUnion"; - static constexpr auto Fields = 3; bool Bool; uint32_t Int = 5; char String[32]; @@ -24,7 +23,6 @@ union TestUnion { struct TestStructNest { static constexpr auto TypeName = "TestStructNest"; - static constexpr auto Fields = 3; bool Bool = false; uint32_t Int = 0; ox::BString<32> String = ""; @@ -32,7 +30,6 @@ struct TestStructNest { struct TestStruct { static constexpr auto TypeName = "TestStruct"; - static constexpr auto Fields = 17; bool Bool = false; int32_t Int = 0; int32_t Int1 = 0; @@ -44,7 +41,6 @@ struct TestStruct { int32_t Int7 = 0; int32_t Int8 = 0; TestUnion Union; - char *CString = nullptr; ox::BString<32> String = ""; uint32_t List[4] = {0, 0, 0, 0}; ox::HashMap Map; @@ -55,8 +51,7 @@ struct TestStruct { TestStruct(TestStruct &&other) noexcept; - ~TestStruct() noexcept { - delete[] CString; + constexpr ~TestStruct() noexcept { } constexpr TestStruct &operator=(TestStruct&&) noexcept; @@ -95,7 +90,6 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept { oxReturnError(io->field("Int7", &obj->Int7)); oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1})); - oxReturnError(io->field("CString", ox::SerStr(&obj->CString))); oxReturnError(io->field("String", &obj->String)); oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("Map", &obj->Map)); @@ -132,8 +126,6 @@ const std::map tests = { testIn.Int = 42; testIn.Union.Int = 52; testIn.String = "Test String 1"; - testIn.CString = new char[ox_strlen("c-string") + 1]; - ox_strcpy(testIn.CString, "c-string"); testIn.List[0] = 1; testIn.List[1] = 2; testIn.List[2] = 3; @@ -160,7 +152,6 @@ const std::map tests = { oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch"); oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch"); oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); - oxAssert(ox_strcmp(testIn.CString, testOut.CString) == 0, "CString value mismatch"); oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch"); oxAssert(testIn.String == testOut.String, "String value mismatch"); oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); @@ -197,10 +188,12 @@ const std::map tests = { auto [oc, ocErr] = ox::writeOC(&testIn); oxAssert(ocErr, "Data generation failed"); - auto type = ox::buildTypeDef(&testIn); + ox::TypeStore typeStore; + auto type = ox::buildTypeDef(&typeStore, &testIn); oxAssert(type.error, "Descriptor write failed"); - oxReturnError(ox::walkModel(type.value.get(), oc.data(), oc.size(), - [](const ox::Vector&, const ox::Vector&, const ox::DescriptorField &f, ox::OrganicClawReader *rdr) -> ox::Error { + oxReturnError(ox::walkModel(type.value, oc.data(), oc.size(), + [](const ox::Vector&, const ox::Vector&, const ox::DescriptorField &f, + ox::OrganicClawReader *rdr) -> ox::Error { auto fieldName = f.fieldName.c_str(); switch (f.type->primitiveType) { case ox::PrimitiveType::UnsignedInteger: diff --git a/src/ox/std/assert.hpp b/src/ox/std/assert.hpp index 5f3360906..abb39a212 100644 --- a/src/ox/std/assert.hpp +++ b/src/ox/std/assert.hpp @@ -36,7 +36,7 @@ constexpr void assertFunc(const char *file, int line, bool pass, [[maybe_unused] if (!pass) { if (!std::is_constant_evaluated()) { #ifdef OX_USE_STDLIB - oxErrf("\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); + oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); printStackTrace(2); oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); std::abort(); @@ -53,7 +53,7 @@ constexpr void assertFunc(const char *file, int line, const Error &err, const ch if (err) { if (!std::is_constant_evaluated()) { #if defined(OX_USE_STDLIB) - oxErrf("\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); + oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); if (err.msg) { oxErrf("\tError Message:\t{}\n", err.msg); } diff --git a/src/ox/std/error.hpp b/src/ox/std/error.hpp index 56a1258bb..0478121a4 100644 --- a/src/ox/std/error.hpp +++ b/src/ox/std/error.hpp @@ -135,6 +135,10 @@ struct [[nodiscard]] Result { constexpr Result(const Result &other) noexcept: value(other.value), error(other.error) { } + template + constexpr Result(const Result &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) { + } + constexpr Result(const Error &error) noexcept: error(error) { }