EnTT: src/entt/poly/poly.hpp Source File

EnTT 3.15.0

Loading...
Searching...
No Matches
poly.hpp
1#ifndef ENTT_POLY_POLY_HPP
2#define ENTT_POLY_POLY_HPP
3
4#include <cstddef>
5#include <functional>
6#include <tuple>
7#include <type_traits>
8#include <utility>
9#include "../core/any.hpp"
10#include "../core/type_info.hpp"
11#include "../core/type_traits.hpp"
12#include "fwd.hpp"
13
14namespace entt {
15
17 struct poly_inspector {
22 template<typename Type>
23 operator Type &&() const;
24
32 template<std::size_t Member, typename... Args>
33 [[nodiscard]] poly_inspector invoke(Args &&...args) const;
34
36 template<std::size_t Member, typename... Args>
37 [[nodiscard]] poly_inspector invoke(Args &&...args);
38};
39
46template<typename Concept, std::size_t Len, std::size_t Align>
47 class poly_vtable {
48 using inspector = typename Concept::template type<poly_inspector>;
49
50 template<typename Ret, typename Clazz, typename... Args>
51 static auto vtable_entry(Ret (*)(Clazz &, Args...))
52 -> std::enable_if_t<std::is_base_of_v<std::remove_const_t<Clazz>, inspector>, Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...)>;
53
54 template<typename Ret, typename... Args>
55 static auto vtable_entry(Ret (*)(Args...))
56 -> Ret (*)(const basic_any<Len, Align> &, Args...);
57
58 template<typename Ret, typename Clazz, typename... Args>
59 static auto vtable_entry(Ret (Clazz::*)(Args...))
60 -> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(basic_any<Len, Align> &, Args...)>;
61
62 template<typename Ret, typename Clazz, typename... Args>
63 static auto vtable_entry(Ret (Clazz::*)(Args...) const)
64 -> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(const basic_any<Len, Align> &, Args...)>;
65
66 template<auto... Candidate>
67 static auto make_vtable(value_list<Candidate...>) noexcept
68 -> decltype(std::make_tuple(vtable_entry(Candidate)...));
69
70 template<typename... Func>
71 [[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) noexcept {
72 if constexpr(sizeof...(Func) == 0u) {
73 return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
74 } else if constexpr((std::is_function_v<Func> && ...)) {
75 return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector::*>())...)){};
76 }
77 }
78
79 template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
80 static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept {
81 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
82 entry = +[](Any &, Args... args) -> Ret {
83 return std::invoke(Candidate, std::forward<Args>(args)...);
84 };
85 } else {
86 entry = +[](Any &instance, Args... args) -> Ret {
87 return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), std::forward<Args>(args)...));
88 };
89 }
90 }
91
92 template<typename Type, auto... Index>
93 [[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) noexcept {
94 vtable_type impl{};
95 (fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
96 return impl;
97 }
98
99 using vtable_type = decltype(make_vtable(Concept{}));
100 static constexpr bool is_mono = std::tuple_size_v<vtable_type> == 1u;
101
102public:
104 using type = std::conditional_t<is_mono, std::tuple_element_t<0u, vtable_type>, const vtable_type *>;
105
111 template<typename Type>
112 [[nodiscard]] static type instance() noexcept {
113 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
114 static const vtable_type vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
115
116 if constexpr(is_mono) {
117 return std::get<0>(vtable);
118 } else {
119 return &vtable;
120 }
121 }
122};
123
128template<typename Poly>
129 struct poly_base {
138 template<std::size_t Member, typename... Args>
139 [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const {
140 const auto &poly = static_cast<const Poly &>(self);
141
142 if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
143 return poly.vtable(poly.storage, std::forward<Args>(args)...);
144 } else {
145 return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
146 }
147 }
148
150 template<std::size_t Member, typename... Args>
151 [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) {
152 auto &poly = static_cast<Poly &>(self);
153
154 if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
155 static_assert(Member == 0u, "Unknown member");
156 return poly.vtable(poly.storage, std::forward<Args>(args)...);
157 } else {
158 return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
159 }
160 }
161};
162
172template<std::size_t Member, typename Poly, typename... Args>
173 decltype(auto) poly_call(Poly &&self, Args &&...args) {
174 return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
175}
176
192template<typename Concept, std::size_t Len, std::size_t Align>
193 class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
194 friend struct poly_base<basic_poly>;
195
196public:
198 using concept_type = typename Concept::template type<poly_base<basic_poly>>;
200 using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
201
203 basic_poly() noexcept = default;
204
211 template<typename Type, typename... Args>
212 explicit basic_poly(std::in_place_type_t<Type>, Args &&...args)
213 : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
214 vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>()} {}
215
221 template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
222 basic_poly(Type &&value) noexcept
223 : basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
224
229 [[nodiscard]] const type_info &type() const noexcept {
230 return storage.type();
231 }
232
237 [[nodiscard]] const void *data() const noexcept {
238 return storage.data();
239 }
240
242 [[nodiscard]] void *data() noexcept {
243 return storage.data();
244 }
245
252 template<typename Type, typename... Args>
253 void emplace(Args &&...args) {
254 storage.template emplace<Type>(std::forward<Args>(args)...);
255 vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>();
256 }
257
259 void reset() {
260 storage.reset();
261 vtable = {};
262 }
263
268 [[nodiscard]] explicit operator bool() const noexcept {
269 return static_cast<bool>(storage);
270 }
271
276 [[nodiscard]] concept_type *operator->() noexcept {
277 return this;
278 }
279
281 [[nodiscard]] const concept_type *operator->() const noexcept {
282 return this;
283 }
284
289 [[nodiscard]] basic_poly as_ref() noexcept {
290 basic_poly ref{};
291 ref.storage = storage.as_ref();
292 ref.vtable = vtable;
293 return ref;
294 }
295
297 [[nodiscard]] basic_poly as_ref() const noexcept {
298 basic_poly ref{};
299 ref.storage = storage.as_ref();
300 ref.vtable = vtable;
301 return ref;
302 }
303
304private:
305 basic_any<Len, Align> storage{};
306 vtable_type vtable{};
307};
308
309} // namespace entt
310
311#endif
entt::basic_any
A SBO friendly, type-safe container for single values of any type.
Definition any.hpp:38
entt::basic_poly::type
const type_info & type() const noexcept
Returns the object type if any, type_id<void>() otherwise.
Definition poly.hpp:229
entt::basic_poly::as_ref
basic_poly as_ref() noexcept
Aliasing constructor.
Definition poly.hpp:289
entt::basic_poly::data
void * data() noexcept
Returns an opaque pointer to the contained instance.
Definition poly.hpp:242
entt::basic_poly::reset
void reset()
Destroys contained object.
Definition poly.hpp:259
entt::basic_poly::operator->
concept_type * operator->() noexcept
Returns a pointer to the underlying concept.
Definition poly.hpp:276
entt::basic_poly::emplace
void emplace(Args &&...args)
Replaces the contained object by creating a new instance directly.
Definition poly.hpp:253
entt::basic_poly< Concept >::concept_type
typename Concept::template type< poly_base< basic_poly > > concept_type
Definition poly.hpp:198
entt::basic_poly::as_ref
basic_poly as_ref() const noexcept
Aliasing constructor.
Definition poly.hpp:297
entt::basic_poly::operator->
const concept_type * operator->() const noexcept
Returns a pointer to the underlying concept.
Definition poly.hpp:281
entt::basic_poly::basic_poly
basic_poly(Type &&value) noexcept
Constructs a poly from a given value.
Definition poly.hpp:222
entt::basic_poly< Concept >::vtable_type
typename poly_vtable< Concept, Len, Align >::type vtable_type
Definition poly.hpp:200
entt::basic_poly::data
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
Definition poly.hpp:237
entt::basic_poly::basic_poly
basic_poly() noexcept=default
Default constructor.
entt::poly_vtable
Static virtual table factory.
Definition poly.hpp:47
entt::poly_vtable::instance
static type instance() noexcept
Returns a static virtual table for a specific concept and type.
Definition poly.hpp:112
entt::poly_vtable::type
std::conditional_t< is_mono, std::tuple_element_t< 0u, vtable_type >, const vtable_type * > type
Virtual table type.
Definition poly.hpp:104
entt
EnTT default namespace.
Definition dense_map.hpp:22
entt::constness_as_t
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
Definition type_traits.hpp:841
entt::any_cast
std::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
Definition any.hpp:464
entt::poly_call
decltype(auto) poly_call(Poly &&self, Args &&...args)
Shortcut for calling poly_base<Type>::invoke.
Definition poly.hpp:173
entt::poly
basic_poly< Concept > poly
Alias declaration for the most common use case.
Definition fwd.hpp:17
entt::invoke
void invoke(Registry &reg, const typename Registry::entity_type entt)
Helper to create a listener that directly invokes a member function.
Definition helper.hpp:108
entt::any_policy::ref
@ ref
Aliasing mode, the object points to a non-const element.
Definition fwd.hpp:19
entt::storage
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:78
entt::poly_base
Poly base class used to inject functionalities into concepts.
Definition poly.hpp:129
entt::poly_base::invoke
decltype(auto) invoke(const poly_base &self, Args &&...args) const
Invokes a function from the static virtual table.
Definition poly.hpp:139
entt::poly_base::invoke
decltype(auto) invoke(poly_base &self, Args &&...args)
Invokes a function from the static virtual table.
Definition poly.hpp:151
entt::poly_inspector
Inspector class used to infer the type of the virtual table.
Definition poly.hpp:17
entt::poly_inspector::invoke
poly_inspector invoke(Args &&...args) const
Dummy invocation function (definition only).
entt::poly_inspector::invoke
poly_inspector invoke(Args &&...args)
Dummy invocation function (definition only).
entt::type_info
Implementation specific information about a type.
Definition type_info.hpp:133
entt::type_list
A class to use to push around lists of types, nothing more.
Definition type_traits.hpp:111
entt::value_list
A class to use to push around lists of constant values, nothing more.
Definition type_traits.hpp:366