STL/stl/inc/any

451 строка
17 KiB
C++

// any standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once
#ifndef _ANY_
#define _ANY_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#if !_HAS_CXX17
#pragma message("The contents of <any> are available only with C++17 or later.")
#else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv
#include <initializer_list>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <xmemory>
#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 <class _Ty>
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 <class _Ty>
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 <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;
using _Copy_fn = void __CLRCALL_PURE_OR_CDECL(void*, const void*);
using _Move_fn = void __CLRCALL_PURE_OR_CDECL(void*, void*) noexcept;
template <class _Ty>
static void __CLRCALL_PURE_OR_CDECL _Destroy_impl(void* const _Target) noexcept {
_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) {
_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 {
_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>
inline constexpr _Any_big_RTTI _Any_big_RTTI_obj = {
&_Any_big_RTTI::_Destroy_impl<_Ty>, &_Any_big_RTTI::_Copy_impl<_Ty>};
template <class _Ty>
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 <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) {
*this = any{_That};
return *this;
}
any& operator=(any&& _That) noexcept {
reset();
_Move_from(_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
*this = any{_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;
}
}
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);
_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);
_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]
inline void swap(any& _Left, any& _Right) noexcept {
_Left.swap(_Right);
}
template <class _ValueType, class... _Types>
_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 <class _ValueType, class _Elem, class... _Types>
_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 <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>>();
}
}
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>>();
}
}
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);
}
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);
}
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_CXX17
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _ANY_