aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/any.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EASTL/any.h')
-rw-r--r--include/EASTL/any.h652
1 files changed, 0 insertions, 652 deletions
diff --git a/include/EASTL/any.h b/include/EASTL/any.h
deleted file mode 100644
index c2ef638..0000000
--- a/include/EASTL/any.h
+++ /dev/null
@@ -1,652 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-// Copyright (c) Electronic Arts Inc. All rights reserved.
-/////////////////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////////////////
-// This file implements the eastl::any which is part of the C++ standard STL
-// library specification.
-//
-// eastl::any is a type-safe container for single values of any type. Our
-// implementation makes use of the "small local buffer" optimization to avoid
-// unnecessary dynamic memory allocation if the specified type is eligible to
-// be stored in its local buffer. The user type must satisfy the size
-// requirements and must be no-throw move-constructible to qualify for the local
-// buffer optimization.
-//
-// To consider: Implement a fixed_any<SIZE> variant to allow users to customize
-// the size of the "small local buffer" optimization.
-//
-// http://en.cppreference.com/w/cpp/utility/any
-///////////////////////////////////////////////////////////////////////////////
-
-
-#ifndef EASTL_ANY_H
-#define EASTL_ANY_H
-
-#if defined(EA_PRAGMA_ONCE_SUPPORTED)
- #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
-#endif
-
-#include <EASTL/internal/config.h>
-#include <EASTL/internal/in_place_t.h>
-#if EASTL_RTTI_ENABLED
- #include <typeinfo>
-#endif
-#if EASTL_EXCEPTIONS_ENABLED
- #include <exception>
-#endif
-
-
-namespace eastl
-{
- ///////////////////////////////////////////////////////////////////////////////
- // bad_any_cast
- //
- // The type thrown by any_cast on failure.
- //
- // http://en.cppreference.com/w/cpp/utility/any/bad_any_cast
- //
- #if EASTL_EXCEPTIONS_ENABLED
- struct bad_cast : std::exception
- {
- const char* what() const EA_NOEXCEPT EA_OVERRIDE
- { return "bad cast"; }
- };
-
- struct bad_any_cast : public bad_cast
- {
- const char* what() const EA_NOEXCEPT EA_OVERRIDE
- { return "bad_any_cast"; }
- };
- #endif
-
- namespace Internal
- {
- // utility to switch between exceptions and asserts
- inline void DoBadAnyCast()
- {
- #if EASTL_EXCEPTIONS_ENABLED
- throw bad_any_cast();
- #else
- EASTL_ASSERT_MSG(false, "bad_any_cast\n");
-
- // NOTE(rparolin): CRASH!
- // You crashed here because you requested a type that was not contained in the object.
- // We choose to intentionally crash here instead of returning invalid data to the calling
- // code which could cause hard to track down bugs.
- *((volatile int*)0) = 0xDEADC0DE;
- #endif
- }
-
- template<typename T, typename... Args>
- void* DefaultConstruct(Args&&... args)
- {
- auto* pMem = EASTLAllocatorDefault()->allocate(sizeof(T), alignof(T), 0);
-
- return ::new(pMem) T(eastl::forward<Args>(args)...);
- }
-
- template<typename T>
- void DefaultDestroy(T* p)
- {
- p->~T();
-
- EASTLAllocatorDefault()->deallocate(static_cast<void*>(p), sizeof(T));
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // 20.7.3, class any
- //
- 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
- };
-
-
-
- //////////////////////////////////////////////////////////////////////////////////////////
- // 20.7.4, non-member functions
- //
- inline void swap(any& rhs, any& lhs) EA_NOEXCEPT { rhs.swap(lhs); }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////
- // 20.7.4, The non-member any_cast functions provide type-safe access to the contained object.
- //
- template <class ValueType>
- inline ValueType any_cast(const any& operand)
- {
- static_assert(eastl::is_reference<ValueType>::value || eastl::is_copy_constructible<ValueType>::value,
- "ValueType must be a reference or copy constructible");
-
- auto* p = any_cast<typename add_const<typename remove_reference<ValueType>::type>::type>(&operand);
-
- if(p == nullptr)
- Internal::DoBadAnyCast();
-
- return *p;
- }
-
- template <class ValueType>
- inline ValueType any_cast(any& operand)
- {
- static_assert(eastl::is_reference<ValueType>::value || eastl::is_copy_constructible<ValueType>::value,
- "ValueType must be a reference or copy constructible");
-
- auto* p = any_cast<typename remove_reference<ValueType>::type>(&operand);
-
- if(p == nullptr)
- Internal::DoBadAnyCast();
-
- return *p;
- }
-
- template <class ValueType>
- inline ValueType any_cast(any&& operand)
- {
- static_assert(eastl::is_reference<ValueType>::value || eastl::is_copy_constructible<ValueType>::value,
- "ValueType must be a reference or copy constructible");
-
- auto* p = any_cast<typename remove_reference<ValueType>::type>(&operand);
-
- if (p == nullptr)
- Internal::DoBadAnyCast();
-
- return *p;
- }
-
- // NOTE(rparolin): The runtime type check was commented out because in DLL builds the templated function pointer
- // value will be different -- completely breaking the validation mechanism. Due to the fact that eastl::any uses
- // type erasure we can't refresh (on copy/move) the cached function pointer to the internal handler function because
- // we don't statically know the type.
- template <class ValueType>
- inline const ValueType* any_cast(const any* pAny) EA_NOEXCEPT
- {
- return (pAny && pAny->m_handler EASTL_IF_NOT_DLL(== &any::storage_handler<decay_t<ValueType>>::handler_func)
- #if EASTL_RTTI_ENABLED
- && pAny->type() == typeid(typename remove_reference<ValueType>::type)
- #endif
- ) ?
- static_cast<const ValueType*>(pAny->m_handler(any::storage_operation::GET, pAny, nullptr)) :
- nullptr;
- }
-
- template <class ValueType>
- inline ValueType* any_cast(any* pAny) EA_NOEXCEPT
- {
- return (pAny && pAny->m_handler EASTL_IF_NOT_DLL(== &any::storage_handler<decay_t<ValueType>>::handler_func)
- #if EASTL_RTTI_ENABLED
- && pAny->type() == typeid(typename remove_reference<ValueType>::type)
- #endif
- ) ?
- static_cast<ValueType*>(pAny->m_handler(any::storage_operation::GET, pAny, nullptr)) :
- nullptr;
- }
-
- //Unsafe operations - use with caution
- template <class ValueType>
- inline const ValueType* unsafe_any_cast(const any* pAny) EA_NOEXCEPT
- {
- return unsafe_any_cast<ValueType>(const_cast<any*>(pAny));
- }
-
- template <class ValueType>
- inline ValueType* unsafe_any_cast(any* pAny) EA_NOEXCEPT
- {
- return static_cast<ValueType*>(pAny->m_handler(any::storage_operation::GET, pAny, nullptr));
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////
- // make_any
- //
- #if EASTL_VARIADIC_TEMPLATES_ENABLED
- template <class T, class... Args>
- inline any make_any(Args&&... args)
- {
- return any(eastl::in_place<T>, eastl::forward<Args>(args)...);
- }
-
- template <class T, class U, class... Args>
- inline any make_any(std::initializer_list<U> il, Args&&... args)
- {
- return any(eastl::in_place<T>, il, eastl::forward<Args>(args)...);
- }
- #endif
-
-} // namespace eastl
-
-#endif // EASTL_ANY_H