Class meta_any
Synopsis
#include <src/entt/meta/meta.hpp>
class meta_any
Description
Opaque wrapper for values of any type.
Mentioned in
- Runtime Reflection System / Any to the rescue
- Runtime Reflection System / Enjoy the runtime
- Runtime Reflection System / Container support
- Runtime Reflection System / Pointer-like types
- Runtime Reflection System / Automatic conversions
- Runtime Reflection System / Policies: the more, the less
- Runtime Reflection System / Named constants and enums
- Runtime Reflection System / Properties and meta objects
Methods
meta_any overload | Default constructor. | |
meta_any overload | Constructs a wrapper by directly initializing the new object. | |
meta_any overload | Constructs a wrapper from a given value. | |
meta_any overload | Copy constructor. | |
meta_any overload | Move constructor. | |
~meta_any | Frees the internal storage, whatever it means. | |
allow_cast overload | Converts an object in such a way that a given cast becomes viable. | |
as_associative_container overload | Returns an associative container proxy. | |
as_ref overload | Aliasing constructor. | |
as_sequence_container overload | Returns a sequence container proxy. | |
assign overload | Assigns a value to the contained object without replacing it. | |
cast overload | Tries to cast an instance to a given type. | |
data overload | Returns an opaque pointer to the contained instance. | |
emplace | Replaces the contained object by creating a new instance directly. | |
get overload | Gets the value of a given variable. | |
invoke overload | Invokes the underlying function, if possible. | |
operator bool | Returns false if a wrapper is invalid, true otherwise. | |
operator* | Indirection operator for dereferencing opaque objects. | |
operator= overload | Copy assignment operator. | |
operator= overload | Move assignment operator. | |
operator= overload | Value assignment operator. | |
operator== | Checks if two wrappers differ in their content. | |
owner | Returns true if a wrapper owns its object, false otherwise. | |
reset | Destroys contained object. | |
set | Sets the value of a given variable. | |
try_cast overload | Tries to cast an instance to a given type. | |
type | Returns the object type if any, type_id<void>() otherwise. |
Source
Lines 141-569 in src/entt/meta/meta.hpp.
class meta_any {
enum class operation : std::uint8_t {
deref,
seq,
assoc
};
using vtable_type = void(const operation, const any &, void *);
template<typename Type>
static void basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any &value, [[maybe_unused]] void *other) {
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
if constexpr(!std::is_void_v<Type>) {
switch(op) {
case operation::deref:
if constexpr(is_meta_pointer_like_v<Type>) {
if constexpr(std::is_function_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
*static_cast<meta_any *>(other) = any_cast<Type>(value);
} else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>, void>) {
using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(value)));
if constexpr(std::is_constructible_v<bool, Type>) {
if(const auto &pointer_like = any_cast<const Type &>(value); pointer_like) {
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(pointer_like));
}
} else {
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(value)));
}
}
}
break;
case operation::seq:
if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
*static_cast<meta_sequence_container *>(other) = {std::in_place_type<Type>, std::move(const_cast<any &>(value))};
}
break;
case operation::assoc:
if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
*static_cast<meta_associative_container *>(other) = {std::in_place_type<Type>, std::move(const_cast<any &>(value))};
}
break;
}
}
}
void release() {
if(node && node->dtor && storage.owner()) {
node->dtor(storage.data());
}
}
meta_any(const meta_any &other, any ref) ENTT_NOEXCEPT
: storage{std::move(ref)},
node{storage ? other.node : nullptr},
vtable{storage ? other.vtable : &basic_vtable<void>} {}
public:
/*! @brief Default constructor. */
meta_any() ENTT_NOEXCEPT
: storage{},
node{},
vtable{&basic_vtable<void>} {}
/**
* @brief Constructs a wrapper by directly initializing the new object.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
explicit meta_any(std::in_place_type_t<Type>, Args &&...args)
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
node{internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve()},
vtable{&basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>} {}
/**
* @brief Constructs a wrapper from a given value.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
meta_any(Type &&value)
: meta_any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
meta_any(const meta_any &other) = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
meta_any(meta_any &&other) ENTT_NOEXCEPT
: storage{std::move(other.storage)},
node{std::exchange(other.node, nullptr)},
vtable{std::exchange(other.vtable, &basic_vtable<void>)} {}
/*! @brief Frees the internal storage, whatever it means. */
~meta_any() {
release();
}
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @return This meta any object.
*/
meta_any &operator=(const meta_any &other) {
release();
vtable = other.vtable;
storage = other.storage;
node = other.node;
return *this;
}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This meta any object.
*/
meta_any &operator=(meta_any &&other) ENTT_NOEXCEPT {
release();
vtable = std::exchange(other.vtable, &basic_vtable<void>);
storage = std::move(other.storage);
node = std::exchange(other.node, nullptr);
return *this;
}
/**
* @brief Value assignment operator.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
* @return This meta any object.
*/
template<typename Type>
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>, meta_any &>
operator=(Type &&value) {
emplace<std::decay_t<Type>>(std::forward<Type>(value));
return *this;
}
/*! @copydoc any::type */
[[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT;
/*! @copydoc any::data */
[[nodiscard]] const void *data() const ENTT_NOEXCEPT {
return storage.data();
}
/*! @copydoc any::data */
[[nodiscard]] void *data() ENTT_NOEXCEPT {
return storage.data();
}
/**
* @brief Invokes the underlying function, if possible.
*
* @sa meta_func::invoke
*
* @tparam Args Types of arguments to use to invoke the function.
* @param id Unique identifier.
* @param args Parameters to use to invoke the function.
* @return A wrapper containing the returned value, if any.
*/
template<typename... Args>
meta_any invoke(const id_type id, Args &&...args) const;
/*! @copydoc invoke */
template<typename... Args>
meta_any invoke(const id_type id, Args &&...args);
/**
* @brief Sets the value of a given variable.
*
* The type of the value is such that a cast or conversion to the type of
* the variable is possible. Otherwise, invoking the setter does nothing.
*
* @tparam Type Type of value to assign.
* @param id Unique identifier.
* @param value Parameter to use to set the underlying variable.
* @return True in case of success, false otherwise.
*/
template<typename Type>
bool set(const id_type id, Type &&value);
/**
* @brief Gets the value of a given variable.
* @param id Unique identifier.
* @return A wrapper containing the value of the underlying variable.
*/
[[nodiscard]] meta_any get(const id_type id) const;
/*! @copydoc get */
[[nodiscard]] meta_any get(const id_type id);
/**
* @brief Tries to cast an instance to a given type.
* @tparam Type Type to which to cast the instance.
* @return A (possibly null) pointer to the contained instance.
*/
template<typename Type>
[[nodiscard]] const Type *try_cast() const {
if(const auto &info = type_id<Type>(); node && *node->info == info) {
return any_cast<Type>(&storage);
} else if(node) {
for(auto *it = node->base; it; it = it->next) {
const auto as_const = it->cast(as_ref());
if(const Type *base = as_const.template try_cast<Type>(); base) {
return base;
}
}
}
return nullptr;
}
/*! @copydoc try_cast */
template<typename Type>
[[nodiscard]] Type *try_cast() {
if(const auto &info = type_id<Type>(); node && *node->info == info) {
return any_cast<Type>(&storage);
} else if(node) {
for(auto *it = node->base; it; it = it->next) {
if(Type *base = it->cast(as_ref()).template try_cast<Type>(); base) {
return base;
}
}
}
return nullptr;
}
/**
* @brief Tries to cast an instance to a given type.
*
* The type of the instance must be such that the cast is possible.
*
* @warning
* Attempting to perform an invalid cast results is undefined behavior.
*
* @tparam Type Type to which to cast the instance.
* @return A reference to the contained instance.
*/
template<typename Type>
[[nodiscard]] Type cast() const {
auto *const instance = try_cast<std::remove_reference_t<Type>>();
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc cast */
template<typename Type>
[[nodiscard]] Type cast() {
// forces const on non-reference types to make them work also with wrappers for const references
auto *const instance = try_cast<std::remove_reference_t<const Type>>();
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/**
* @brief Converts an object in such a way that a given cast becomes viable.
* @param type Meta type to which the cast is requested.
* @return A valid meta any object if there exists a viable conversion, an
* invalid one otherwise.
*/
[[nodiscard]] meta_any allow_cast(const meta_type &type) const;
/**
* @brief Converts an object in such a way that a given cast becomes viable.
* @param type Meta type to which the cast is requested.
* @return True if there exists a viable conversion, false otherwise.
*/
[[nodiscard]] bool allow_cast(const meta_type &type) {
if(auto other = std::as_const(*this).allow_cast(type); other) {
if(other.storage.owner()) {
std::swap(*this, other);
}
return true;
}
return false;
}
/**
* @brief Converts an object in such a way that a given cast becomes viable.
* @tparam Type Type to which the cast is requested.
* @return A valid meta any object if there exists a viable conversion, an
* invalid one otherwise.
*/
template<typename Type>
[[nodiscard]] meta_any allow_cast() const {
const auto other = allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve());
if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
return other.storage.owner() ? other : meta_any{};
} else {
return other;
}
}
/**
* @brief Converts an object in such a way that a given cast becomes viable.
* @tparam Type Type to which the cast is requested.
* @return True if there exists a viable conversion, false otherwise.
*/
template<typename Type>
bool allow_cast() {
if(auto other = std::as_const(*this).allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve()); other) {
if(other.storage.owner()) {
std::swap(*this, other);
return true;
}
return (static_cast<constness_as_t<any, std::remove_reference_t<const Type>> &>(storage).data() != nullptr);
}
return false;
}
/*! @copydoc any::emplace */
template<typename Type, typename... Args>
void emplace(Args &&...args) {
release();
vtable = &basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
storage.emplace<Type>(std::forward<Args>(args)...);
node = internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::resolve();
}
/*! @copydoc any::assign */
bool assign(const meta_any &other);
/*! @copydoc any::assign */
bool assign(meta_any &&other);
/*! @copydoc any::reset */
void reset() {
release();
vtable = &basic_vtable<void>;
storage.reset();
node = nullptr;
}
/**
* @brief Returns a sequence container proxy.
* @return A sequence container proxy for the underlying object.
*/
[[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT {
any detached = storage.as_ref();
meta_sequence_container proxy;
vtable(operation::seq, detached, &proxy);
return proxy;
}
/*! @copydoc as_sequence_container */
[[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT {
any detached = storage.as_ref();
meta_sequence_container proxy;
vtable(operation::seq, detached, &proxy);
return proxy;
}
/**
* @brief Returns an associative container proxy.
* @return An associative container proxy for the underlying object.
*/
[[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT {
any detached = storage.as_ref();
meta_associative_container proxy;
vtable(operation::assoc, detached, &proxy);
return proxy;
}
/*! @copydoc as_associative_container */
[[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT {
any detached = storage.as_ref();
meta_associative_container proxy;
vtable(operation::assoc, detached, &proxy);
return proxy;
}
/**
* @brief Indirection operator for dereferencing opaque objects.
* @return A wrapper that shares a reference to an unmanaged object if the
* wrapped element is dereferenceable, an invalid meta any otherwise.
*/
[[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT {
meta_any ret{};
vtable(operation::deref, storage, &ret);
return ret;
}
/**
* @brief Returns false if a wrapper is invalid, true otherwise.
* @return False if the wrapper is invalid, true otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return !(node == nullptr);
}
/*! @copydoc any::operator== */
[[nodiscard]] bool operator==(const meta_any &other) const {
return (!node && !other.node) || (node && other.node && *node->info == *other.node->info && storage == other.storage);
}
/*! @copydoc any::as_ref */
[[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT {
return meta_any{*this, storage.as_ref()};
}
/*! @copydoc any::as_ref */
[[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT {
return meta_any{*this, storage.as_ref()};
}
/*! @copydoc any::owner */
[[nodiscard]] bool owner() const ENTT_NOEXCEPT {
return storage.owner();
}
private:
any storage;
internal::meta_type_node *node;
vtable_type *vtable;
};