EnTT 4.0.0
Loading...
Searching...
No Matches
poly.hpp
1#ifndef ENTT_POLY_POLY_HPP
2#define ENTT_POLY_POLY_HPP
3
4#include "../core/any.hpp"
5#include "../core/concepts.hpp"
6#include "../core/type_info.hpp"
7#include "../core/type_traits.hpp"
8#include "../stl/concepts.hpp"
9#include "../stl/cstddef.hpp"
10#include "../stl/functional.hpp"
11#include "../stl/tuple.hpp"
12#include "../stl/type_traits.hpp"
13#include "../stl/utility.hpp"
14#include "fwd.hpp"
15
16namespace entt {
17
24 template<typename Type>
25 operator Type &&() const;
26
34 template<stl::size_t Member, typename... Args>
35 [[nodiscard]] poly_inspector invoke(Args &&...args) const;
36
38 template<stl::size_t Member, typename... Args>
39 [[nodiscard]] poly_inspector invoke(Args &&...args);
40};
41
48template<typename Concept, stl::size_t Len, stl::size_t Align>
50 using inspector = Concept::template type<poly_inspector>;
51
52 template<typename Ret, typename Clazz, typename... Args>
53 requires stl::derived_from<inspector, stl::remove_const_t<Clazz>>
54 static auto vtable_entry(Ret (*)(Clazz &, Args...))
55 -> Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...);
56
57 template<typename Ret, typename... Args>
58 static auto vtable_entry(Ret (*)(Args...))
59 -> Ret (*)(const basic_any<Len, Align> &, Args...);
60
61 template<typename Ret, typename Clazz, typename... Args>
62 requires stl::derived_from<inspector, Clazz>
63 static auto vtable_entry(Ret (Clazz::*)(Args...))
64 -> Ret (*)(basic_any<Len, Align> &, Args...);
65
66 template<typename Ret, typename Clazz, typename... Args>
67 requires stl::derived_from<inspector, Clazz>
68 static auto vtable_entry(Ret (Clazz::*)(Args...) const)
69 -> Ret (*)(const basic_any<Len, Align> &, Args...);
70
71 template<auto... Candidate>
72 static auto make_vtable(value_list<Candidate...>) noexcept
73 -> decltype(stl::make_tuple(vtable_entry(Candidate)...));
74
75 template<typename... Func>
76 [[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list<Func...>) noexcept {
77 if constexpr(sizeof...(Func) == 0u) {
78 return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
79 } else if constexpr((stl::is_function_v<Func> && ...)) {
80 return decltype(stl::make_tuple(vtable_entry(stl::declval<Func inspector::*>())...)){};
81 }
82 }
83
84 template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
85 static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept {
86 if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
87 entry = +[](Any &, Args... args) -> Ret {
88 return stl::invoke(Candidate, stl::forward<Args>(args)...);
89 };
90 } else {
91 entry = +[](Any &instance, Args... args) -> Ret {
92 return static_cast<Ret>(stl::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), stl::forward<Args>(args)...));
93 };
94 }
95 }
96
97 template<typename Type, auto... Index>
98 [[nodiscard]] static auto fill_vtable(stl::index_sequence<Index...>) noexcept {
99 vtable_type impl{};
100 (fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(stl::get<Index>(impl)), ...);
101 return impl;
102 }
103
104 using vtable_type = decltype(make_vtable(Concept{}));
105 static constexpr bool is_mono = stl::tuple_size_v<vtable_type> == 1u;
106
107public:
109 using type = stl::conditional_t<is_mono, stl::tuple_element_t<0u, vtable_type>, const vtable_type *>;
110
116 template<cvref_unqualified Type>
117 [[nodiscard]] static type instance() noexcept {
118 static const vtable_type vtable = fill_vtable<Type>(stl::make_index_sequence<Concept::template impl<Type>::size>{});
119
120 if constexpr(is_mono) {
121 return stl::get<0>(vtable);
122 } else {
123 return &vtable;
124 }
125 }
126};
127
132template<typename Poly>
133struct poly_base {
142 template<stl::size_t Member, typename... Args>
143 [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const {
144 const auto &poly = static_cast<const Poly &>(self);
145
146 if constexpr(stl::is_function_v<stl::remove_pointer_t<decltype(poly.vtable)>>) {
147 return poly.vtable(poly.storage, stl::forward<Args>(args)...);
148 } else {
149 return stl::get<Member>(*poly.vtable)(poly.storage, stl::forward<Args>(args)...);
150 }
151 }
152
154 template<stl::size_t Member, typename... Args>
155 [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) {
156 auto &poly = static_cast<Poly &>(self);
157
158 if constexpr(stl::is_function_v<stl::remove_pointer_t<decltype(poly.vtable)>>) {
159 static_assert(Member == 0u, "Unknown member");
160 return poly.vtable(poly.storage, stl::forward<Args>(args)...);
161 } else {
162 return stl::get<Member>(*poly.vtable)(poly.storage, stl::forward<Args>(args)...);
163 }
164 }
165};
166
176template<stl::size_t Member, typename Poly, typename... Args>
177decltype(auto) poly_call(Poly &&self, Args &&...args) {
178 return stl::forward<Poly>(self).template invoke<Member>(self, stl::forward<Args>(args)...);
179}
180
196template<typename Concept, stl::size_t Len, stl::size_t Align>
197class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
198 friend struct poly_base<basic_poly>;
199
200public:
202 using concept_type = Concept::template type<poly_base<basic_poly>>;
205
207 basic_poly() noexcept = default;
208
215 template<typename Type, typename... Args>
216 explicit basic_poly(stl::in_place_type_t<Type>, Args &&...args)
217 : storage{stl::in_place_type<Type>, stl::forward<Args>(args)...},
218 vtable{poly_vtable<Concept, Len, Align>::template instance<stl::remove_cvref_t<Type>>()} {}
219
225 template<typename Type>
226 requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_poly>)
227 basic_poly(Type &&value) noexcept
228 : basic_poly{stl::in_place_type<stl::remove_cvref_t<Type>>, stl::forward<Type>(value)} {}
229
234 [[nodiscard]] const type_info &info() const noexcept {
235 return storage.info();
236 }
237
242 [[nodiscard]] const void *data() const noexcept {
243 return storage.data();
244 }
245
247 [[nodiscard]] void *data() noexcept {
248 return storage.data();
249 }
250
257 template<typename Type, typename... Args>
258 void emplace(Args &&...args) {
259 storage.template emplace<Type>(stl::forward<Args>(args)...);
260 vtable = poly_vtable<Concept, Len, Align>::template instance<stl::remove_cvref_t<Type>>();
261 }
262
264 void reset() {
265 storage.reset();
266 vtable = {};
267 }
268
273 [[nodiscard]] explicit operator bool() const noexcept {
274 return static_cast<bool>(storage);
275 }
276
281 [[nodiscard]] concept_type *operator->() noexcept {
282 return this;
283 }
284
286 [[nodiscard]] const concept_type *operator->() const noexcept {
287 return this;
288 }
289
294 [[nodiscard]] basic_poly as_ref() noexcept {
295 basic_poly ref{};
296 ref.storage = storage.as_ref();
297 ref.vtable = vtable;
298 return ref;
299 }
300
302 [[nodiscard]] basic_poly as_ref() const noexcept {
303 basic_poly ref{};
304 ref.storage = storage.as_ref();
305 ref.vtable = vtable;
306 return ref;
307 }
308
309private:
311 vtable_type vtable{};
312};
313
314} // namespace entt
315
316#endif
A SBO friendly, type-safe container for single values of any type.
Definition any.hpp:63
poly_vtable< Concept, Len, Align >::type vtable_type
Definition poly.hpp:204
basic_poly as_ref() noexcept
Aliasing constructor.
Definition poly.hpp:294
void * data() noexcept
Returns an opaque pointer to the contained instance.
Definition poly.hpp:247
void reset()
Destroys contained object.
Definition poly.hpp:264
concept_type * operator->() noexcept
Returns a pointer to the underlying concept.
Definition poly.hpp:281
const type_info & info() const noexcept
Returns the object type info if any, type_id<void>() otherwise.
Definition poly.hpp:234
void emplace(Args &&...args)
Replaces the contained object by creating a new instance directly.
Definition poly.hpp:258
basic_poly as_ref() const noexcept
Aliasing constructor.
Definition poly.hpp:302
const concept_type * operator->() const noexcept
Returns a pointer to the underlying concept.
Definition poly.hpp:286
Concept::template type< poly_base< basic_poly > > concept_type
Definition poly.hpp:202
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
Definition poly.hpp:242
basic_poly() noexcept=default
Default constructor.
basic_poly(Type &&value) noexcept
Constructs a poly from a given value.
Definition poly.hpp:227
Static virtual table factory.
Definition poly.hpp:49
stl::conditional_t< is_mono, stl::tuple_element_t< 0u, vtable_type >, const vtable_type * > type
Virtual table type.
Definition poly.hpp:109
static type instance() noexcept
Returns a static virtual table for a specific concept and type.
Definition poly.hpp:117
Custom EnTT namespace for the standard template library.
Definition entt.hpp:5
EnTT default namespace.
Definition dense_map.hpp:25
decltype(auto) poly_call(Poly &&self, Args &&...args)
Shortcut for calling poly_base<Type>::invoke.
Definition poly.hpp:177
stl::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
Definition any.hpp:545
basic_poly< Concept > poly
Alias declaration for the most common use case.
Definition fwd.hpp:17
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
@ ref
Aliasing mode, non-const reference.
Definition fwd.hpp:19
constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
basic_storage< Type > storage
Alias declaration for the most common use case.
Definition fwd.hpp:79
Poly base class used to inject functionalities into concepts.
Definition poly.hpp:133
decltype(auto) invoke(const poly_base &self, Args &&...args) const
Invokes a function from the static virtual table.
Definition poly.hpp:143
decltype(auto) invoke(poly_base &self, Args &&...args)
Invokes a function from the static virtual table.
Definition poly.hpp:155
Inspector class used to infer the type of the virtual table.
Definition poly.hpp:19
poly_inspector invoke(Args &&...args) const
Dummy invocation function (definition only).
poly_inspector invoke(Args &&...args)
Dummy invocation function (definition only).
Implementation specific information about a type.
A class to use to push around lists of types, nothing more.
A class to use to push around lists of constant values, nothing more.