EnTT 3.13.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
22 template<typename Type>
23 operator Type &&() const;
24
32 template<std::size_t Member, typename... Args>
33 poly_inspector invoke(Args &&...args) const;
34
36 template<std::size_t Member, typename... Args>
37 poly_inspector invoke(Args &&...args);
38};
39
46template<typename Concept, std::size_t Len, std::size_t Align>
48 using inspector = typename Concept::template type<poly_inspector>;
49
50 template<typename Ret, typename... Args>
51 static auto vtable_entry(Ret (*)(inspector &, Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
52
53 template<typename Ret, typename... Args>
54 static auto vtable_entry(Ret (*)(const inspector &, Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
55
56 template<typename Ret, typename... Args>
57 static auto vtable_entry(Ret (*)(Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
58
59 template<typename Ret, typename... Args>
60 static auto vtable_entry(Ret (inspector::*)(Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
61
62 template<typename Ret, typename... Args>
63 static auto vtable_entry(Ret (inspector::*)(Args...) const) -> Ret (*)(const basic_any<Len, Align> &, Args...);
64
65 template<auto... Candidate>
66 static auto make_vtable(value_list<Candidate...>) noexcept
67 -> decltype(std::make_tuple(vtable_entry(Candidate)...));
68
69 template<typename... Func>
70 [[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) noexcept {
71 if constexpr(sizeof...(Func) == 0u) {
72 return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
73 } else if constexpr((std::is_function_v<Func> && ...)) {
74 return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector::*>())...)){};
75 }
76 }
77
78 template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
79 static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept {
80 if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
81 entry = +[](Any &, Args... args) -> Ret {
82 return std::invoke(Candidate, std::forward<Args>(args)...);
83 };
84 } else {
85 entry = +[](Any &instance, Args... args) -> Ret {
86 return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), std::forward<Args>(args)...));
87 };
88 }
89 }
90
91 template<typename Type, auto... Index>
92 [[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) noexcept {
93 vtable_type impl{};
94 (fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
95 return impl;
96 }
97
98 using vtable_type = decltype(make_vtable(Concept{}));
99 static constexpr bool is_mono_v = std::tuple_size_v<vtable_type> == 1u;
100
101public:
103 using type = std::conditional_t<is_mono_v, std::tuple_element_t<0u, vtable_type>, const vtable_type *>;
104
110 template<typename Type>
111 [[nodiscard]] static type instance() noexcept {
112 static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
113 static const vtable_type vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
114
115 if constexpr(is_mono_v) {
116 return std::get<0>(vtable);
117 } else {
118 return &vtable;
119 }
120 }
121};
122
127template<typename Poly>
128struct poly_base {
137 template<std::size_t Member, typename... Args>
138 [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const {
139 const auto &poly = static_cast<const Poly &>(self);
140
141 if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
142 return poly.vtable(poly.storage, std::forward<Args>(args)...);
143 } else {
144 return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
145 }
146 }
147
149 template<std::size_t Member, typename... Args>
150 [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) {
151 auto &poly = static_cast<Poly &>(self);
152
153 if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
154 static_assert(Member == 0u, "Unknown member");
155 return poly.vtable(poly.storage, std::forward<Args>(args)...);
156 } else {
157 return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
158 }
159 }
160};
161
171template<std::size_t Member, typename Poly, typename... Args>
172decltype(auto) poly_call(Poly &&self, Args &&...args) {
173 return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
174}
175
191template<typename Concept, std::size_t Len, std::size_t Align>
192class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
193 friend struct poly_base<basic_poly>;
194
195public:
197 using concept_type = typename Concept::template type<poly_base<basic_poly>>;
200
202 basic_poly() noexcept
203 : storage{},
204 vtable{} {}
205
212 template<typename Type, typename... Args>
213 explicit basic_poly(std::in_place_type_t<Type>, Args &&...args)
214 : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
215 vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>()} {}
216
222 template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
223 basic_poly(Type &&value) noexcept
224 : basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
225
230 [[nodiscard]] const type_info &type() const noexcept {
231 return storage.type();
232 }
233
238 [[nodiscard]] const void *data() const noexcept {
239 return storage.data();
240 }
241
243 [[nodiscard]] void *data() noexcept {
244 return storage.data();
245 }
246
253 template<typename Type, typename... Args>
254 void emplace(Args &&...args) {
255 storage.template emplace<Type>(std::forward<Args>(args)...);
256 vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>();
257 }
258
260 void reset() {
261 storage.reset();
262 vtable = {};
263 }
264
269 [[nodiscard]] explicit operator bool() const noexcept {
270 return static_cast<bool>(storage);
271 }
272
277 [[nodiscard]] concept_type *operator->() noexcept {
278 return this;
279 }
280
282 [[nodiscard]] const concept_type *operator->() const noexcept {
283 return this;
284 }
285
290 [[nodiscard]] basic_poly as_ref() noexcept {
291 basic_poly ref{};
292 ref.storage = storage.as_ref();
293 ref.vtable = vtable;
294 return ref;
295 }
296
298 [[nodiscard]] basic_poly as_ref() const noexcept {
299 basic_poly ref{};
300 ref.storage = storage.as_ref();
301 ref.vtable = vtable;
302 return ref;
303 }
304
305private:
307 vtable_type vtable;
308};
309
310} // namespace entt
311
312#endif
A SBO friendly, type-safe container for single values of any type.
Definition any.hpp:48
Static polymorphism made simple and within everyone's reach.
Definition poly.hpp:192
const type_info & type() const noexcept
Returns the object type if any, type_id<void>() otherwise.
Definition poly.hpp:230
basic_poly as_ref() noexcept
Aliasing constructor.
Definition poly.hpp:290
void * data() noexcept
Returns an opaque pointer to the contained instance.
Definition poly.hpp:243
void reset()
Destroys contained object.
Definition poly.hpp:260
concept_type * operator->() noexcept
Returns a pointer to the underlying concept.
Definition poly.hpp:277
void emplace(Args &&...args)
Replaces the contained object by creating a new instance directly.
Definition poly.hpp:254
basic_poly as_ref() const noexcept
Aliasing constructor.
Definition poly.hpp:298
const concept_type * operator->() const noexcept
Returns a pointer to the underlying concept.
Definition poly.hpp:282
basic_poly(Type &&value) noexcept
Constructs a poly from a given value.
Definition poly.hpp:223
typename poly_vtable< Concept, Len, Align >::type vtable_type
Virtual table type.
Definition poly.hpp:199
typename Concept::template type< poly_base< basic_poly > > concept_type
Concept type.
Definition poly.hpp:197
basic_poly() noexcept
Default constructor.
Definition poly.hpp:202
basic_poly(std::in_place_type_t< Type >, Args &&...args)
Constructs a poly by directly initializing the new object.
Definition poly.hpp:213
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
Definition poly.hpp:238
pointer data() const noexcept
Direct access to the internal packed array.
const type_info & type() const noexcept
Returned value type, if any.
Basic storage implementation.
Definition storage.hpp:229
Static virtual table factory.
Definition poly.hpp:47
std::conditional_t< is_mono_v, std::tuple_element_t< 0u, vtable_type >, const vtable_type * > type
Virtual table type.
Definition poly.hpp:103
static type instance() noexcept
Returns a static virtual table for a specific concept and type.
Definition poly.hpp:111
EnTT default namespace.
Definition dense_map.hpp:21
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
decltype(auto) poly_call(Poly &&self, Args &&...args)
Shortcut for calling poly_base<Type>::invoke.
Definition poly.hpp:172
Type any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
Definition any.hpp:434
@ ref
Aliasing mode, the object points to a non-const element.
Poly base class used to inject functionalities into concepts.
Definition poly.hpp:128
decltype(auto) invoke(const poly_base &self, Args &&...args) const
Invokes a function from the static virtual table.
Definition poly.hpp:138
decltype(auto) invoke(poly_base &self, Args &&...args)
Invokes a function from the static virtual table.
Definition poly.hpp:150
Inspector class used to infer the type of the virtual table.
Definition poly.hpp:17
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.