Class meta_any

Synopsis

#include <src/entt/meta/meta.hpp>

class meta_any

Description

Opaque wrapper for values of any type.

Mentioned in

Methods

meta_any overloadDefault constructor.
meta_any overloadConstructs a meta any by directly initializing the new object.
meta_any overloadConstructs a meta any that holds an unmanaged object.
meta_any overloadConstructs a meta any from a given value.
meta_any overloadCopy constructor.
meta_any overloadMove constructor.
~meta_anyFrees the internal storage, whatever it means.
allow_cast overloadTries to make an instance castable to a certain type.
as_associative_container overloadReturns an associative container proxy.
as_sequence_container overloadReturns a sequence container proxy.
cast overloadTries to cast an instance to a given type.
data overloadReturns an opaque pointer to the contained instance.
emplaceReplaces the contained object by creating a new instance directly.
get overloadGets the value of a given variable.
invoke overloadInvokes the underlying function, if possible.
operator boolReturns false if a wrapper is invalid, true otherwise.
operator* overloadIndirection operator for dereferencing opaque objects.
operator=Assignment operator.
operator==Checks if two wrappers differ in their content.
setSets the value of a given variable.
try_cast overloadTries to cast an instance to a given type.
typeReturns the meta type of the underlying object.

Source

Lines 158-553 in src/entt/meta/meta.hpp.

class meta_any {
    enum class operation { DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC };

    using vtable_type = void(const operation, const any &, void *);

    template<typename Type>
    static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) {
        switch(op) {
        case operation::DEREF:
            if constexpr(is_meta_pointer_like_v<Type>) {
                *static_cast<meta_any *>(to) = std::reference_wrapper{adl_meta_pointer_like<Type>::dereference(any_cast<const Type>(from))};
            }
            break;
        case operation::CDEREF:
            if constexpr(is_meta_pointer_like_v<Type>) {
                *static_cast<meta_any *>(to) = std::cref(adl_meta_pointer_like<Type>::dereference(any_cast<const Type>(from)));
            }
            break;
        case operation::SEQ:
            if constexpr(has_meta_sequence_container_traits_v<Type>) {
                *static_cast<meta_sequence_container *>(to) = { std::in_place_type<Type>, as_ref(const_cast<any &>(from)) };
            }
            break;
        case operation::CSEQ:
            if constexpr(has_meta_sequence_container_traits_v<Type>) {
                *static_cast<meta_sequence_container *>(to) = { std::in_place_type<Type>, as_ref(from) };
            }
            break;
        case operation::ASSOC:
            if constexpr(has_meta_associative_container_traits_v<Type>) {
                *static_cast<meta_associative_container *>(to) = { std::in_place_type<Type>, as_ref(const_cast<any &>(from)) };
            }
            break;
        case operation::CASSOC:
            if constexpr(has_meta_associative_container_traits_v<Type>) {
                *static_cast<meta_associative_container *>(to) = { std::in_place_type<Type>, as_ref(from) };
            }
            break;
        }
    }

public:
    /*! @brief Default constructor. */
    meta_any() ENTT_NOEXCEPT
        : storage{},
          vtable{},
          node{}
    {}

    /**
     * @brief Constructs a meta any 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)...),
          vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
          node{internal::meta_info<std::remove_const_t<std::remove_reference_t<Type>>>::resolve()}
    {}

    /**
     * @brief Constructs a meta any that holds an unmanaged object.
     * @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>
    meta_any(std::reference_wrapper<Type> value)
        : meta_any{std::in_place_type<Type &>, &value.get()}
    {}

    /**
     * @brief Constructs a meta any 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::remove_cv_t<std::remove_reference_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
        : meta_any{}
    {
        swap(*this, other);
    }

    /*! @brief Frees the internal storage, whatever it means. */
    ~meta_any() {
        if(node && node->dtor) {
            node->dtor(storage.data());
        }
    }

    /**
     * @brief Assignment operator.
     * @param other The instance to assign from.
     * @return This meta any object.
     */
    meta_any & operator=(meta_any other) {
        swap(other, *this);
        return *this;
    }

    /**
     * @brief Returns the meta type of the underlying object.
     * @return The meta type of the underlying object, if any.
     */
    [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT;

    /**
     * @brief Returns an opaque pointer to the contained instance.
     * @return An opaque pointer the contained instance, if any.
     */
    [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
        return storage.data();
    }

    /*! @copydoc data */
    [[nodiscard]] void * data() ENTT_NOEXCEPT {
        return storage.data();
    }

    /**
     * @brief Invokes the underlying function, if possible.
     *
     * @sa 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 meta any 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 must be 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 meta any 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(node) {
            if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
                return any_cast<Type>(&storage);
            } else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
                return static_cast<const Type *>(base->cast(storage.data()));
            }
        }

        return nullptr;
    }

    /*! @copydoc try_cast */
    template<typename Type>
    [[nodiscard]] Type * try_cast() {
        if(node) {
            if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
                return any_cast<Type>(&storage);
            } else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
                return static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(base->cast(static_cast<constness_as_t<any, Type> &>(storage).data())));
            }
        }

        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 a cast that isn't viable results in 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 actual = try_cast<std::remove_reference_t<Type>>();
        ENTT_ASSERT(actual);
        return static_cast<Type>(*actual);
    }

    /*! @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 actual = try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>();
        ENTT_ASSERT(actual);
        return static_cast<Type>(*actual);
    }

    /**
     * @brief Tries to make an instance castable to a certain type.
     * @tparam Type Type to which the cast is requested.
     * @return A valid meta any object if there exists a a viable conversion
     * that makes the cast possible, an invalid object otherwise.
     */
    template<typename Type>
    [[nodiscard]] meta_any allow_cast() const {
        if(try_cast<std::remove_reference_t<Type>>() != nullptr) {
            return as_ref(*this);
        } else if(node) {
            if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info<Type>::resolve()->info](const auto *curr) {
                return curr->type()->info == info;
            }, node); conv) {
                return conv->conv(storage.data());
            }
        }

        return {};
    }

    /**
     * @brief Tries to make an instance castable to a certain type.
     * @tparam Type Type to which the cast is requested.
     * @return True if there exists a a viable conversion that makes the cast
     * possible, false otherwise.
     */
    template<typename Type>
    bool allow_cast() {
        if(try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>() != nullptr) {
            return true;
        } else if(node) {
            if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info<Type>::resolve()->info](const auto *curr) {
                return curr->type()->info == info;
            }, node); conv) {
                auto other = conv->conv(std::as_const(storage).data());
                swap(other, *this);
                return true;
            }
        }

        return false;
    }

    /**
     * @brief Replaces the contained object by creating a new instance directly.
     * @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>
    void emplace(Args &&... args) {
        *this = meta_any{std::in_place_type<Type>, std::forward<Args>(args)...};
    }

    /**
     * @brief Returns a sequence container proxy.
     * @return A sequence container proxy for the underlying object.
     */
    [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT {
        meta_sequence_container proxy;
        vtable(operation::SEQ, storage, &proxy);
        return proxy;
    }

    /*! @copydoc as_sequence_container */
    [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT {
        meta_sequence_container proxy;
        vtable(operation::CSEQ, storage, &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 {
        meta_associative_container proxy;
        vtable(operation::ASSOC, storage, &proxy);
        return proxy;
    }

    /*! @copydoc as_associative_container */
    [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT {
        meta_associative_container proxy;
        vtable(operation::CASSOC, storage, &proxy);
        return proxy;
    }

    /**
     * @brief Indirection operator for dereferencing opaque objects.
     * @return A meta any that shares a reference to an unmanaged object if the
     * wrapped element is dereferenceable, an invalid meta any otherwise.
     */
    [[nodiscard]] meta_any operator*() ENTT_NOEXCEPT {
        meta_any any{};
        vtable(operation::DEREF, storage, &any);
        return any;
    }

    /*! @copydoc operator* */
    [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT {
        meta_any any{};
        vtable(operation::CDEREF, storage, &any);
        return any;
    }

    /**
     * @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);
    }

    /**
     * @brief Checks if two wrappers differ in their content.
     * @param other Wrapper with which to compare.
     * @return False if the two objects differ in their content, true otherwise.
     */
    [[nodiscard]] bool operator==(const meta_any &other) const {
        return (node == other.node) && (storage == other.storage);
    }

    /**
     * @brief Swaps two meta any objects.
     * @param lhs A valid meta any object.
     * @param rhs A valid meta any object.
     */
    friend void swap(meta_any &lhs, meta_any &rhs) {
        using std::swap;
        swap(lhs.storage, rhs.storage);
        swap(lhs.vtable, rhs.vtable);
        swap(lhs.node, rhs.node);
    }

    /**
     * @brief Aliasing constructor.
     * @param other A reference to an object that isn't necessarily initialized.
     * @return A meta any that shares a reference to an unmanaged object.
     */
    [[nodiscard]] friend meta_any as_ref(meta_any &other) ENTT_NOEXCEPT {
        meta_any ref = as_ref(std::as_const(other));
        ref.storage = as_ref(other.storage);
        return ref;
    }

    /*! @copydoc as_ref */
    [[nodiscard]] friend meta_any as_ref(const meta_any &other) ENTT_NOEXCEPT {
        meta_any ref{};
        ref.node = other.node;
        ref.storage = as_ref(other.storage);
        ref.vtable = other.vtable;
        return ref;
    }

private:
    any storage;
    vtable_type *vtable;
    internal::meta_type_node *node;
};





Add Discussion

Log in to comment