From patchwork Fri Mar 1 13:50:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1050188 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-497225-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="Duq0NU5Y"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 449rRZ0Tpvz9s70 for ; Sat, 2 Mar 2019 00:51:04 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=iQjBKD2g3Kz/vTz8GYYvpdOVmllPlWLyqD3pjQ72rGPcvQmGVUoiI +P3teKaZUECcFoKMRvn7Z0X/BSvhqXj/T1XYUU69Kav5tHWcMNYdmYE9eGpHH+bk AtjFAJ0fvrrrpyvqa0ujS5fw9m6hyVrmFNjNpnBsx8Uho/Ci9s4+2Q= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=BXLCFryClTIXPyXjQHvISJlNgGA=; b=Duq0NU5Y0dTiq76TRaMs bTRuROR4W9PGrqx1y9OaEh1PNM0uGQG3I17oJPNqJ9LXO6fD9iEqJbpLMajYZsrF 8UTc1nC6ZX2TdLd/wQoKHTGrODu5YPEqkvpRGlv3bgk7mc4/LB4deYellVl3lc/6 ZbEG9fdQelBKITPG0900bVg= Received: (qmail 124462 invoked by alias); 1 Mar 2019 13:50:43 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 124293 invoked by uid 89); 1 Mar 2019 13:50:42 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=fitness, __x, MERCHANTABILITY, merchantability X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 01 Mar 2019 13:50:38 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9C4613088A69; Fri, 1 Mar 2019 13:50:36 +0000 (UTC) Received: from localhost (unknown [10.33.36.107]) by smtp.corp.redhat.com (Postfix) with ESMTP id 22AE4611B2; Fri, 1 Mar 2019 13:50:35 +0000 (UTC) Date: Fri, 1 Mar 2019 13:50:35 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] C++2a Utility functions to implement uses-allocator construction (P0591R4) Message-ID: <20190301135035.GA15423@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.11.3 (2019-02-01) * include/std/memory (uses_allocator_construction_args): New set of overloaded functions. (make_obj_using_allocator, uninitialized_construct_using_allocator): New functions. * include/std/memory_resource (polymorphic_allocator::construct) [__cplusplus > 201703l]: Replace all overloads with a single function using uses_allocator_construction_args. * testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New test. * testsuite/20_util/uses_allocator/make_obj.cc: New test. Tested powerpc64le-linux, committed to trunk. commit e2d0fdcde8a7dcebfab8246372d3756c5c489717 Author: Jonathan Wakely Date: Fri Mar 1 13:27:58 2019 +0000 C++2a Utility functions to implement uses-allocator construction (P0591R4) * include/std/memory (uses_allocator_construction_args): New set of overloaded functions. (make_obj_using_allocator, uninitialized_construct_using_allocator): New functions. * include/std/memory_resource (polymorphic_allocator::construct) [__cplusplus > 201703l]: Replace all overloads with a single function using uses_allocator_construction_args. * testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New test. * testsuite/20_util/uses_allocator/make_obj.cc: New test. diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index ff9add9cef2..00a85eef25e 100644 --- a/libstdc++-v3/include/std/memory +++ b/libstdc++-v3/include/std/memory @@ -91,6 +91,8 @@ #include #if __cplusplus > 201703L # include // for ispow2 +# include // for placement operator new +# include // for tuple, make_tuple, make_from_tuple #endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -166,6 +168,197 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; } } #endif // C++2a +#if __cplusplus > 201703L + template + struct __is_pair : false_type { }; + template + struct __is_pair> : true_type { }; + template + struct __is_pair> : true_type { }; + + template>>, + typename _Alloc, typename... _Args> + constexpr auto + __uses_alloc_args(const _Alloc& __a, _Args&&... __args) noexcept + { + if constexpr (uses_allocator_v, _Alloc>) + { + if constexpr (is_constructible_v<_Tp, allocator_arg_t, + const _Alloc&, _Args...>) + { + return tuple( + allocator_arg, __a, std::forward<_Args>(__args)...); + } + else + { + static_assert(is_constructible_v<_Tp, _Args..., const _Alloc&>); + + return tuple<_Args&&..., const _Alloc&>( + std::forward<_Args>(__args)..., __a); + } + } + else + { + static_assert(is_constructible_v<_Tp, _Args...>); + + return tuple<_Args&&...>(std::forward<_Args>(__args)...); + } + } + +#if __cpp_concepts + template + concept bool _Std_pair = __is_pair<_Tp>::value; +#endif + +// This is a temporary workaround until -fconcepts is implied by -std=gnu++2a +#if __cpp_concepts +# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) _Std_pair T +# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) _Std_pair T +#else +# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) \ + typename T, typename __ = _Require<__is_pair> +# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) typename T, typename +#endif + + template>>, +#endif + typename _Alloc, typename... _Args> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + _Args&&... __args) noexcept +#if __cpp_concepts + requires ! _Std_pair<_Tp> +#endif + { + return std::__uses_alloc_args<_Tp>(__a, std::forward<_Args>(__args)...); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Tuple1, typename _Tuple2> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t, + _Tuple1&& __x, _Tuple2&& __y) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc> + constexpr auto + uses_allocator_construction_args(const _Alloc&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, _Up&&, _Vp&&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, + const pair<_Up, _Vp>&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Tuple1, typename _Tuple2> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t, + _Tuple1&& __x, _Tuple2&& __y) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::apply([&__a](auto&&... __args1) { + return std::uses_allocator_construction_args<_Tp1>( + __a, std::forward(__args1)...); + }, std::forward<_Tuple1>(__x)), + std::apply([&__a](auto&&... __args2) { + return std::uses_allocator_construction_args<_Tp2>( + __a, std::forward(__args2)...); + }, std::forward<_Tuple2>(__y))); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a), + std::uses_allocator_construction_args<_Tp2>(__a)); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, _Up&& __u, _Vp&& __v) + noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, + std::forward<_Up>(__u)), + std::uses_allocator_construction_args<_Tp2>(__a, + std::forward<_Vp>(__v))); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + const pair<_Up, _Vp>& __pr) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, __pr.first), + std::uses_allocator_construction_args<_Tp2>(__a, __pr.second)); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + pair<_Up, _Vp>&& __pr) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, + std::move(__pr).first), + std::uses_allocator_construction_args<_Tp2>(__a, + std::move(__pr).second)); + } + + template + inline _Tp + make_obj_using_allocator(const _Alloc& __a, _Args&&... __args) + { + return std::make_from_tuple<_Tp>(uses_allocator_construction_args<_Tp>( + __a, std::forward<_Args>(__args)...)); + } + + template + inline _Tp* + uninitialized_construct_using_allocator(_Tp* __p, const _Alloc& __a, + _Args&&... __args) + { + void* __vp = const_cast(static_cast(__p)); + return ::new(__vp) _Tp(std::make_obj_using_allocator<_Tp>(__a, + std::forward<_Args>(__args)...)); + } + +#endif // C++2a + _GLIBCXX_END_NAMESPACE_VERSION } // namespace #endif // C++11 diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index 93b2ebd9759..a212bccc9b1 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -170,6 +170,7 @@ namespace pmr __attribute__((__nonnull__)) { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } +#if __cplusplus <= 201703L template __attribute__((__nonnull__)) typename __not_pair<_Tp1>::type @@ -242,6 +243,16 @@ namespace pmr forward_as_tuple(std::forward<_Up>(__pr.first)), forward_as_tuple(std::forward<_Vp>(__pr.second))); } +#else + template + __attribute__((__nonnull__)) + void + construct(_Tp1* __p, _Args&&... __args) + { + std::uninitialized_construct_using_allocator(__p, *this, + std::forward<_Args>(__args)...); + } +#endif template __attribute__((__nonnull__)) diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_c++2a.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_c++2a.cc new file mode 100644 index 00000000000..9048ca196ff --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_c++2a.cc @@ -0,0 +1,125 @@ +// Copyright (C) 2016-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct do_not_copy { + do_not_copy() = default; + do_not_copy(const do_not_copy&) { throw 1; } +}; + +void +test01() +{ + struct X { + X(do_not_copy&&) { } + }; + + using pair = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test02() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator; + X(do_not_copy&&, const allocator_type&) { } + }; + + using pair = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test03() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator; + X(std::allocator_arg_t, const allocator_type&, do_not_copy&&) { } + }; + + using pair = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test04() +{ + struct X + { + using allocator_type = std::pmr::polymorphic_allocator; + X() = default; + X(const X&) { throw 1; } + X(const X&, const allocator_type&) { } + }; + + struct Y + { + using allocator_type = std::pmr::polymorphic_allocator; + Y() = default; + Y(const Y&) = delete; + Y(std::allocator_arg_t, const allocator_type&, const Y&) { } + }; + + using pair_type = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + /* not const */ pair_type p; + a.construct(ptr, p); // LWG 2975 + a.deallocate(ptr, 1); +} + +void +test05() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator; + X(int); + X(int, const allocator_type&) { } + }; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, 1); + a.deallocate(ptr, 1); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc b/libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc new file mode 100644 index 00000000000..670c59afb33 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc @@ -0,0 +1,403 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +using test_allocator = __gnu_test::uneq_allocator; + +struct Arg { }; + +struct A +{ + A() : nargs(0) { } + A(float&) : nargs(1) { } + A(int, void*) : nargs(2) { } + + // These should not be used: + A(const test_allocator& a); + A(float&, const test_allocator& a); + A(int, void*, const test_allocator& a); + + const int nargs; + const int alloc_id = -1; + + // std::uses_allocator should be false: + using allocator_type = void*(); +}; + +struct B +{ + // This means std::uses_allocator is true: + using allocator_type = test_allocator; + + B() : nargs(0) { } + B(float&) : nargs(1) { } + B(int, void*) : nargs(2) { } + + B(std::allocator_arg_t, const test_allocator& a) + : nargs(0), alloc_id(a.get_personality()) { } + B(std::allocator_arg_t, const test_allocator& a, float&) + : nargs(1), alloc_id(a.get_personality()) { } + B(std::allocator_arg_t, const test_allocator& a, int, void*) + : nargs(2), alloc_id(a.get_personality()) { } + B(std::allocator_arg_t, const test_allocator& a, B&& b) + : nargs(b.nargs), alloc_id(a.get_personality()) { } + + // These should not be used: + B(const test_allocator&); + B(float&, const test_allocator&, float&); + B(int, void*, const test_allocator&); + B(const test_allocator&, float&); + B(const test_allocator&, int, void*); + B(B&&); + B(B&&, const test_allocator&); + + const int nargs; + const int alloc_id = -1; +}; + +struct C +{ + C() : nargs(0) { } + C(float&) : nargs(1) { } + C(int, void*) : nargs(2) { } + + C(const test_allocator& a) + : nargs(0), alloc_id(a.get_personality()) { } + C(float&, const test_allocator& a) + : nargs(1), alloc_id(a.get_personality()) { } + C(int, void*, const test_allocator& a) + : nargs(2), alloc_id(a.get_personality()) { } + C(C&& c, const test_allocator& a) + : nargs(c.nargs), alloc_id(a.get_personality()) { } + + C(C&&); + + const int nargs; + const int alloc_id = -1; +}; + +namespace std { + // This means std::uses_allocator is true: + template<> struct uses_allocator : std::true_type { }; +} + +test_allocator alloc1(1); +test_allocator alloc2(2); + +void +test01() +{ + auto i0 = std::make_obj_using_allocator(alloc1, 2); + VERIFY( i0 == 2 ); + + float f = 0.0f; + + auto a0 = std::make_obj_using_allocator(alloc1); + VERIFY( a0.nargs == 0 ); + VERIFY( a0.alloc_id == -1 ); + auto a1 = std::make_obj_using_allocator(alloc1, f); + VERIFY( a1.nargs == 1 ); + VERIFY( a1.alloc_id == -1 ); + auto a2 = std::make_obj_using_allocator(alloc1, 123, nullptr); + VERIFY( a2.nargs == 2 ); + VERIFY( a2.alloc_id == -1 ); + + auto b0 = std::make_obj_using_allocator(alloc1); + VERIFY( b0.nargs == 0 ); + VERIFY( b0.alloc_id == 1 ); + auto b1 = std::make_obj_using_allocator(alloc2, f); + VERIFY( b1.nargs == 1 ); + VERIFY( b1.alloc_id == 2 ); + auto b2 = std::make_obj_using_allocator(alloc1, 123, nullptr); + VERIFY( b2.nargs == 2 ); + VERIFY( b2.alloc_id == 1 ); + + auto c0 = std::make_obj_using_allocator(alloc1); + VERIFY( c0.nargs == 0 ); + VERIFY( c0.alloc_id == 1 ); + auto c1 = std::make_obj_using_allocator(alloc2, f); + VERIFY( c1.nargs == 1 ); + VERIFY( c1.alloc_id == 2 ); + auto c2 = std::make_obj_using_allocator(alloc1, 123, nullptr); + VERIFY( c2.nargs == 2 ); + VERIFY( c2.alloc_id == 1 ); +} + +void +test02() +{ + decltype(auto) b + = std::make_obj_using_allocator(alloc1, 123, nullptr); + static_assert( std::is_const_v ); + VERIFY( b.nargs == 2 ); + VERIFY( b.alloc_id == 1 ); + + decltype(auto) c = std::make_obj_using_allocator(alloc1); + static_assert( std::is_const_v ); + VERIFY( c.nargs == 0 ); + VERIFY( c.alloc_id == 1 ); +} + +void +test03() +{ + B b; + decltype(auto) ref = std::make_obj_using_allocator(alloc1, b); + static_assert( std::is_same_v ); + VERIFY( &ref == &b ); + VERIFY( ref.nargs == 0 ); + VERIFY( ref.alloc_id == -1 ); + const B& cref = std::make_obj_using_allocator(alloc1, b); + static_assert( std::is_same_v ); + VERIFY( &cref == &b ); + VERIFY( cref.nargs == 0 ); + VERIFY( cref.alloc_id == -1 ); +} + +void +test04() +{ + struct D + { + D(std::allocator_arg_t) { } + D(std::allocator_arg_t, int) { } + + // These should not be used: + D(std::allocator_arg_t, const test_allocator&); + D(std::allocator_arg_t, const test_allocator&, int); + + ~D() { } + }; + + D d1 = std::make_obj_using_allocator(alloc1, std::allocator_arg); + + struct E + { + using allocator_type = test_allocator; + + E(std::allocator_arg_t, const test_allocator&) { } + E(std::allocator_arg_t, int, const test_allocator&) { } + + // These should not be used: + E(std::allocator_arg_t); + E(std::allocator_arg_t, int); + + ~E() { } + }; + + E e1 = std::make_obj_using_allocator(alloc1, std::allocator_arg); + E e2 = std::make_obj_using_allocator(alloc2, std::allocator_arg, 2); +} + +void +test05() +{ + using std::pair; + std::piecewise_construct_t p; + std::tuple<> t0; + float f = 0.0f; + std::tuple t1(f); + std::tuple t2{}; + + auto aa00 = std::make_obj_using_allocator>(alloc1, p, t0, t0); + VERIFY( aa00.first.nargs == 0 ); + VERIFY( aa00.first.alloc_id == -1 ); + VERIFY( aa00.second.nargs == 0 ); + VERIFY( aa00.second.alloc_id == -1 ); + auto ab00 = std::make_obj_using_allocator>(alloc1, p, t0, t0); + VERIFY( ab00.first.nargs == 0 ); + VERIFY( ab00.first.alloc_id == -1 ); + VERIFY( ab00.second.nargs == 0 ); + VERIFY( ab00.second.alloc_id == 1 ); + auto bc00 = std::make_obj_using_allocator>(alloc2, p, t0, t0); + VERIFY( bc00.first.nargs == 0 ); + VERIFY( bc00.first.alloc_id == 2 ); + VERIFY( bc00.second.nargs == 0 ); + VERIFY( bc00.second.alloc_id == 2 ); + auto cb00 = std::make_obj_using_allocator>(alloc2, p, t0, t0); + VERIFY( cb00.first.nargs == 0 ); + VERIFY( cb00.first.alloc_id == 2 ); + VERIFY( cb00.second.nargs == 0 ); + VERIFY( cb00.second.alloc_id == 2 ); + auto cc00 + = std::make_obj_using_allocator>(alloc1, p, t0, t0); + VERIFY( cc00.first.nargs == 0 ); + VERIFY( cc00.first.alloc_id == 1 ); + VERIFY( cc00.second.nargs == 0 ); + VERIFY( cc00.second.alloc_id == 1 ); + + auto aa21 = std::make_obj_using_allocator>(alloc1, p, t2, t1); + VERIFY( aa21.first.nargs == 2 ); + VERIFY( aa21.first.alloc_id == -1 ); + VERIFY( aa21.second.nargs == 1 ); + VERIFY( aa21.second.alloc_id == -1 ); + auto ab21 = std::make_obj_using_allocator>(alloc1, p, t2, t1); + VERIFY( ab21.first.nargs == 2 ); + VERIFY( ab21.first.alloc_id == -1 ); + VERIFY( ab21.second.nargs == 1 ); + VERIFY( ab21.second.alloc_id == 1 ); + auto bc11 = std::make_obj_using_allocator>(alloc2, p, t1, t1); + VERIFY( bc11.first.nargs == 1 ); + VERIFY( bc11.first.alloc_id == 2 ); + VERIFY( bc11.second.nargs == 1 ); + VERIFY( bc11.second.alloc_id == 2 ); + auto cb12 = std::make_obj_using_allocator>(alloc2, p, t1, t2); + VERIFY( cb12.first.nargs == 1 ); + VERIFY( cb12.first.alloc_id == 2 ); + VERIFY( cb12.second.nargs == 2 ); + VERIFY( cb12.second.alloc_id == 2 ); + auto cc22 + = std::make_obj_using_allocator>(alloc1, p, t2, t1); + VERIFY( cc22.first.nargs == 2 ); + VERIFY( cc22.first.alloc_id == 1 ); + VERIFY( cc22.second.nargs == 1 ); + VERIFY( cc22.second.alloc_id == 1 ); +} + +void +test06() +{ + using std::pair; + float f = 0.0f; + + auto aa00 = std::make_obj_using_allocator>(alloc1); + VERIFY( aa00.first.nargs == 0 ); + VERIFY( aa00.first.alloc_id == -1 ); + VERIFY( aa00.second.nargs == 0 ); + VERIFY( aa00.second.alloc_id == -1 ); + auto ab00 = std::make_obj_using_allocator>(alloc1); + VERIFY( ab00.first.nargs == 0 ); + VERIFY( ab00.first.alloc_id == -1 ); + VERIFY( ab00.second.nargs == 0 ); + VERIFY( ab00.second.alloc_id == 1 ); + auto bc00 = std::make_obj_using_allocator>(alloc2); + VERIFY( bc00.first.nargs == 0 ); + VERIFY( bc00.first.alloc_id == 2 ); + VERIFY( bc00.second.nargs == 0 ); + VERIFY( bc00.second.alloc_id == 2 ); + auto cb00 = std::make_obj_using_allocator>(alloc2); + VERIFY( cb00.first.nargs == 0 ); + VERIFY( cb00.first.alloc_id == 2 ); + VERIFY( cb00.second.nargs == 0 ); + VERIFY( cb00.second.alloc_id == 2 ); + auto cc00 = std::make_obj_using_allocator>(alloc1); + VERIFY( cc00.first.nargs == 0 ); + VERIFY( cc00.first.alloc_id == 1 ); + VERIFY( cc00.second.nargs == 0 ); + VERIFY( cc00.second.alloc_id == 1 ); + + auto aa11 = std::make_obj_using_allocator>(alloc1, f, f); + VERIFY( aa11.first.nargs == 1 ); + VERIFY( aa11.first.alloc_id == -1 ); + VERIFY( aa11.second.nargs == 1 ); + VERIFY( aa11.second.alloc_id == -1 ); + auto aba1 = std::make_obj_using_allocator>(alloc1, A{}, f); + VERIFY( aba1.first.nargs == 0 ); + VERIFY( aba1.first.alloc_id == -1 ); + VERIFY( aba1.second.nargs == 1 ); + VERIFY( aba1.second.alloc_id == 1 ); + auto bc11 = std::make_obj_using_allocator>(alloc2, f, f); + VERIFY( bc11.first.nargs == 1 ); + VERIFY( bc11.first.alloc_id == 2 ); + VERIFY( bc11.second.nargs == 1 ); + VERIFY( bc11.second.alloc_id == 2 ); + auto cb1b = std::make_obj_using_allocator>(alloc2, f, B{}); + VERIFY( cb1b.first.nargs == 1 ); + VERIFY( cb1b.first.alloc_id == 2 ); + VERIFY( cb1b.second.nargs == 0 ); + VERIFY( cb1b.second.alloc_id == 2 ); + auto cccc + = std::make_obj_using_allocator>(alloc1, C{}, C{}); + VERIFY( cccc.first.nargs == 0 ); + VERIFY( cccc.first.alloc_id == 1 ); + VERIFY( cccc.second.nargs == 0 ); + VERIFY( cccc.second.alloc_id == 1 ); + + pair p1a(f, A{}); + pair p11(f, f); + auto aa1a = std::make_obj_using_allocator>(alloc1, p1a); + VERIFY( aa1a.first.nargs == 1 ); + VERIFY( aa1a.first.alloc_id == -1 ); + VERIFY( aa1a.second.nargs == 0 ); + VERIFY( aa1a.second.alloc_id == -1 ); + auto ab11 = std::make_obj_using_allocator>(alloc1, p11); + VERIFY( ab11.first.nargs == 1 ); + VERIFY( ab11.first.alloc_id == -1 ); + VERIFY( ab11.second.nargs == 1 ); + VERIFY( ab11.second.alloc_id == 1 ); + auto cb11 = std::make_obj_using_allocator>(alloc2, p11); + VERIFY( cb11.first.nargs == 1 ); + VERIFY( cb11.first.alloc_id == 2 ); + VERIFY( cb11.second.nargs == 1 ); + VERIFY( cb11.second.alloc_id == 2 ); + + auto bcbc = std::make_obj_using_allocator>(alloc2, pair()); + VERIFY( bcbc.first.nargs == 0 ); + VERIFY( bcbc.first.alloc_id == 2 ); + VERIFY( bcbc.second.nargs == 0 ); + VERIFY( bcbc.second.alloc_id == 2 ); + + auto cc11 = std::make_obj_using_allocator>(alloc2, std::move(p11)); + VERIFY( cc11.first.nargs == 1 ); + VERIFY( cc11.first.alloc_id == 2 ); + VERIFY( cc11.second.nargs == 1 ); + VERIFY( cc11.second.alloc_id == 2 ); +} + +void +test07() +{ + using nested_pair = std::pair, C>; + auto p = std::make_obj_using_allocator(alloc1); + VERIFY( p.first.first.alloc_id == 1 ); + VERIFY( p.first.second.alloc_id == 1 ); + VERIFY( p.second.alloc_id == 1 ); +} + +void +test08() +{ + // LWG DR 3187. + // P0591R4 reverted DR 2586 fixes to scoped_allocator_adaptor::construct() + + struct X { + using allocator_type = std::allocator; + X(std::allocator_arg_t, allocator_type&&) { } + X(const allocator_type&) { } + }; + + std::allocator a; + std::make_obj_using_allocator(a); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test08(); +}