diff --git a/stl/inc/scoped_allocator b/stl/inc/scoped_allocator index feb10d164fa..c2376f65092 100644 --- a/stl/inc/scoped_allocator +++ b/stl/inc/scoped_allocator @@ -235,7 +235,16 @@ public: template void construct(_Ty* _Ptr, _Types&&... _Args) { // construct with varying allocator styles +#if _HAS_CXX20 + _STD apply( + [_Ptr, this](auto&&... _New_args) { + _Scoped_outermost_traits::construct( + _Scoped_outermost(*this), _Ptr, _STD forward(_New_args)...); + }, + uses_allocator_construction_args<_Ty>(inner_allocator(), _STD forward<_Types>(_Args)...)); +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _Uses_allocator_construct(_Ptr, _Scoped_outermost(*this), inner_allocator(), _STD forward<_Types>(_Args)...); +#endif } template diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e2065d559f9..31a7bebd0db 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -15,6 +15,10 @@ #include #include +#if _HAS_CXX20 +#include +#endif // _HAS_CXX20 + #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) @@ -2068,6 +2072,98 @@ void _Erase_nodes_if(_Container& _Cont, _Pr _Pred) { // erase each element satis } } } + +#if _HAS_CXX20 + +template , int> = 0> +constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Types&&... _Args) noexcept { + if constexpr (!uses_allocator_v<_Ty, _Alloc>) { + static_assert(is_constructible_v<_Ty, _Types...>, + "T must be constructible from Types... if uses_allocator_v is false"); + (void) _Al; + return _STD forward_as_tuple(_STD forward<_Types>(_Args)...); + } else { + if constexpr (is_constructible_v<_Ty, allocator_arg_t, const _Alloc&, _Types...>) { + using _Return_type = tuple; + return _ReturnType(allocator_arg, _Al, _STD forward<_Types>(_Args)...); + } else if constexpr (is_constructible_v<_Ty, _Types..., const _Alloc&>) { + return _STD forward_as_tuple(_STD forward<_Types>(_Args)..., _Al); + } else { + static_assert(_Always_false<_Ty>, + "T must be constructible from either (allocator_arg_t, const Alloc&, Types...)" + "or (Types..., const Alloc&) if uses_allocator_v is true"); + } + } +} + +template , int> = 0> +constexpr auto uses_allocator_construction_args( + const _Alloc& _Al, piecewise_construct_t, _Tuple1&& _Tup1, _Tuple2&& _Tup2) noexcept { + return _STD make_tuple(piecewise_construct, + _STD apply( + [&_Al](auto&&... _Tuple_args) { + return uses_allocator_construction_args( + _Al, _STD forward(_Tuple_args)...); + }, + _STD forward<_Tuple1>(_Tup1)), + _STD apply( + [&_Al](auto&&... _Tuple_args) { + return uses_allocator_construction_args( + _Al, _STD forward(_Tuple_args)...); + }, + _STD forward<_Tuple2>(_Tup2))); +} + +template , int> = 0> +constexpr auto uses_allocator_construction_args(const _Alloc& _Al) noexcept { + // equivalent to + // return uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, tuple<>(), tuple<>()); + return _STD make_tuple(piecewise_construct, uses_allocator_construction_args(_Al), + uses_allocator_construction_args(_Al)); +} + +template , int> = 0> +constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty1&& _Val1, _Uty2&& _Val2) noexcept { + // equivalent to + // return uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(_STD forward<_Uty1>(_Val1)), _STD forward_as_tuple(_STD forward<_Uty2>(_Val2))); + return _STD make_tuple(piecewise_construct, + uses_allocator_construction_args(_Al, _STD forward<_Uty1>(_Val1)), + uses_allocator_construction_args(_Al, _STD forward<_Uty2>(_Val2))); +} + +template , int> = 0> +constexpr auto uses_allocator_construction_args(const _Alloc& _Al, const pair<_Uty1, _Uty2>& _Pair) noexcept { + // equivalent to + // return uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(pr.first), _STD forward_as_tuple(pr.second)); + return _STD make_tuple(piecewise_construct, + uses_allocator_construction_args(_Al, _Pair.first), + uses_allocator_construction_args(_Al, _Pair.second)); +} + +template , int> = 0> +constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>&& _Pair) noexcept { + // equivalent to + // return uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(_STD move(pr).first), _STD forward_as_tuple(_STD move(pr).second)); + return _STD make_tuple(piecewise_construct, + uses_allocator_construction_args(_Al, _STD move(_Pair).first), + uses_allocator_construction_args(_Al, _STD move(_Pair).second)); +} + +template +constexpr _Ty make_obj_using_allocator(const _Alloc& _Al, _Types&&... _Args) { + return _STD make_from_tuple<_Ty>(uses_allocator_construction_args<_Ty>(_Al, _STD forward<_Types>(_Args)...)); +} + +template +constexpr _Ty* uninitialized_construct_using_allocator(_Ty* _Ptr, const _Alloc& _Al, _Types&&... _Args) { + return ::new (static_cast(_Ptr)) _Ty(make_obj_using_allocator<_Ty>(_Al, _STD forward<_Types>(_Args)...)); +} + +#endif // _HAS_CXX20 + _STD_END #pragma pop_macro("new") diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index 3f3d21e3042..bd7d25e6d05 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -67,6 +67,8 @@ void _Uses_allocator_construct(_Ty* const _Ptr, _Outer_alloc& _Outer, _Inner_all _STD forward<_Types>(_Args)...); // TRANSITION, if constexpr } +#if !_HAS_CXX20 + template auto _Uses_allocator_piecewise2(true_type, _Alloc& _Al, tuple<_Types...>&& _Tuple) { return _STD tuple_cat(tuple(allocator_arg, _Al), _STD move(_Tuple)); @@ -134,6 +136,8 @@ void _Uses_allocator_construct( _STD forward_as_tuple(_STD forward<_Vty>(_Pair.second))); } +#endif // !_HAS_CXX20 + #if _HAS_CXX17 namespace pmr { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 296bb4ab5e1..db47b0f8d1f 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -135,6 +135,7 @@ // P0457R2 starts_with()/ends_with() For basic_string/basic_string_view // P0458R2 contains() For Ordered And Unordered Associative Containers // P0463R1 endian +// P0475R1 Guaranteed Copy Elision For Piecewise Construction // P0482R6 Library Support For char8_t // (mbrtoc8 and c8rtomb not yet implemented) // P0487R1 Fixing operator>>(basic_istream&, CharT*) @@ -142,6 +143,7 @@ // P0553R4 Rotating And Counting Functions // P0556R3 ispow2(), ceil2(), floor2(), log2p1() // (log2p1() is called bit_length() as of D1956) +// P0591R4 Utility Functions For Uses-Allocator Construction // P0595R2 is_constant_evaluated() // P0616R0 Using move() In // P0631R8 Math Constants