зеркало из https://github.com/microsoft/STL.git
451 строка
18 KiB
C++
451 строка
18 KiB
C++
// any standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef _ANY_
|
|
#define _ANY_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
|
|
#if !_HAS_CXX17
|
|
_EMIT_STL_WARNING(STL4038, "The contents of <any> are available only with C++17 or later.");
|
|
#elif !_HAS_STATIC_RTTI // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv
|
|
_EMIT_STL_WARNING(STL4040, "The contents of <any> require static RTTI.");
|
|
#else // ^^^ !_HAS_STATIC_RTTI / _HAS_STATIC_RTTI vvv
|
|
#include <initializer_list>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
#include <utility>
|
|
#include <xmemory>
|
|
|
|
#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
|
|
|
|
_EXPORT_STD class bad_any_cast : public bad_cast { // thrown by failed any_cast
|
|
public:
|
|
_NODISCARD 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 <class _Ty>
|
|
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 <class _Ty>
|
|
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_FNPTR;
|
|
using _Copy_fn = void* __CLRCALL_PURE_OR_CDECL(const void*);
|
|
|
|
template <class _Ty>
|
|
static void __CLRCALL_PURE_OR_CDECL _Destroy_impl(void* const _Target) noexcept {
|
|
::delete static_cast<_Ty*>(_Target);
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD static void* __CLRCALL_PURE_OR_CDECL _Copy_impl(const void* const _Source) {
|
|
return ::new _Ty(*static_cast<const _Ty*>(_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_FNPTR;
|
|
using _Copy_fn = void __CLRCALL_PURE_OR_CDECL(void*, const void*);
|
|
using _Move_fn = void __CLRCALL_PURE_OR_CDECL(void*, void*) _NOEXCEPT_FNPTR;
|
|
|
|
template <class _Ty>
|
|
static void __CLRCALL_PURE_OR_CDECL _Destroy_impl(void* const _Target) noexcept {
|
|
_STD _Destroy_in_place(*static_cast<_Ty*>(_Target));
|
|
}
|
|
|
|
template <class _Ty>
|
|
static void __CLRCALL_PURE_OR_CDECL _Copy_impl(void* const _Target, const void* const _Source) {
|
|
_STD _Construct_in_place(*static_cast<_Ty*>(_Target), *static_cast<const _Ty*>(_Source));
|
|
}
|
|
|
|
template <class _Ty>
|
|
static void __CLRCALL_PURE_OR_CDECL _Move_impl(void* const _Target, void* const _Source) noexcept {
|
|
_STD _Construct_in_place(*static_cast<_Ty*>(_Target), _STD move(*static_cast<_Ty*>(_Source)));
|
|
}
|
|
|
|
_Destroy_fn* _Destroy;
|
|
_Copy_fn* _Copy;
|
|
_Move_fn* _Move;
|
|
};
|
|
|
|
template <class _Ty>
|
|
constexpr _Any_big_RTTI _Any_big_RTTI_obj = {&_Any_big_RTTI::_Destroy_impl<_Ty>, &_Any_big_RTTI::_Copy_impl<_Ty>};
|
|
|
|
template <class _Ty>
|
|
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>};
|
|
|
|
_EXPORT_STD 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 <class _ValueType, enable_if_t<conjunction_v<negation<is_same<decay_t<_ValueType>, any>>,
|
|
negation<_Is_specialization<decay_t<_ValueType>, in_place_type_t>>,
|
|
is_copy_constructible<decay_t<_ValueType>>>,
|
|
int> = 0>
|
|
any(_ValueType&& _Value) { // initialize with _Value
|
|
_Emplace<decay_t<_ValueType>>(_STD forward<_ValueType>(_Value));
|
|
}
|
|
|
|
template <class _ValueType, class... _Types,
|
|
enable_if_t<
|
|
conjunction_v<is_constructible<decay_t<_ValueType>, _Types...>, is_copy_constructible<decay_t<_ValueType>>>,
|
|
int> = 0>
|
|
explicit any(in_place_type_t<_ValueType>, _Types&&... _Args) {
|
|
// in-place initialize a value of type decay_t<_ValueType> with _Args...
|
|
_Emplace<decay_t<_ValueType>>(_STD forward<_Types>(_Args)...);
|
|
}
|
|
|
|
template <class _ValueType, class _Elem, class... _Types,
|
|
enable_if_t<conjunction_v<is_constructible<decay_t<_ValueType>, initializer_list<_Elem>&, _Types...>,
|
|
is_copy_constructible<decay_t<_ValueType>>>,
|
|
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<decay_t<_ValueType>>(_Ilist, _STD forward<_Types>(_Args)...);
|
|
}
|
|
|
|
~any() noexcept {
|
|
reset();
|
|
}
|
|
|
|
// Assignment [any.assign]
|
|
any& operator=(const any& _That) {
|
|
_Assign(_That);
|
|
return *this;
|
|
}
|
|
|
|
any& operator=(any&& _That) noexcept {
|
|
_Assign(_STD move(_That));
|
|
return *this;
|
|
}
|
|
|
|
template <class _ValueType, enable_if_t<conjunction_v<negation<is_same<decay_t<_ValueType>, any>>,
|
|
is_copy_constructible<decay_t<_ValueType>>>,
|
|
int> = 0>
|
|
any& operator=(_ValueType&& _Value) {
|
|
// replace contained value with an object of type decay_t<_ValueType> initialized from _Value
|
|
_Assign(_STD forward<_ValueType>(_Value));
|
|
return *this;
|
|
}
|
|
|
|
// Modifiers [any.modifiers]
|
|
template <class _ValueType, class... _Types,
|
|
enable_if_t<
|
|
conjunction_v<is_constructible<decay_t<_ValueType>, _Types...>, is_copy_constructible<decay_t<_ValueType>>>,
|
|
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<decay_t<_ValueType>>(_STD forward<_Types>(_Args)...);
|
|
}
|
|
template <class _ValueType, class _Elem, class... _Types,
|
|
enable_if_t<conjunction_v<is_constructible<decay_t<_ValueType>, initializer_list<_Elem>&, _Types...>,
|
|
is_copy_constructible<decay_t<_ValueType>>>,
|
|
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<decay_t<_ValueType>>(_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 <class _Decayed>
|
|
_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<const _Decayed*>(&_Storage._TrivialData);
|
|
} else if constexpr (_Any_is_small<_Decayed>) {
|
|
// get a pointer to the contained _Small value of type _Decayed
|
|
return reinterpret_cast<const _Decayed*>(&_Storage._SmallStorage._Data);
|
|
} else {
|
|
// get a pointer to the contained _Big value of type _Decayed
|
|
return static_cast<const _Decayed*>(_Storage._BigStorage._Ptr);
|
|
}
|
|
}
|
|
|
|
template <class _Decayed>
|
|
_NODISCARD _Decayed* _Cast() noexcept { // if *this contains a value of type _Decayed, return a pointer to it
|
|
return const_cast<_Decayed*>(static_cast<const any*>(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<const type_info*>(_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;
|
|
}
|
|
}
|
|
|
|
void _Assign(any _That) noexcept { // intentionally pass by value
|
|
reset();
|
|
_Move_from(_That);
|
|
}
|
|
|
|
template <class _Decayed, class... _Types>
|
|
_Decayed& _Emplace(_Types&&... _Args) { // emplace construct _Decayed
|
|
if constexpr (_Any_is_trivial<_Decayed>) {
|
|
// using the _Trivial representation
|
|
auto& _Obj = reinterpret_cast<_Decayed&>(_Storage._TrivialData);
|
|
_STD _Construct_in_place(_Obj, _STD forward<_Types>(_Args)...);
|
|
_Storage._TypeData =
|
|
reinterpret_cast<uintptr_t>(&typeid(_Decayed)) | static_cast<uintptr_t>(_Any_representation::_Trivial);
|
|
return _Obj;
|
|
} else if constexpr (_Any_is_small<_Decayed>) {
|
|
// using the _Small representation
|
|
auto& _Obj = reinterpret_cast<_Decayed&>(_Storage._SmallStorage._Data);
|
|
_STD _Construct_in_place(_Obj, _STD forward<_Types>(_Args)...);
|
|
_Storage._SmallStorage._RTTI = &_Any_small_RTTI_obj<_Decayed>;
|
|
_Storage._TypeData =
|
|
reinterpret_cast<uintptr_t>(&typeid(_Decayed)) | static_cast<uintptr_t>(_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<uintptr_t>(&typeid(_Decayed)) | static_cast<uintptr_t>(_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]
|
|
_EXPORT_STD inline void swap(any& _Left, any& _Right) noexcept {
|
|
_Left.swap(_Right);
|
|
}
|
|
|
|
_EXPORT_STD template <class _ValueType, class... _Types,
|
|
enable_if_t<is_constructible_v<any, in_place_type_t<_ValueType>, _Types...>, int> = 0>
|
|
_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)...};
|
|
}
|
|
_EXPORT_STD template <class _ValueType, class _Elem, class... _Types,
|
|
enable_if_t<is_constructible_v<any, in_place_type_t<_ValueType>, initializer_list<_Elem>&, _Types...>, int> = 0>
|
|
_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)...};
|
|
}
|
|
|
|
_EXPORT_STD template <class _ValueType>
|
|
_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>>();
|
|
}
|
|
}
|
|
_EXPORT_STD template <class _ValueType>
|
|
_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>>();
|
|
}
|
|
}
|
|
|
|
_EXPORT_STD template <class _Ty>
|
|
_NODISCARD remove_cv_t<_Ty> any_cast(const any& _Any) {
|
|
static_assert(is_constructible_v<remove_cv_t<_Ty>, const _Remove_cvref_t<_Ty>&>,
|
|
"any_cast<T>(const any&) requires remove_cv_t<T> to be constructible from "
|
|
"const remove_cv_t<remove_reference_t<T>>&");
|
|
|
|
const auto _Ptr = _STD any_cast<_Remove_cvref_t<_Ty>>(&_Any);
|
|
if (!_Ptr) {
|
|
_Throw_bad_any_cast();
|
|
}
|
|
|
|
return static_cast<remove_cv_t<_Ty>>(*_Ptr);
|
|
}
|
|
_EXPORT_STD template <class _Ty>
|
|
_NODISCARD remove_cv_t<_Ty> any_cast(any& _Any) {
|
|
static_assert(is_constructible_v<remove_cv_t<_Ty>, _Remove_cvref_t<_Ty>&>,
|
|
"any_cast<T>(any&) requires remove_cv_t<T> to be constructible from remove_cv_t<remove_reference_t<T>>&");
|
|
|
|
const auto _Ptr = _STD any_cast<_Remove_cvref_t<_Ty>>(&_Any);
|
|
if (!_Ptr) {
|
|
_Throw_bad_any_cast();
|
|
}
|
|
|
|
return static_cast<remove_cv_t<_Ty>>(*_Ptr);
|
|
}
|
|
_EXPORT_STD template <class _Ty>
|
|
_NODISCARD remove_cv_t<_Ty> any_cast(any&& _Any) {
|
|
static_assert(is_constructible_v<remove_cv_t<_Ty>, _Remove_cvref_t<_Ty>>,
|
|
"any_cast<T>(any&&) requires remove_cv_t<T> to be constructible from remove_cv_t<remove_reference_t<T>>");
|
|
|
|
const auto _Ptr = _STD any_cast<_Remove_cvref_t<_Ty>>(&_Any);
|
|
if (!_Ptr) {
|
|
_Throw_bad_any_cast();
|
|
}
|
|
|
|
return static_cast<remove_cv_t<_Ty>>(_STD move(*_Ptr));
|
|
}
|
|
|
|
_STD_END
|
|
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
#endif // ^^^ _HAS_STATIC_RTTI ^^^
|
|
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _ANY_
|