Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -626,6 +626,24 @@ atomic_compare_exchange_strong_explicit(shared_ptr* p, shared_ptr* v, shared_ptr w, memory_order success, memory_order failure); + +template + auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args); +template + auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y); +template + auto uses_allocator_construction_args(const Alloc& alloc); +template + auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v); +template + auto uses_allocator_construction_args(const Alloc& alloc, const pair& pr); +template + auto uses_allocator_construction_args(const Alloc& alloc, pair&& pr); +template + T make_obj_using_allocator(const Alloc& alloc, Args&&... args); +template + T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); + // Hash support template struct hash; template struct hash >; @@ -5667,6 +5685,109 @@ typename __void_t().allocate(size_t(0)))>::type > : true_type {}; + +#if _LIBCPP_STD_VER > 17 + +template struct __is_pair : false_type { }; + +template +struct __is_pair> : true_type { }; + +template +auto +__uses_allocator_construction_args_no_pair(false_type, _Un, const _Alloc, _Args&&... __args) { + return _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...); +} + +template +auto +__uses_allocator_construction_args_no_pair(true_type, true_type, const _Alloc __alloc, _Args&&... __args) { + return _VSTD::forward_as_tuple(allocator_arg, __alloc, _VSTD::forward<_Args>(__args)...); +} + +template +auto + __uses_allocator_construction_args_no_pair(false_type, false_type, const _Alloc __alloc, _Args&&... __args) { + return _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)..., __alloc); +} + +template::value>> +auto +uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) { + return __uses_allocator_construction_args_no_pair<_Tp>( + _VSTD::uses_allocator<_Tp, _Alloc>(), + _VSTD::is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>(), + __alloc, _VSTD::forward<_Args>(__args)...); +} + +template::value>> +auto +uses_allocator_construction_args(const _Alloc& __alloc, + piecewise_construct_t, + _T1&& __a, _T2&& __b) { + return std::make_tuple(piecewise_construct, + _VSTD::apply( [&__alloc](auto&&... __args) { + return _VSTD::uses_allocator_construction_args<_T1>(__alloc, _VSTD::forward(__args)...); + }, _VSTD::forward<_T1>(__a)), + _VSTD::apply( [&__alloc](auto&&... __args) { + return _VSTD::uses_allocator_construction_args<_T2>(__alloc, _VSTD::forward(__args)...); + }, _VSTD::forward<_T2>(__b))); +} + +template::value>> +auto +uses_allocator_construction_args(const _Alloc& __alloc) { + return uses_allocator_construction_args<_Tp>(__alloc, piecewise_construct, _VSTD::tuple<>{}, _VSTD::tuple<>{}); +} + +template::value>> +auto +uses_allocator_construction_args(const _Alloc& __alloc, _T1&& __a, _T2&& __b) { + return uses_allocator_construction_args<_Tp>( + __alloc, piecewise_construct, + _VSTD::forward_as_tuple(_VSTD::forward<_T1>(__a)), + _VSTD::forward_as_tuple(_VSTD::forward<_T2>(__b))); +} + +template::value>> +auto +uses_allocator_construction_args(const _Alloc& __alloc, const _VSTD::pair<_T1, _T2>& __p) { + return uses_allocator_construction_args<_Tp>(__alloc, piecewise_construct, + forward_as_tuple(__p.first), + forward_as_tuple(__p.second)); +} + +template::value>> +auto +uses_allocator_construction_args(const _Alloc& __alloc, _VSTD::pair<_T1, _T2>&& __p) { + return uses_allocator_construction_args<_Tp>(__alloc, + piecewise_construct, + forward_as_tuple(_VSTD::move(__p).first), + forward_as_tuple(_VSTD::move(__p).first)); +} + +template +_Tp +make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) { + return make_from_tuple<_Tp>( + uses_allocator_construction_args<_Tp>(__alloc, _VSTD::forward<_Args>(__args)...)); +} + +template +_Tp* +uninitialized_construct_using_allocator(_Tp* __p, const _Alloc& __alloc, _Args&&... __args) { + return ::new(static_cast(__p)) _Tp( + make_obj_using_allocator<_Tp>(__alloc, _VSTD::forward<_Args>(__args)...) + ); +} + +#endif // _LIBCPP_STD_VER > 17 _LIBCPP_END_NAMESPACE_STD Index: test/std/utilities/memory/uses_allocator_construction_args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/memory/uses_allocator_construction_args.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include +#include + +using pair_t = std::pair; + +struct A +{ + int a; + float b; + + A(int a, float b): a(a), b(b) { } +}; + +template +void test_pair (Args&&... args) +{ + auto args_tuple = std::uses_allocator_construction_args(std::forward(args)...); + auto arg_count = std::tuple_size::value; + assert(arg_count == 3); +} + +int main(int, char**) +{ + // non pair contruction + std::allocator alloc; + auto a = std::make_obj_using_allocator(alloc, 10, 5.0); + + assert(a.a == 10); + assert(a.b == 5.0); + + auto* b = std::uninitialized_construct_using_allocator(&a, alloc, 20, 10.0); + + assert(a.a == 20); + assert(a.b == 10.0); + + assert(b->a == 20); + assert(b->b == 10.0); + + assert(&a == b); + + // pair construction + std::allocator p_alloc; + pair_t p { 10, 5.0 }; + + test_pair(p_alloc); + test_pair(p_alloc, 10, 5.0); + test_pair(p_alloc, p); + + return 0; +}