nostalgia/deps/ox/src/ox/model/modelvalue.hpp
2024-02-04 10:19:30 -06:00

1343 lines
34 KiB
C++

/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/memory.hpp>
#include <ox/std/serialize.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/typetraits.hpp>
#include <ox/std/types.hpp>
#include <ox/std/utility.hpp>
#include <ox/std/vector.hpp>
#include "def.hpp"
#include "desctypes.hpp"
#include "fieldcounter.hpp"
#include "metadata.hpp"
#include "optype.hpp"
#include "typenamecatcher.hpp"
#include "types.hpp"
#include "typestore.hpp"
namespace ox {
class ModelObject;
class ModelUnion;
class ModelValue;
class ModelValueArray;
class ModelValueVector;
class ModelValue {
public:
enum class Type {
Undefined,
Bool,
UnsignedInteger8,
UnsignedInteger16,
UnsignedInteger32,
UnsignedInteger64,
SignedInteger8,
SignedInteger16,
SignedInteger32,
SignedInteger64,
String,
Object,
Union,
Vector,
InlineArray,
};
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 = 0;
String *str;
ModelObject *obj;
ModelUnion *uni;
ModelValueVector *vec;
ModelValueArray *array;
} m_data;
template<typename T>
static consteval Type getType() noexcept {
using U = typename ox::remove_reference<T>::type;
if constexpr(is_bool_v<U>) {
return Type::Bool;
} else if constexpr(is_integer_v<U>) {
if constexpr(!is_signed_v<U> && sizeof(U) == 1) {
return Type::UnsignedInteger8;
} else if constexpr(!is_signed_v<U> && sizeof(U) == 2) {
return Type::UnsignedInteger16;
} else if constexpr(!is_signed_v<U> && sizeof(U) == 4) {
return Type::UnsignedInteger32;
} else if constexpr(!is_signed_v<U> && sizeof(U) == 8) {
return Type::UnsignedInteger64;
} else if constexpr(is_signed_v<U> && sizeof(U) == 1) {
return Type::SignedInteger8;
} else if constexpr(is_signed_v<U> && sizeof(U) == 2) {
return Type::SignedInteger16;
} else if constexpr(is_signed_v<U> && sizeof(U) == 4) {
return Type::SignedInteger32;
} else if constexpr(is_signed_v<U> && sizeof(U) == 8) {
return Type::SignedInteger64;
}
} else if constexpr(is_same_v<U, ModelUnion>) {
return Type::Union;
} else if constexpr(is_same_v<U, ModelObject>) {
return Type::Object;
} else if constexpr(isBasicString_v<U> || isBString_v<U>) {
return Type::String;
} else if constexpr(is_same_v<U, ModelValueVector>) {
return Type::Vector;
} else if constexpr(is_same_v<U, ModelValueArray>) {
return Type::InlineArray;
} else {
return Type::Undefined;
}
}
template<Type type>
static constexpr auto &getValue(auto &t) noexcept {
if constexpr(type == Type::Bool) {
return t.m_data.b;
} else if constexpr(type == Type::UnsignedInteger8) {
return t.m_data.ui8;
} else if constexpr(type == Type::UnsignedInteger16) {
return t.m_data.ui16;
} else if constexpr(type == Type::UnsignedInteger32) {
return t.m_data.ui32;
} else if constexpr(type == Type::UnsignedInteger64) {
return t.m_data.ui64;
} else if constexpr(type == Type::SignedInteger8) {
return t.m_data.i8;
} else if constexpr(type == Type::SignedInteger16) {
return t.m_data.i16;
} else if constexpr(type == Type::SignedInteger32) {
return t.m_data.i32;
} else if constexpr(type == Type::SignedInteger64) {
return t.m_data.i64;
} else if constexpr(type == Type::String) {
return *t.m_data.str;
} else if constexpr(type == Type::Union) {
return *t.m_data.uni;
} else if constexpr(type == Type::Object) {
return *t.m_data.obj;
} else if constexpr(type == Type::Vector) {
return *t.m_data.vec;
} else if constexpr(type == Type::InlineArray) {
return *t.m_data.array;
} else {
return t.m_data.i32;
}
}
public:
constexpr ModelValue() noexcept = default;
constexpr ModelValue(const ModelValue &other) noexcept;
constexpr ModelValue(ModelValue &&other) noexcept;
template<typename T>
explicit constexpr ModelValue(const T &val) noexcept
requires(!ox::is_same_v<ox::remove_reference_t<T>, ModelValue>);
template<typename T>
explicit constexpr ModelValue(T &&val) noexcept
requires(!ox::is_same_v<ox::remove_reference_t<T>, ModelValue>);
constexpr ~ModelValue() noexcept;
template<typename T>
[[nodiscard]]
constexpr const auto &get() const noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(OxError(1), "invalid cast");
}
return getValue<type>(*this);
}
template<typename T>
[[nodiscard]]
constexpr auto &get() noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
oxPanic(OxError(1), "invalid cast");
}
return getValue<type>(*this);
}
[[nodiscard]]
constexpr Type type() const noexcept;
constexpr Error setType(
DescriptorType const*type,
int subscriptLevels = 0,
SubscriptStack const& = {}) noexcept;
template<typename T>
constexpr Error setType() noexcept;
template<typename T>
constexpr Error set(const T &v) noexcept;
template<typename T>
constexpr Error set(T &&v) noexcept;
constexpr ModelValue &operator=(ModelValue &val) noexcept;
constexpr ModelValue &operator=(const ModelValue &val) noexcept;
constexpr ModelValue &operator=(ModelValue &&val) noexcept;
private:
constexpr void freeResources() noexcept;
};
class ModelValueArray {
private:
Vector<ModelValue> m_vec;
const DescriptorType *m_type = nullptr;
int m_typeSubscriptLevels = 0;
SubscriptStack m_subscriptStack;
String m_typeName;
int m_typeVersion = 0;
public:
constexpr explicit ModelValueArray() noexcept = default;
constexpr ModelValueArray(ModelValueArray const&other) noexcept {
for (auto &v : other.m_vec) {
m_vec.emplace_back(v);
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelValueArray(ModelValueArray &&other) noexcept {
m_vec = std::move(other.m_vec);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
}
constexpr ox::Error setSize(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) {
oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels));
}
}
return {};
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_vec.data();
}
[[nodiscard]]
constexpr auto data() noexcept {
return m_vec.data();
}
constexpr static ox::Result<ModelValueArray> make(size_t sz) noexcept {
ox::Result<ModelValueArray> out;
out.error = out.value.setSize(sz);
return out;
}
[[nodiscard]]
constexpr auto &get() noexcept {
return m_vec;
}
[[nodiscard]]
constexpr auto const&get() const noexcept {
return m_vec;
}
constexpr Error setType(
DescriptorType const*type,
int subscriptLevels,
SubscriptStack subscriptStack) noexcept {
m_type = type;
m_typeSubscriptLevels = subscriptLevels;
m_subscriptStack = std::move(subscriptStack);
return {};
}
[[nodiscard]]
constexpr String const&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 begin() const noexcept {
return m_vec.cbegin();
}
[[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 end() const noexcept {
return m_vec.cend();
}
[[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();
}
};
class ModelValueVector {
private:
Vector<ModelValue> m_vec;
const DescriptorType *m_type = nullptr;
int m_typeSubscriptLevels = 0;
SubscriptStack m_subscriptStack;
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 ox::Error 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) {
oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels, m_subscriptStack));
}
}
return {};
}
[[nodiscard]]
constexpr auto &get() noexcept {
return m_vec;
}
[[nodiscard]]
constexpr const auto &get() const noexcept {
return m_vec;
}
constexpr Error setType(
DescriptorType const*type,
int subscriptLevels,
SubscriptStack subscriptStack) noexcept {
m_type = type;
m_typeSubscriptLevels = subscriptLevels;
m_subscriptStack = std::move(subscriptStack);
return {};
}
[[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 begin() const noexcept {
return m_vec.cbegin();
}
[[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 end() const noexcept {
return m_vec.cend();
}
[[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;
}
constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept;
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept;
class ModelObject {
friend constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept;
public:
struct Field {
String name;
ModelValue value;
};
protected:
oxModelFriend(ModelObject);
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields;
const DescriptorType *m_type = nullptr;
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{ox::String(f->name), f->value});
m_fields[field->name] = &field->value;
}
m_type = other.m_type;
}
constexpr ModelObject(ModelObject &&other) noexcept {
m_fields = std::move(other.m_fields);
m_type = other.m_type;
m_fieldsOrder = std::move(other.m_fieldsOrder);
}
[[nodiscard]]
constexpr auto begin() noexcept {
return m_fieldsOrder.begin();
}
[[nodiscard]]
constexpr auto end() noexcept {
return m_fieldsOrder.end();
}
[[nodiscard]]
constexpr auto begin() const noexcept {
return m_fieldsOrder.begin();
}
[[nodiscard]]
constexpr auto end() const noexcept {
return m_fieldsOrder.end();
}
[[nodiscard]]
constexpr auto rbegin() noexcept {
return m_fieldsOrder.rbegin();
}
[[nodiscard]]
constexpr auto rend() noexcept {
return m_fieldsOrder.rend();
}
[[nodiscard]]
constexpr auto rbegin() const noexcept {
return m_fieldsOrder.rbegin();
}
[[nodiscard]]
constexpr auto rend() const noexcept {
return m_fieldsOrder.rend();
}
[[nodiscard]]
constexpr auto cbegin() const noexcept {
return m_fieldsOrder.cbegin();
}
[[nodiscard]]
constexpr auto cend() const noexcept {
return m_fieldsOrder.cend();
}
[[nodiscard]]
constexpr auto crbegin() const noexcept {
return m_fieldsOrder.crbegin();
}
[[nodiscard]]
constexpr auto crend() const noexcept {
return m_fieldsOrder.crend();
}
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{ox::String(f->name), f->value});
m_fields[field->name] = &field->value;
}
m_type = other.m_type;
return *this;
}
constexpr auto &operator=(ModelObject &&other) noexcept {
if (&other == this) [[unlikely]] {
return *this;
}
m_type = other.m_type;
m_fields = std::move(other.m_fields);
m_fieldsOrder = std::move(other.m_fieldsOrder);
return *this;
}
template<typename T>
constexpr auto set(const std::size_t &i, T &&val) noexcept {
auto &f = *m_fieldsOrder[i];
f = val;
}
constexpr Result<const ModelValue*> get(StringView const&k) const noexcept {
if (m_fields.contains(k)) {
return *m_fields.at(k).value;
}
return OxError(1);
}
template<typename T>
constexpr Error set(const String &k, T &&val) noexcept {
oxRequire(t, m_fields.at(k));
*t = ox::forward<T>(val);
return {};
}
constexpr auto &operator[](StringView const&k) noexcept {
auto [v, err] = m_fields.at(k);
if (err) [[unlikely]] {
oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str());
}
return **v;
}
constexpr auto &operator[](const std::size_t i) noexcept {
return *m_fieldsOrder[i];
}
[[nodiscard]]
constexpr CRString typeName() const noexcept {
return m_type->typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_type->typeVersion;
}
[[nodiscard]]
constexpr auto type() const noexcept {
return m_type;
}
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_type = type;
for (const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
oxReturnError(field->value.setType(f.type, f.subscriptLevels, f.subscriptStack));
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;
};
friend constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept;
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields;
const DescriptorType *m_type = nullptr;
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, ox::String(f->name), f->value});
m_fields[field->name] = field.get();
++i;
}
m_type = other.m_type;
m_unionIdx = other.m_unionIdx;
}
constexpr ModelUnion(ModelUnion &&other) noexcept {
m_fieldsOrder = std::move(other.m_fieldsOrder);
m_fields = std::move(other.m_fields);
m_type = other.m_type;
m_unionIdx = other.m_unionIdx;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const DescriptorType *type) noexcept {
UniquePtr<ModelUnion> out(new ModelUnion);
oxReturnError(out->setType(type));
return out;
}
static constexpr Result<UniquePtr<ModelUnion>> make(const ModelUnion &other) noexcept {
return UniquePtr<ModelUnion>(new ModelUnion(other));
}
constexpr auto &operator[](StringView const&k) noexcept {
const auto [v, err] = m_fields.at(k);
if (err) [[unlikely]] {
oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str());
}
return (*v)->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 auto set(int i, auto val) noexcept {
m_unionIdx = i;
return m_fieldsOrder[static_cast<std::size_t>(i)]->value.set(val);
}
constexpr void set(std::size_t i, auto val) noexcept {
m_unionIdx = static_cast<int>(i);
*m_fieldsOrder[i] = val;
}
[[nodiscard]]
constexpr Result<const ModelValue*> get(std::size_t i) const noexcept {
if (i < m_fieldsOrder.size()) {
return &m_fieldsOrder[i]->value;
}
return {};
}
[[nodiscard]]
constexpr Result<const ModelValue*> get(StringView const&k) const noexcept {
oxRequire(t, m_fields.at(k));
return &(*t)->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_type->typeName;
}
[[nodiscard]]
constexpr int typeVersion() const noexcept {
return m_type->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_type = type;
for (auto i = 0; const auto &f : type->fieldList) {
auto field = make_unique<Field>();
field->name = f.fieldName;
field->idx = i;
oxReturnError(field->value.setType(f.type, f.subscriptLevels));
m_fields[field->name] = field.get();
m_fieldsOrder.emplace_back(std::move(field));
++i;
}
return OxError(0);
}
[[nodiscard]]
constexpr auto fieldCount() const noexcept {
return m_fields.size();
}
[[nodiscard]]
constexpr auto unionIdx() const noexcept {
return m_unionIdx;
}
};
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(const ModelValueVector*) noexcept {
VectorMemMap<PlatSpec> v;
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(const ModelUnion*) noexcept {
VectorMemMap<PlatSpec> v;
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(const ModelValue *t) noexcept {
std::size_t size = 0;
switch (t->type()) {
case ModelValue::Type::Bool:
size = sizeof(t->get<bool>());
break;
case ModelValue::Type::Undefined:
size = 1;
break;
case ModelValue::Type::UnsignedInteger8:
size = sizeof(t->get<uint8_t>());
break;
case ModelValue::Type::UnsignedInteger16:
size = sizeof(t->get<uint16_t>());
break;
case ModelValue::Type::UnsignedInteger32:
size = sizeof(t->get<uint32_t>());
break;
case ModelValue::Type::UnsignedInteger64:
size = sizeof(t->get<uint64_t>());
break;
case ModelValue::Type::SignedInteger8:
size = sizeof(t->get<int8_t>());
break;
case ModelValue::Type::SignedInteger16:
size = sizeof(t->get<int16_t>());
break;
case ModelValue::Type::SignedInteger32:
size = sizeof(t->get<int32_t>());
break;
case ModelValue::Type::SignedInteger64:
size = sizeof(t->get<int64_t>());
break;
case ModelValue::Type::String:
size = sizeOf<PlatSpec>(&t->get<ox::String>());
break;
case ModelValue::Type::Object:
size = sizeOf<PlatSpec>(&t->get<ox::ModelObject>());
break;
case ModelValue::Type::Union:
size = sizeOf<PlatSpec>(&t->get<ox::ModelUnion>());
break;
case ModelValue::Type::Vector:
size = sizeOf<PlatSpec>(&t->get<ox::ModelValueVector>());
break;
case ModelValue::Type::InlineArray:
{
auto &list = t->get<ox::ModelValueArray>();
size = sizeOf<PlatSpec>(&list[0]) * list.size();
break;
}
}
return size;
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t alignOf(const ModelValueVector&) noexcept {
VectorMemMap<PlatSpec> v;
return alignOf<PlatSpec>(v);
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t alignOf(const ModelValue &t) noexcept {
std::size_t alignment = 0;
switch (t.type()) {
case ModelValue::Type::Bool:
alignment = PlatSpec::alignOf(t.get<bool>());
break;
case ModelValue::Type::Undefined:
alignment = 1;
break;
case ModelValue::Type::UnsignedInteger8:
alignment = PlatSpec::alignOf(t.get<uint8_t>());
break;
case ModelValue::Type::UnsignedInteger16:
alignment = PlatSpec::alignOf(t.get<uint16_t>());
break;
case ModelValue::Type::UnsignedInteger32:
alignment = PlatSpec::alignOf(t.get<uint32_t>());
break;
case ModelValue::Type::UnsignedInteger64:
alignment = PlatSpec::alignOf(t.get<uint64_t>());
break;
case ModelValue::Type::SignedInteger8:
alignment = PlatSpec::alignOf(t.get<int8_t>());
break;
case ModelValue::Type::SignedInteger16:
alignment = PlatSpec::alignOf(t.get<int16_t>());
break;
case ModelValue::Type::SignedInteger32:
alignment = PlatSpec::alignOf(t.get<int32_t>());
break;
case ModelValue::Type::SignedInteger64:
alignment = PlatSpec::alignOf(t.get<int64_t>());
break;
case ModelValue::Type::String:
alignment = alignOf<PlatSpec>(t.get<ox::String>());
break;
case ModelValue::Type::Object:
alignment = alignOf<PlatSpec>(t.get<ox::ModelObject>());
break;
case ModelValue::Type::Union:
alignment = alignOf<PlatSpec>(t.get<ox::ModelUnion>());
break;
case ModelValue::Type::Vector:
alignment = alignOf<PlatSpec>(t.get<ox::ModelValueVector>());
break;
case ModelValue::Type::InlineArray:
{
auto &list = t.get<ox::ModelValueArray>();
alignment = alignOf<PlatSpec>(list[0]);
break;
}
}
return alignment;
}
constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
oxReturnError(h->template setTypeInfo<ModelObject>(
obj->typeName().c_str(), obj->typeVersion(), {}, obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
return OxError(0);
}
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
oxReturnError(h->template setTypeInfo<ModelUnion>(
obj->typeName().c_str(), obj->typeVersion(), {}, obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
return OxError(0);
}
constexpr ModelValue::ModelValue(const ModelValue &other) noexcept {
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
break;
case Type::Union:
m_data.uni = new ModelUnion(other.get<ModelUnion>());
break;
case Type::Object:
m_data.obj = new ModelObject(other.get<ModelObject>());
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
case Type::InlineArray:
m_data.array = new ModelValueArray(*other.m_data.array);
break;
}
}
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 = other.m_data.uni;
other.m_data.uni = new ModelUnion;
break;
case Type::Object:
m_data.obj = other.m_data.obj;
other.m_data.obj = new ModelObject;
break;
case Type::Vector:
m_data.vec = other.m_data.vec;
other.m_data.vec = new ModelValueVector;
break;
case Type::InlineArray:
m_data.array = other.m_data.array;
other.m_data.array = new ModelValueArray();
break;
}
}
template<typename T>
constexpr ModelValue::ModelValue(const T &val) noexcept
requires(!ox::is_same_v<ox::remove_reference_t<T>, ModelValue>) {
oxIgnoreError(set(val));
}
template<typename T>
constexpr ModelValue::ModelValue(T &&val) noexcept
requires(!ox::is_same_v<ox::remove_reference_t<T>, ModelValue>) {
oxIgnoreError(set(ox::forward<T>(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,
SubscriptStack const&subscriptStack) noexcept {
freeResources();
if (subscriptLevels) {
auto const&subscript = subscriptStack[subscriptStack.size() - static_cast<size_t>(subscriptLevels)];
if (subscript.subscriptType == Subscript::SubscriptType::InlineArray) {
m_type = Type::InlineArray;
m_data.array = new ModelValueArray;
oxReturnError(m_data.array->setSize(static_cast<size_t>(subscript.length)));
} else {
m_type = Type::Vector;
m_data.vec = new ModelValueVector;
}
return m_data.vec->setType(type, subscriptLevels - 1, subscriptStack);
} else if (type->typeName == types::Bool) {
m_type = Type::Bool;
} else if (type->typeName == types::BasicString ||
type->typeName == types::BString ||
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));
}
oxAssert(m_type != Type::Undefined, "No type set");
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::setType() noexcept {
constexpr auto type = getType<T>();
freeResources();
m_type = type;
// 2022.09.04: Clang retardedly requires initializing the union values directly,
// rather than using getValue<type>()
if constexpr(type == Type::Object) {
m_data.obj = new ModelObject;
oxReturnError(m_data.obj->setType(type));
} else if constexpr(type == Type::Union) {
oxRequireM(u, ModelUnion::make(type));
m_data.uni = u.release();
oxReturnError(m_data.uni->setType(type));
} else if constexpr(type == Type::String) {
m_data.str = new String;
} else if constexpr(type == Type::Vector) {
m_data.vec = new ModelValueVector;
} else if constexpr(type == Type::Bool) {
m_data.b = false;
} else if constexpr(type == Type::SignedInteger8) {
m_data.i8 = 0;
} else if constexpr(type == Type::SignedInteger16) {
m_data.i16 = 0;
} else if constexpr(type == Type::SignedInteger32) {
m_data.i32 = 0;
} else if constexpr(type == Type::SignedInteger64) {
m_data.i64 = 0;
} else if constexpr(type == Type::UnsignedInteger8) {
m_data.ui8 = 0;
} else if constexpr(type == Type::UnsignedInteger16) {
m_data.ui16 = 0;
} else if constexpr(type == Type::UnsignedInteger32) {
m_data.ui32 = 0;
} else if constexpr(type == Type::UnsignedInteger64) {
m_data.ui64 = 0;
}
return {};
}
template<typename T>
constexpr Error ModelValue::set(const T &v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
type == Type::Union || type == Type::String || type == Type::InlineArray) {
safeDelete(&value);
}
value = v;
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::set(T &&v) noexcept {
constexpr auto type = getType<T>();
if (m_type != type) [[unlikely]] {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
type == Type::Union || type == Type::String || type == Type::InlineArray) {
safeDelete(&value);
}
value = std::move(v);
return OxError(0);
}
constexpr ModelValue &ModelValue::operator=(ModelValue &other) noexcept {
return this->operator=(const_cast<const ModelValue&>(other));
}
constexpr ModelValue &ModelValue::operator=(const ModelValue &other) noexcept {
if (this == &other) [[unlikely]] {
return *this;
}
freeResources();
m_type = other.m_type;
switch (m_type) {
case Type::Undefined:
case Type::Bool:
case Type::UnsignedInteger8:
case Type::UnsignedInteger16:
case Type::UnsignedInteger32:
case Type::UnsignedInteger64:
case Type::SignedInteger8:
case Type::SignedInteger16:
case Type::SignedInteger32:
case Type::SignedInteger64:
ox_memcpy(&m_data, &other.m_data, sizeof(m_data));
break;
case Type::String:
m_data.str = new String(other.get<String>());
break;
case Type::Union:
m_data.uni = new ModelUnion(other.get<ModelUnion>());
break;
case Type::Object:
m_data.obj = new ModelObject(other.get<ModelObject>());
break;
case Type::Vector:
m_data.vec = new ModelValueVector(*other.m_data.vec);
break;
case Type::InlineArray:
m_data.array = new ModelValueArray(*other.m_data.array);
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 = other.m_data.obj;
other.m_data.obj = new ModelObject;
break;
case Type::Union:
m_data.uni = other.m_data.uni;
other.m_data.uni = new ModelUnion;
break;
case Type::Vector:
m_data.vec = other.m_data.vec;
other.m_data.vec = new ModelValueVector;
break;
case Type::InlineArray:
m_data.array = other.m_data.array;
other.m_data.array = new ModelValueArray;
break;
}
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;
case Type::InlineArray:
safeDelete(m_data.array);
break;
}
m_type = Type::Undefined;
}
constexpr ModelValueVector::ModelValueVector(const ModelValueVector &other) noexcept {
for (auto &v : other.m_vec) {
m_vec.emplace_back(v);
}
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
m_vec = std::move(other.m_vec);
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_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
}
constexpr ModelValueVector &ModelValueVector::operator=(ModelValueVector &&other) noexcept {
if (this == &other) {
return *this;
}
m_vec = std::move(other.m_vec);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
return *this;
}
}