summaryrefslogtreecommitdiffhomepage
path: root/entity/metadata.hpp
blob: 8e3b41d3369ed76799039bdb4591f3113e02bc77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#pragma once
#include "name-of.hpp"
#include "accessor.hpp"
#include "field.hpp"
#include "concepts.hpp"
#include <utility>
#include <array>
#include <compat/function2.hpp>
#include <Corrade/Containers/StringView.h>

namespace floormat::entities::detail {

template<typename F, typename Tuple, size_t N>
requires std::invocable<F, decltype(std::get<N>(std::declval<Tuple>()))>
constexpr CORRADE_ALWAYS_INLINE void visit_tuple(F&& fun, Tuple&& tuple)
{
    using Size = std::tuple_size<std::remove_cvref_t<Tuple>>;
    static_assert(N < Size());

    fun(std::get<N>(tuple));
    if constexpr(N+1 < Size())
        visit_tuple<F, Tuple, N+1>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
}

template<typename F, typename Tuple, size_t N>
requires std::is_invocable_r_v<bool, F, decltype(std::get<N>(std::declval<Tuple>()))>
constexpr CORRADE_ALWAYS_INLINE bool find_in_tuple(F&& fun, Tuple&& tuple)
{
    using Size = std::tuple_size<std::remove_cvref_t<Tuple>>;
    static_assert(N < Size());

    if (fun(std::get<N>(tuple)))
        return true;
    if constexpr(N+1 < Size())
        return find_in_tuple<F, Tuple, N+1>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
    return false;
}

template<typename T> struct decay_tuple_;
template<typename... Ts> struct decay_tuple_<std::tuple<Ts...>> { using type = std::tuple<std::decay_t<Ts>...>; };
template<typename T> using decay_tuple = typename decay_tuple_<T>::type;

} // namespace floormat::entities::detail

namespace floormat::entities {

template<typename F, typename Tuple>
constexpr void visit_tuple(F&& fun, Tuple&& tuple)
{
    using Size = std::tuple_size<std::decay_t<Tuple>>;
    if constexpr(Size() > 0)
        detail::visit_tuple<F, Tuple, 0>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
}

template<typename F, typename Tuple>
constexpr bool find_in_tuple(F&& fun, Tuple&& tuple)
{
    using Size = std::tuple_size<std::decay_t<Tuple>>;
    if constexpr(Size() > 0)
        return detail::find_in_tuple<F, Tuple, 0>(floormat::forward<F>(fun), floormat::forward<Tuple>(tuple));
    else
        return false;
}

struct inspect_intent_t   {};
struct serialize_intent_t {};
struct report_intent_t    {};

template<typename T, typename Intent> struct entity_accessors;

template<typename Obj>
struct Entity final {
    static_assert(std::is_same_v<Obj, std::decay_t<Obj>>);

    template<typename Type>
    struct type final
    {
        template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
        struct field final : entity_field<Obj, Type, R, W, Ts...>
        {
            constexpr field(StringView field_name, R r, W w, Ts&&... ts) noexcept :
                entity_field<Obj, Type, R, W, Ts...>{field_name, r, w, floormat::forward<Ts>(ts)...}
            {}
        };

        template<FieldReader<Obj, Type> R, FieldWriter<Obj, Type> W, typename... Ts>
        field(StringView name, R r, W w, Ts&&... ts) -> field<R, W, Ts...>;
    };
};

constexpr inline auto ignored_write = []<typename O, typename T>(O&, T) {};

} // namespace floormat::entities

namespace floormat {

template<typename T, typename Intent>
class entity_metadata final {
    static_assert(std::is_same_v<T, std::decay_t<T>>);

    template<typename Tuple, std::size_t... Ns>
    static consteval auto erased_helper(const Tuple& tuple, std::index_sequence<Ns...>);

public:
    static constexpr StringView class_name = name_of<T>;
    static constexpr auto accessors = entities::entity_accessors<T, Intent>::accessors();
    static constexpr size_t size = std::tuple_size_v<std::decay_t<decltype(accessors)>>;
    static constexpr auto erased_accessors = erased_helper(accessors, std::make_index_sequence<size>{});

    entity_metadata() = default;
};

template<typename T, typename Intent>
template<typename Tuple, std::size_t... Ns>
consteval auto entity_metadata<T, Intent>::erased_helper(const Tuple& tuple, std::index_sequence<Ns...>)
{
    std::array<entities::erased_accessor, sizeof...(Ns)> array { std::get<Ns>(tuple).erased()..., };
    return array;
}

} // namespace floormat