// any standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _ANY_ #define _ANY_ #include #if _STL_COMPILER_PREPROCESSOR #if !_HAS_CXX17 #pragma message("The contents of are available only with C++17 or later.") #else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv #include #include #include #include #include #if !_HAS_STATIC_RTTI #error class any requires static RTTI. #endif // _HAS_STATIC_RTTI #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN // CLASS bad_any_cast class bad_any_cast : public bad_cast { // thrown by failed any_cast public: _NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept override { return "Bad any_cast"; } }; [[noreturn]] inline void _Throw_bad_any_cast() { _THROW(bad_any_cast{}); } inline constexpr size_t _Any_trivial_space_size = (_Small_object_num_ptrs - 1) * sizeof(void*); template inline constexpr bool _Any_is_trivial = alignof(_Ty) <= alignof(max_align_t) && is_trivially_copyable_v<_Ty> && sizeof(_Ty) <= _Any_trivial_space_size; inline constexpr size_t _Any_small_space_size = (_Small_object_num_ptrs - 2) * sizeof(void*); template inline constexpr bool _Any_is_small = alignof(_Ty) <= alignof(max_align_t) && is_nothrow_move_constructible_v<_Ty> && sizeof(_Ty) <= _Any_small_space_size; enum class _Any_representation : uintptr_t { _Trivial, _Big, _Small }; struct _Any_big_RTTI { // Hand-rolled vtable for types that must be heap allocated in an any using _Destroy_fn = void __CLRCALL_PURE_OR_CDECL(void*) noexcept; using _Copy_fn = void* __CLRCALL_PURE_OR_CDECL(const void*); template static void __CLRCALL_PURE_OR_CDECL _Destroy_impl(void* const _Target) noexcept { ::delete static_cast<_Ty*>(_Target); } template _NODISCARD static void* __CLRCALL_PURE_OR_CDECL _Copy_impl(const void* const _Source) { return ::new _Ty(*static_cast(_Source)); } _Destroy_fn* _Destroy; _Copy_fn* _Copy; }; struct _Any_small_RTTI { // Hand-rolled vtable for nontrivial types that can be stored internally in an any using _Destroy_fn = void __CLRCALL_PURE_OR_CDECL(void*) noexcept; using _Copy_fn = void __CLRCALL_PURE_OR_CDECL(void*, const void*); using _Move_fn = void __CLRCALL_PURE_OR_CDECL(void*, void*) noexcept; template static void __CLRCALL_PURE_OR_CDECL _Destroy_impl(void* const _Target) noexcept { _Destroy_in_place(*static_cast<_Ty*>(_Target)); } template static void __CLRCALL_PURE_OR_CDECL _Copy_impl(void* const _Target, const void* const _Source) { _Construct_in_place(*static_cast<_Ty*>(_Target), *static_cast(_Source)); } template static void __CLRCALL_PURE_OR_CDECL _Move_impl(void* const _Target, void* const _Source) noexcept { _Construct_in_place(*static_cast<_Ty*>(_Target), _STD move(*static_cast<_Ty*>(_Source))); } _Destroy_fn* _Destroy; _Copy_fn* _Copy; _Move_fn* _Move; }; template inline constexpr _Any_big_RTTI _Any_big_RTTI_obj = { &_Any_big_RTTI::_Destroy_impl<_Ty>, &_Any_big_RTTI::_Copy_impl<_Ty>}; template inline constexpr _Any_small_RTTI _Any_small_RTTI_obj = { &_Any_small_RTTI::_Destroy_impl<_Ty>, &_Any_small_RTTI::_Copy_impl<_Ty>, &_Any_small_RTTI::_Move_impl<_Ty>}; // CLASS any class any { // storage for any (CopyConstructible) type public: // Construction and destruction [any.cons] constexpr any() noexcept {} any(const any& _That) { _Storage._TypeData = _That._Storage._TypeData; switch (_Rep()) { case _Any_representation::_Small: _Storage._SmallStorage._RTTI = _That._Storage._SmallStorage._RTTI; _Storage._SmallStorage._RTTI->_Copy(&_Storage._SmallStorage._Data, &_That._Storage._SmallStorage._Data); break; case _Any_representation::_Big: _Storage._BigStorage._RTTI = _That._Storage._BigStorage._RTTI; _Storage._BigStorage._Ptr = _Storage._BigStorage._RTTI->_Copy(_That._Storage._BigStorage._Ptr); break; case _Any_representation::_Trivial: default: _CSTD memcpy(_Storage._TrivialData, _That._Storage._TrivialData, sizeof(_Storage._TrivialData)); break; } } any(any&& _That) noexcept { _Move_from(_That); } template , any>>, negation<_Is_specialization, in_place_type_t>>, is_copy_constructible>>, int> = 0> any(_ValueType&& _Value) { // initialize with _Value _Emplace>(_STD forward<_ValueType>(_Value)); } template , _Types...>, is_copy_constructible>>, int> = 0> explicit any(in_place_type_t<_ValueType>, _Types&&... _Args) { // in-place initialize a value of type decay_t<_ValueType> with _Args... _Emplace>(_STD forward<_Types>(_Args)...); } template , initializer_list<_Elem>&, _Types...>, is_copy_constructible>>, int> = 0> explicit any(in_place_type_t<_ValueType>, initializer_list<_Elem> _Ilist, _Types&&... _Args) { // in-place initialize a value of type decay_t<_ValueType> with _Ilist and _Args... _Emplace>(_Ilist, _STD forward<_Types>(_Args)...); } ~any() noexcept { reset(); } // Assignment [any.assign] any& operator=(const any& _That) { *this = any{_That}; return *this; } any& operator=(any&& _That) noexcept { reset(); _Move_from(_That); return *this; } template , any>>, is_copy_constructible>>, int> = 0> any& operator=(_ValueType&& _Value) { // replace contained value with an object of type decay_t<_ValueType> initialized from _Value *this = any{_STD forward<_ValueType>(_Value)}; return *this; } // Modifiers [any.modifiers] template , _Types...>, is_copy_constructible>>, int> = 0> decay_t<_ValueType>& emplace(_Types&&... _Args) { // replace contained value with an object of type decay_t<_ValueType> initialized from _Args... reset(); return _Emplace>(_STD forward<_Types>(_Args)...); } template , initializer_list<_Elem>&, _Types...>, is_copy_constructible>>, int> = 0> decay_t<_ValueType>& emplace(initializer_list<_Elem> _Ilist, _Types&&... _Args) { // replace contained value with an object of type decay_t<_ValueType> initialized from _Ilist and _Args... reset(); return _Emplace>(_Ilist, _STD forward<_Types>(_Args)...); } void reset() noexcept { // transition to the empty state switch (_Rep()) { case _Any_representation::_Small: _Storage._SmallStorage._RTTI->_Destroy(&_Storage._SmallStorage._Data); break; case _Any_representation::_Big: _Storage._BigStorage._RTTI->_Destroy(_Storage._BigStorage._Ptr); break; case _Any_representation::_Trivial: default: break; } _Storage._TypeData = 0; } void swap(any& _That) noexcept { _That = _STD exchange(*this, _STD move(_That)); } // Observers [any.observers] _NODISCARD bool has_value() const noexcept { return _Storage._TypeData != 0; } _NODISCARD const type_info& type() const noexcept { // if *this contains a value of type T, return typeid(T); otherwise typeid(void) const type_info* const _Info = _TypeInfo(); if (_Info) { return *_Info; } return typeid(void); } template _NODISCARD const _Decayed* _Cast() const noexcept { // if *this contains a value of type _Decayed, return a pointer to it const type_info* const _Info = _TypeInfo(); if (!_Info || *_Info != typeid(_Decayed)) { return nullptr; } if constexpr (_Any_is_trivial<_Decayed>) { // get a pointer to the contained _Trivial value of type _Decayed return reinterpret_cast(&_Storage._TrivialData); } else if constexpr (_Any_is_small<_Decayed>) { // get a pointer to the contained _Small value of type _Decayed return reinterpret_cast(&_Storage._SmallStorage._Data); } else { // get a pointer to the contained _Big value of type _Decayed return static_cast(_Storage._BigStorage._Ptr); } } template _NODISCARD _Decayed* _Cast() noexcept { // if *this contains a value of type _Decayed, return a pointer to it return const_cast<_Decayed*>(static_cast(this)->_Cast<_Decayed>()); } private: static constexpr uintptr_t _Rep_mask = 3; _NODISCARD _Any_representation _Rep() const noexcept { // extract the representation format from _TypeData return static_cast<_Any_representation>(_Storage._TypeData & _Rep_mask); } _NODISCARD const type_info* _TypeInfo() const noexcept { // extract the type_info from _TypeData return reinterpret_cast(_Storage._TypeData & ~_Rep_mask); } void _Move_from(any& _That) noexcept { _Storage._TypeData = _That._Storage._TypeData; switch (_Rep()) { case _Any_representation::_Small: _Storage._SmallStorage._RTTI = _That._Storage._SmallStorage._RTTI; _Storage._SmallStorage._RTTI->_Move(&_Storage._SmallStorage._Data, &_That._Storage._SmallStorage._Data); break; case _Any_representation::_Big: _Storage._BigStorage._RTTI = _That._Storage._BigStorage._RTTI; _Storage._BigStorage._Ptr = _That._Storage._BigStorage._Ptr; _That._Storage._TypeData = 0; break; case _Any_representation::_Trivial: default: _CSTD memcpy(_Storage._TrivialData, _That._Storage._TrivialData, sizeof(_Storage._TrivialData)); break; } } template _Decayed& _Emplace(_Types&&... _Args) { // emplace construct _Decayed if constexpr (_Any_is_trivial<_Decayed>) { // using the _Trivial representation auto& _Obj = reinterpret_cast<_Decayed&>(_Storage._TrivialData); _Construct_in_place(_Obj, _STD forward<_Types>(_Args)...); _Storage._TypeData = reinterpret_cast(&typeid(_Decayed)) | static_cast(_Any_representation::_Trivial); return _Obj; } else if constexpr (_Any_is_small<_Decayed>) { // using the _Small representation auto& _Obj = reinterpret_cast<_Decayed&>(_Storage._SmallStorage._Data); _Construct_in_place(_Obj, _STD forward<_Types>(_Args)...); _Storage._SmallStorage._RTTI = &_Any_small_RTTI_obj<_Decayed>; _Storage._TypeData = reinterpret_cast(&typeid(_Decayed)) | static_cast(_Any_representation::_Small); return _Obj; } else { // using the _Big representation _Decayed* const _Ptr = ::new _Decayed(_STD forward<_Types>(_Args)...); _Storage._BigStorage._Ptr = _Ptr; _Storage._BigStorage._RTTI = &_Any_big_RTTI_obj<_Decayed>; _Storage._TypeData = reinterpret_cast(&typeid(_Decayed)) | static_cast(_Any_representation::_Big); return *_Ptr; } } struct _Small_storage_t { unsigned char _Data[_Any_small_space_size]; const _Any_small_RTTI* _RTTI; }; static_assert(sizeof(_Small_storage_t) == _Any_trivial_space_size); struct _Big_storage_t { // Pad so that _Ptr and _RTTI might share _TypeData's cache line unsigned char _Padding[_Any_small_space_size - sizeof(void*)]; void* _Ptr; const _Any_big_RTTI* _RTTI; }; static_assert(sizeof(_Big_storage_t) == _Any_trivial_space_size); struct _Storage_t { union { unsigned char _TrivialData[_Any_trivial_space_size]; _Small_storage_t _SmallStorage; _Big_storage_t _BigStorage; }; uintptr_t _TypeData; }; static_assert(sizeof(_Storage_t) == _Any_trivial_space_size + sizeof(void*)); static_assert(is_standard_layout_v<_Storage_t>); union { _Storage_t _Storage{}; max_align_t _Dummy; }; }; // Non-member functions [any.nonmembers] inline void swap(any& _Left, any& _Right) noexcept { _Left.swap(_Right); } template _NODISCARD any make_any(_Types&&... _Args) { // construct an any containing a _ValueType initialized with _Args... return any{in_place_type<_ValueType>, _STD forward<_Types>(_Args)...}; } template _NODISCARD any make_any(initializer_list<_Elem> _Ilist, _Types&&... _Args) { // construct an any containing a _ValueType initialized with _Ilist and _Args... return any{in_place_type<_ValueType>, _Ilist, _STD forward<_Types>(_Args)...}; } template _NODISCARD const _ValueType* any_cast(const any* const _Any) noexcept { // retrieve a pointer to the _ValueType contained in _Any, or null static_assert(!is_void_v<_ValueType>, "std::any cannot contain void."); if constexpr (is_function_v<_ValueType> || is_array_v<_ValueType>) { return nullptr; } else { if (!_Any) { return nullptr; } return _Any->_Cast<_Remove_cvref_t<_ValueType>>(); } } template _NODISCARD _ValueType* any_cast(any* const _Any) noexcept { // retrieve a pointer to the _ValueType contained in _Any, or null static_assert(!is_void_v<_ValueType>, "std::any cannot contain void."); if constexpr (is_function_v<_ValueType> || is_array_v<_ValueType>) { return nullptr; } else { if (!_Any) { return nullptr; } return _Any->_Cast<_Remove_cvref_t<_ValueType>>(); } } template _NODISCARD _Ty any_cast(const any& _Any) { // retrieve _Any's contained value as _Ty static_assert(is_constructible_v<_Ty, const _Remove_cvref_t<_Ty>&>, "any_cast(const any&) requires T to be constructible from const remove_cv_t>&"); const auto _Ptr = _STD any_cast<_Remove_cvref_t<_Ty>>(&_Any); if (!_Ptr) { _Throw_bad_any_cast(); } return static_cast<_Ty>(*_Ptr); } template _NODISCARD _Ty any_cast(any& _Any) { // retrieve _Any's contained value as _Ty static_assert(is_constructible_v<_Ty, _Remove_cvref_t<_Ty>&>, "any_cast(any&) requires T to be constructible from remove_cv_t>&"); const auto _Ptr = _STD any_cast<_Remove_cvref_t<_Ty>>(&_Any); if (!_Ptr) { _Throw_bad_any_cast(); } return static_cast<_Ty>(*_Ptr); } template _NODISCARD _Ty any_cast(any&& _Any) { // retrieve _Any's contained value as _Ty static_assert(is_constructible_v<_Ty, _Remove_cvref_t<_Ty>>, "any_cast(any&&) requires T to be constructible from remove_cv_t>"); const auto _Ptr = _STD any_cast<_Remove_cvref_t<_Ty>>(&_Any); if (!_Ptr) { _Throw_bad_any_cast(); } return static_cast<_Ty>(_STD move(*_Ptr)); } _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _HAS_CXX17 #endif // _STL_COMPILER_PREPROCESSOR #endif // _ANY_