Class any

Synopsis

#include <include/EASTL/any.h>

class any

Description

20.7.3, class any

Methods

any overloadTODO(rparolin): renable constexpr for GCC.
~any
has_value20.7.3.4, observers
operator= overload20.7.3.2, assignments
reset20.7.3.3, modifiers
swap

Source

Lines 103-537 in include/EASTL/any.h.

class any
{
    //////////////////////////////////////////////////////////////////////////////////////////
    // storage_operation 
    //
    // operations supported by the storage handler 
    //
    enum class storage_operation
    {
        GET,
        DESTROY,
        COPY,
        MOVE,
        TYPE_INFO
    };
    //////////////////////////////////////////////////////////////////////////////////////////
    // storage 
    //
    // the underlying storage type which enables the switching between objects stored in
    // the heap and objects stored within the any type.
    //
    union storage
    {
        typedef aligned_storage_t<4 * sizeof(void*), alignment_of<void*>::value> internal_storage_t;
        void* external_storage = nullptr;
        internal_storage_t internal_storage;
    };
    //////////////////////////////////////////////////////////////////////////////////////////
    // use_internal_storage 
    //
    // determines when the "local buffer optimization" is used 
    //
    template <typename T>
    using use_internal_storage = bool_constant
    <
        is_nothrow_move_constructible<T>::value 
        && (sizeof(T) <= sizeof(storage)) &&
        (alignment_of<storage>::value % alignment_of<T>::value == 0)  
    >;
    //////////////////////////////////////////////////////////////////////////////////////////
    // non-member friend functions  
    //
    template <class ValueType> friend const ValueType* any_cast(const any* pAny) EA_NOEXCEPT;
    template <class ValueType> friend ValueType* any_cast(any* pAny) EA_NOEXCEPT; 
    template <class ValueType> friend ValueType any_cast(const any& operand);
    template <class ValueType> friend ValueType any_cast(any& operand);
    template <class ValueType> friend ValueType any_cast(any&& operand);
    //Adding Unsafe any cast operations
    template <class ValueType> friend const ValueType* unsafe_any_cast(const any* pAny) EA_NOEXCEPT;
    template <class ValueType> friend ValueType* unsafe_any_cast(any* pAny) EA_NOEXCEPT;
    //////////////////////////////////////////////////////////////////////////////////////////
    // internal storage handler
    //
    template <typename T>
    struct storage_handler_internal
    {
        template <typename V>
        static void construct(storage& s, V&& v)
        {
            ::new(&s.internal_storage) T(eastl::forward<V>(v));
        }
        template <typename... Args>
        static void construct_inplace(storage& s, Args... args)
        {
            ::new(&s.internal_storage) T(eastl::forward<Args>(args)...);
        }
        template <class NT, class U, class... Args>
        static void construct_inplace(storage& s, std::initializer_list<U> il, Args&&... args)
        {
            ::new(&s.internal_storage) NT(il, eastl::forward<Args>(args)...);
        }
        static inline void destroy(any& refAny)
        {
            T& t = *static_cast<T*>(static_cast<void*>(&refAny.m_storage.internal_storage));
            EA_UNUSED(t);
            t.~T();
            refAny.m_handler = nullptr;
        }
        static void* handler_func(storage_operation op, const any* pThis, any* pOther)
        {
            switch (op)
            {
                case storage_operation::GET:
                {
                    EASTL_ASSERT(pThis);
                    return (void*)(&pThis->m_storage.internal_storage);
                }
                break;
                case storage_operation::DESTROY:
                {
                    EASTL_ASSERT(pThis);
                    destroy(const_cast<any&>(*pThis));
                }
                break;
                case storage_operation::COPY:
                {
                    EASTL_ASSERT(pThis);
                    EASTL_ASSERT(pOther);
                    construct(pOther->m_storage, *(T*)(&pThis->m_storage.internal_storage));
                }
                break;
                case storage_operation::MOVE:
                {
                    EASTL_ASSERT(pThis);
                    EASTL_ASSERT(pOther);
                    construct(pOther->m_storage, eastl::move(*(T*)(&pThis->m_storage.internal_storage)));
                    destroy(const_cast<any&>(*pThis));
                }
                break;
                case storage_operation::TYPE_INFO:
                {
                #if EASTL_RTTI_ENABLED
                    return (void*)&typeid(T);
                #endif
                }
                break;
                default:
                {
                    EASTL_ASSERT_MSG(false, "unknown storage operation\n");
                }
                break;
            };
            return nullptr;
        }
    };
    //////////////////////////////////////////////////////////////////////////////////////////
    // external storage handler
    //
    template <typename T>
    struct storage_handler_external
    {
        template <typename V>
        static inline void construct(storage& s, V&& v) 
        {
            s.external_storage = Internal::DefaultConstruct<T>(eastl::forward<V>(v));
        }
        template <typename... Args>
        static inline void construct_inplace(storage& s, Args... args)
        {
            s.external_storage = Internal::DefaultConstruct<T>(eastl::forward<Args>(args)...);
        }
        template <class NT, class U, class... Args>
        static inline void construct_inplace(storage& s, std::initializer_list<U> il, Args&&... args)
        {
            s.external_storage = Internal::DefaultConstruct<NT>(il, eastl::forward<Args>(args)...);
        }
        static inline void destroy(any& refAny)
        {
            Internal::DefaultDestroy(static_cast<T*>(refAny.m_storage.external_storage));
            refAny.m_handler = nullptr;
        }
        static void* handler_func(storage_operation op, const any* pThis, any* pOther)
        {
            switch (op)
            {
                case storage_operation::GET:
                {
                    EASTL_ASSERT(pThis);
                    EASTL_ASSERT(pThis->m_storage.external_storage);
                    return static_cast<void*>(pThis->m_storage.external_storage);
                }
                break;
                case storage_operation::DESTROY:
                {
                    EASTL_ASSERT(pThis);
                    destroy(*const_cast<any*>(pThis));
                }
                break;
                case storage_operation::COPY:
                {
                    EASTL_ASSERT(pThis);
                    EASTL_ASSERT(pOther);
                    construct(pOther->m_storage, *static_cast<T*>(pThis->m_storage.external_storage));
                }
                break;
                case storage_operation::MOVE:
                {
                    EASTL_ASSERT(pThis);
                    EASTL_ASSERT(pOther);
                    construct(pOther->m_storage, eastl::move(*(T*)(pThis->m_storage.external_storage)));
                    destroy(const_cast<any&>(*pThis));
                }
                break;
                case storage_operation::TYPE_INFO:
                {
                #if EASTL_RTTI_ENABLED
                    return (void*)&typeid(T);
                #endif
                }
                break;
                default:
                {
                    EASTL_ASSERT_MSG(false, "unknown storage operation\n");
                }
                break;
            };
            return nullptr;
        }
    };
    //////////////////////////////////////////////////////////////////////////////////////////
    // storage_handler_ptr 
    //
    // defines the function signature of the storage handler that both the internal and
    // external storage handlers must implement to retrieve the underlying type of the any
    // object.
    //
    using storage_handler_ptr = void* (*)(storage_operation, const any*, any*);
    //////////////////////////////////////////////////////////////////////////////////////////
    // storage_handler 
    //
    // based on the specified type T we select the appropriate underlying storage handler
    // based on the 'use_internal_storage' trait.
    //
    template <typename T>
    using storage_handler = typename conditional<use_internal_storage<T>::value,
                                                 storage_handler_internal<T>,
                                                 storage_handler_external<T>>::type;
    //////////////////////////////////////////////////////////////////////////////////////////
    // data layout
    //
    storage m_storage;
    storage_handler_ptr m_handler;
public:
        #ifndef EA_COMPILER_GNUC
            // TODO(rparolin):  renable constexpr for GCC
            EA_CONSTEXPR 
        #endif
        any() EA_NOEXCEPT 
        : m_storage(), m_handler(nullptr) {}
    any(const any& other) : m_handler(nullptr)
    {
        if (other.m_handler)
        {
            // NOTE(rparolin): You can not simply copy the underlying
            // storage because it could hold a pointer to an object on the
            // heap which breaks the copy semantics of the language. 
            other.m_handler(storage_operation::COPY, &other, this);
            m_handler = other.m_handler;
        }
    }
    any(any&& other) EA_NOEXCEPT : m_handler(nullptr)
    { 
        if(other.m_handler)
        {
            // NOTE(rparolin): You can not simply move the underlying
            // storage because because the storage class has effectively
            // type erased user type so we have to defer to the handler
            // function to get the type back and pass on the move request.
            m_handler = eastl::move(other.m_handler);
            other.m_handler(storage_operation::MOVE, &other, this);
        }
    }
    ~any() { reset(); }
    template <class ValueType>
    any(ValueType&& value,
        typename eastl::enable_if<!eastl::is_same<typename eastl::decay<ValueType>::type, any>::value>::type* = 0)
    {
        typedef decay_t<ValueType> DecayedValueType;
        static_assert(is_copy_constructible<DecayedValueType>::value, "ValueType must be copy-constructible");
        storage_handler<DecayedValueType>::construct(m_storage, eastl::forward<ValueType>(value));
        m_handler = &storage_handler<DecayedValueType>::handler_func;
    }
    template <class T, class... Args>
    explicit any(in_place_type_t<T>, Args&&... args) 
    {
        typedef storage_handler<decay_t<T>> StorageHandlerT;
        static_assert(eastl::is_constructible<T, Args...>::value, "T must be constructible with Args...");
        StorageHandlerT::construct_inplace(m_storage, eastl::forward<Args>(args)...);
        m_handler = &StorageHandlerT::handler_func;
    }
    template <class T, class U, class... Args>
    explicit any(in_place_type_t<T>,
                 std::initializer_list<U> il,
                 Args&&... args,
                 typename eastl::enable_if<eastl::is_constructible<T, std::initializer_list<U>&, Args...>::value,
                                           void>::type* = 0)
    {
        typedef storage_handler<decay_t<T>> StorageHandlerT;
        StorageHandlerT::construct_inplace(m_storage, il, eastl::forward<Args>(args)...);
        m_handler = &StorageHandlerT::handler_func;
    }
    // 20.7.3.2, assignments
    template <class ValueType>
    any& operator=(ValueType&& value)
    {
        static_assert(is_copy_constructible<decay_t<ValueType>>::value, "ValueType must be copy-constructible");
        any(eastl::forward<ValueType>(value)).swap(*this);
        return *this;
    }
    any& operator=(const any& other) 
    { 
        any(other).swap(*this);
        return *this; 
    }
    any& operator=(any&& other) EA_NOEXCEPT 
    { 
        any(eastl::move(other)).swap(*this);
        return *this; 
    }
       // 20.7.3.3, modifiers
    #if EASTL_VARIADIC_TEMPLATES_ENABLED
        template <class T, class... Args>
        void emplace(Args&&... args)
        {
            typedef storage_handler<decay_t<T>> StorageHandlerT;
            static_assert(eastl::is_constructible<T, Args...>::value, "T must be constructible with Args...");
            reset();
            StorageHandlerT::construct_inplace(m_storage, eastl::forward<Args>(args)...);
            m_handler = &StorageHandlerT::handler_func;
        }
        template <class NT, class U, class... Args>
        typename eastl::enable_if<eastl::is_constructible<NT, std::initializer_list<U>&, Args...>::value, void>::type
        emplace(std::initializer_list<U> il, Args&&... args)
        {
            typedef storage_handler<decay_t<NT>> StorageHandlerT;
            reset();
            StorageHandlerT::construct_inplace(m_storage, il, eastl::forward<Args>(args)...);
            m_handler = &StorageHandlerT::handler_func;
        }
       #endif
    void reset() EA_NOEXCEPT 
    {
        if(m_handler)
            m_handler(storage_operation::DESTROY, this, nullptr);
    }
    void swap(any& other) EA_NOEXCEPT 
    {
        if(this == &other)
            return;
        if(m_handler && other.m_handler)
        {
            any tmp;
            tmp.m_handler = other.m_handler;
            other.m_handler(storage_operation::MOVE, &other, &tmp);
            other.m_handler = m_handler;
            m_handler(storage_operation::MOVE, this, &other);
            m_handler = tmp.m_handler;
            tmp.m_handler(storage_operation::MOVE, &tmp, this);
        }
        else if (m_handler == nullptr && other.m_handler)
        {
            eastl::swap(m_handler, other.m_handler);
            m_handler(storage_operation::MOVE, &other, this);
        }
        else if(m_handler && other.m_handler == nullptr)
        {
            eastl::swap(m_handler, other.m_handler);
            other.m_handler(storage_operation::MOVE, this, &other);
        }
        //else if (m_handler == nullptr && other.m_handler == nullptr)
        //{
        //     // nothing to swap 
        //}
    }
    // 20.7.3.4, observers
    bool has_value() const EA_NOEXCEPT { return m_handler != nullptr; }
       #if EASTL_RTTI_ENABLED
        inline const std::type_info& type() const EA_NOEXCEPT 
        {
            if(m_handler)
            {
                auto* pTypeInfo = m_handler(storage_operation::TYPE_INFO, this, nullptr);
                return *static_cast<const std::type_info*>(pTypeInfo);
            }
            else
            {
                return typeid(void);
            }
        }
    #endif
};





Add Discussion as Guest

Log in