зеркало из https://github.com/microsoft/STL.git
P0784R7 Library Support For More constexpr Containers (#1369)
Co-authored-by: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Co-authored-by: Curtis Jacques Bezault <curtbezault@gmail.com> Co-authored-by: Michael Schellenberger Costa <mschellenbergercosta@gmail.com> Co-authored-by: mnatsuhara <46756417+mnatsuhara@users.noreply.github.com> Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
This commit is contained in:
Родитель
54cce5e15e
Коммит
256197425b
|
@ -496,22 +496,7 @@ namespace ranges {
|
|||
};
|
||||
|
||||
inline constexpr _Uninitialized_fill_n_fn uninitialized_fill_n{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE construct_at
|
||||
#if _HAS_CXX20
|
||||
template <class _Ty, class... _Types>
|
||||
_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(
|
||||
noexcept(::new (const_cast<void*>(static_cast<const volatile void*>(_Location)))
|
||||
_Ty(_STD forward<_Types>(_Args)...))) // strengthened
|
||||
-> decltype(
|
||||
::new (const_cast<void*>(static_cast<const volatile void*>(_Location))) _Ty(_STD forward<_Types>(_Args)...)) {
|
||||
return ::new (const_cast<void*>(static_cast<const volatile void*>(_Location))) _Ty(_STD forward<_Types>(_Args)...);
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::construct_at
|
||||
class _Construct_at_fn : private _Not_quite_object {
|
||||
public:
|
||||
|
@ -532,26 +517,7 @@ namespace ranges {
|
|||
};
|
||||
|
||||
inline constexpr _Construct_at_fn construct_at{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
#if _HAS_CXX17
|
||||
// FUNCTION TEMPLATE destroy_at
|
||||
template <class _Ty>
|
||||
_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ {
|
||||
#if _HAS_CXX20
|
||||
if constexpr (is_array_v<_Ty>) {
|
||||
_Destroy_range(_STD begin(*_Location), _STD end(*_Location));
|
||||
} else
|
||||
#endif // _HAS_CXX20
|
||||
{
|
||||
_Location->~_Ty();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::destroy_at
|
||||
// clang-format off
|
||||
template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se>
|
||||
|
@ -577,9 +543,11 @@ namespace ranges {
|
|||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
#if _HAS_CXX17
|
||||
// FUNCTION TEMPLATE destroy
|
||||
template <class _NoThrowFwdIt>
|
||||
void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) { // destroy all elements in [_First, _Last)
|
||||
_CONSTEXPR20_DYNALLOC void destroy(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) {
|
||||
// destroy all elements in [_First, _Last)
|
||||
_Adl_verify_range(_First, _Last);
|
||||
_Destroy_range(_Get_unwrapped(_First), _Get_unwrapped(_Last));
|
||||
}
|
||||
|
@ -606,7 +574,7 @@ namespace ranges {
|
|||
// clang-format off
|
||||
template <_No_throw_input_iterator _It, _No_throw_sentinel_for<_It> _Se>
|
||||
requires destructible<iter_value_t<_It>>
|
||||
/* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, _Se _Last) const noexcept {
|
||||
_CONSTEXPR20_DYNALLOC _It operator()(_It _First, _Se _Last) const noexcept {
|
||||
// clang-format on
|
||||
_Adl_verify_range(_First, _Last);
|
||||
_Seek_wrapped(_First,
|
||||
|
@ -617,7 +585,7 @@ namespace ranges {
|
|||
// clang-format off
|
||||
template <_No_throw_input_range _Rng>
|
||||
requires destructible<range_value_t<_Rng>>
|
||||
/* _CONSTEXPR20_DYNALLOC */ borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const noexcept {
|
||||
_CONSTEXPR20_DYNALLOC borrowed_iterator_t<_Rng> operator()(_Rng&& _Range) const noexcept {
|
||||
// clang-format on
|
||||
auto _First = _RANGES begin(_Range);
|
||||
_Seek_wrapped(_First, _RANGES _Destroy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range)));
|
||||
|
@ -631,7 +599,7 @@ namespace ranges {
|
|||
|
||||
// FUNCTION TEMPLATE destroy_n
|
||||
template <class _NoThrowFwdIt, class _Diff>
|
||||
_NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) {
|
||||
_CONSTEXPR20_DYNALLOC _NoThrowFwdIt destroy_n(_NoThrowFwdIt _First, const _Diff _Count_raw) {
|
||||
// destroy all elements in [_First, _First + _Count)
|
||||
_Algorithm_int_t<_Diff> _Count = _Count_raw;
|
||||
if (_Count <= 0) {
|
||||
|
@ -661,8 +629,9 @@ namespace ranges {
|
|||
// clang-format off
|
||||
template <_No_throw_input_iterator _It>
|
||||
requires destructible<iter_value_t<_It>>
|
||||
/* _CONSTEXPR20_DYNALLOC */ _It operator()(_It _First, const iter_difference_t<_It> _Count) const noexcept {
|
||||
_CONSTEXPR20_DYNALLOC _It operator()(_It _First, const iter_difference_t<_It> _Count_raw) const noexcept {
|
||||
// clang-format on
|
||||
_Algorithm_int_t<iter_difference_t<_It>> _Count = _Count_raw;
|
||||
if (_Count <= 0) {
|
||||
return _First;
|
||||
}
|
||||
|
|
204
stl/inc/xmemory
204
stl/inc/xmemory
|
@ -73,13 +73,30 @@ _INLINE_VAR constexpr size_t _New_alignof = (_STD max)(alignof(_Ty),
|
|||
|
||||
// STRUCT _Default_allocate_traits
|
||||
struct _Default_allocate_traits {
|
||||
__declspec(allocator) static void* _Allocate(const size_t _Bytes) {
|
||||
__declspec(allocator) static
|
||||
#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532
|
||||
_CONSTEXPR20_DYNALLOC
|
||||
#endif // __clang__
|
||||
void* _Allocate(const size_t _Bytes) {
|
||||
return ::operator new(_Bytes);
|
||||
}
|
||||
|
||||
#ifdef __cpp_aligned_new
|
||||
__declspec(allocator) static void* _Allocate_aligned(const size_t _Bytes, const size_t _Align) {
|
||||
return ::operator new (_Bytes, align_val_t{_Align});
|
||||
__declspec(allocator) static
|
||||
#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532
|
||||
_CONSTEXPR20_DYNALLOC
|
||||
#endif // __clang__
|
||||
void* _Allocate_aligned(const size_t _Bytes, const size_t _Align) {
|
||||
#ifdef __clang__ // Clang and MSVC implement P0784R7 differently; see GH-1532
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
if (_STD is_constant_evaluated()) {
|
||||
return ::operator new(_Bytes);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
#endif // __clang__
|
||||
{
|
||||
return ::operator new (_Bytes, align_val_t{_Align});
|
||||
}
|
||||
}
|
||||
#endif // __cpp_aligned_new
|
||||
};
|
||||
|
@ -157,34 +174,46 @@ inline void _Adjust_manually_vector_aligned(void*& _Ptr, size_t& _Bytes) {
|
|||
#ifdef __cpp_aligned_new
|
||||
template <size_t _Align, class _Traits = _Default_allocate_traits,
|
||||
enable_if_t<(_Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
||||
__declspec(allocator) void* _Allocate(const size_t _Bytes) {
|
||||
__declspec(allocator) _CONSTEXPR20_DYNALLOC void* _Allocate(const size_t _Bytes) {
|
||||
// allocate _Bytes when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
if (_Bytes == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t _Passed_align = _Align;
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (_STD is_constant_evaluated()) {
|
||||
return _Traits::_Allocate(_Bytes);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
size_t _Passed_align = _Align;
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
if (_Bytes >= _Big_allocation_threshold) {
|
||||
// boost the alignment of big allocations to help autovectorization
|
||||
_Passed_align = (_STD max)(_Align, _Big_allocation_alignment);
|
||||
}
|
||||
if (_Bytes >= _Big_allocation_threshold) {
|
||||
// boost the alignment of big allocations to help autovectorization
|
||||
_Passed_align = (_STD max)(_Align, _Big_allocation_alignment);
|
||||
}
|
||||
#endif // defined(_M_IX86) || defined(_M_X64)
|
||||
|
||||
return _Traits::_Allocate_aligned(_Bytes, _Passed_align);
|
||||
return _Traits::_Allocate_aligned(_Bytes, _Passed_align);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t _Align, enable_if_t<(_Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
||||
void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept {
|
||||
_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept {
|
||||
// deallocate storage allocated by _Allocate when __cpp_aligned_new && _Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
size_t _Passed_align = _Align;
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (_STD is_constant_evaluated()) {
|
||||
::operator delete(_Ptr);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
size_t _Passed_align = _Align;
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
||||
_Passed_align = (_STD max)(_Align, _Big_allocation_alignment);
|
||||
}
|
||||
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
||||
_Passed_align = (_STD max)(_Align, _Big_allocation_alignment);
|
||||
}
|
||||
#endif // defined(_M_IX86) || defined(_M_X64)
|
||||
|
||||
::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align});
|
||||
::operator delete (_Ptr, _Bytes, align_val_t{_Passed_align});
|
||||
}
|
||||
}
|
||||
|
||||
#define _HAS_ALIGNED_NEW 1
|
||||
|
@ -194,11 +223,16 @@ void _Deallocate(void* _Ptr, const size_t _Bytes) noexcept {
|
|||
|
||||
template <size_t _Align, class _Traits = _Default_allocate_traits,
|
||||
enable_if_t<(!_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
||||
__declspec(allocator) void* _Allocate(const size_t _Bytes) {
|
||||
__declspec(allocator) _CONSTEXPR20_DYNALLOC void* _Allocate(const size_t _Bytes) {
|
||||
// allocate _Bytes when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
||||
return _Allocate_manually_vector_aligned<_Traits>(_Bytes);
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (!_STD is_constant_evaluated())
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
||||
return _Allocate_manually_vector_aligned<_Traits>(_Bytes);
|
||||
}
|
||||
}
|
||||
#endif // defined(_M_IX86) || defined(_M_X64)
|
||||
|
||||
|
@ -210,15 +244,21 @@ __declspec(allocator) void* _Allocate(const size_t _Bytes) {
|
|||
}
|
||||
|
||||
template <size_t _Align, enable_if_t<(!_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__), int> = 0>
|
||||
void _Deallocate(void* _Ptr, size_t _Bytes) noexcept {
|
||||
_CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept {
|
||||
// deallocate storage allocated by _Allocate when !_HAS_ALIGNED_NEW || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (_STD is_constant_evaluated()) {
|
||||
::operator delete(_Ptr);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
||||
_Adjust_manually_vector_aligned(_Ptr, _Bytes);
|
||||
}
|
||||
if (_Bytes >= _Big_allocation_threshold) { // boost the alignment of big allocations to help autovectorization
|
||||
_Adjust_manually_vector_aligned(_Ptr, _Bytes);
|
||||
}
|
||||
#endif // defined(_M_IX86) || defined(_M_X64)
|
||||
|
||||
::operator delete(_Ptr, _Bytes);
|
||||
::operator delete(_Ptr, _Bytes);
|
||||
}
|
||||
}
|
||||
|
||||
#undef _HAS_ALIGNED_NEW
|
||||
|
@ -268,6 +308,21 @@ _CONSTEXPR20_DYNALLOC void _Destroy_in_place(_Ty& _Obj) noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
#if _HAS_CXX17
|
||||
// FUNCTION TEMPLATE destroy_at
|
||||
template <class _Ty>
|
||||
_CONSTEXPR20_DYNALLOC void destroy_at(_Ty* const _Location) noexcept /* strengthened */ {
|
||||
#if _HAS_CXX20
|
||||
if constexpr (is_array_v<_Ty>) {
|
||||
_Destroy_range(_STD begin(*_Location), _STD end(*_Location));
|
||||
} else
|
||||
#endif // _HAS_CXX20
|
||||
{
|
||||
_Location->~_Ty();
|
||||
}
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
// FUNCTION TEMPLATE _Const_cast
|
||||
template <class _Ptrty>
|
||||
auto _Const_cast(_Ptrty _Ptr) noexcept { // remove constness from a fancy pointer
|
||||
|
@ -516,11 +571,12 @@ struct _Normal_allocator_traits { // defines traits for allocators
|
|||
template <class _Other>
|
||||
using rebind_traits = allocator_traits<rebind_alloc<_Other>>;
|
||||
|
||||
_NODISCARD static __declspec(allocator) pointer allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) {
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
||||
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) {
|
||||
return _Al.allocate(_Count);
|
||||
}
|
||||
|
||||
_NODISCARD static __declspec(allocator) pointer
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
||||
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const const_void_pointer _Hint) {
|
||||
if constexpr (_Has_allocate_hint<_Alloc, size_type, const_void_pointer>::value) {
|
||||
return _Al.allocate(_Count, _Hint);
|
||||
|
@ -529,30 +585,38 @@ struct _Normal_allocator_traits { // defines traits for allocators
|
|||
}
|
||||
}
|
||||
|
||||
static void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) {
|
||||
static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, pointer _Ptr, size_type _Count) {
|
||||
_Al.deallocate(_Ptr, _Count);
|
||||
}
|
||||
|
||||
template <class _Ty, class... _Types>
|
||||
static void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) {
|
||||
static _CONSTEXPR20_DYNALLOC void construct(_Alloc& _Al, _Ty* _Ptr, _Types&&... _Args) {
|
||||
if constexpr (_Uses_default_construct<_Alloc, _Ty*, _Types...>::value) {
|
||||
(void) _Al; // TRANSITION, DevCom-1004719
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
_STD construct_at(_Ptr, _STD forward<_Types>(_Args)...);
|
||||
#else // __cpp_lib_constexpr_dynamic_alloc
|
||||
::new (static_cast<void*>(_Ptr)) _Ty(_STD forward<_Types>(_Args)...);
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
} else {
|
||||
_Al.construct(_Ptr, _STD forward<_Types>(_Args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Ty>
|
||||
static void destroy(_Alloc& _Al, _Ty* _Ptr) {
|
||||
static _CONSTEXPR20_DYNALLOC void destroy(_Alloc& _Al, _Ty* _Ptr) {
|
||||
if constexpr (_Uses_default_destroy<_Alloc, _Ty*>::value) {
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
_STD destroy_at(_Ptr);
|
||||
#else // __cpp_lib_constexpr_dynamic_alloc
|
||||
_Ptr->~_Ty();
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
} else {
|
||||
_Al.destroy(_Ptr);
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD static size_type max_size(const _Alloc& _Al) noexcept {
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc& _Al) noexcept {
|
||||
if constexpr (_Has_max_size<_Alloc>::value) {
|
||||
return _Al.max_size();
|
||||
} else {
|
||||
|
@ -560,7 +624,7 @@ struct _Normal_allocator_traits { // defines traits for allocators
|
|||
}
|
||||
}
|
||||
|
||||
_NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) {
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) {
|
||||
if constexpr (_Has_select_on_container_copy_construction<_Alloc>::value) {
|
||||
return _Al.select_on_container_copy_construction();
|
||||
} else {
|
||||
|
@ -594,35 +658,73 @@ struct _Default_allocator_traits { // traits for std::allocator
|
|||
template <class _Other>
|
||||
using rebind_traits = allocator_traits<allocator<_Other>>;
|
||||
|
||||
_NODISCARD static __declspec(allocator) pointer allocate(_Alloc&, _CRT_GUARDOVERFLOW const size_type _Count) {
|
||||
return static_cast<pointer>(_Allocate<_New_alignof<value_type>>(_Get_size_of_n<sizeof(value_type)>(_Count)));
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
||||
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count) {
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (_STD is_constant_evaluated()) {
|
||||
return _Al.allocate(_Count);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
(void) _Al;
|
||||
return static_cast<pointer>(
|
||||
_Allocate<_New_alignof<value_type>>(_Get_size_of_n<sizeof(value_type)>(_Count)));
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD static __declspec(allocator) pointer
|
||||
allocate(_Alloc&, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) {
|
||||
return static_cast<pointer>(_Allocate<_New_alignof<value_type>>(_Get_size_of_n<sizeof(value_type)>(_Count)));
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC __declspec(allocator) pointer
|
||||
allocate(_Alloc& _Al, _CRT_GUARDOVERFLOW const size_type _Count, const_void_pointer) {
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (_STD is_constant_evaluated()) {
|
||||
return _Al.allocate(_Count);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
(void) _Al;
|
||||
return static_cast<pointer>(
|
||||
_Allocate<_New_alignof<value_type>>(_Get_size_of_n<sizeof(value_type)>(_Count)));
|
||||
}
|
||||
}
|
||||
|
||||
static void deallocate(_Alloc&, const pointer _Ptr, const size_type _Count) {
|
||||
static _CONSTEXPR20_DYNALLOC void deallocate(_Alloc& _Al, const pointer _Ptr, const size_type _Count) {
|
||||
// no overflow check on the following multiply; we assume _Allocate did that check
|
||||
_Deallocate<_New_alignof<value_type>>(_Ptr, sizeof(value_type) * _Count);
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, GH-1532
|
||||
if (_STD is_constant_evaluated()) {
|
||||
_Al.deallocate(_Ptr, _Count);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
(void) _Al;
|
||||
_Deallocate<_New_alignof<value_type>>(_Ptr, sizeof(value_type) * _Count);
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Objty, class... _Types>
|
||||
static void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) {
|
||||
::new (const_cast<void*>(static_cast<const volatile void*>(_Ptr))) _Objty(_STD forward<_Types>(_Args)...);
|
||||
static _CONSTEXPR20_DYNALLOC void construct(_Alloc&, _Objty* const _Ptr, _Types&&... _Args) {
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
if (_STD is_constant_evaluated()) {
|
||||
_STD construct_at(_Ptr, _STD forward<_Types>(_Args)...);
|
||||
} else
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
{
|
||||
::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Uty>
|
||||
static void destroy(_Alloc&, _Uty* const _Ptr) {
|
||||
static _CONSTEXPR20_DYNALLOC void destroy(_Alloc&, _Uty* const _Ptr) {
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
_STD destroy_at(_Ptr);
|
||||
#else // __cpp_lib_constexpr_dynamic_alloc
|
||||
_Ptr->~_Uty();
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
}
|
||||
|
||||
_NODISCARD static size_type max_size(const _Alloc&) noexcept {
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC size_type max_size(const _Alloc&) noexcept {
|
||||
return static_cast<size_t>(-1) / sizeof(value_type);
|
||||
}
|
||||
|
||||
_NODISCARD static _Alloc select_on_container_copy_construction(const _Alloc& _Al) {
|
||||
_NODISCARD static _CONSTEXPR20_DYNALLOC _Alloc select_on_container_copy_construction(const _Alloc& _Al) {
|
||||
return _Al;
|
||||
}
|
||||
};
|
||||
|
@ -716,13 +818,15 @@ public:
|
|||
constexpr allocator(const allocator&) noexcept = default;
|
||||
template <class _Other>
|
||||
constexpr allocator(const allocator<_Other>&) noexcept {}
|
||||
_CONSTEXPR20_DYNALLOC ~allocator() = default;
|
||||
_CONSTEXPR20_DYNALLOC allocator& operator=(const allocator&) = default;
|
||||
|
||||
void deallocate(_Ty* const _Ptr, const size_t _Count) {
|
||||
_CONSTEXPR20_DYNALLOC void deallocate(_Ty* const _Ptr, const size_t _Count) {
|
||||
// no overflow check on the following multiply; we assume _Allocate did that check
|
||||
_Deallocate<_New_alignof<_Ty>>(_Ptr, sizeof(_Ty) * _Count);
|
||||
}
|
||||
|
||||
_NODISCARD __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) {
|
||||
_NODISCARD _CONSTEXPR20_DYNALLOC __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) {
|
||||
return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n<sizeof(_Ty)>(_Count)));
|
||||
}
|
||||
|
||||
|
@ -767,12 +871,12 @@ public:
|
|||
};
|
||||
|
||||
template <class _Ty, class _Other>
|
||||
_NODISCARD bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept {
|
||||
_NODISCARD _CONSTEXPR20_DYNALLOC bool operator==(const allocator<_Ty>&, const allocator<_Other>&) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class _Ty, class _Other>
|
||||
_NODISCARD bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept {
|
||||
_NODISCARD _CONSTEXPR20_DYNALLOC bool operator!=(const allocator<_Ty>&, const allocator<_Other>&) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ struct _Get_rebind_alias<_Ty, _Other, void_t<typename _Ty::template rebind<_Othe
|
|||
|
||||
// FUNCTION TEMPLATE _Voidify_iter
|
||||
template <class _Iter>
|
||||
_NODISCARD void* _Voidify_iter(_Iter _It) noexcept {
|
||||
_NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept {
|
||||
if constexpr (is_pointer_v<_Iter>) {
|
||||
return const_cast<void*>(static_cast<const volatile void*>(_It));
|
||||
} else {
|
||||
|
@ -129,6 +129,16 @@ _NODISCARD void* _Voidify_iter(_Iter _It) noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
// FUNCTION TEMPLATE construct_at
|
||||
#if _HAS_CXX20
|
||||
template <class _Ty, class... _Types>
|
||||
_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept(
|
||||
noexcept(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) // strengthened
|
||||
-> decltype(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...)) {
|
||||
return ::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...);
|
||||
}
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
// FUNCTION TEMPLATE _Construct_in_place
|
||||
template <class _Ty, class... _Types>
|
||||
void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) {
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
// P0758R1 is_nothrow_convertible
|
||||
// P0768R1 Library Support For The Spaceship Comparison Operator <=>
|
||||
// P0769R2 shift_left(), shift_right()
|
||||
// P0784R7 Library Support For More constexpr Containers
|
||||
// P0811R3 midpoint(), lerp()
|
||||
// P0879R0 constexpr For Swapping Functions
|
||||
// P0887R1 type_identity
|
||||
|
@ -550,13 +551,6 @@
|
|||
#define _CONSTEXPR20 inline
|
||||
#endif // ^^^ inline (not constexpr) in C++17 and earlier ^^^
|
||||
|
||||
// Functions that became constexpr in C++20 via P0784R7
|
||||
#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc)
|
||||
#define _CONSTEXPR20_DYNALLOC constexpr
|
||||
#else
|
||||
#define _CONSTEXPR20_DYNALLOC inline
|
||||
#endif
|
||||
|
||||
// P0607R0 Inline Variables For The STL
|
||||
#if _HAS_CXX17
|
||||
#define _INLINE_VAR inline
|
||||
|
@ -1185,8 +1179,14 @@
|
|||
#define __cpp_lib_concepts 201907L
|
||||
#endif // !defined(__EDG__) || defined(__INTELLISENSE__)
|
||||
|
||||
#define __cpp_lib_constexpr_algorithms 201806L
|
||||
#define __cpp_lib_constexpr_complex 201711L
|
||||
#define __cpp_lib_constexpr_algorithms 201806L
|
||||
#define __cpp_lib_constexpr_complex 201711L
|
||||
|
||||
#if defined(__cpp_constexpr_dynamic_alloc) \
|
||||
&& defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation
|
||||
#define __cpp_lib_constexpr_dynamic_alloc 201907L
|
||||
#endif // defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__)
|
||||
|
||||
#define __cpp_lib_constexpr_functional 201907L
|
||||
#define __cpp_lib_constexpr_iterator 201811L
|
||||
#define __cpp_lib_constexpr_memory 201811L
|
||||
|
@ -1255,6 +1255,13 @@
|
|||
#define __cpp_lib_experimental_erase_if 201411L
|
||||
#define __cpp_lib_experimental_filesystem 201406L
|
||||
|
||||
// Functions that became constexpr in C++20 via P0784R7
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
#define _CONSTEXPR20_DYNALLOC constexpr
|
||||
#else
|
||||
#define _CONSTEXPR20_DYNALLOC inline
|
||||
#endif
|
||||
|
||||
#ifdef _RTC_CONVERSION_CHECKS_ENABLED
|
||||
#ifndef _ALLOW_RTCc_IN_STL
|
||||
#error /RTCc rejects conformant code, so it is not supported by the C++ Standard Library. Either remove this \
|
||||
|
|
|
@ -493,19 +493,18 @@ std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp FAIL
|
|||
std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp FAIL
|
||||
|
||||
# C++20 P0784R7 "More constexpr containers"
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp:0 FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp:0 FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp:0 FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp FAIL
|
||||
std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp FAIL
|
||||
std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp:1 FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp:0 FAIL
|
||||
std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp:0 FAIL
|
||||
std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp:0 FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp:0 FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp:0 FAIL
|
||||
std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp:0 FAIL
|
||||
|
||||
# C++20 P0896R4 "<ranges>"
|
||||
std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp FAIL
|
||||
|
|
|
@ -501,7 +501,6 @@ utilities\memory\allocator.traits\allocator.traits.members\destroy.pass.cpp
|
|||
utilities\memory\allocator.traits\allocator.traits.members\max_size.pass.cpp
|
||||
utilities\memory\allocator.traits\allocator.traits.members\select_on_container_copy_construction.pass.cpp
|
||||
utilities\memory\default.allocator\allocator.globals\eq.pass.cpp
|
||||
utilities\memory\default.allocator\allocator.members\allocate.pass.cpp
|
||||
utilities\memory\specialized.algorithms\specialized.construct\construct_at.pass.cpp
|
||||
utilities\memory\specialized.algorithms\specialized.destroy\destroy.pass.cpp
|
||||
utilities\memory\specialized.algorithms\specialized.destroy\destroy_at.pass.cpp
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
@ -143,7 +145,6 @@ static_assert(destroy_at_noexcept<volatile string>());
|
|||
static_assert(destroy_at_noexcept<const volatile int>());
|
||||
static_assert(destroy_at_noexcept<const volatile string>());
|
||||
|
||||
#if _HAS_CXX20
|
||||
static_assert(destroy_at_noexcept<int[42]>());
|
||||
static_assert(destroy_at_noexcept<string[42]>());
|
||||
static_assert(destroy_at_noexcept<const int[42]>());
|
||||
|
@ -152,16 +153,13 @@ static_assert(destroy_at_noexcept<volatile int[42]>());
|
|||
static_assert(destroy_at_noexcept<volatile string[42]>());
|
||||
static_assert(destroy_at_noexcept<const volatile int[42]>());
|
||||
static_assert(destroy_at_noexcept<const volatile string[42]>());
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
struct throwing_dtor {
|
||||
~throwing_dtor() noexcept(false) {}
|
||||
};
|
||||
|
||||
static_assert(destroy_at_noexcept<throwing_dtor>());
|
||||
#if _HAS_CXX20
|
||||
static_assert(destroy_at_noexcept<throwing_dtor[42]>());
|
||||
#endif // _HAS_CXX20
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
static_assert(!can_ranges_destroy_at<throwing_dtor>);
|
||||
|
@ -205,7 +203,6 @@ void test_array(const T& val) {
|
|||
constexpr int N = 42;
|
||||
(void) val;
|
||||
|
||||
#if _HAS_CXX20
|
||||
alignas(T) unsigned char storage[sizeof(T) * N];
|
||||
using U = conditional_t<is_scalar_v<T>, const volatile T, T>;
|
||||
const auto ptr = reinterpret_cast<U*>(storage);
|
||||
|
@ -227,10 +224,9 @@ void test_array(const T& val) {
|
|||
ranges::destroy_at(reinterpret_cast<T(*)[N]>(const_cast<T*>(ptr)));
|
||||
#endif // TRANSITION, VSO-1049320
|
||||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX20
|
||||
}
|
||||
|
||||
#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc)
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
template <class T>
|
||||
struct storage_for {
|
||||
union {
|
||||
|
@ -272,7 +268,262 @@ constexpr void test_compiletime() {
|
|||
}
|
||||
}
|
||||
static_assert((test_compiletime(), true));
|
||||
#endif // _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc)
|
||||
|
||||
template <class T>
|
||||
struct A {
|
||||
T value;
|
||||
|
||||
constexpr A() noexcept = default;
|
||||
constexpr ~A() = default;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct nontrivial_A {
|
||||
T value;
|
||||
|
||||
constexpr nontrivial_A(T in = T{}) noexcept : value(in) {}
|
||||
constexpr ~nontrivial_A() {}
|
||||
};
|
||||
|
||||
constexpr void test_compiletime_destroy_variants() {
|
||||
{
|
||||
allocator<A<int>> alloc{};
|
||||
A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
construct_at(a + i);
|
||||
}
|
||||
destroy(a, a + 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
{
|
||||
allocator<nontrivial_A<int>> alloc{};
|
||||
nontrivial_A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
construct_at(a + i);
|
||||
}
|
||||
destroy(a, a + 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
#ifdef __cpp_lib_concepts
|
||||
{
|
||||
allocator<A<int>> alloc{};
|
||||
A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ranges::construct_at(a + i);
|
||||
}
|
||||
ranges::destroy(a, a + 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
{
|
||||
allocator<nontrivial_A<int>> alloc{};
|
||||
nontrivial_A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ranges::construct_at(a + i);
|
||||
}
|
||||
ranges::destroy(a, a + 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
{
|
||||
allocator<A<int>> alloc{};
|
||||
A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ranges::construct_at(a + i);
|
||||
}
|
||||
span s{a, 10};
|
||||
ranges::destroy(s);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
{
|
||||
allocator<nontrivial_A<int>> alloc{};
|
||||
nontrivial_A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ranges::construct_at(a + i);
|
||||
}
|
||||
span s{a, 10};
|
||||
ranges::destroy(s);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
#endif // __cpp_lib_concepts
|
||||
{
|
||||
allocator<A<int>> alloc{};
|
||||
A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
construct_at(a + i);
|
||||
}
|
||||
destroy_n(a, 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
{
|
||||
allocator<nontrivial_A<int>> alloc{};
|
||||
nontrivial_A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
construct_at(a + i);
|
||||
}
|
||||
destroy_n(a, 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
#ifdef __cpp_lib_concepts
|
||||
{
|
||||
allocator<A<int>> alloc{};
|
||||
A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ranges::construct_at(a + i);
|
||||
}
|
||||
ranges::destroy_n(a, 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
{
|
||||
allocator<nontrivial_A<int>> alloc{};
|
||||
nontrivial_A<int>* a = alloc.allocate(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ranges::construct_at(a + i);
|
||||
}
|
||||
ranges::destroy_n(a, 10);
|
||||
alloc.deallocate(a, 10);
|
||||
}
|
||||
#endif // __cpp_lib_concepts
|
||||
}
|
||||
static_assert((test_compiletime_destroy_variants(), true));
|
||||
|
||||
template <class T, bool Construct = false, bool Destroy = false>
|
||||
struct Alloc {
|
||||
using value_type = T;
|
||||
using size_type = size_t;
|
||||
|
||||
template <class U>
|
||||
struct rebind {
|
||||
using other = Alloc<U, Construct, Destroy>;
|
||||
};
|
||||
|
||||
constexpr Alloc(int id_) noexcept : id(id_) {}
|
||||
|
||||
template <class U>
|
||||
constexpr Alloc(const Alloc<U, Construct, Destroy>& al) noexcept : id(al.id) {}
|
||||
|
||||
constexpr value_type* allocate(size_t n) {
|
||||
assert(n == 10);
|
||||
return allocator<T>{}.allocate(n);
|
||||
}
|
||||
|
||||
constexpr void deallocate(value_type* ptr, size_t n) {
|
||||
assert(n == 10);
|
||||
allocator<T>{}.deallocate(ptr, n);
|
||||
}
|
||||
|
||||
constexpr void construct(value_type* ptr, value_type n) requires(Construct) {
|
||||
construct_at(ptr, n);
|
||||
}
|
||||
|
||||
constexpr void destroy(value_type* ptr) requires(Destroy) {
|
||||
destroy_at(ptr);
|
||||
}
|
||||
|
||||
constexpr Alloc select_on_container_copy_construction() const noexcept {
|
||||
return Alloc{id + 1};
|
||||
}
|
||||
|
||||
constexpr size_type max_size() const noexcept {
|
||||
return numeric_limits<size_type>::max() / sizeof(value_type);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
constexpr bool operator==(const Alloc<U, Construct, Destroy>&) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
int id;
|
||||
};
|
||||
|
||||
constexpr void test_compiletime_allocator_traits() {
|
||||
{
|
||||
storage_for<A<int>> a;
|
||||
Alloc<A<int>> alloc{10};
|
||||
assert(alloc.id == 10);
|
||||
|
||||
auto result = allocator_traits<Alloc<A<int>>>::allocate(alloc, 10);
|
||||
assert(result != nullptr);
|
||||
allocator_traits<Alloc<A<int>>>::deallocate(alloc, result, 10);
|
||||
|
||||
allocator_traits<Alloc<A<int>>>::construct(alloc, &a.object);
|
||||
assert(a.object.value == 0);
|
||||
allocator_traits<Alloc<A<int>>>::destroy(alloc, &a.object);
|
||||
|
||||
assert(allocator_traits<Alloc<A<int>>>::select_on_container_copy_construction(alloc).id == 11);
|
||||
|
||||
assert(allocator_traits<Alloc<A<int>>>::max_size(alloc)
|
||||
== numeric_limits<Alloc<A<int>>::size_type>::max() / sizeof(Alloc<A<int>>::value_type));
|
||||
}
|
||||
{
|
||||
storage_for<nontrivial_A<int>> a;
|
||||
Alloc<nontrivial_A<int>> alloc{10};
|
||||
assert(alloc.id == 10);
|
||||
|
||||
auto result = allocator_traits<Alloc<nontrivial_A<int>>>::allocate(alloc, 10);
|
||||
assert(result != nullptr);
|
||||
allocator_traits<Alloc<nontrivial_A<int>>>::deallocate(alloc, result, 10);
|
||||
|
||||
allocator_traits<Alloc<nontrivial_A<int>>>::construct(alloc, &a.object, 10);
|
||||
assert(a.object.value == 10);
|
||||
allocator_traits<Alloc<nontrivial_A<int>>>::destroy(alloc, &a.object);
|
||||
|
||||
assert(allocator_traits<Alloc<nontrivial_A<int>>>::select_on_container_copy_construction(alloc).id == 11);
|
||||
|
||||
assert(allocator_traits<Alloc<nontrivial_A<int>>>::max_size(alloc)
|
||||
== numeric_limits<Alloc<nontrivial_A<int>>::size_type>::max()
|
||||
/ sizeof(Alloc<nontrivial_A<int>>::value_type));
|
||||
}
|
||||
{
|
||||
storage_for<nontrivial_A<int>> a;
|
||||
Alloc<nontrivial_A<int>, true> alloc{10};
|
||||
|
||||
allocator_traits<Alloc<nontrivial_A<int>, true>>::construct(alloc, &a.object, 10);
|
||||
assert(a.object.value == 10);
|
||||
allocator_traits<Alloc<nontrivial_A<int>, true>>::destroy(alloc, &a.object);
|
||||
}
|
||||
{
|
||||
storage_for<nontrivial_A<int>> a;
|
||||
Alloc<nontrivial_A<int>, false, true> alloc{10};
|
||||
|
||||
allocator_traits<Alloc<nontrivial_A<int>, false, true>>::construct(alloc, &a.object, 10);
|
||||
assert(a.object.value == 10);
|
||||
allocator_traits<Alloc<nontrivial_A<int>, false, true>>::destroy(alloc, &a.object);
|
||||
}
|
||||
{
|
||||
storage_for<nontrivial_A<int>> a;
|
||||
Alloc<nontrivial_A<int>, true, true> alloc{10};
|
||||
|
||||
allocator_traits<Alloc<nontrivial_A<int>, true, true>>::construct(alloc, &a.object, 10);
|
||||
assert(a.object.value == 10);
|
||||
allocator_traits<Alloc<nontrivial_A<int>, true, true>>::destroy(alloc, &a.object);
|
||||
}
|
||||
}
|
||||
static_assert((test_compiletime_allocator_traits(), true));
|
||||
|
||||
constexpr void test_compiletime_allocator() {
|
||||
{
|
||||
auto result = allocator<A<int>>{}.allocate(10);
|
||||
allocator<A<int>>{}.deallocate(result, 10);
|
||||
}
|
||||
{
|
||||
auto result = allocator<nontrivial_A<int>>{}.allocate(10);
|
||||
allocator<nontrivial_A<int>>{}.deallocate(result, 10);
|
||||
}
|
||||
}
|
||||
static_assert((test_compiletime_allocator(), true));
|
||||
|
||||
constexpr void test_compiletime_operators() {
|
||||
{
|
||||
allocator<int> allocatorA{};
|
||||
allocator<float> allocatorB{};
|
||||
constexpr auto allocatorC = allocatorA;
|
||||
|
||||
static_assert(allocatorA == allocatorB);
|
||||
static_assert(!(allocatorA != allocatorB));
|
||||
static_assert(allocatorA == allocatorC);
|
||||
}
|
||||
}
|
||||
static_assert((test_compiletime_operators(), true));
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
|
||||
int main() {
|
||||
test_runtime(1234);
|
||||
|
|
|
@ -411,6 +411,21 @@ STATIC_ASSERT(__cpp_lib_constexpr_complex == 201711L);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) \
|
||||
&& defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation
|
||||
#ifndef __cpp_lib_constexpr_dynamic_alloc
|
||||
#error __cpp_lib_constexpr_dynamic_alloc is not defined
|
||||
#elif __cpp_lib_constexpr_dynamic_alloc != 201907L
|
||||
#error __cpp_lib_constexpr_dynamic_alloc is not 201907L
|
||||
#else
|
||||
STATIC_ASSERT(__cpp_lib_constexpr_dynamic_alloc == 201907L);
|
||||
#endif
|
||||
#else
|
||||
#ifdef __cpp_lib_constexpr_dynamic_alloc
|
||||
#error __cpp_lib_constexpr_dynamic_alloc is defined
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _HAS_CXX20
|
||||
#ifndef __cpp_lib_constexpr_functional
|
||||
#error __cpp_lib_constexpr_functional is not defined
|
||||
|
|
Загрузка…
Ссылка в новой задаче