Index: include/experimental/memory_resource =================================================================== --- include/experimental/memory_resource +++ include/experimental/memory_resource @@ -200,6 +200,15 @@ __res_->deallocate(__p, __n * sizeof(_ValueType), _LIBCPP_ALIGNOF(_ValueType)); } +#if _LIBCPP_STD_VER > 17 + template + _LIBCPP_INLINE_VISIBILITY + void construct(_Tp* __p, _Args&&... __args) + { + return uninitialized_construct_using_allocator(__p, *this, + _VSTD::forward<_Args>(__args)...); + } +#else template _LIBCPP_INLINE_VISIBILITY void construct(_Tp* __p, _Ts &&... __args) @@ -261,6 +270,7 @@ , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first)) , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second))); } +#endif // _LIBCPP_STD_VER > 17 template _LIBCPP_INLINE_VISIBILITY 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 >; @@ -5668,6 +5686,163 @@ > : true_type {}; +#if _LIBCPP_STD_VER > 17 + +template struct __is_pair : false_type { }; + +template +struct __is_pair> : true_type { }; + +template +struct __pair_uses_allocator : _VSTD::uses_allocator<_Tp, _Alloc> {}; + +template +struct __pair_uses_allocator<_VSTD::pair<_T1, _T2>, _Alloc> + : _VSTD::integral_constant::value || + __pair_uses_allocator<_T2, _Alloc>::value> {}; + +template +auto uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args); // this needs to be forward declared for some __uses_allocator_construction_args_impl overloads + +template +auto +__uses_allocator_construction_args_impl(_Un1, // is pair + false_type, // uses allocator + _Un2, // is constructible + const _Alloc&, _Args&&... __args) +{ + return _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...); +} + +template +auto +__uses_allocator_construction_args_impl(false_type, // is pair + true_type, // uses allocator + true_type, // is constructible + const _Alloc& __alloc, _Args&&... __args) +{ + return _VSTD::forward_as_tuple(allocator_arg, __alloc, _VSTD::forward<_Args>(__args)...); +} + +template +auto + __uses_allocator_construction_args_impl(false_type, // is pair + true_type, // uses allocator + false_type, // is constructible + const _Alloc& __alloc, _Args&&... __args) +{ + return _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)..., __alloc); +} + +template +auto +__uses_allocator_construction_args_impl(true_type, // is pair + true_type, // uses allocator + false_type, // is constructible + const _Alloc& __alloc, + piecewise_construct_t, + _T1&& __a, _T2&& __b) +{ + using _First = typename _Tp::first_type; + using _Second = typename _Tp::second_type; + + return _VSTD::make_tuple(_VSTD::piecewise_construct, + _VSTD::apply([&__alloc](auto&&... __args_a) -> auto { + return uses_allocator_construction_args<_First>(__alloc, + _VSTD::forward(__args_a)...); + }, _VSTD::forward<_T1>(__a)), + _VSTD::apply([&__alloc](auto&&... __args_b) -> auto { + return uses_allocator_construction_args<_Second>(__alloc, + _VSTD::forward(__args_b)...); + }, _VSTD::forward<_T2>(__b))); +} + +template +auto +__uses_allocator_construction_args_impl(true_type, // is pair + true_type, // uses allocator + _Un, // is constructible + const _Alloc& __alloc) +{ + return uses_allocator_construction_args<_Tp>(__alloc, + piecewise_construct, + _VSTD::tuple<>{}, + _VSTD::tuple<>{}); +} + +template +auto +__uses_allocator_construction_args_impl(true_type, // is pair + true_type, // uses allocator + _Un, // is constructible + const _Alloc& __alloc, + const _VSTD::pair<_T1, _T2>& __p) +{ + return uses_allocator_construction_args<_Tp>(__alloc, + piecewise_construct, + _VSTD::forward_as_tuple(__p.first), + _VSTD::forward_as_tuple(__p.second)); +} + +template +auto +__uses_allocator_construction_args_impl(true_type, // is pair + true_type, // uses allocator + _Un, // is constructible + const _Alloc& __alloc, + _VSTD::pair<_T1, _T2>&& __p) +{ + return uses_allocator_construction_args<_Tp>(__alloc, + piecewise_construct, + _VSTD::forward_as_tuple(_VSTD::forward<_T1>(__p.first)), + _VSTD::forward_as_tuple(_VSTD::forward<_T2>(__p.second))); +} + +template +auto +__uses_allocator_construction_args_impl(true_type, // is pair + true_type, // uses allocator + _Un, // is constructible + 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 +auto +uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) +{ + return __uses_allocator_construction_args_impl<_Tp>( + __is_pair<_Tp>{}, // TODO: vstd::is_pair + __pair_uses_allocator<_Tp, _Alloc>{}, + _VSTD::is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>{}, + __alloc, + _VSTD::forward<_Args>(__args)...); +} + +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 _LIBCPP_POP_MACROS Index: include/scoped_allocator =================================================================== --- include/scoped_allocator +++ include/scoped_allocator @@ -498,9 +498,23 @@ template _LIBCPP_INLINE_VISIBILITY void construct(_Tp* __p, _Args&& ...__args) - {__construct(__uses_alloc_ctor<_Tp, inner_allocator_type&, _Args...>(), - __p, _VSTD::forward<_Args>(__args)...);} + { + +#if _LIBCPP_STD_VER > 17 + using _OM = __outermost; + _VSTD::apply([__p, this](auto&&... __alloc_args) { + allocator_traits::construct( + _OM()(outer_allocator()), __p, + _VSTD::forward(__alloc_args)...); + }, _VSTD::uses_allocator_construction_args<_Tp>(inner_allocator(), + _VSTD::forward<_Args>(__args)...)); +#else + __construct(__uses_alloc_ctor<_Tp, inner_allocator_type&, _Args...>(), + __p, _VSTD::forward<_Args>(__args)...); +#endif // _LIBCPP_STD_VER > 17 + } +#if _LIBCPP_STD_VER <= 17 template void construct(pair<_T1, _T2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) @@ -549,6 +563,7 @@ _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__x.first)), _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__x.second))); } +#endif // _LIBCPP_STD_VER <= 17 template _LIBCPP_INLINE_VISIBILITY Index: include/tuple =================================================================== --- include/tuple +++ include/tuple @@ -1374,7 +1374,7 @@ inline _LIBCPP_INLINE_VISIBILITY constexpr _Tp __make_from_tuple_impl(_Tuple&& __t, __tuple_indices<_Idx...>) _LIBCPP_NOEXCEPT_RETURN( - _Tp(_VSTD::get<_Idx>(_VSTD::forward<_Tuple>(__t))...) + _Tp(_VSTD::move(_VSTD::get<_Idx>(_VSTD::forward<_Tuple>(__t)))...) ) template Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp =================================================================== --- test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp +++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair.pass.cpp @@ -44,9 +44,9 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, CA)); assert(checkConstruct<>(ptr->second, UA_AllocLast, CA)); - assert((P.checkConstruct&&, - std::tuple&& + assert((P.checkConstruct&&, + std::tuple&& >(CA, ptr))); A.destroy(ptr); std::free(ptr); @@ -67,8 +67,8 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, CA)); assert(checkConstruct<>(ptr->second, UA_None)); - assert((P.checkConstruct&&, + assert((P.checkConstruct&&, std::tuple<>&& >(CA, ptr))); A.destroy(ptr); @@ -100,9 +100,9 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, I)); assert(checkConstruct<>(ptr->second, UA_AllocLast)); - assert((POuter.checkConstruct&&, - std::tuple&& + assert((POuter.checkConstruct&&, + std::tuple&& >(O, ptr))); A.destroy(ptr); std::free(ptr); @@ -127,8 +127,8 @@ A.construct(ptr); assert(checkConstruct<>(ptr->first, UA_AllocArg, I)); assert(checkConstruct<>(ptr->second, UA_None)); - assert((POuter.checkConstruct&&, + assert((POuter.checkConstruct&&, std::tuple<>&& >(O, ptr))); A.destroy(ptr); Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp =================================================================== --- test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp +++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_const_lvalue_pair.pass.cpp @@ -48,9 +48,9 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); - assert((P.checkConstruct&&, - std::tuple&& + assert((P.checkConstruct&&, + std::tuple&& >(CA, ptr))); A.destroy(ptr); std::free(ptr); @@ -75,8 +75,8 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); - assert((P.checkConstruct&&, + assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); A.destroy(ptr); @@ -112,9 +112,9 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); - assert((POuter.checkConstruct&&, - std::tuple&& + assert((POuter.checkConstruct&&, + std::tuple&& >(O, ptr))); A.destroy(ptr); std::free(ptr); @@ -143,8 +143,8 @@ A.construct(ptr, in); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); - assert((POuter.checkConstruct&&, + assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); A.destroy(ptr); Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp =================================================================== --- test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp +++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_piecewise.pass.cpp @@ -49,9 +49,9 @@ std::forward_as_tuple(std::move(y))); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); - assert((P.checkConstruct&&, - std::tuple&& + assert((P.checkConstruct&&, + std::tuple&& >(CA, ptr))); A.destroy(ptr); std::free(ptr); @@ -76,8 +76,8 @@ std::forward_as_tuple(y)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); - assert((P.checkConstruct&&, + assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); A.destroy(ptr); @@ -113,9 +113,9 @@ std::forward_as_tuple(std::move(y))); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); - assert((POuter.checkConstruct&&, - std::tuple&& + assert((POuter.checkConstruct&&, + std::tuple&& >(O, ptr))); A.destroy(ptr); std::free(ptr); @@ -144,8 +144,8 @@ std::forward_as_tuple(std::move(y))); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); - assert((POuter.checkConstruct&&, + assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); A.destroy(ptr); Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp =================================================================== --- test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp +++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_rvalue.pass.cpp @@ -48,9 +48,9 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); - assert((P.checkConstruct&&, - std::tuple&& + assert((P.checkConstruct&&, + std::tuple&& >(CA, ptr))); A.destroy(ptr); std::free(ptr); @@ -75,8 +75,8 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); - assert((P.checkConstruct&&, + assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); A.destroy(ptr); @@ -112,9 +112,9 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); - assert((POuter.checkConstruct&&, - std::tuple&& + assert((POuter.checkConstruct&&, + std::tuple&& >(O, ptr))); A.destroy(ptr); std::free(ptr); @@ -143,8 +143,8 @@ A.construct(ptr, std::move(in)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); - assert((POuter.checkConstruct&&, + assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); A.destroy(ptr); Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp =================================================================== --- test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp +++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_pair_values.pass.cpp @@ -46,9 +46,9 @@ A.construct(ptr, x, std::move(y)); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_AllocLast, CA)); - assert((P.checkConstruct&&, - std::tuple&& + assert((P.checkConstruct&&, + std::tuple&& >(CA, ptr))); A.destroy(ptr); std::free(ptr); @@ -71,8 +71,8 @@ A.construct(ptr, std::move(x), y); assert(checkConstruct(ptr->first, UA_AllocArg, CA)); assert(checkConstruct(ptr->second, UA_None)); - assert((P.checkConstruct&&, + assert((P.checkConstruct&&, std::tuple&& >(CA, ptr))); A.destroy(ptr); @@ -106,9 +106,9 @@ A.construct(ptr, x, std::move(y)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_AllocLast)); - assert((POuter.checkConstruct&&, - std::tuple&& + assert((POuter.checkConstruct&&, + std::tuple&& >(O, ptr))); A.destroy(ptr); std::free(ptr); @@ -135,8 +135,8 @@ A.construct(ptr, std::move(x), std::move(y)); assert(checkConstruct(ptr->first, UA_AllocArg, I)); assert(checkConstruct(ptr->second, UA_None)); - assert((POuter.checkConstruct&&, + assert((POuter.checkConstruct&&, std::tuple&& >(O, ptr))); A.destroy(ptr); Index: test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp =================================================================== --- test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp +++ test/std/utilities/allocator.adaptor/allocator.adaptor.members/construct_type.pass.cpp @@ -83,7 +83,7 @@ A.construct(ptr, x, cx, std::move(x)); assert((checkConstruct(*ptr, UA_AllocArg, I))); assert((POuter.checkConstruct(O, ptr))); + SA::inner_allocator_type const&, int&, int const&, int&&>(O, ptr))); A.destroy(ptr); ::operator delete((void*)ptr); } @@ -117,7 +117,7 @@ assert((checkConstruct(*ptr, UA_AllocLast, I))); assert((POuter.checkConstruct< int&, int const&, int&&, - SA::inner_allocator_type&>(O, ptr))); + SA::inner_allocator_type const&>(O, ptr))); A.destroy(ptr); ::operator delete((void*)ptr); } Index: test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp @@ -0,0 +1,455 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// 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); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "type_id.h" + +// Uses alloc types + +struct A +{ + int a; + float b; + + A(int a, float b) : a(a), b(b) { } +}; + +struct B : A +{ + using allocator_type = std::allocator; + B(std::allocator_arg_t, std::allocator, int a, int b) : A(a, b) { } +}; + +struct C : A +{ + using allocator_type = std::allocator; + C(int a, int b, std::allocator) : A(a, b) { } +}; + +struct D +{ + using allocator_type = std::allocator; +}; + +struct E +{ + using allocator_type = std::allocator; + + int i; + + E(std::allocator_arg_t, std::allocator, int i) : i(i) { } +}; + +struct F +{ + using allocator_type = std::allocator; + + int i; + + F(std::allocator_arg_t, std::allocator, int&& i) : i(i) { } +}; + +// Move / Copy only types + +struct MoveOnly +{ + MoveOnly(MoveOnly const&) { assert(false); } + MoveOnly(MoveOnly&&) { } + + MoveOnly() { } +}; + +struct CopyOnly +{ + CopyOnly(CopyOnly const&) { } + CopyOnly(CopyOnly&&) { assert(false); } + + CopyOnly() { } +}; + +struct AcceptBoth +{ + using allocator_type = std::allocator; + + AcceptBoth(std::allocator_arg_t, std::allocator, CopyOnly const&) { } + AcceptBoth(std::allocator_arg_t, std::allocator, MoveOnly&&) { } + + AcceptBoth(std::allocator_arg_t, std::allocator, CopyOnly const&, CopyOnly const&) { } + AcceptBoth(std::allocator_arg_t, std::allocator, MoveOnly&&, MoveOnly&&) { } +}; + +struct AcceptBothC +{ + using allocator_type = std::allocator; + + AcceptBothC(CopyOnly const&, std::allocator) { } + AcceptBothC(MoveOnly&&, std::allocator) { } +}; + +// Util function + +template +void assert_same_typeid() +{ + auto a = &makeTypeID(); + auto b = &makeTypeID(); + assert(COMPARE_TYPEID(a, b) && "Comparison of types using typeid failed!"); +} + +// Tests + +template +T test_uses_alloc(Args&&... args) +{ + auto args_tuple = std::uses_allocator_construction_args(std::forward(args)...); + const auto arg_count = std::tuple_size::value; + static_assert(arg_count == sizeof...(Args) - 1); + + return std::make_from_tuple(args_tuple); +} + +void general_tests() +{ + using pair_t = std::pair; + + // non pair contruction + std::allocator alloc; + auto a = std::make_obj_using_allocator(alloc, 10, 5.0); + + ASSERT_SAME_TYPE(decltype(a), A); + 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_SAME_TYPE(decltype(b), A*); + assert(b->a == 20); + assert(b->b == 10.0); + + assert(&a == b); + + // pair construction + std::allocator p_alloc; + pair_t p { 10, 5 }; + + test_uses_alloc(p_alloc); + auto res = test_uses_alloc(p_alloc, 10, 5); + auto res1 = test_uses_alloc(p_alloc, p); + assert(res.first == res1.first && + res.second == res1.second && + res.first == 10 && + res.second == 5); + + auto res2 = test_uses_alloc(std::allocator(), 10, 10.0); + assert(res2.a == res2.b && res2.a == 10); +} + +void test_no_allocator() +{ + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, 10, 5.0); + const auto arg_count = std::tuple_size::value; + static_assert(arg_count == 2); + + assert(std::get<0>(args_tuple) == 10); + assert(std::get<1>(args_tuple) == 5.0); + + auto a = std::make_from_tuple(args_tuple); + assert(a.a == 10); + assert(a.b == 5.0); +} + +void test_no_pair() +{ + { // make sure we are calling the correct overload + static_assert(!std::uses_allocator>::value); + static_assert(!std::is_constructible, int, int>::value); + static_assert( std::is_constructible::value); + static_assert( std::uses_allocator>::value); + static_assert( std::is_constructible, int, int>::value); + static_assert( std::uses_allocator>::value); + static_assert( std::is_constructible>::value); // TODO: should this be checked? + } + { + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, 10, 5.0); + const auto arg_count = std::tuple_size::value; + static_assert(arg_count == 4); + + assert(std::get<2>(args_tuple) == 10); + assert(std::get<3>(args_tuple) == 5.0); + + auto b = std::make_from_tuple(args_tuple); + assert(b.a == 10); + assert(b.b == 5.0); + } + { + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, 10, 5.0); + const auto arg_count = std::tuple_size::value; + static_assert(arg_count == 3); + + assert(std::get<0>(args_tuple) == 10); + assert(std::get<1>(args_tuple) == 5.0); + + auto c = std::make_from_tuple(args_tuple); + assert(c.a == 10); + assert(c.b == 5.0); + } +} + +void test_pair() +{ + using pair_t = std::pair; + + { + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, + std::piecewise_construct, + std::make_tuple(10, 5), + std::make_tuple(4, 2)); + const auto arg_count = std::tuple_size::value; + const auto arg_count1 = std::tuple_size(args_tuple))>>::value; + const auto arg_count2 = std::tuple_size(args_tuple))>>::value; + static_assert(arg_count == 3); + static_assert(arg_count1 == 4); + static_assert(arg_count2 == 4); + + assert_same_typeid(args_tuple)), std::piecewise_construct_t&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator const&>(); + + assert(std::get<2>(std::get<1>(args_tuple)) == 10); + assert(std::get<3>(std::get<1>(args_tuple)) == 5); + assert(std::get<2>(std::get<2>(args_tuple)) == 4); + assert(std::get<3>(std::get<2>(args_tuple)) == 2); + + auto p = std::make_from_tuple(args_tuple); + assert(p.first.a == 10); + assert(p.first.b == 5); + assert(p.second.a == 4); + assert(p.second.b == 2); + } + { + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}); + const auto arg_count = std::tuple_size::value; + const auto arg_count1 = std::tuple_size(args_tuple))>>::value; + const auto arg_count2 = std::tuple_size(args_tuple))>>::value; + static_assert(arg_count == 3); + static_assert(arg_count1 == 1); + static_assert(arg_count2 == 1); + + assert_same_typeid(args_tuple)), std::piecewise_construct_t&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator const&>(); + } + { + using pair_e = std::pair; + auto args_pair = std::make_pair(10, 5); + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, + args_pair); + const auto arg_count = std::tuple_size::value; + const auto arg_count1 = std::tuple_size(args_tuple))>>::value; + const auto arg_count2 = std::tuple_size(args_tuple))>>::value; + static_assert(arg_count == 3); + static_assert(arg_count1 == 3); + static_assert(arg_count2 == 3); + + assert_same_typeid(args_tuple)), std::piecewise_construct_t&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator const&>(); + + assert(std::get<2>(std::get<1>(args_tuple)) == 10); + assert(std::get<2>(std::get<2>(args_tuple)) == 5); + + auto p = std::make_from_tuple(args_tuple); + assert(p.first.i == 10); + assert(p.second.i == 5); + } + { + using pair_e = std::pair; + auto args_pair = std::make_pair(10, 5); + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, + std::move(args_pair)); + const auto arg_count = std::tuple_size::value; + const auto arg_count1 = std::tuple_size(args_tuple))>>::value; + const auto arg_count2 = std::tuple_size(args_tuple))>>::value; + static_assert(arg_count == 3); + static_assert(arg_count1 == 3); + static_assert(arg_count2 == 3); + + assert_same_typeid(args_tuple)), std::piecewise_construct_t&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator const&>(); + + assert(std::get<2>(std::get<1>(args_tuple)) == 10); + assert(std::get<2>(std::get<2>(args_tuple)) == 5); + + auto p = std::make_from_tuple(args_tuple); + assert(p.first.i == 10); + assert(p.second.i == 5); + } + { + using pair_e = std::pair; + int x = 42; + int y = 101; + auto args_tuple = std::uses_allocator_construction_args(std::allocator{}, + std::move(x), std::move(y)); + const auto arg_count = std::tuple_size::value; + const auto arg_count1 = std::tuple_size(args_tuple))>>::value; + const auto arg_count2 = std::tuple_size(args_tuple))>>::value; + static_assert(arg_count == 3); + static_assert(arg_count1 == 3); + static_assert(arg_count2 == 3); + + assert_same_typeid(args_tuple)), std::piecewise_construct_t&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<1>(args_tuple))), std::allocator const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator_arg_t const&>(); + assert_same_typeid(std::get<2>(args_tuple))), std::allocator const&>(); + + assert(std::get<2>(std::get<1>(args_tuple)) == 42); + assert(std::get<2>(std::get<2>(args_tuple)) == 101); + + auto p = std::make_from_tuple(args_tuple); + assert(p.first.i == 42); + assert(p.second.i == 101); + } +} + +void test_make_obj() +{ + using pair_t = std::pair; + + { + pair_t p = std::make_obj_using_allocator(std::allocator{}, + std::piecewise_construct, + std::make_tuple(10, 5), + std::make_tuple(4, 2)); + assert(p.first.a == 10); + assert(p.first.b == 5); + assert(p.second.a == 4); + assert(p.second.b == 2); + } + { + using pair_e = std::pair; + auto args_pair = std::make_pair(10, 5); + auto p = std::make_obj_using_allocator(std::allocator{}, args_pair); + + assert(p.first.i == 10); + assert(p.second.i == 5); + } + { + using pair_e = std::pair; + auto args_pair = std::make_pair(10, 5); + auto p = std::make_obj_using_allocator(std::allocator{}, + std::move(args_pair)); + + assert(p.first.i == 10); + assert(p.second.i == 5); + } + { + auto b = std::make_obj_using_allocator(std::allocator{}, 10, 5.0); + + assert(b.a == 10); + assert(b.b == 5.0); + } + { + auto c = std::make_obj_using_allocator(std::allocator{}, 10, 5.0); + + assert(c.a == 10); + assert(c.b == 5.0); + } +} + +void test_forwarding() +{ + using pair_t = std::pair; + auto copy_only = CopyOnly(); + auto move_only = MoveOnly(); + + { + auto move_args = std::make_tuple(std::move(move_only), std::move(move_only)); + auto copy_args = std::make_tuple(copy_only, copy_only); + std::uses_allocator_construction_args(std::allocator{}, + std::piecewise_construct, + std::move(move_args), + std::move(move_args)); + std::uses_allocator_construction_args(std::allocator{}, + std::piecewise_construct, + copy_args, + copy_args); + } + { + auto args_pair = std::make_pair(copy_only, copy_only); + std::uses_allocator_construction_args(std::allocator{}, args_pair); + } + { + auto args_pair = std::make_pair(std::move(move_only), std::move(move_only)); + std::uses_allocator_construction_args(std::allocator{}, + std::move(args_pair)); + } + { + auto x = MoveOnly(); + auto y = MoveOnly(); + auto z = CopyOnly(); + auto w = CopyOnly(); + std::uses_allocator_construction_args(std::allocator{}, + std::move(x), std::move(y)); + std::uses_allocator_construction_args(std::allocator{}, z, w); + } + { + std::uses_allocator_construction_args(std::allocator{}, copy_only); + std::uses_allocator_construction_args(std::allocator{}, std::move(move_only)); + } + { + std::uses_allocator_construction_args(std::allocator{}, copy_only); + std::uses_allocator_construction_args(std::allocator{}, std::move(move_only)); + } +} + +int main(int, char**) +{ + general_tests(); + test_no_allocator(); + test_no_pair(); + test_pair(); + test_make_obj(); + test_forwarding(); + + return 0; +}