| // -*- C++ -*- |
| //===------------------------------ any -----------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef _LIBCPP_EXPERIMENTAL_ANY |
| #define _LIBCPP_EXPERIMENTAL_ANY |
| |
| /* |
| experimental/any synopsis |
| |
| namespace std { |
| namespace experimental { |
| inline namespace fundamentals_v1 { |
| |
| class bad_any_cast : public bad_cast |
| { |
| public: |
| virtual const char* what() const noexcept; |
| }; |
| |
| class any |
| { |
| public: |
| |
| // 6.3.1 any construct/destruct |
| any() noexcept; |
| |
| any(const any& other); |
| any(any&& other) noexcept; |
| |
| template <class ValueType> |
| any(ValueType&& value); |
| |
| ~any(); |
| |
| // 6.3.2 any assignments |
| any& operator=(const any& rhs); |
| any& operator=(any&& rhs) noexcept; |
| |
| template <class ValueType> |
| any& operator=(ValueType&& rhs); |
| |
| // 6.3.3 any modifiers |
| void clear() noexcept; |
| void swap(any& rhs) noexcept; |
| |
| // 6.3.4 any observers |
| bool empty() const noexcept; |
| const type_info& type() const noexcept; |
| }; |
| |
| // 6.4 Non-member functions |
| void swap(any& x, any& y) noexcept; |
| |
| template<class ValueType> |
| ValueType any_cast(const any& operand); |
| template<class ValueType> |
| ValueType any_cast(any& operand); |
| template<class ValueType> |
| ValueType any_cast(any&& operand); |
| |
| template<class ValueType> |
| const ValueType* any_cast(const any* operand) noexcept; |
| template<class ValueType> |
| ValueType* any_cast(any* operand) noexcept; |
| |
| } // namespace fundamentals_v1 |
| } // namespace experimental |
| } // namespace std |
| |
| */ |
| |
| #include <experimental/__config> |
| #include <memory> |
| #include <new> |
| #include <typeinfo> |
| #include <type_traits> |
| #include <cstdlib> |
| |
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| #pragma GCC system_header |
| #endif |
| |
| _LIBCPP_BEGIN_NAMESPACE_LFTS |
| |
| class _LIBCPP_EXCEPTION_ABI bad_any_cast : public bad_cast |
| { |
| public: |
| virtual const char* what() const _NOEXCEPT; |
| }; |
| |
| #if _LIBCPP_STD_VER > 11 // C++ > 11 |
| |
| _LIBCPP_NORETURN inline _LIBCPP_ALWAYS_INLINE |
| void __throw_bad_any_cast() |
| { |
| #ifndef _LIBCPP_NO_EXCEPTIONS |
| throw bad_any_cast(); |
| #else |
| _VSTD::abort(); |
| #endif |
| } |
| |
| // Forward declarations |
| class any; |
| |
| template <class _ValueType> |
| typename add_pointer<typename add_const<_ValueType>::type>::type |
| _LIBCPP_INLINE_VISIBILITY |
| any_cast(any const *) _NOEXCEPT; |
| |
| template <class _ValueType> |
| typename add_pointer<_ValueType>::type |
| _LIBCPP_INLINE_VISIBILITY |
| any_cast(any *) _NOEXCEPT; |
| |
| namespace __any_imp |
| { |
| typedef typename aligned_storage<3*sizeof(void*), alignment_of<void*>::value>::type |
| _Buffer; |
| |
| template <class _Tp> |
| struct _IsSmallObject |
| : public integral_constant<bool |
| , sizeof(_Tp) <= sizeof(_Buffer) |
| && alignment_of<_Buffer>::value |
| % alignment_of<_Tp>::value == 0 |
| && is_nothrow_move_constructible<_Tp>::value |
| > |
| {}; |
| |
| enum class _Action |
| { |
| _Destroy, |
| _Copy, |
| _Move, |
| _Get, |
| _TypeInfo |
| }; |
| |
| template <class _Tp> |
| struct _SmallHandler; |
| |
| template <class _Tp> |
| struct _LargeHandler; |
| |
| template <class _Tp> |
| using _Handler = typename conditional<_IsSmallObject<_Tp>::value |
| , _SmallHandler<_Tp> |
| , _LargeHandler<_Tp> |
| >::type; |
| template <class _ValueType> |
| using _EnableIfNotAny = typename |
| enable_if< |
| !is_same<typename decay<_ValueType>::type, any>::value |
| >::type; |
| |
| } // namespace __any_imp |
| |
| class any |
| { |
| public: |
| // 6.3.1 any construct/destruct |
| _LIBCPP_INLINE_VISIBILITY |
| any() _NOEXCEPT : __h(nullptr) {} |
| |
| _LIBCPP_INLINE_VISIBILITY |
| any(any const & __other) : __h(nullptr) |
| { |
| if (__other.__h) __other.__call(_Action::_Copy, this); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| any(any && __other) _NOEXCEPT : __h(nullptr) |
| { |
| if (__other.__h) __other.__call(_Action::_Move, this); |
| } |
| |
| template < |
| class _ValueType |
| , class = __any_imp::_EnableIfNotAny<_ValueType> |
| > |
| _LIBCPP_INLINE_VISIBILITY |
| any(_ValueType && __value); |
| |
| _LIBCPP_INLINE_VISIBILITY |
| ~any() |
| { |
| this->clear(); |
| } |
| |
| // 6.3.2 any assignments |
| _LIBCPP_INLINE_VISIBILITY |
| any & operator=(any const & __rhs) |
| { |
| any(__rhs).swap(*this); |
| return *this; |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| any & operator=(any && __rhs) _NOEXCEPT |
| { |
| any(_VSTD::move(__rhs)).swap(*this); |
| return *this; |
| } |
| |
| template < |
| class _ValueType |
| , class = __any_imp::_EnableIfNotAny<_ValueType> |
| > |
| _LIBCPP_INLINE_VISIBILITY |
| any & operator=(_ValueType && __rhs); |
| |
| // 6.3.3 any modifiers |
| _LIBCPP_INLINE_VISIBILITY |
| void clear() _NOEXCEPT |
| { |
| if (__h) this->__call(_Action::_Destroy); |
| } |
| |
| _LIBCPP_INLINE_VISIBILITY |
| void swap(any & __rhs) _NOEXCEPT; |
| |
| // 6.3.4 any observers |
| _LIBCPP_INLINE_VISIBILITY |
| bool empty() const _NOEXCEPT |
| { |
| return __h == nullptr; |
| } |
| |
| #if !defined(_LIBCPP_NO_RTTI) |
| _LIBCPP_INLINE_VISIBILITY |
| const type_info & type() const _NOEXCEPT |
| { |
| if (__h) { |
| return *static_cast<type_info const *>(this->__call(_Action::_TypeInfo)); |
| } else { |
| return typeid(void); |
| } |
| } |
| #endif |
| |
| private: |
| typedef __any_imp::_Action _Action; |
| |
| typedef void* (*_HandleFuncPtr)(_Action, any const *, any *, const type_info *); |
| |
| union _Storage |
| { |
| void * __ptr; |
| __any_imp::_Buffer __buf; |
| }; |
| |
| _LIBCPP_ALWAYS_INLINE |
| void * __call(_Action __a, any * __other = nullptr, |
| type_info const * __info = nullptr) const |
| { |
| return __h(__a, this, __other, __info); |
| } |
| |
| _LIBCPP_ALWAYS_INLINE |
| void * __call(_Action __a, any * __other = nullptr, |
| type_info const * __info = nullptr) |
| { |
| return __h(__a, this, __other, __info); |
| } |
| |
| template <class> |
| friend struct __any_imp::_SmallHandler; |
| template <class> |
| friend struct __any_imp::_LargeHandler; |
| |
| template <class _ValueType> |
| friend typename add_pointer<typename add_const<_ValueType>::type>::type |
| any_cast(any const *) _NOEXCEPT; |
| |
| template <class _ValueType> |
| friend typename add_pointer<_ValueType>::type |
| any_cast(any *) _NOEXCEPT; |
| |
| _HandleFuncPtr __h; |
| _Storage __s; |
| }; |
| |
| namespace __any_imp |
| { |
| |
| template <class _Tp> |
| struct _LIBCPP_TEMPLATE_VIS _SmallHandler |
| { |
| _LIBCPP_INLINE_VISIBILITY |
| static void* __handle(_Action __act, any const * __this, any * __other, |
| type_info const * __info) |
| { |
| switch (__act) |
| { |
| case _Action::_Destroy: |
| __destroy(const_cast<any &>(*__this)); |
| return nullptr; |
| case _Action::_Copy: |
| __copy(*__this, *__other); |
| return nullptr; |
| case _Action::_Move: |
| __move(const_cast<any &>(*__this), *__other); |
| return nullptr; |
| case _Action::_Get: |
| return __get(const_cast<any &>(*__this), __info); |
| case _Action::_TypeInfo: |
| return __type_info(); |
| } |
| } |
| |
| template <class _Up> |
| _LIBCPP_INLINE_VISIBILITY |
| static void __create(any & __dest, _Up && __v) |
| { |
| ::new (static_cast<void*>(&__dest.__s.__buf)) _Tp(_VSTD::forward<_Up>(__v)); |
| __dest.__h = &_SmallHandler::__handle; |
| } |
| |
| private: |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void __destroy(any & __this) |
| { |
| _Tp & __value = *static_cast<_Tp *>(static_cast<void*>(&__this.__s.__buf)); |
| __value.~_Tp(); |
| __this.__h = nullptr; |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void __copy(any const & __this, any & __dest) |
| { |
| _SmallHandler::__create(__dest, *static_cast<_Tp const *>( |
| static_cast<void const *>(&__this.__s.__buf))); |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void __move(any & __this, any & __dest) |
| { |
| _SmallHandler::__create(__dest, _VSTD::move( |
| *static_cast<_Tp*>(static_cast<void*>(&__this.__s.__buf)))); |
| __destroy(__this); |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void* __get(any & __this, type_info const * __info) |
| { |
| #if !defined(_LIBCPP_NO_RTTI) |
| if (typeid(_Tp) == *__info) { |
| return static_cast<void*>(&__this.__s.__buf); |
| } |
| return nullptr; |
| #else |
| return static_cast<void*>(&__this.__s.__buf); |
| #endif |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void* __type_info() |
| { |
| #if !defined(_LIBCPP_NO_RTTI) |
| return const_cast<void*>(static_cast<void const *>(&typeid(_Tp))); |
| #else |
| return nullptr; |
| #endif |
| } |
| }; |
| |
| template <class _Tp> |
| struct _LIBCPP_TEMPLATE_VIS _LargeHandler |
| { |
| _LIBCPP_INLINE_VISIBILITY |
| static void* __handle(_Action __act, any const * __this, any * __other, |
| type_info const * __info) |
| { |
| switch (__act) |
| { |
| case _Action::_Destroy: |
| __destroy(const_cast<any &>(*__this)); |
| return nullptr; |
| case _Action::_Copy: |
| __copy(*__this, *__other); |
| return nullptr; |
| case _Action::_Move: |
| __move(const_cast<any &>(*__this), *__other); |
| return nullptr; |
| case _Action::_Get: |
| return __get(const_cast<any &>(*__this), __info); |
| case _Action::_TypeInfo: |
| return __type_info(); |
| } |
| } |
| |
| template <class _Up> |
| _LIBCPP_INLINE_VISIBILITY |
| static void __create(any & __dest, _Up && __v) |
| { |
| typedef allocator<_Tp> _Alloc; |
| typedef __allocator_destructor<_Alloc> _Dp; |
| _Alloc __a; |
| unique_ptr<_Tp, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); |
| ::new ((void*)__hold.get()) _Tp(_VSTD::forward<_Up>(__v)); |
| __dest.__s.__ptr = __hold.release(); |
| __dest.__h = &_LargeHandler::__handle; |
| } |
| |
| private: |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void __destroy(any & __this) |
| { |
| delete static_cast<_Tp*>(__this.__s.__ptr); |
| __this.__h = nullptr; |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void __copy(any const & __this, any & __dest) |
| { |
| _LargeHandler::__create(__dest, *static_cast<_Tp const *>(__this.__s.__ptr)); |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void __move(any & __this, any & __dest) |
| { |
| __dest.__s.__ptr = __this.__s.__ptr; |
| __dest.__h = &_LargeHandler::__handle; |
| __this.__h = nullptr; |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void* __get(any & __this, type_info const * __info) |
| { |
| #if !defined(_LIBCPP_NO_RTTI) |
| if (typeid(_Tp) == *__info) { |
| return static_cast<void*>(__this.__s.__ptr); |
| } |
| return nullptr; |
| #else |
| return static_cast<void*>(__this.__s.__ptr); |
| #endif |
| } |
| |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY |
| static void* __type_info() |
| { |
| #if !defined(_LIBCPP_NO_RTTI) |
| return const_cast<void*>(static_cast<void const *>(&typeid(_Tp))); |
| #else |
| return nullptr; |
| #endif |
| } |
| }; |
| |
| } // namespace __any_imp |
| |
| |
| template <class _ValueType, class> |
| any::any(_ValueType && __v) : __h(nullptr) |
| { |
| typedef typename decay<_ValueType>::type _Tp; |
| static_assert(is_copy_constructible<_Tp>::value, |
| "_ValueType must be CopyConstructible."); |
| typedef __any_imp::_Handler<_Tp> _HandlerType; |
| _HandlerType::__create(*this, _VSTD::forward<_ValueType>(__v)); |
| } |
| |
| template <class _ValueType, class> |
| any & any::operator=(_ValueType && __v) |
| { |
| typedef typename decay<_ValueType>::type _Tp; |
| static_assert(is_copy_constructible<_Tp>::value, |
| "_ValueType must be CopyConstructible."); |
| any(_VSTD::forward<_ValueType>(__v)).swap(*this); |
| return *this; |
| } |
| |
| inline |
| void any::swap(any & __rhs) _NOEXCEPT |
| { |
| if (__h && __rhs.__h) { |
| any __tmp; |
| __rhs.__call(_Action::_Move, &__tmp); |
| this->__call(_Action::_Move, &__rhs); |
| __tmp.__call(_Action::_Move, this); |
| } |
| else if (__h) { |
| this->__call(_Action::_Move, &__rhs); |
| } |
| else if (__rhs.__h) { |
| __rhs.__call(_Action::_Move, this); |
| } |
| } |
| |
| // 6.4 Non-member functions |
| |
| inline _LIBCPP_INLINE_VISIBILITY |
| void swap(any & __lhs, any & __rhs) _NOEXCEPT |
| { |
| __lhs.swap(__rhs); |
| } |
| |
| template <class _ValueType> |
| _LIBCPP_INLINE_VISIBILITY |
| _ValueType any_cast(any const & __v) |
| { |
| static_assert( |
| is_reference<_ValueType>::value |
| || is_copy_constructible<_ValueType>::value, |
| "_ValueType is required to be a reference or a CopyConstructible type."); |
| typedef typename add_const<typename remove_reference<_ValueType>::type>::type |
| _Tp; |
| _Tp * __tmp = any_cast<_Tp>(&__v); |
| if (__tmp == nullptr) |
| __throw_bad_any_cast(); |
| return *__tmp; |
| } |
| |
| template <class _ValueType> |
| _LIBCPP_INLINE_VISIBILITY |
| _ValueType any_cast(any & __v) |
| { |
| static_assert( |
| is_reference<_ValueType>::value |
| || is_copy_constructible<_ValueType>::value, |
| "_ValueType is required to be a reference or a CopyConstructible type."); |
| typedef typename remove_reference<_ValueType>::type _Tp; |
| _Tp * __tmp = any_cast<_Tp>(&__v); |
| if (__tmp == nullptr) |
| __throw_bad_any_cast(); |
| return *__tmp; |
| } |
| |
| template <class _ValueType> |
| _LIBCPP_INLINE_VISIBILITY |
| _ValueType any_cast(any && __v) |
| { |
| static_assert( |
| is_reference<_ValueType>::value |
| || is_copy_constructible<_ValueType>::value, |
| "_ValueType is required to be a reference or a CopyConstructible type."); |
| typedef typename remove_reference<_ValueType>::type _Tp; |
| _Tp * __tmp = any_cast<_Tp>(&__v); |
| if (__tmp == nullptr) |
| __throw_bad_any_cast(); |
| return *__tmp; |
| } |
| |
| template <class _ValueType> |
| inline |
| typename add_pointer<typename add_const<_ValueType>::type>::type |
| any_cast(any const * __any) _NOEXCEPT |
| { |
| static_assert(!is_reference<_ValueType>::value, |
| "_ValueType may not be a reference."); |
| return any_cast<_ValueType>(const_cast<any *>(__any)); |
| } |
| |
| template <class _ValueType> |
| typename add_pointer<_ValueType>::type |
| any_cast(any * __any) _NOEXCEPT |
| { |
| using __any_imp::_Action; |
| static_assert(!is_reference<_ValueType>::value, |
| "_ValueType may not be a reference."); |
| typedef typename add_pointer<_ValueType>::type _ReturnType; |
| if (__any && __any->__h) { |
| |
| return static_cast<_ReturnType>( |
| __any->__call(_Action::_Get, nullptr, |
| #if !defined(_LIBCPP_NO_RTTI) |
| &typeid(_ValueType) |
| #else |
| nullptr |
| #endif |
| )); |
| |
| } |
| return nullptr; |
| } |
| |
| #endif // _LIBCPP_STD_VER > 11 |
| |
| _LIBCPP_END_NAMESPACE_LFTS |
| |
| #endif // _LIBCPP_EXPERIMENTAL_ANY |