1#ifndef ENTT_CORE_ANY_HPP
2#define ENTT_CORE_ANY_HPP
8#include "../config/config.h"
9#include "../core/utility.hpp"
11#include "type_info.hpp"
12#include "type_traits.hpp"
19enum class any_operation : std::uint8_t {
47template<std::
size_t Len, std::
size_t Align>
49 using operation = internal::any_operation;
50 using vtable_type =
const void *(
const operation,
const basic_any &,
const void *);
53 alignas(Align) std::byte data[Len + !Len];
56 template<
typename Type>
57 static constexpr bool in_situ = Len &&
alignof(Type) <= Align &&
sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
59 template<
typename Type>
60 static const void *basic_vtable(
const operation op,
const basic_any &value,
const void *other) {
61 static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>,
"Invalid type");
62 const Type *element =
nullptr;
64 if constexpr(in_situ<Type>) {
65 element = (value.mode ==
any_policy::owner) ?
reinterpret_cast<const Type *
>(&value.storage) :
static_cast<const Type *
>(value.instance);
67 element =
static_cast<const Type *
>(value.instance);
72 if constexpr(std::is_copy_constructible_v<Type>) {
73 static_cast<basic_any *
>(
const_cast<void *
>(other))->initialize<Type>(*element);
77 if constexpr(in_situ<Type>) {
79 return new(&
static_cast<basic_any *
>(
const_cast<void *
>(other))->storage) Type{std::move(*
const_cast<Type *
>(element))};
83 return (
static_cast<basic_any *
>(
const_cast<void *
>(other))->instance = std::exchange(
const_cast<basic_any &
>(value).instance,
nullptr));
84 case operation::transfer:
85 if constexpr(std::is_move_assignable_v<Type>) {
86 *
const_cast<Type *
>(element) = std::move(*
static_cast<Type *
>(
const_cast<void *
>(other)));
90 case operation::assign:
91 if constexpr(std::is_copy_assignable_v<Type>) {
92 *
const_cast<Type *
>(element) = *
static_cast<const Type *
>(other);
96 case operation::destroy:
97 if constexpr(in_situ<Type>) {
99 }
else if constexpr(std::is_array_v<Type>) {
105 case operation::compare:
106 if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
107 return *element == *
static_cast<const Type *
>(other) ? other :
nullptr;
109 return (element == other) ? other :
nullptr;
118 template<
typename Type,
typename... Args>
119 void initialize([[maybe_unused]] Args &&...args) {
120 info = &type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
122 if constexpr(!std::is_void_v<Type>) {
123 vtable = basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
125 if constexpr(std::is_lvalue_reference_v<Type>) {
126 static_assert((std::is_lvalue_reference_v<Args> && ...) && (
sizeof...(Args) == 1u),
"Invalid arguments");
128 instance = (std::addressof(args), ...);
129 }
else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) {
130 if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (
sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
131 new(&
storage) std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
133 new(&
storage) std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
136 if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (
sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
137 instance =
new std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
139 instance =
new std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
146 : instance{other.data()},
148 vtable{other.vtable},
167 template<
typename Type,
typename... Args>
168 explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
173 initialize<Type>(std::forward<Args>(args)...);
181 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
183 :
basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
192 other.vtable(operation::copy, other,
this);
203 vtable{other.vtable},
206 other.vtable(operation::move, other,
this);
213 vtable(operation::destroy, *
this,
nullptr);
226 other.vtable(operation::copy, other,
this);
241 other.vtable(operation::move, other,
this);
243 vtable = other.vtable;
256 template<
typename Type>
259 emplace<std::decay_t<Type>>(std::forward<Type>(value));
275 [[nodiscard]]
const void *
data() const noexcept {
276 return vtable ? vtable(operation::get, *
this,
nullptr) :
nullptr;
285 return *info == req ?
data() :
nullptr;
292 [[nodiscard]]
void *
data() noexcept {
293 return mode ==
any_policy::cref ? nullptr :
const_cast<void *
>(std::as_const(*this).data());
302 return mode ==
any_policy::cref ? nullptr :
const_cast<void *
>(std::as_const(*this).data(req));
311 template<
typename Type,
typename... Args>
314 initialize<Type>(std::forward<Args>(args)...);
324 return (vtable(operation::assign, *
this, other.
data()) !=
nullptr);
333 if(
auto *val = other.data(); val) {
334 return (vtable(operation::transfer, *
this, val) !=
nullptr);
336 return (vtable(operation::assign, *
this, std::as_const(other).
data()) !=
nullptr);
346 vtable(operation::destroy, *
this,
nullptr);
350 ENTT_ASSERT((instance =
nullptr) ==
nullptr,
"");
351 info = &type_id<void>();
360 [[nodiscard]]
explicit operator bool() const noexcept {
361 return vtable !=
nullptr;
370 if(vtable && *info == *other.info) {
371 return (vtable(operation::compare, *
this, other.data()) !=
nullptr);
374 return (!vtable && !other.vtable);
383 return !(*
this == other);
403 [[deprecated(
"use policy() and any_policy instead")]] [[nodiscard]]
bool owner() const noexcept {
417 const void *instance;
420 const type_info *info;
433template<
typename Type, std::
size_t Len, std::
size_t Align>
435 const auto *
const instance = any_cast<std::remove_reference_t<Type>>(&data);
436 ENTT_ASSERT(instance,
"Invalid instance");
437 return static_cast<Type
>(*instance);
441template<
typename Type, std::
size_t Len, std::
size_t Align>
444 auto *
const instance = any_cast<std::remove_reference_t<const Type>>(&data);
445 ENTT_ASSERT(instance,
"Invalid instance");
446 return static_cast<Type
>(*instance);
450template<
typename Type, std::
size_t Len, std::
size_t Align>
452 if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
453 if(
auto *
const instance =
any_cast<std::remove_reference_t<Type>>(&data); instance) {
454 return static_cast<Type
>(std::move(*instance));
456 return any_cast<Type>(data);
459 auto *
const instance = any_cast<std::remove_reference_t<Type>>(&data);
460 ENTT_ASSERT(instance,
"Invalid instance");
461 return static_cast<Type
>(std::move(*instance));
466template<
typename Type, std::
size_t Len, std::
size_t Align>
468 const auto &info = type_id<std::remove_cv_t<Type>>();
469 return static_cast<const Type *
>(data->data(info));
473template<
typename Type, std::
size_t Len, std::
size_t Align>
475 if constexpr(std::is_const_v<Type>) {
477 return any_cast<Type>(&std::as_const(*data));
479 const auto &info = type_id<std::remove_cv_t<Type>>();
480 return static_cast<Type *
>(data->data(info));
493template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align =
basic_any<Len>::alignment,
typename... Args>
A SBO friendly, type-safe container for single values of any type.
void reset()
Destroys contained object.
constexpr basic_any() noexcept
Default constructor.
std::enable_if_t<!std::is_same_v< std::decay_t< Type >, basic_any >, basic_any & > operator=(Type &&value)
Value assignment operator.
basic_any(const basic_any &other)
Copy constructor.
basic_any(std::in_place_type_t< Type >, Args &&...args)
Constructs a wrapper by directly initializing the new object.
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
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
Size of the internal storage.
void emplace(Args &&...args)
Replaces the contained object by creating a new instance directly.
const type_info & type() const noexcept
Returns the object type if any, type_id<void>() otherwise.
bool operator!=(const basic_any &other) const noexcept
Checks if two wrappers differ in their content.
static constexpr auto alignment
Alignment requirement.
basic_any(basic_any &&other) noexcept
Move constructor.
any_policy policy() const noexcept
Returns the current mode of an any object.
basic_any as_ref() noexcept
Aliasing constructor.
~basic_any()
Frees the internal storage, 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.
basic_any & operator=(basic_any &&other) noexcept
Move assignment operator.
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.
basic_any(Type &&value)
Constructs a wrapper from a given value.
const void * data(const type_info &req) const noexcept
Returns an opaque pointer to the contained instance.
Basic storage implementation.
constexpr get_t< Type... > get
Variable template for lists of observed components.
Type any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
basic_any< Len, Align > make_any(Args &&...args)
Constructs a wrapper from a given type, passing it all arguments.
any_policy
Possible modes of an any object.
@ ref
Aliasing mode, the object points to a non-const element.
@ cref
Const aliasing mode, the object points to a const element.
@ owner
Default mode, the object owns the contained element.
basic_any< Len, Align > forward_as_any(Type &&value)
Forwards its argument and avoids copies for lvalue references.
Provides a common way to define storage types.
Implementation specific information about a type.