#pragma once #include "compat/integer-types.hpp" #include #include #include #include #include #include namespace floormat {} namespace floormat::entities { template struct pass_by_value : std::bool_constant> {}; template<> struct pass_by_value : std::true_type {}; template constexpr inline bool pass_by_value_v = pass_by_value::value; template using const_qualified = std::conditional_t, T, const T&>; template using ref_qualified = std::conditional_t, T, T&>; template using move_qualified = std::conditional_t, T, T&&>; template concept FieldReader_memfn = requires(const T x, F f) { { (x.*f)() } -> std::convertible_to; }; template concept FieldReader_ptr = requires(const T x, F f) { { x.*f } -> std::convertible_to; }; template concept FieldReader_function = requires(const T x, F f) { { f(x) } -> std::convertible_to; }; template concept FieldReader = requires { requires FieldReader_memfn || FieldReader_ptr || FieldReader_function; }; template concept FieldWriter_memfn = requires(T x, move_qualified value, F f) { { (x.*f)(value) } -> std::same_as; }; template concept FieldWriter_ptr = requires(T x, move_qualified value, F f) { { x.*f = value }; }; template concept FieldWriter_function = requires(T x, move_qualified value, F f) { { f(x, value) } -> std::same_as; }; template concept FieldWriter = requires { requires FieldWriter_memfn || FieldWriter_ptr || FieldWriter_function; }; namespace detail { template R> struct read_field { static constexpr Type read(const Obj& x, R r) { return r(x); } }; template struct read_field { static constexpr Type read(const Obj& x, Type (Obj::*r)() const) { return (x.*r)(); } }; template struct read_field { static constexpr Type read(const Obj& x, Type Obj::*r) { return x.*r; } }; template W> struct write_field { static constexpr void write(Obj& x, W w, move_qualified value) { w(x, value); } }; template struct write_field)> { static constexpr void write(Obj& x, void(Obj::*w)(move_qualified), move_qualified value) { (x.*w)(value); } }; template struct write_field { static constexpr void write(Obj& x, FieldType Obj::* w, move_qualified value) { x.*w = value; } }; } // namespace detail struct EntityBase {}; template struct Entity final : EntityBase { static_assert(std::is_same_v>); struct type_base {}; template struct type final : type_base { static_assert(std::is_same_v>); struct field_base {}; template R, FieldWriter W> struct field final : field_base { using ObjectType = Obj; using FieldType = Type; using Reader = R; using Writer = W; StringView name; [[no_unique_address]] Reader reader; [[no_unique_address]] Writer writer; constexpr field(const field&) = default; constexpr field& operator=(const field&) = default; constexpr decltype(auto) read(const Obj& x) const { return detail::read_field::read(x, reader); } constexpr void write(Obj& x, move_qualified v) const { detail::write_field::write(x, writer, v); } constexpr field(StringView name, Reader r, Writer w) noexcept : name{name}, reader{r}, writer{w} {} }; template R, FieldWriter W> field(StringView name, R r, W w) -> field; }; }; namespace detail { template requires std::invocable(std::declval()))> constexpr CORRADE_ALWAYS_INLINE void visit_tuple(F&& fun, Tuple&& tuple) { using Size = std::tuple_size>; static_assert(N < Size()); fun(std::get(tuple)); if constexpr(N+1 < Size()) visit_tuple(std::forward(fun), std::forward(tuple)); } template requires std::is_invocable_r_v(std::declval()))> constexpr CORRADE_ALWAYS_INLINE bool find_in_tuple(F&& fun, Tuple&& tuple) { using Size = std::tuple_size>; static_assert(N < Size()); if (fun(std::get(tuple))) return true; if constexpr(N+1 < Size()) return find_in_tuple(std::forward(fun), std::forward(tuple)); return false; } template class F, typename Acc, typename T, typename... Fs> struct reduce0_; template class F, typename Acc, template class T, typename... Fs> struct reduce0_, Fs...> { using type = Acc; }; template class F, typename Acc, template class X, typename T, typename... Ts, typename... Fs> struct reduce0_, Fs...> { using type = typename reduce0_< F, F, X, Fs... >::type; }; template class F, typename XC, typename... Fs> struct reduce_; template class F, template class X, typename T1, typename... Ts, typename... Fs> struct reduce_, Fs...> { using type = typename reduce0_< F, T1, X, Fs... >::type; }; template class F, typename T, typename... Fs> using reduce = typename reduce_::type; template struct parameter_pack; template typename C, typename... Args2> struct lift_; template class C, template class T, typename... Args, typename... CArgs> struct lift_, C, CArgs...> { using type = C; }; template class C, typename... CArgs> using lift = typename lift_::type; template class F, template class C, typename T, typename... Us> struct map_; template class F, template class C, template class X, typename... Ts, typename... Us> struct map_, Us...> { using type = C...>; }; template class F, typename X, typename... Us> using map = typename map_::type; } // namespace detail template constexpr void visit_tuple(F&& fun, Tuple&& tuple) { using Size = std::tuple_size>; if constexpr(Size() > 0) detail::visit_tuple(std::forward(fun), std::forward(tuple)); } template constexpr bool find_in_tuple(F&& fun, Tuple&& tuple) { using Size = std::tuple_size>; if constexpr(Size() > 0) return detail::find_in_tuple(std::forward(fun), std::forward(tuple)); else return false; } enum class erased_field_type : std::uint32_t { none, string, u8, u16, u32, u64, s8, s16, s32, s64, user_type_start, MAX = (1u << 31) - 1u, DYNAMIC = (std::uint32_t)-1, }; template struct type_of_erased_field; template struct erased_field_type_v_ : std::integral_constant {}; #define FM_ERASED_FIELD_TYPE(TYPE, ENUM) \ template<> struct erased_field_type_v_ : std::integral_constant {}; \ template<> struct type_of_erased_field { using type = TYPE; } FM_ERASED_FIELD_TYPE(std::uint8_t, u8); FM_ERASED_FIELD_TYPE(std::uint16_t, u16); FM_ERASED_FIELD_TYPE(std::uint32_t, u32); FM_ERASED_FIELD_TYPE(std::uint64_t, u64); FM_ERASED_FIELD_TYPE(std::int8_t, s8); FM_ERASED_FIELD_TYPE(std::int16_t, s16); FM_ERASED_FIELD_TYPE(std::int32_t, s32); FM_ERASED_FIELD_TYPE(std::int64_t, s64); FM_ERASED_FIELD_TYPE(StringView, string); #undef FM_ERASED_FIELD_TYPE } // namespace floormat::entities