1#ifndef ENTT_CORE_ANY_HPP
2#define ENTT_CORE_ANY_HPP
4#include "../config/config.h"
5#include "../core/concepts.hpp"
6#include "../stl/concepts.hpp"
7#include "../stl/cstddef.hpp"
8#include "../stl/cstdint.hpp"
9#include "../stl/memory.hpp"
10#include "../stl/type_traits.hpp"
11#include "../stl/utility.hpp"
13#include "type_info.hpp"
14#include "type_traits.hpp"
22enum class any_request : stl::uint8_t {
31template<stl::
size_t Len, stl::
size_t Align>
32struct basic_any_storage {
33 static constexpr bool has_buffer =
true;
35 const void *instance{};
37 alignas(Align) stl::byte buffer[Len];
41template<stl::
size_t Align>
42struct basic_any_storage<0u, Align> {
43 static constexpr bool has_buffer =
false;
44 const void *instance{};
47template<
typename Type, stl::
size_t Len, stl::
size_t Align>
49struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v<Type>> {};
51template<stl::size_t Len, stl::size_t Align>
52struct in_situ<void, Len, Align>: stl::false_type {};
62template<stl::size_t Len, stl::size_t Align>
63class basic_any: private internal::basic_any_storage<Len, Align> {
64 using request = internal::any_request;
65 using base_type = internal::basic_any_storage<Len, Align>;
66 using vtable_type = const void *(const request, const basic_any &, const void *);
67 using deleter_type = void(const basic_any &);
69 template<typename Type>
70 static constexpr bool in_situ_v = internal::in_situ<Type, Len, Align>::value;
72 template<cvref_unqualified Type>
73 static const void *basic_vtable(const request req, const basic_any &value, const void *other) {
74 switch(const auto *elem = static_cast<const Type *>(value.data()); req) {
75 using enum internal::any_request;
77 return &type_id<Type>();
79 if constexpr(stl::is_move_assignable_v<Type>) {
81 *const_cast<Type *>(elem) = stl::move(*static_cast<Type *>(const_cast<void *>(other)));
86 if constexpr(stl::is_copy_assignable_v<Type>) {
87 *const_cast<Type *>(elem) = *static_cast<const Type *>(other);
92 if constexpr(!stl::is_function_v<Type> && !stl::is_array_v<Type> && is_equality_comparable_v<Type>) {
93 return (*elem == *static_cast<const Type *>(other)) ? other : nullptr;
95 return (elem == other) ? other : nullptr;
98 if constexpr(stl::is_copy_constructible_v<Type>) {
100 static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*elem);
104 ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy");
105 if constexpr(in_situ_v<Type>) {
107 return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->buffer) Type{stl::move(*
const_cast<Type *
>(elem))};
114 template<cvref_unqualified Type>
115 static void basic_deleter(
const basic_any &value) {
116 ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v<Type>),
"Unexpected policy");
118 const auto *elem =
static_cast<const Type *
>(value.data());
120 if constexpr(in_situ_v<Type>) {
121 (value.mode == any_policy::embedded) ? elem->~Type() : (
delete elem);
122 }
else if constexpr(stl::is_array_v<Type>) {
129 template<
typename Type,
typename... Args>
130 void initialize([[maybe_unused]] Args &&...args) {
131 using plain_type = stl::remove_cvref_t<Type>;
133 vtable = basic_vtable<plain_type>;
134 underlying_type = type_hash<plain_type>::value();
136 if constexpr(stl::is_void_v<Type>) {
138 mode = any_policy::empty;
139 this->instance =
nullptr;
140 }
else if constexpr(stl::is_lvalue_reference_v<Type>) {
142 mode = stl::is_const_v<stl::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
143 static_assert((stl::is_lvalue_reference_v<Args> && ...) && (
sizeof...(Args) == 1u),
"Invalid arguments");
145 this->instance = (stl::addressof(args), ...);
146 }
else if constexpr(in_situ_v<plain_type>) {
147 if constexpr(stl::is_trivially_destructible_v<plain_type>) {
150 deleter = &basic_deleter<plain_type>;
153 mode = any_policy::embedded;
155 if constexpr(stl::is_aggregate_v<plain_type> && (
sizeof...(Args) != 0u || !stl::is_default_constructible_v<plain_type>)) {
156 ::new(&this->buffer) plain_type{stl::forward<Args>(args)...};
159 ::new(&this->buffer) plain_type(stl::forward<Args>(args)...);
162 deleter = &basic_deleter<plain_type>;
163 mode = any_policy::dynamic;
165 if constexpr(stl::is_aggregate_v<plain_type> && (
sizeof...(Args) != 0u || !stl::is_default_constructible_v<plain_type>)) {
166 this->instance =
new plain_type{stl::forward<Args>(args)...};
167 }
else if constexpr(stl::is_array_v<plain_type>) {
168 static_assert(
sizeof...(Args) == 0u,
"Invalid arguments");
169 this->instance =
new plain_type[stl::extent_v<plain_type>]();
171 this->instance =
new plain_type(stl::forward<Args>(args)...);
176 void invoke_deleter_if_exists() {
177 if(deleter !=
nullptr) {
198 template<
typename Type,
typename... Args>
199 explicit basic_any(stl::in_place_type_t<Type>, Args &&...args)
201 initialize<Type>(stl::forward<Args>(args)...);
209 template<
typename Type>
210 requires (!stl::is_const_v<Type> && !stl::is_void_v<Type>)
213 if(value ==
nullptr) {
216 initialize<Type &>(*value);
217 deleter = &basic_deleter<Type>;
218 mode = any_policy::dynamic;
227 template<
typename Type>
228 requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_any>)
230 :
basic_any{stl::in_place_type<stl::decay_t<Type>>, stl::forward<Type>(value)} {}
238 other.vtable(request::copy, other,
this);
247 vtable{other.vtable},
248 deleter{other.deleter},
249 underlying_type{other.underlying_type},
251 if(other.mode == any_policy::embedded) {
252 other.vtable(request::move, other,
this);
253 }
else if(other.mode != any_policy::empty) {
254 this->instance = stl::exchange(other.instance,
nullptr);
260 invoke_deleter_if_exists();
270 invoke_deleter_if_exists();
273 other.vtable(request::copy, other,
this);
289 invoke_deleter_if_exists();
292 other.vtable(request::move, other,
this);
294 this->instance = stl::exchange(other.instance,
nullptr);
297 vtable = other.vtable;
298 deleter = other.deleter;
299 underlying_type = other.underlying_type;
312 template<
typename Type>
313 requires (!stl::same_as<stl::remove_cvref_t<Type>,
basic_any>)
335 return (underlying_type == req.hash());
345 template<cvref_unqualified Type>
355 return *
static_cast<const type_info *
>(vtable(request::info, *
this,
nullptr));
362 [[nodiscard]]
const void *
data() const noexcept {
363 if constexpr(base_type::has_buffer) {
366 return this->instance;
384 template<
typename Type>
385 [[nodiscard]]
const Type *
data() const noexcept {
393 [[nodiscard]]
void *
data() noexcept {
394 return (mode ==
any_policy::cref) ? nullptr :
const_cast<void *
>(stl::as_const(*this).data());
403 return (mode ==
any_policy::cref) ? nullptr :
const_cast<void *
>(stl::as_const(*this).data(req));
411 template<
typename Type>
412 [[nodiscard]] Type *
data() noexcept {
413 if constexpr(stl::is_const_v<Type>) {
414 return stl::as_const(*this).template
data<stl::remove_const_t<Type>>();
416 return (mode ==
any_policy::cref) ? nullptr :
const_cast<Type *
>(stl::as_const(*this).template
data<stl::remove_const_t<Type>>());
426 template<
typename Type,
typename... Args>
428 invoke_deleter_if_exists();
429 initialize<Type>(stl::forward<Args>(args)...);
438 if(other && (mode !=
any_policy::cref) && (underlying_type == other.underlying_type)) {
439 return (vtable(request::assign, *
this, other.
data()) !=
nullptr);
448 if(other && (mode !=
any_policy::cref) && (underlying_type == other.underlying_type)) {
449 return (other.mode ==
any_policy::cref) ? (vtable(request::assign, *
this, stl::as_const(other).
data()) !=
nullptr) : (vtable(request::transfer, *
this, other.data()) !=
nullptr);
457 invoke_deleter_if_exists();
465 [[nodiscard]]
explicit operator bool() const noexcept {
475 if(other && (underlying_type == other.underlying_type)) {
476 return (vtable(request::compare, *
this, other.data()) !=
nullptr);
479 return (!*
this && !other);
487 basic_any other = stl::as_const(*this).as_ref();
506 other.instance =
data();
507 other.vtable = vtable;
508 other.underlying_type = underlying_type;
517 [[nodiscard]]
bool owner() const noexcept {
530 vtable_type *vtable{};
531 deleter_type *deleter{};
544template<
typename Type, stl::
size_t Len, stl::
size_t Align>
547 ENTT_ASSERT(instance,
"Invalid instance");
548 return static_cast<Type
>(*instance);
552template<
typename Type, stl::
size_t Len, stl::
size_t Align>
556 ENTT_ASSERT(instance,
"Invalid instance");
557 return static_cast<Type
>(*instance);
561template<
typename Type, stl::
size_t Len, stl::
size_t Align>
564 if constexpr(stl::is_copy_constructible_v<stl::remove_cvref_t<Type>>) {
565 if(
auto *
const instance =
any_cast<stl::remove_reference_t<Type>>(&data); instance) {
566 return static_cast<Type
>(stl::move(*instance));
572 ENTT_ASSERT(instance,
"Invalid instance");
573 return static_cast<Type
>(stl::move(*instance));
578template<
typename Type, stl::
size_t Len, stl::
size_t Align>
580 return data->template data<stl::remove_const_t<Type>>();
584template<
typename Type, stl::
size_t Len, stl::
size_t Align>
586 if constexpr(stl::is_const_v<Type>) {
590 return data->template data<Type>();
603template<typename Type, stl::size_t Len = basic_any<>::length, stl::size_t Align = basic_any<Len>::alignment,
typename... Args>
616template<stl::size_t Len = basic_any<>::length, stl::size_t Align = basic_any<Len>::alignment,
typename Type>
A SBO friendly, type-safe container for single values of any type.
void reset()
Destroys contained object.
constexpr basic_any() noexcept
Default constructor.
basic_any(const basic_any &other)
Copy constructor.
const Type * data() const noexcept
Returns an opaque pointer to the contained instance.
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
bool has_value() const noexcept
Returns false if a wrapper is empty, true otherwise.
bool owner() const noexcept
Returns true if a wrapper owns its object, false otherwise.
bool assign(const basic_any &other)
Assigns a value to the contained object without replacing it.
bool assign(basic_any &&other)
Assigns a value to the contained object without replacing it.
static constexpr auto length
void emplace(Args &&...args)
static constexpr auto alignment
const type_info & info() const noexcept
Returns the object type info if any, type_id<void>() otherwise.
basic_any(basic_any &&other) noexcept
Move constructor.
any_policy policy() const noexcept
Returns the current mode of an any object.
basic_any(stl::in_place_type_t< Type >, Args &&...args)
Constructs a wrapper by directly initializing the new object.
basic_any as_ref() noexcept
Aliasing constructor.
basic_any(Type &&value)
Constructs a wrapper from a given value.
~basic_any()
Frees the internal buffer, whatever it means.
basic_any & operator=(const basic_any &other)
Copy assignment operator.
void * data(const type_info &req) noexcept
Returns an opaque pointer to the contained instance.
basic_any as_ref() const noexcept
Aliasing constructor.
bool has_value() const noexcept
Returns false if the wrapper does not contain the expected type, true otherwise.
basic_any & operator=(basic_any &&other) noexcept
Move assignment operator.
bool has_value(const type_info &req) const noexcept
Returns false if the wrapper does not contain the expected type, true otherwise.
bool operator==(const basic_any &other) const noexcept
Checks if two wrappers differ in their content.
void * data() noexcept
Returns an opaque pointer to the contained instance.
Type * data() noexcept
Returns an opaque pointer to the contained instance.
const void * data(const type_info &req) const noexcept
Returns an opaque pointer to the contained instance.
basic_any(stl::in_place_t, Type *value)
Constructs a wrapper taking ownership of the passed object.
stl::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
any_policy
Possible modes of an any object.
@ ref
Aliasing mode, non-const reference.
@ cref
Const aliasing mode, const reference.
@ embedded
Owning mode, embedded element.
@ empty
Default mode, no element available.
@ dynamic
Owning mode, dynamically allocated element.
basic_any< Len, Align > make_any(Args &&...args)
Constructs a wrapper from a given type, passing it all arguments.
stl::uint32_t id_type
Alias declaration for type identifiers.
basic_any< Len, Align > forward_as_any(Type &&value)
Forwards its argument and avoids copies for lvalue references.
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.
Implementation specific information about a type.