EnTT  3.10.0
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 "../config/config.h"
10 #include "../core/any.hpp"
11 #include "../core/type_info.hpp"
12 #include "../core/type_traits.hpp"
13 #include "fwd.hpp"
14 
15 namespace entt {
16 
23  template<class Type>
24  operator Type &&() const;
25 
33  template<std::size_t Member, typename... Args>
34  poly_inspector invoke(Args &&...args) const;
35 
37  template<std::size_t Member, typename... Args>
38  poly_inspector invoke(Args &&...args);
39 };
40 
47 template<typename Concept, std::size_t Len, std::size_t Align>
48 class poly_vtable {
49  using inspector = typename Concept::template type<poly_inspector>;
50 
51  template<typename Ret, typename... Args>
52  static auto vtable_entry(Ret (*)(inspector &, Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
53 
54  template<typename Ret, typename... Args>
55  static auto vtable_entry(Ret (*)(const inspector &, Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
56 
57  template<typename Ret, typename... Args>
58  static auto vtable_entry(Ret (*)(Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
59 
60  template<typename Ret, typename... Args>
61  static auto vtable_entry(Ret (inspector::*)(Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
62 
63  template<typename Ret, typename... Args>
64  static auto vtable_entry(Ret (inspector::*)(Args...) const) -> Ret (*)(const basic_any<Len, Align> &, Args...);
65 
66  template<auto... Candidate>
67  static auto make_vtable(value_list<Candidate...>) ENTT_NOEXCEPT
68  -> decltype(std::make_tuple(vtable_entry(Candidate)...));
69 
70  template<typename... Func>
71  [[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) ENTT_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...)) ENTT_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...>) ENTT_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_v = std::tuple_size_v<vtable_type> == 1u;
101 
102 public:
104  using type = std::conditional_t<is_mono_v, std::tuple_element_t<0u, vtable_type>, const vtable_type *>;
105 
111  template<typename Type>
112  [[nodiscard]] static type instance() ENTT_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_v) {
117  return std::get<0>(vtable);
118  } else {
119  return &vtable;
120  }
121  }
122 };
123 
128 template<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 
172 template<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 
192 template<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>>> {
195  friend struct poly_base<basic_poly>;
196 
197 public:
199  using concept_type = typename Concept::template type<poly_base<basic_poly>>;
202 
204  basic_poly() ENTT_NOEXCEPT
205  : storage{},
206  vtable{} {}
207 
214  template<typename Type, typename... Args>
215  explicit basic_poly(std::in_place_type_t<Type>, Args &&...args)
216  : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
217  vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>()} {}
218 
224  template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
225  basic_poly(Type &&value) ENTT_NOEXCEPT
226  : basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
227 
232  [[nodiscard]] const type_info &type() const ENTT_NOEXCEPT {
233  return storage.type();
234  }
235 
240  [[nodiscard]] const void *data() const ENTT_NOEXCEPT {
241  return storage.data();
242  }
243 
245  [[nodiscard]] void *data() ENTT_NOEXCEPT {
246  return storage.data();
247  }
248 
255  template<typename Type, typename... Args>
256  void emplace(Args &&...args) {
257  storage.template emplace<Type>(std::forward<Args>(args)...);
258  vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>();
259  }
260 
262  void reset() {
263  storage.reset();
264  vtable = {};
265  }
266 
271  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
272  return static_cast<bool>(storage);
273  }
274 
279  [[nodiscard]] concept_type *operator->() ENTT_NOEXCEPT {
280  return this;
281  }
282 
284  [[nodiscard]] const concept_type *operator->() const ENTT_NOEXCEPT {
285  return this;
286  }
287 
292  [[nodiscard]] basic_poly as_ref() ENTT_NOEXCEPT {
293  basic_poly ref{};
294  ref.storage = storage.as_ref();
295  ref.vtable = vtable;
296  return ref;
297  }
298 
300  [[nodiscard]] basic_poly as_ref() const ENTT_NOEXCEPT {
301  basic_poly ref{};
302  ref.storage = storage.as_ref();
303  ref.vtable = vtable;
304  return ref;
305  }
306 
307 private:
309  vtable_type vtable;
310 };
311 
312 } // namespace entt
313 
314 #endif
A SBO friendly, type-safe container for single values of any type.
Definition: any.hpp:22
Static polymorphism made simple and within everyone's reach.
Definition: poly.hpp:193
concept_type * operator->()
Returns a pointer to the underlying concept.
Definition: poly.hpp:279
const concept_type * operator->() const
Returns a pointer to the underlying concept.
Definition: poly.hpp:284
void * data()
Returns an opaque pointer to the contained instance.
Definition: poly.hpp:245
void reset()
Destroys contained object.
Definition: poly.hpp:262
void emplace(Args &&...args)
Replaces the contained object by creating a new instance directly.
Definition: poly.hpp:256
basic_poly(Type &&value)
Constructs a poly from a given value.
Definition: poly.hpp:225
basic_poly as_ref()
Aliasing constructor.
Definition: poly.hpp:292
basic_poly()
Default constructor.
Definition: poly.hpp:204
const type_info & type() const
Returns the object type if any, type_id<void>() otherwise.
Definition: poly.hpp:232
basic_poly as_ref() const
Aliasing constructor.
Definition: poly.hpp:300
typename poly_vtable< Concept, Len, Align >::type vtable_type
Virtual table type.
Definition: poly.hpp:201
const void * data() const
Returns an opaque pointer to the contained instance.
Definition: poly.hpp:240
typename Concept::template type< poly_base< basic_poly > > concept_type
Concept type.
Definition: poly.hpp:199
basic_poly(std::in_place_type_t< Type >, Args &&...args)
Constructs a poly by directly initializing the new object.
Definition: poly.hpp:215
const type_info & type() const
Returned value type, if any.
Definition: sparse_set.hpp:942
pointer data() const
Direct access to the internal packed array.
Definition: sparse_set.hpp:481
Basic storage implementation.
Definition: storage.hpp:234
Static virtual table factory.
Definition: poly.hpp:48
std::conditional_t< is_mono_v, std::tuple_element_t< 0u, vtable_type >, const vtable_type * > type
Virtual table type.
Definition: poly.hpp:104
static type instance()
Returns a static virtual table for a specific concept and type.
Definition: poly.hpp:112
EnTT default namespace.
Definition: dense_map.hpp:22
Type any_cast(const basic_any< Len, Align > &data)
Performs type-safe access to the contained object.
Definition: any.hpp:415
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:173
Poly base class used to inject functionalities into concepts.
Definition: poly.hpp:129
decltype(auto) invoke(const poly_base &self, Args &&...args) const
Invokes a function from the static virtual table.
Definition: poly.hpp:139
Inspector class used to infer the type of the virtual table.
Definition: poly.hpp:18
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.
Definition: type_info.hpp:141
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.