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 *);
54 alignas(
Align) std::byte data[
Len +
static_cast<std::size_t
>(
Len == 0
u)];
57 template<
typename Type>
58 static constexpr bool in_situ = (
Len != 0
u) &&
alignof(Type) <=
Align &&
sizeof(Type) <=
Len && std::is_nothrow_move_constructible_v<Type>;
60 template<
typename Type>
61 static const void *basic_vtable(
const operation
op,
const basic_any &value,
const void *
other) {
62 static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>,
"Invalid type");
63 const Type *
elem =
nullptr;
66 elem = (value.mode ==
any_policy::owner) ?
reinterpret_cast<const Type *
>(&value.storage) :
static_cast<const Type *
>(value.instance);
68 elem =
static_cast<const Type *
>(value.instance);
73 if constexpr(std::is_copy_constructible_v<Type>) {
74 static_cast<basic_any *
>(
const_cast<void *
>(
other))->initialize<Type>(*elem);
84 return (
static_cast<basic_any *
>(
const_cast<void *
>(
other))->instance = std::exchange(
const_cast<basic_any &
>(value).instance,
nullptr));
85 case operation::transfer:
86 if constexpr(std::is_move_assignable_v<Type>) {
87 *
const_cast<Type *
>(
elem) = std::move(*
static_cast<Type *
>(
const_cast<void *
>(
other)));
91 case operation::assign:
92 if constexpr(std::is_copy_assignable_v<Type>) {
93 *
const_cast<Type *
>(
elem) = *
static_cast<const Type *
>(
other);
97 case operation::destroy:
100 }
else if constexpr(std::is_array_v<Type>) {
106 case operation::compare:
108 return *
elem == *
static_cast<const Type *
>(
other) ?
other :
nullptr;
119 template<
typename Type,
typename...
Args>
121 using plain_type = std::remove_cv_t<std::remove_reference_t<Type>>;
124 if constexpr(!std::is_void_v<Type>) {
127 if constexpr(std::is_lvalue_reference_v<Type>) {
128 static_assert((std::is_lvalue_reference_v<Args> && ...) && (
sizeof...(Args) == 1u),
"Invalid arguments");
130 instance = (std::addressof(
args), ...);
132 if constexpr(std::is_aggregate_v<plain_type> && (
sizeof...(Args) != 0
u || !std::is_default_constructible_v<plain_type>)) {
139 if constexpr(std::is_aggregate_v<plain_type> && (
sizeof...(Args) != 0
u || !std::is_default_constructible_v<plain_type>)) {
141 }
else if constexpr(std::is_array_v<plain_type>) {
142 static_assert(
sizeof...(Args) == 0
u,
"Invalid arguments");
143 instance =
new plain_type[std::extent_v<plain_type>]();
152 : instance{
other.data()},
154 vtable{
other.vtable},
173 template<
typename Type,
typename...
Args>
187 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
209 vtable{
other.vtable},
219 vtable(operation::destroy, *
this,
nullptr);
246 ENTT_ASSERT(
this != &
other,
"Self move assignment");
253 vtable =
other.vtable;
266 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
285 return vtable ? vtable(operation::get, *
this,
nullptr) :
nullptr;
294 return *info ==
req ?
data() :
nullptr;
320 template<
typename Type,
typename...
Args>
333 return (vtable(operation::assign, *
this,
other.data()) !=
nullptr);
343 return (vtable(operation::transfer, *
this,
val) !=
nullptr);
346 return (vtable(operation::assign, *
this, std::as_const(
other).
data()) !=
nullptr);
355 vtable(operation::destroy, *
this,
nullptr);
359 ENTT_ASSERT((instance =
nullptr) ==
nullptr,
"");
370 return vtable !=
nullptr;
379 if(vtable && *info == *
other.info) {
380 return (vtable(operation::compare, *
this,
other.data()) !=
nullptr);
383 return (!vtable && !
other.vtable);
392 return !(*
this ==
other);
418 const void *instance;
421 const type_info *info;
434template<
typename Type, std::
size_t Len, std::
size_t Align>
437 ENTT_ASSERT(instance,
"Invalid instance");
438 return static_cast<Type
>(*instance);
442template<
typename Type, std::
size_t Len, std::
size_t Align>
446 ENTT_ASSERT(instance,
"Invalid instance");
447 return static_cast<Type
>(*instance);
451template<
typename Type, std::
size_t Len, std::
size_t Align>
453 if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
454 if(
auto *
const instance =
any_cast<std::remove_reference_t<Type>>(&data); instance) {
455 return static_cast<Type
>(std::move(*instance));
461 ENTT_ASSERT(instance,
"Invalid instance");
462 return static_cast<Type
>(std::move(*instance));
467template<
typename Type, std::
size_t Len, std::
size_t Align>
470 return static_cast<const Type *
>(data->data(info));
474template<
typename Type, std::
size_t Len, std::
size_t Align>
476 if constexpr(std::is_const_v<Type>) {
481 return static_cast<Type *
>(data->data(info));
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 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=(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 Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
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.
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.