nostalgia/deps/ox/src/ox/model/modelops.hpp

304 lines
6.4 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/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/types.hpp>
#include <ox/std/utility.hpp>
#include "fieldcounter.hpp"
#include "modelvalue.hpp"
#include "optype.hpp"
#include "types.hpp"
namespace ox {
namespace detail {
class Wrap {
public:
virtual ~Wrap() = default;
};
template<typename T>
class WrapT: public Wrap {
private:
T *m_obj = nullptr;
public:
constexpr WrapT(T *obj) noexcept: m_obj(obj) {
}
constexpr WrapT() = default;
[[nodiscard]]
constexpr auto obj() noexcept {
return m_obj;
}
};
template<std::size_t size>
class MemberList {
private:
std::size_t m_i = 0;
public:
Array<void*, size> vars;
template<typename T>
constexpr Error field(const char*, T *v) noexcept {
vars[m_i++] = static_cast<void*>(v);
return OxError(0);
}
template<typename T>
constexpr Error field(const char*, T *v, int) noexcept {
vars[m_i++] = static_cast<void*>(v);
return OxError(0);
}
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
vars[m_i++] = static_cast<void*>(u.get());
return OxError(0);
}
template<typename T>
constexpr ox::Error setTypeInfo(
const char* = T::TypeName,
int = T::TypeVersion,
const Vector<String>& = {},
std::size_t = ModelFieldCount_v<T>) noexcept {
return {};
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Reflect;
}
};
template<std::size_t size>
class Copier {
private:
std::size_t m_i = 0;
MemberList<size> *m_dst = nullptr;
public:
constexpr explicit Copier(MemberList<size> *dst) noexcept: m_dst(dst) {
}
template<typename FT>
constexpr Error field(const char *name, const FT *v) noexcept {
if constexpr(isVector_v<FT>) {
return field(name, v->data(), v->size());
} else {
auto &src = *v;
auto &dst = *cbit_cast<FT*>(m_dst->vars[m_i]);
dst = src;
++m_i;
return OxError(0);
}
}
template<typename FT>
constexpr Error field(const char*, const FT *list, int elements) {
for (auto i = 0l; i < elements; ++i) {
auto &src = list[i];
auto &dst = cbit_cast<FT*>(m_dst->vars[m_i])[i];
dst = src;
}
++m_i;
return OxError(0);
}
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) {
auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]);
auto &src = *u.get();
dst = src;
++m_i;
return OxError(0);
}
template<typename T = void>
constexpr ox::Error setTypeInfo(
const char* = T::TypeName,
int = T::TypeVersion,
const Vector<String>& = {},
int = ModelFieldCount_v<T>) noexcept {
return {};
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Read;
}
};
template<std::size_t size>
class Mover {
private:
std::size_t m_i = 0;
MemberList<size> *m_dst = nullptr;
public:
constexpr explicit Mover(MemberList<size> *dst) noexcept: m_dst(dst) {
}
template<typename FT>
constexpr Error field(const char *name, FT *v) noexcept {
if constexpr(isVector_v<FT>) {
return field(name, v->data(), v->size());
} else {
auto &src = *v;
auto &dst = *cbit_cast<FT*>(m_dst->vars[m_i]);
dst = std::move(src);
src = FT{};
++m_i;
return OxError(0);
}
}
template<typename FT>
constexpr Error field(const char*, FT *list, int elements) noexcept {
for (auto i = 0l; i < elements; ++i) {
auto &src = list[i];
auto &dst = cbit_cast<FT*>(m_dst->vars[m_i])[i];
dst = std::move(src);
src = FT{};
}
++m_i;
return OxError(0);
}
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
auto &dst = *cbit_cast<U*>(m_dst->vars[m_i]);
auto &src = *u.get();
dst = std::move(src);
++m_i;
return OxError(0);
}
template<typename T = void>
constexpr ox::Error setTypeInfo(
const char* = T::TypeName,
int = T::TypeVersion,
const Vector<String>& = {},
int = ModelFieldCount_v<T>) noexcept {
return {};
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Read;
}
};
template<std::size_t size>
class Equals {
private:
std::size_t m_i = 0;
MemberList<size> *m_other = nullptr;
public:
bool value = false;
constexpr Equals(MemberList<size> *other) noexcept: m_other(other) {
}
template<typename FT>
constexpr Error field(const char*, const FT *v) noexcept {
const auto &src = *v;
const auto &dst = std::bit_cast<FT>(*m_other->vars[m_i]);
++m_i;
if (dst == src) {
return OxError(0);
} else {
this->value = false;
return OxError(1);
}
}
template<typename FT>
constexpr Error field(const char*, const FT *list, int elements) noexcept {
for (auto i = 0l; i < elements; ++i) {
const auto &src = list[i];
const auto &dst = cbit_cast<FT*>(m_other->vars[m_i])[i];
if (!(dst == src)) {
this->value = false;
return OxError(1);
}
}
++m_i;
return OxError(0);
}
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> u) noexcept {
const auto &dst = *cbit_cast<U*>(m_other->vars[m_i]);
const auto &src = *u.get();
++m_i;
if (dst == src) {
return OxError(0);
} else {
this->value = false;
return OxError(1);
}
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Read;
}
};
}
template<typename T>
constexpr void moveModel(T *dst, T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&mover, src));
}
template<typename T>
constexpr void copyModel(T *dst, const T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&copier, src));
}
template<typename T>
[[nodiscard]]
constexpr bool equalsModel(T *a, T *b) noexcept {
constexpr auto size = T::Fields;
detail::MemberList<size> aFields;
detail::Equals<size> equals(&aFields);
oxIgnoreError(model(&aFields, a));
oxIgnoreError(model(&equals, b));
return equals.value;
}
}