[ox] Make TypeStore own all type info

This commit is contained in:
Gary Talent 2022-05-28 19:55:46 -05:00
parent 440d9c0a46
commit 9c3a46d144
18 changed files with 312 additions and 258 deletions

View File

@ -72,7 +72,7 @@ template<typename T>
Result<T> readClaw(const char *buff, std::size_t buffLen) {
T val;
oxReturnError(readClaw(buff, buffLen, &val));
return std::move(val);
return val;
}
template<typename T>

View File

@ -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<ox::String, ox::Error(*)()> 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<ox::String, ox::Error(*)()> 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<ox::MetalClawReader>(type.value.get(), dataBuff, dataBuffLen,
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
oxReturnError(ox::walkModel<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, 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<ox::String, ox::Error(*)()> tests = {
break;
}
case ox::PrimitiveType::String: {
ox::Vector<char> 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:

View File

@ -30,6 +30,7 @@ install(
modelops.hpp
typenamecatcher.hpp
types.hpp
typestore.hpp
walk.hpp
DESTINATION
include/ox/model

View File

@ -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<typename ReaderBase>
TypeDescReader<ReaderBase>::TypeDescReader(const uint8_t *buff, std::size_t buffLen) noexcept: ReaderBase(buff, buffLen) {
constexpr TypeDescReader<ReaderBase>::TypeDescReader(const uint8_t *buff, std::size_t buffLen) noexcept:
ReaderBase(buff, buffLen) {
}
template<typename ReaderBase>
const TypeStore &TypeDescReader<ReaderBase>::typeStore() const noexcept {
constexpr const auto &TypeDescReader<ReaderBase>::typeStore() const noexcept {
return m_typeStore;
}
template<typename ReaderBase, typename T>
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<ReaderBase> reader(buff, buffLen);
return model(&reader, val);
}

View File

@ -10,10 +10,4 @@
namespace ox {
DescriptorField::~DescriptorField() {
if (ownsType) {
safeDelete(type);
}
}
}

View File

@ -11,6 +11,7 @@
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/vector.hpp>
@ -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<DescriptorField>;
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<typename T>
constexpr Error model(T *io, DescriptorType *type) noexcept {
io->template setTypeInfo<T>("net.drinkingtea.ox.DescriptorType", 5);
io->template setTypeInfo<DescriptorType>();
oxReturnError(io->field("typeName", &type->typeName));
auto pt = std::bit_cast<uint8_t>(type->primitiveType);
auto pt = static_cast<uint8_t>(type->primitiveType);
oxReturnError(io->field("primitiveType", &pt));
type->primitiveType = std::bit_cast<PrimitiveType>(pt);
type->primitiveType = static_cast<PrimitiveType>(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<typename T>
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_cast<decltype(field->type)>(nullptr)));
}
constexpr Error model(T *io, DescriptorField *field) noexcept {
io->template setTypeInfo<DescriptorField>(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<typename ReaderBase>
class TypeDescReader;
template<typename T>
Error modelRead(T *io, DescriptorField *field) noexcept {
auto &typeStore = io->typeStore();
io->setTypeInfo("ox::DescriptorField", 4);
constexpr Error model(TypeDescReader<T> *io, DescriptorField *field) noexcept {
io->template setTypeInfo<DescriptorField>(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<String, DescriptorType*>;
}

View File

@ -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<DescriptorType>(tn);
dt->primitiveType = pt;
dt->length = b;
const auto out = dt.get();
m_typeStore->set(tn, std::move(dt));
return out;
}
}

View File

@ -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<typename T>
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<typename T>
Error field(const char *name, T val) noexcept;
constexpr Error field(const char *name, T val) noexcept;
template<typename T>
Error field(const char *name, T *val) noexcept;
constexpr Error field(const char *name, T *val) noexcept;
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int fields = countFields<T>()) noexcept;
constexpr void setTypeInfo(const char *name = T::TypeName, int fields = countFields<T>()) 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<std::size_t sz>
DescriptorType *type(BString<sz> *val, bool *alreadyExisted) noexcept;
constexpr const DescriptorType *type(BString<sz> *val, bool *alreadyExisted) noexcept;
template<typename T>
DescriptorType *type(T *val, bool *alreadyExisted) noexcept;
constexpr const DescriptorType *type(T *val, bool *alreadyExisted) noexcept;
template<typename T>
DescriptorType *type(Vector<T> *val, bool *alreadyExisted) noexcept;
constexpr const DescriptorType *type(Vector<T> *val, bool *alreadyExisted) noexcept;
template<typename T>
DescriptorType *type(HashMap<String, T> *val, bool *alreadyExisted) noexcept;
constexpr const DescriptorType *type(HashMap<String, T> *val, bool *alreadyExisted) noexcept;
template<typename U>
DescriptorType *type(UnionView<U> val, bool *alreadyExisted) noexcept;
constexpr const DescriptorType *type(UnionView<U> 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<typename T>
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<decltype(val)>::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<typename T>
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<typename T>
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<std::size_t sz>
DescriptorType *TypeDescWriter::type(BString<sz> *val, bool *alreadyExisted) noexcept {
constexpr const DescriptorType *TypeDescWriter::type(BString<sz> *val, bool *alreadyExisted) noexcept {
return type(SerStr(val), alreadyExisted);
}
template<typename T>
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<T>();
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<typename T>
DescriptorType *TypeDescWriter::type(Vector<T> *val, bool *alreadyExisted) noexcept {
constexpr const DescriptorType *TypeDescWriter::type(Vector<T> *val, bool *alreadyExisted) noexcept {
return type(val->data(), alreadyExisted);
}
template<typename T>
DescriptorType *TypeDescWriter::type(HashMap<String, T>*, bool *alreadyExisted) noexcept {
constexpr const DescriptorType *TypeDescWriter::type(HashMap<String, T>*, bool *alreadyExisted) noexcept {
return type(static_cast<T*>(nullptr), alreadyExisted);
}
template<typename U>
DescriptorType *TypeDescWriter::type(UnionView<U> val, bool *alreadyExisted) noexcept {
constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val, bool *alreadyExisted) noexcept {
return type(val.get(), alreadyExisted);
}
template<typename T>
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<T>) {
constexpr void TypeDescWriter::setTypeInfo(const char *name, int) noexcept {
m_type = m_typeStore->getInit(name);
if constexpr(is_union_v<T>) {
m_type->primitiveType = PrimitiveType::Union;
} else {
m_type->primitiveType = PrimitiveType::Struct;
@ -200,21 +197,16 @@ void TypeDescWriter::setTypeInfo(const char *name, int) noexcept {
}
template<typename T>
Result<UniquePtr<DescriptorType>> buildTypeDef(T *val) noexcept {
TypeDescWriter writer;
Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept {
TypeDescWriter writer(typeStore);
oxReturnError(model(&writer, val));
return UniquePtr<DescriptorType>{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<Buffer> 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());
}
}

View File

@ -49,10 +49,19 @@ class FieldCounter {
template<typename T>
constexpr int countFields() noexcept {
if (std::is_constant_evaluated()) {
auto a = std::allocator<T>();
auto t = a.allocate(1);
FieldCounter<T> c;
oxIgnoreError(model(&c, t));
a.deallocate(t, 1);
return c.fields;
} else {
T t;
FieldCounter<T> c;
oxIgnoreError(model(&c, &t));
return c.fields;
}
}
}

View File

@ -16,4 +16,5 @@
#include "modelops.hpp"
#include "typenamecatcher.hpp"
#include "types.hpp"
#include "typestore.hpp"
#include "walk.hpp"

View File

@ -13,6 +13,7 @@
#include <ox/std/types.hpp>
#include <ox/std/utility.hpp>
#include "fieldcounter.hpp"
#include "types.hpp"
namespace ox {
@ -51,7 +52,7 @@ class MemberList {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = countFields<T>()) noexcept {
}
[[nodiscard]]
@ -171,7 +172,7 @@ class Mover {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = countFields<T>()) noexcept {
}
[[nodiscard]]
@ -261,7 +262,7 @@ class Equals {
template<typename T>
constexpr void moveModel(T *dst, T *src) noexcept {
constexpr auto size = T::Fields;
constexpr auto size = countFields<T>();
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
@ -270,7 +271,7 @@ constexpr void moveModel(T *dst, T *src) noexcept {
template<typename T>
constexpr void copyModel(T *dst, const T *src) noexcept {
constexpr auto size = T::Fields;
constexpr auto size = countFields<T>();
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));

View File

@ -129,7 +129,6 @@ constexpr Str getModelTypeName(T *val) noexcept {
template<typename T>
consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T>();
static_assert(ox_strcmp(name, "") != 0, "TypeName is required");
return name;
}

View File

@ -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<std::size_t cap>
explicit constexpr SerStr(char (&str)[cap]) noexcept {
m_str = str;

96
deps/ox/src/ox/model/typestore.hpp vendored Normal file
View File

@ -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 <ox/std/hashmap.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include "typenamecatcher.hpp"
#include "desctypes.hpp"
namespace ox {
class TypeStore {
private:
HashMap<String, UniquePtr<DescriptorType>> m_cache;
public:
constexpr TypeStore() noexcept = default;
constexpr virtual ~TypeStore() noexcept = default;
constexpr Result<DescriptorType*> get(const auto &name) const noexcept {
oxRequire(out, m_cache.at(name));
return out->get();
}
template<typename T>
constexpr Result<DescriptorType*> get() const noexcept {
constexpr auto name = requireModelTypeName<T>();
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<DescriptorType>(name);
return out.get();
}
return out->get();
}
template<typename T>
constexpr DescriptorType *getInit() noexcept {
constexpr auto name = requireModelTypeName<T>();
return getInit(name);
}
template<typename T>
constexpr Result<DescriptorType*> getLoad() noexcept {
constexpr auto nameCstr = requireModelTypeName<T>();
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<DescriptorType> dt) noexcept {
m_cache[name] = std::move(dt);
}
constexpr void set(const String &name, DescriptorType *dt) noexcept {
m_cache[name] = UniquePtr<DescriptorType>(dt);
}
[[nodiscard]]
constexpr auto typeList() const noexcept {
auto keys = m_cache.keys();
ox::Vector<DescriptorType*> descs;
for (const auto &k : keys) {
descs.emplace_back(m_cache.at(k).value->get());
}
return descs;
}
protected:
constexpr virtual Result<UniquePtr<DescriptorType>> loadDescriptor(const ox::String&) noexcept {
return OxError(1);
}
};
}

View File

@ -23,7 +23,7 @@ class DataWalker {
Vector<const DescriptorType*> m_typeStack;
T m_fieldHandler;
Vector<FieldName> m_path;
Vector<TypeName> m_typePath;
Vector<String> m_typePath;
public:
DataWalker(DescriptorType *type, T fieldHandler) noexcept;

View File

@ -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<ox::String, int> 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<std::string_view, ox::Error(*)()> 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<std::string_view, ox::Error(*)()> 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<std::string_view, ox::Error(*)()> 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<ox::OrganicClawReader>(type.value.get(), oc.data(), oc.size(),
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::OrganicClawReader *rdr) -> ox::Error {
oxReturnError(ox::walkModel<ox::OrganicClawReader>(type.value, oc.data(), oc.size(),
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f,
ox::OrganicClawReader *rdr) -> ox::Error {
auto fieldName = f.fieldName.c_str();
switch (f.type->primitiveType) {
case ox::PrimitiveType::UnsignedInteger:

View File

@ -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);
}

View File

@ -135,6 +135,10 @@ struct [[nodiscard]] Result {
constexpr Result(const Result<U> &other) noexcept: value(other.value), error(other.error) {
}
template<typename U>
constexpr Result(const Result<U> &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) {
}
constexpr Result(const Error &error) noexcept: error(error) {
}