405 lines
13 KiB
C++
405 lines
13 KiB
C++
/*
|
|
* Copyright 2015 - 2025 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/byteswap.hpp>
|
|
#include <ox/std/istring.hpp>
|
|
#include <ox/std/memory.hpp>
|
|
#include <ox/std/string.hpp>
|
|
#include <ox/std/trace.hpp>
|
|
#include <ox/std/types.hpp>
|
|
#include <ox/std/vector.hpp>
|
|
|
|
#include "desctypes.hpp"
|
|
#include "fieldcounter.hpp"
|
|
#include "metadata.hpp"
|
|
#include "modelhandleradaptor.hpp"
|
|
#include "optype.hpp"
|
|
#include "typenamecatcher.hpp"
|
|
#include "types.hpp"
|
|
#include "typestore.hpp"
|
|
|
|
namespace ox {
|
|
|
|
namespace detail {
|
|
|
|
template<typename T>
|
|
constexpr int indirectionLevels_v = 0;
|
|
|
|
template<typename T>
|
|
constexpr int indirectionLevels_v<T*> = 1 + indirectionLevels_v<T>;
|
|
|
|
template<typename T, std::size_t sz>
|
|
constexpr int indirectionLevels_v<T[sz]> = 1 + indirectionLevels_v<T>;
|
|
|
|
template<typename T, std::size_t SmallVecSz>
|
|
constexpr int indirectionLevels_v<::ox::Vector<T, SmallVecSz>> = 1 + indirectionLevels_v<T>;
|
|
|
|
template<typename T>
|
|
constexpr auto buildSubscriptStack(const T*, SubscriptStack*) noexcept {
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr auto buildSubscriptStack(const T**, SubscriptStack *s) noexcept {
|
|
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr auto buildSubscriptStack(const UniquePtr<T>*, SubscriptStack *s) noexcept {
|
|
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
|
|
}
|
|
|
|
template<typename T, std::size_t sz>
|
|
constexpr auto buildSubscriptStack(const Array<T, sz>*, SubscriptStack *s) noexcept {
|
|
s->push_back({.subscriptType = Subscript::SubscriptType::InlineArray, .length = sz});
|
|
buildSubscriptStack(static_cast<T*>(nullptr), s);
|
|
}
|
|
|
|
template<typename T, std::size_t SmallVecSz>
|
|
constexpr auto buildSubscriptStack(const Vector<T, SmallVecSz>*, SubscriptStack *s) noexcept {
|
|
s->push_back({
|
|
.subscriptType = Subscript::SubscriptType::Vector,
|
|
.smallSzLen = SmallVecSz,
|
|
});
|
|
buildSubscriptStack(static_cast<T*>(nullptr), s);
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr auto buildSubscriptStack(const T*) {
|
|
SubscriptStack s;
|
|
buildSubscriptStack(static_cast<const T*>(nullptr), &s);
|
|
return s;
|
|
}
|
|
|
|
}
|
|
|
|
class TypeDescWriter {
|
|
|
|
private:
|
|
TypeStore *m_typeStore = nullptr;
|
|
DescriptorType *m_type = nullptr;
|
|
|
|
public:
|
|
explicit constexpr TypeDescWriter(TypeStore *typeStore = nullptr) noexcept;
|
|
|
|
constexpr ~TypeDescWriter() noexcept = default;
|
|
|
|
template<typename T = std::nullptr_t>
|
|
constexpr ox::Error setTypeInfo(StringViewCR name = T::TypeName,
|
|
int version = T::TypeVersion,
|
|
const TypeParamPack &typeParams = {},
|
|
std::size_t fields = ModelFieldCount_v<T>) noexcept;
|
|
|
|
template<typename T>
|
|
constexpr Error field(
|
|
StringViewCR name,
|
|
T const*val,
|
|
std::size_t valLen,
|
|
SubscriptStack const&subscriptStack) noexcept;
|
|
|
|
template<typename T>
|
|
constexpr Error field(StringViewCR name, T const*val, std::size_t valLen) noexcept;
|
|
|
|
template<typename T, bool force>
|
|
constexpr Error field(StringViewCR name, UnionView<T, force> val) noexcept;
|
|
|
|
template<typename T>
|
|
constexpr Error field(StringViewCR name, const T *val) noexcept;
|
|
|
|
template<typename ...Args>
|
|
constexpr Error fieldCString(StringViewCR name, Args&&...) noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr DescriptorType *definition() noexcept {
|
|
return m_type;
|
|
}
|
|
|
|
static constexpr auto opType() noexcept {
|
|
return OpType::Reflect;
|
|
}
|
|
|
|
private:
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const int8_t *val) const noexcept;
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const int16_t *val) const noexcept;
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const int32_t *val) const noexcept;
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const int64_t *val) const noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const uint8_t *val) const noexcept;
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const uint16_t *val) const noexcept;
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const uint32_t *val) const noexcept;
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const uint64_t *val) const noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const bool *val) const noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const char *val) const noexcept;
|
|
|
|
template<std::size_t SmallStrSz>
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const BasicString<SmallStrSz>*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::String;
|
|
return getType(types::BasicString, 1, PT, 0, {sfmt("{}", SmallStrSz)});
|
|
}
|
|
|
|
template<std::size_t sz>
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const IString<sz> *val) const noexcept;
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const T *val) const noexcept;
|
|
|
|
template<typename T>
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(const HashMap<String, T> *val) const noexcept;
|
|
|
|
template<typename U>
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *type(UnionView<U> val) const noexcept;
|
|
|
|
[[nodiscard]]
|
|
constexpr const DescriptorType *getType(StringViewCR tn, int typeVersion, PrimitiveType t, int b,
|
|
const TypeParamPack &typeParams = {}) const noexcept;
|
|
|
|
};
|
|
|
|
constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {}
|
|
|
|
template<typename T>
|
|
constexpr ox::Error TypeDescWriter::setTypeInfo(
|
|
StringViewCR typeName, int typeVersion,
|
|
const TypeParamPack &typeParams, std::size_t) noexcept {
|
|
PrimitiveType pt;
|
|
if constexpr(is_union_v<T>) {
|
|
pt = PrimitiveType::Union;
|
|
} else if constexpr(isBasicString_v<T> || isBString_v<T>) {
|
|
pt = PrimitiveType::String;
|
|
} else {
|
|
pt = PrimitiveType::Struct;
|
|
}
|
|
m_type = m_typeStore->getInit(typeName, typeVersion, pt, typeParams);
|
|
m_type->preloadable = preloadable<T>::value;
|
|
return {};
|
|
}
|
|
|
|
// array handler
|
|
template<typename T>
|
|
constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t, SubscriptStack const&subscriptStack) noexcept {
|
|
if (m_type) {
|
|
constexpr typename remove_pointer<T>::type *p = nullptr;
|
|
const auto t = type(p);
|
|
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
|
|
m_type->fieldList.emplace_back(t, String(name), detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t));
|
|
return ox::Error(0);
|
|
}
|
|
return ox::Error(1);
|
|
}
|
|
|
|
// array handler
|
|
template<typename T>
|
|
constexpr Error TypeDescWriter::field(StringViewCR name, T const*, std::size_t) noexcept {
|
|
if (m_type) {
|
|
constexpr typename remove_pointer<T>::type *p = nullptr;
|
|
const auto t = type(p);
|
|
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
|
|
auto const lvls = detail::indirectionLevels_v<T> + 1;
|
|
SubscriptStack subscriptStack{lvls};
|
|
m_type->fieldList.emplace_back(t, String(name), lvls, subscriptStack, buildTypeId(*t));
|
|
return ox::Error(0);
|
|
}
|
|
return ox::Error(1);
|
|
}
|
|
|
|
template<typename T, bool force>
|
|
constexpr Error TypeDescWriter::field(StringViewCR name, UnionView<T, force> val) noexcept {
|
|
if (m_type) {
|
|
const auto t = type(val);
|
|
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
|
|
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
|
|
return ox::Error(0);
|
|
}
|
|
return ox::Error(1);
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr Error TypeDescWriter::field(StringViewCR name, const T *val) noexcept {
|
|
if (m_type) {
|
|
if constexpr(isVector_v<T> || isArray_v<T>) {
|
|
typename T::value_type *data = nullptr;
|
|
return field(name, data, 0, detail::buildSubscriptStack(val));
|
|
} else if constexpr(isSmartPtr_v<T>) {
|
|
typename T::value_type *data = nullptr;
|
|
return field(name, data, 0, detail::buildSubscriptStack(val));
|
|
} else if constexpr(is_pointer_v<T>) {
|
|
return field(name, val, 0, detail::buildSubscriptStack(val));
|
|
} else {
|
|
const auto t = type(val);
|
|
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
|
|
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, buildTypeId(*t));
|
|
return {};
|
|
}
|
|
}
|
|
return ox::Error(1);
|
|
}
|
|
|
|
template<typename ...Args>
|
|
constexpr Error TypeDescWriter::fieldCString(StringViewCR name, Args&&...) noexcept {
|
|
constexpr auto s = "";
|
|
const auto t = type(s);
|
|
m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
|
|
return {};
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr const DescriptorType *TypeDescWriter::type(const T *val) const noexcept {
|
|
if constexpr(isVector_v<T>) {
|
|
return type(static_cast<typename T::value_type*>(nullptr));
|
|
} else {
|
|
auto [t, err] = m_typeStore->template get<T>();
|
|
if (!err) {
|
|
return t;
|
|
} else {
|
|
TypeDescWriter dw(m_typeStore);
|
|
const auto reflectErr = model(&dw, val);
|
|
oxLogError(reflectErr);
|
|
oxAssert(reflectErr, "field(const char *name, T val): Type info could not be generated");
|
|
return dw.m_type;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr const DescriptorType *TypeDescWriter::type(const HashMap<String, T>*) const noexcept {
|
|
return type(static_cast<T*>(nullptr));
|
|
}
|
|
|
|
template<typename U>
|
|
constexpr const DescriptorType *TypeDescWriter::type(UnionView<U> val) const noexcept {
|
|
const auto t = type(val.get());
|
|
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
|
|
return t;
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const int8_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::SignedInteger;
|
|
constexpr auto Bytes = 1;
|
|
return getType(types::Int8, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const int16_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::SignedInteger;
|
|
constexpr auto Bytes = 2;
|
|
return getType(types::Int16, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const int32_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::SignedInteger;
|
|
constexpr auto Bytes = 4;
|
|
return getType(types::Int32, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const int64_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::SignedInteger;
|
|
constexpr auto Bytes = 8;
|
|
return getType(types::Int64, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const uint8_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
|
constexpr auto Bytes = 1;
|
|
return getType(types::Uint8, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const uint16_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
|
constexpr auto Bytes = 2;
|
|
return getType(types::Uint16, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const uint32_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
|
constexpr auto Bytes = 4;
|
|
return getType(types::Uint32, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const uint64_t*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::UnsignedInteger;
|
|
constexpr auto Bytes = 8;
|
|
return getType(types::Uint64, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const bool*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::Bool;
|
|
constexpr auto Bytes = 0;
|
|
return getType(types::Bool, 0, PT, Bytes);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::String;
|
|
return getType(types::String, 0, PT, 0);
|
|
}
|
|
|
|
template<std::size_t sz>
|
|
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
|
|
constexpr auto PT = PrimitiveType::String;
|
|
return getType(types::BString, 0, PT, 0);
|
|
}
|
|
|
|
constexpr const DescriptorType *TypeDescWriter::getType(StringViewCR tn, int typeVersion, PrimitiveType pt, int b,
|
|
const TypeParamPack &typeParams) const noexcept {
|
|
auto t = m_typeStore->get(tn, typeVersion, typeParams);
|
|
if (!t.error) {
|
|
auto type = t.value;
|
|
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
|
|
return type;
|
|
} else {
|
|
auto dt = ox::make_unique<DescriptorType>(String(tn), typeVersion, pt, typeParams);
|
|
dt->length = b;
|
|
const auto out = dt.get();
|
|
const auto typeId = buildTypeId(tn, typeVersion, typeParams);
|
|
m_typeStore->set(typeId, std::move(dt));
|
|
return out;
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore) noexcept {
|
|
TypeDescWriter writer(&typeStore);
|
|
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
|
|
if (std::is_constant_evaluated()) {
|
|
std::allocator<T> a;
|
|
T *t = a.allocate(1);
|
|
OX_RETURN_ERROR(model(&handler, t));
|
|
a.deallocate(t, 1);
|
|
} else {
|
|
auto t = ox_malloca(sizeof(T), T);
|
|
OX_RETURN_ERROR(model(&handler, t.get()));
|
|
}
|
|
return writer.definition();
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr Result<DescriptorType*> buildTypeDef(TypeStore &typeStore, T &val) noexcept {
|
|
TypeDescWriter writer(&typeStore);
|
|
ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
|
|
OX_RETURN_ERROR(model(&handler, &val));
|
|
return writer.definition();
|
|
}
|
|
|
|
}
|