1 #ifndef ENTT_POLY_POLY_HPP
2 #define ENTT_POLY_POLY_HPP
10 #include "../config/config.h"
11 #include "../core/any.hpp"
12 #include "../core/type_info.hpp"
13 #include "../core/type_traits.hpp"
27 operator Type &&()
const;
36 template<
auto Member,
typename... Args>
40 template<
auto Member,
typename... Args>
51 template<
typename Concept, std::
size_t Len, std::
size_t Align>
55 template<
typename Ret,
typename... Args>
58 template<
typename Ret,
typename... Args>
59 static auto vtable_entry(Ret(*)(
const inspector &, Args...)) -> Ret(*)(
const basic_any<Len, Align> &, Args...);
61 template<
typename Ret,
typename... Args>
64 template<
typename Ret,
typename... Args>
67 template<
typename Ret,
typename... Args>
68 static auto vtable_entry(Ret(inspector:: *)(Args...)
const) -> Ret(*)(
const basic_any<Len, Align> &, Args...);
70 template<
auto... Candidate>
72 -> decltype(std::make_tuple(vtable_entry(Candidate)...));
74 template<
typename... 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:: *>())...)){};
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)...);
90 entry = +[](Any &
instance, Args... args) -> Ret {
96 template<
typename Type,
auto... Index>
97 [[nodiscard]]
static auto fill_vtable(std::index_sequence<Index...>) {
99 (fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
105 using type = decltype(make_vtable(Concept{}));
112 template<
typename Type>
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>{});
125 template<
typename Poly>
135 template<
auto Member,
typename... Args>
137 const auto &
poly =
static_cast<const Poly &
>(
self);
138 return std::get<Member>(*
poly.vtable)(
poly.storage, std::forward<Args>(args)...);
142 template<
auto Member,
typename... Args>
144 auto &
poly =
static_cast<Poly &
>(
self);
145 return std::get<Member>(*
poly.vtable)(
poly.storage, std::forward<Args>(args)...);
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)...);
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>>> {
189 using concept_type =
typename Concept::template type<poly_base<basic_poly>>;
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>>>()}
214 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
216 :
basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
257 [[nodiscard]]
const void *
data() const ENTT_NOEXCEPT {
262 [[nodiscard]]
void *
data() ENTT_NOEXCEPT {
272 template<
typename Type,
typename... Args>
274 *
this =
basic_poly{std::in_place_type<Type>, std::forward<Args>(args)...};
286 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
287 return !(vtable ==
nullptr);
310 swap(lhs.storage, rhs.storage);
311 swap(lhs.vtable, rhs.vtable);
320 ref.storage =
storage.as_ref();
327 ref.storage =
storage.as_ref();
334 const vtable_type *vtable;
A SBO friendly, type-safe container for single values of any type.
Static polymorphism made simple and within everyone's reach.
concept_type * operator->()
Returns a pointer to the underlying concept.
basic_poly(std::in_place_type_t< Type >, Args &&... args)
Constructs a poly by directly initializing the new object.
void emplace(Args &&... args)
Replaces the contained object by creating a new instance directly.
const concept_type * operator->() const
Returns a pointer to the underlying concept.
void * data()
Returns an opaque pointer to the contained instance.
basic_poly(const basic_poly &other)=default
Copy constructor.
type_info type() const
Returns the type of the contained object.
void reset()
Destroys contained object.
basic_poly(Type &&value)
Constructs a poly from a given value.
basic_poly as_ref()
Aliasing constructor.
basic_poly(basic_poly &&other)
Move constructor.
basic_poly()
Default constructor.
friend void swap(basic_poly &lhs, basic_poly &rhs)
Swaps two poly objects.
basic_poly & operator=(basic_poly other)
Assignment operator.
basic_poly as_ref() const
Aliasing constructor.
const void * data() const
Returns an opaque pointer to the contained instance.
typename Concept::template type< poly_base< basic_poly > > concept_type
Concept type.
pointer data() const
Direct access to the internal packed array.
Static virtual table factory.
static const auto * instance()
Returns a static virtual table for a specific concept and type.
decltype(make_vtable(Concept{})) type
Virtual table type.
Implementation specific information about a type.
Type any_cast(const basic_any< Len, Align > &data)
Performs type-safe access to the contained object.
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.
Storage implementation dispatcher.
Poly base class used to inject functionalities into concepts.
decltype(auto) invoke(const poly_base &self, Args &&... args) const
Invokes a function from the static virtual table.
Inspector class used to infer the type of the virtual table.
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.