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:
Michael S. Rizkalla 2021-01-08 03:01:52 +00:00 коммит произвёл GitHub
Родитель 54cce5e15e
Коммит 256197425b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 472 добавлений и 118 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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