EnTT  3.8.1
poly.hpp
1 #ifndef ENTT_POLY_POLY_HPP
2 #define ENTT_POLY_POLY_HPP
3 
4 
5 #include <cstddef>
6 #include <functional>
7 #include <tuple>
8 #include <type_traits>
9 #include <utility>
10 #include "../config/config.h"
11 #include "../core/any.hpp"
12 #include "../core/type_info.hpp"
13 #include "../core/type_traits.hpp"
14 #include "fwd.hpp"
15 
16 
17 namespace entt {
18 
19 
26  template <class Type>
27  operator Type &&() const;
28 
36  template<auto Member, typename... Args>
37  poly_inspector invoke(Args &&... args) const;
38 
40  template<auto Member, typename... Args>
41  poly_inspector invoke(Args &&... args);
42 };
43 
44 
51 template<typename Concept, std::size_t Len, std::size_t Align>
52 class poly_vtable {
53  using inspector = typename Concept::template type<poly_inspector>;
54 
55  template<typename Ret, typename... Args>
56  static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any<Len, Align> &, Args...);
57 
58  template<typename Ret, typename... Args>
59  static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any<Len, Align> &, Args...);
60 
61  template<typename Ret, typename... Args>
62  static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any<Len, Align> &, Args...);
63 
64  template<typename Ret, typename... Args>
65  static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any<Len, Align> &, Args...);
66 
67  template<typename Ret, typename... Args>
68  static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any<Len, Align> &, Args...);
69 
70  template<auto... Candidate>
71  static auto make_vtable(value_list<Candidate...>)
72  -> decltype(std::make_tuple(vtable_entry(Candidate)...));
73 
74  template<typename... Func>
75  [[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) {
76  if constexpr(sizeof...(Func) == 0) {
77  return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
78  } else if constexpr((std::is_function_v<Func> && ...)) {
79  return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector:: *>())...)){};
80  }
81  }
82 
83  template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
84  static void fill_vtable_entry(Ret(* &entry)(Any &, Args...)) {
85  if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
86  entry = +[](Any &, Args... args) -> Ret {
87  return std::invoke(Candidate, std::forward<Args>(args)...);
88  };
89  } else {
90  entry = +[](Any &instance, Args... args) -> Ret {
91  return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), std::forward<Args>(args)...));
92  };
93  }
94  }
95 
96  template<typename Type, auto... Index>
97  [[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) {
98  type impl{};
99  (fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
100  return impl;
101  }
102 
103 public:
105  using type = decltype(make_vtable(Concept{}));
106 
112  template<typename Type>
113  [[nodiscard]] static const auto * instance() {
114  static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
115  static const auto vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
116  return &vtable;
117  }
118 };
119 
120 
125 template<typename Poly>
126 struct poly_base {
135  template<auto Member, typename... Args>
136  [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&... args) const {
137  const auto &poly = static_cast<const Poly &>(self);
138  return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
139  }
140 
142  template<auto Member, typename... Args>
143  [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&... args) {
144  auto &poly = static_cast<Poly &>(self);
145  return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
146  }
147 };
148 
149 
159 template<auto Member, typename Poly, typename... Args>
160 decltype(auto) poly_call(Poly &&self, Args &&... args) {
161  return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
162 }
163 
164 
180 template<typename Concept, std::size_t Len, std::size_t Align>
181 class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
183  friend struct poly_base<basic_poly>;
184 
185  using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
186 
187 public:
189  using concept_type = typename Concept::template type<poly_base<basic_poly>>;
190 
192  basic_poly() ENTT_NOEXCEPT
193  : storage{},
194  vtable{}
195  {}
196 
203  template<typename Type, typename... Args>
204  explicit basic_poly(std::in_place_type_t<Type>, Args &&... args)
205  : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
206  vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()}
207  {}
208 
214  template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
215  basic_poly(Type &&value) ENTT_NOEXCEPT
216  : basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
217  {}
218 
223  basic_poly(const basic_poly &other) = default;
224 
229  basic_poly(basic_poly &&other) ENTT_NOEXCEPT
230  : basic_poly{}
231  {
232  swap(*this, other);
233  }
234 
241  swap(other, *this);
242  return *this;
243  }
244 
249  [[nodiscard]] type_info type() const ENTT_NOEXCEPT {
250  return storage.type();
251  }
252 
257  [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
258  return storage.data();
259  }
260 
262  [[nodiscard]] void * data() ENTT_NOEXCEPT {
263  return storage.data();
264  }
265 
272  template<typename Type, typename... Args>
273  void emplace(Args &&... args) {
274  *this = basic_poly{std::in_place_type<Type>, std::forward<Args>(args)...};
275  }
276 
278  void reset() {
279  *this = basic_poly{};
280  }
281 
286  [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
287  return !(vtable == nullptr);
288  }
289 
294  [[nodiscard]] concept_type * operator->() ENTT_NOEXCEPT {
295  return this;
296  }
297 
299  [[nodiscard]] const concept_type * operator->() const ENTT_NOEXCEPT {
300  return this;
301  }
302 
308  friend void swap(basic_poly &lhs, basic_poly &rhs) {
309  using std::swap;
310  swap(lhs.storage, rhs.storage);
311  swap(lhs.vtable, rhs.vtable);
312  }
313 
318  [[nodiscard]] basic_poly as_ref() ENTT_NOEXCEPT {
319  basic_poly ref = std::as_const(*this).as_ref();
320  ref.storage = storage.as_ref();
321  return ref;
322  }
323 
325  [[nodiscard]] basic_poly as_ref() const ENTT_NOEXCEPT {
326  basic_poly ref{};
327  ref.storage = storage.as_ref();
328  ref.vtable = vtable;
329  return ref;
330  }
331 
332 private:
334  const vtable_type *vtable;
335 };
336 
337 
338 }
339 
340 
341 #endif
A SBO friendly, type-safe container for single values of any type.
Definition: any.hpp:26
Static polymorphism made simple and within everyone's reach.
Definition: poly.hpp:181
concept_type * operator->()
Returns a pointer to the underlying concept.
Definition: poly.hpp:294
basic_poly(std::in_place_type_t< Type >, Args &&... args)
Constructs a poly by directly initializing the new object.
Definition: poly.hpp:204
void emplace(Args &&... args)
Replaces the contained object by creating a new instance directly.
Definition: poly.hpp:273
const concept_type * operator->() const
Returns a pointer to the underlying concept.
Definition: poly.hpp:299
void * data()
Returns an opaque pointer to the contained instance.
Definition: poly.hpp:262
basic_poly(const basic_poly &other)=default
Copy constructor.
type_info type() const
Returns the type of the contained object.
Definition: poly.hpp:249
void reset()
Destroys contained object.
Definition: poly.hpp:278
basic_poly(Type &&value)
Constructs a poly from a given value.
Definition: poly.hpp:215
basic_poly as_ref()
Aliasing constructor.
Definition: poly.hpp:318
basic_poly(basic_poly &&other)
Move constructor.
Definition: poly.hpp:229
basic_poly()
Default constructor.
Definition: poly.hpp:192
friend void swap(basic_poly &lhs, basic_poly &rhs)
Swaps two poly objects.
Definition: poly.hpp:308
basic_poly & operator=(basic_poly other)
Assignment operator.
Definition: poly.hpp:240
basic_poly as_ref() const
Aliasing constructor.
Definition: poly.hpp:325
const void * data() const
Returns an opaque pointer to the contained instance.
Definition: poly.hpp:257
typename Concept::template type< poly_base< basic_poly > > concept_type
Concept type.
Definition: poly.hpp:189
pointer data() const
Direct access to the internal packed array.
Definition: sparse_set.hpp:443
Static virtual table factory.
Definition: poly.hpp:52
static const auto * instance()
Returns a static virtual table for a specific concept and type.
Definition: poly.hpp:113
decltype(make_vtable(Concept{})) type
Virtual table type.
Definition: poly.hpp:105
Implementation specific information about a type.
Definition: type_info.hpp:150
EnTT default namespace.
Definition: algorithm.hpp:13
Type any_cast(const basic_any< Len, Align > &data)
Performs type-safe access to the contained object.
Definition: any.hpp:382
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:160
Storage implementation dispatcher.
Definition: storage.hpp:1006
Poly base class used to inject functionalities into concepts.
Definition: poly.hpp:126
decltype(auto) invoke(const poly_base &self, Args &&... args) const
Invokes a function from the static virtual table.
Definition: poly.hpp:136
Inspector class used to infer the type of the virtual table.
Definition: poly.hpp:21
poly_inspector invoke(Args &&... args)
Dummy invocation function (definition only).
poly_inspector invoke(Args &&... args) const
Dummy invocation function (definition only).
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.