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_request : std::uint8_t {
37template<std::
size_t Len, std::
size_t Align>
39 using request = internal::any_request;
40 using vtable_type =
const void *(
const request,
const basic_any &,
const void *);
44 alignas(Align) std::byte
data[Len +
static_cast<std::size_t
>(Len == 0u)];
47 template<
typename Type>
49 static constexpr bool in_situ = (Len != 0u) &&
alignof(Type) <= Align &&
sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
51 template<
typename Type>
52 static const void *basic_vtable(
const request req,
const basic_any &value,
const void *other) {
53 static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>,
"Invalid type");
54 const Type *elem =
nullptr;
56 if constexpr(in_situ<Type>) {
57 elem = (value.mode ==
any_policy::embedded) ?
reinterpret_cast<const Type *
>(&value.storage) :
static_cast<const Type *
>(value.instance);
59 elem =
static_cast<const Type *
>(value.instance);
63 case request::transfer:
64 if constexpr(std::is_move_assignable_v<Type>) {
66 *
const_cast<Type *
>(elem) = std::move(*
static_cast<Type *
>(
const_cast<void *
>(other)));
71 if constexpr(std::is_copy_assignable_v<Type>) {
72 *
const_cast<Type *
>(elem) = *
static_cast<const Type *
>(other);
76 case request::destroy:
77 if constexpr(in_situ<Type>) {
79 }
else if constexpr(std::is_array_v<Type>) {
85 case request::compare:
87 return (*elem == *
static_cast<const Type *
>(other)) ? other :
nullptr;
89 return (elem == other) ? other :
nullptr;
92 if constexpr(std::is_copy_constructible_v<Type>) {
94 static_cast<basic_any *
>(
const_cast<void *
>(other))->initialize<Type>(*elem);
99 if constexpr(in_situ<Type>) {
101 return ::new(&
static_cast<basic_any *
>(
const_cast<void *
>(other))->storage) Type{std::move(*
const_cast<Type *
>(elem))};
106 if constexpr(in_situ<Type>) {
115 template<
typename Type,
typename... Args>
116 void initialize([[maybe_unused]] Args &&...args) {
117 if constexpr(!std::is_void_v<Type>) {
118 using plain_type = std::remove_cv_t<std::remove_reference_t<Type>>;
121 vtable = basic_vtable<plain_type>;
123 if constexpr(std::is_lvalue_reference_v<Type>) {
124 static_assert((std::is_lvalue_reference_v<Args> && ...) && (
sizeof...(Args) == 1u),
"Invalid arguments");
127 instance = (std::addressof(args), ...);
128 }
else if constexpr(in_situ<plain_type>) {
131 if constexpr(std::is_aggregate_v<plain_type> && (
sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
132 ::new(&storage) plain_type{std::forward<Args>(args)...};
135 ::new(&storage) plain_type(std::forward<Args>(args)...);
140 if constexpr(std::is_aggregate_v<plain_type> && (
sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
141 instance =
new plain_type{std::forward<Args>(args)...};
142 }
else if constexpr(std::is_array_v<plain_type>) {
143 static_assert(
sizeof...(Args) == 0u,
"Invalid arguments");
144 instance =
new plain_type[std::extent_v<plain_type>]();
146 instance =
new plain_type(std::forward<Args>(args)...);
153 : instance{other.data()},
155 vtable{other.vtable},
166 : basic_any{std::in_place_type<void>} {}
174 template<
typename Type,
typename... Args>
175 explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
177 initialize<Type>(std::forward<Args>(args)...);
185 template<
typename Type>
188 static_assert(!std::is_const_v<Type> && !std::is_void_v<Type>,
"Non-const non-void pointer required");
190 if(value !=
nullptr) {
191 initialize<Type &>(*value);
201 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
203 : basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
212 other.vtable(request::copy, other,
this);
223 vtable{other.vtable},
226 other.vtable(request::move, other,
this);
228 instance = std::exchange(other.instance,
nullptr);
235 vtable(request::destroy, *
this,
nullptr);
249 other.vtable(request::copy, other,
this);
269 other.vtable(request::move, other,
this);
271 instance = std::exchange(other.instance,
nullptr);
275 vtable = other.vtable;
287 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
305 [[nodiscard]]
const void *
data() const noexcept {
315 return (
type() == req) ?
data() :
nullptr;
322 [[nodiscard]]
void *
data() noexcept {
323 return mode ==
any_policy::cref ? nullptr :
const_cast<void *
>(std::as_const(*this).data());
332 return mode ==
any_policy::cref ? nullptr :
const_cast<void *
>(std::as_const(*this).data(req));
341 template<
typename Type,
typename... Args>
344 initialize<Type>(std::forward<Args>(args)...);
354 return (vtable(request::assign, *
this, other.
data()) !=
nullptr);
364 if(
auto *val = other.data(); val) {
365 return (vtable(request::transfer, *
this, val) !=
nullptr);
368 return (vtable(request::assign, *
this, std::as_const(other).
data()) !=
nullptr);
377 vtable(request::destroy, *
this,
nullptr);
390 [[nodiscard]]
explicit operator bool() const noexcept {
391 return vtable !=
nullptr;
399 [[nodiscard]]
bool operator==(
const basic_any &other)
const noexcept {
400 if(vtable && *info == other.type()) {
401 return (vtable(request::compare, *
this, other.data()) !=
nullptr);
404 return (!vtable && !other.vtable);
412 [[nodiscard]]
bool operator!=(
const basic_any &other)
const noexcept {
413 return !(*
this == other);
420 [[nodiscard]] basic_any
as_ref() noexcept {
425 [[nodiscard]] basic_any
as_ref() const noexcept {
433 [[nodiscard]]
bool owner() const noexcept {
447 const void *instance;
450 const type_info *info{};
451 vtable_type *vtable{};
463template<
typename Type, std::
size_t Len, std::
size_t Align>
466 ENTT_ASSERT(instance,
"Invalid instance");
467 return static_cast<Type
>(*instance);
471template<
typename Type, std::
size_t Len, std::
size_t Align>
475 ENTT_ASSERT(instance,
"Invalid instance");
476 return static_cast<Type
>(*instance);
480template<
typename Type, std::
size_t Len, std::
size_t Align>
483 if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
484 if(
auto *
const instance =
any_cast<std::remove_reference_t<Type>>(&data); instance) {
485 return static_cast<Type
>(std::move(*instance));
491 ENTT_ASSERT(instance,
"Invalid instance");
492 return static_cast<Type
>(std::move(*instance));
497template<
typename Type, std::
size_t Len, std::
size_t Align>
500 return static_cast<const Type *
>(data->data(info));
504template<
typename Type, std::
size_t Len, std::
size_t Align>
506 if constexpr(std::is_const_v<Type>) {
511 return static_cast<Type *
>(data->data(info));
524template<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.
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
void emplace(Args &&...args)
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
basic_any(basic_any &&other) noexcept
Move constructor.
any_policy policy() const noexcept
Returns the current mode of an any object.
basic_any(std::in_place_t, Type *value)
Constructs a wrapper taking ownership of the passed 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=(Type &&value)
Value assignment operator.
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.
constexpr bool is_equality_comparable_v
Helper variable template.
std::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
basic_any< Len, Align > make_any(Args &&...args)
Constructs a wrapper from a given type, passing it all arguments.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
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.
@ embedded
Owning mode, the object owns an embedded element.
@ empty
Default mode, the object does not own any elements.
@ dynamic
Owning mode, the object owns a dynamically allocated element.
basic_any< Len, Align > forward_as_any(Type &&value)
Forwards its argument and avoids copies for lvalue references.
basic_storage< Type > storage
Alias declaration for the most common use case.
Provides a common way to define storage types.
Implementation specific information about a type.