From patchwork Fri Oct 19 16:16:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 192768 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 1A7122C008E for ; Sat, 20 Oct 2012 03:17:22 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1351268243; h=Comment: DomainKey-Signature:Received:Received:Received:Received: MIME-Version:Received:Received:Date:Message-ID:Subject:From:To: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=CEmBrSf GQPKIwLD35CQNJtqssPU=; b=EXO6dr4EKC877YsTimY/Pnc5nOFQBRl9lJLSBRI Hz/xOKL3AJt9vgTMifj/HNDVDHbp3v6ewLTCtxz0C1HBEiikvtB6GYJesbwXel7q uPUxuF/woPS6zW19GLzdWJ2bgw7VvrtRTVBWIryqDHyo8SF9hI6zEHi1vqxq6gyi TJrA= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:MIME-Version:Received:Received:Date:Message-ID:Subject:From:To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=yM40+v6SYfYAWSu0qagsSn2s54q/H9ngO4NK4oYIquJuNLBSJZQNGG/NeM8Heg iIG7+Wpalu8NGKpzd2gZ6BN5+AYdd4DdnfvkcqkROWVeO/gYRyrPt/HRC+2C/pvO rTWxbzhYLIUTPDzRMMy4iFpAS5dxzbSvhFGtDpGWoYI4k=; Received: (qmail 1417 invoked by alias); 19 Oct 2012 16:17:02 -0000 Received: (qmail 1391 invoked by uid 22791); 19 Oct 2012 16:16:59 -0000 X-SWARE-Spam-Status: No, hits=-4.5 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KHOP_RCVD_TRUST, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE X-Spam-Check-By: sourceware.org Received: from mail-ie0-f175.google.com (HELO mail-ie0-f175.google.com) (209.85.223.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 19 Oct 2012 16:16:52 +0000 Received: by mail-ie0-f175.google.com with SMTP id c13so929437ieb.20 for ; Fri, 19 Oct 2012 09:16:52 -0700 (PDT) MIME-Version: 1.0 Received: by 10.50.169.100 with SMTP id ad4mr1949568igc.50.1350663411901; Fri, 19 Oct 2012 09:16:51 -0700 (PDT) Received: by 10.42.158.202 with HTTP; Fri, 19 Oct 2012 09:16:51 -0700 (PDT) Date: Fri, 19 Oct 2012 17:16:51 +0100 Message-ID: Subject: [v3] (almost) finish From: Jonathan Wakely To: "libstdc++" , gcc-patches 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 This adds support for piecewise construction of std::pair by scoped_allocator_adaptor. The only thing missing from scoped_allocator_adaptor now is that my definition of OUTERMOST isn't recursive so doesn't work for nested scoped_allocator_adaptors. That's a suitably obscure use case that I'm not going to rush to fix it today. * include/std/scoped_allocator (__outermost_alloc_traits): Define. (scoped_allocator_adaptor::destroy): Use it. (scoped_allocator_adaptor::construct): Likewise. Overload for piecewise construction of std::pair objects. * testsuite/20_util/scoped_allocator/2.cc: New. Tested x86_64-linux, committed to trunk. commit 2a969ae20431833dbb4a2dfdf0be03b5d4b716c9 Author: Jonathan Wakely Date: Fri Oct 19 16:58:53 2012 +0100 * include/std/scoped_allocator (__outermost_alloc_traits): Define. (scoped_allocator_adaptor::destroy): Use it. (scoped_allocator_adaptor::construct): Likewise. Overload for piecewise construction of std::pair objects. * testsuite/20_util/scoped_allocator/2.cc: New. * doc/xml/manual/status_cxx2011.xml: Update. diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml index ba37e0e..226eef9 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml @@ -1037,7 +1037,7 @@ particular release. 20.12.4 Scoped allocator adaptor members Partial - Missing std::pair piecewise construction. + OUTERMOST is not recursive. 20.12.5 diff --git a/libstdc++-v3/include/std/scoped_allocator b/libstdc++-v3/include/std/scoped_allocator index fc2db7c..81365b6 100644 --- a/libstdc++-v3/include/std/scoped_allocator +++ b/libstdc++-v3/include/std/scoped_allocator @@ -74,7 +74,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : allocator_traits<_Alloc>::propagate_on_container_swap { }; - + template inline auto __do_outermost(_Alloc& __a, _Alloc*) -> decltype(__a.outer_allocator()) @@ -85,6 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __do_outermost(_Alloc& __a, ...) { return __a; } + // TODO: make recursive (see note in 20.12.4/1) template inline auto __outermost(_Alloc& __a) -> decltype(__do_outermost(__a, &__a)) @@ -190,15 +191,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_tie() const noexcept { return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); } + template + using __outermost_type = typename + std::decay()))>::type; + + template + using __outermost_alloc_traits + = allocator_traits<__outermost_type<_Alloc>>; template void _M_construct(__uses_alloc0, _Tp* __p, _Args&&... __args) { - auto& __outer = __outermost(*this); - typedef typename std::decay::type __outer_type; - typedef allocator_traits<__outer_type> __o_traits; - __o_traits::construct(__outer, __p, std::forward<_Args>(__args)...); + typedef __outermost_alloc_traits _O_traits; + _O_traits::construct(__outermost(*this), __p, + std::forward<_Args>(__args)...); } typedef __uses_alloc1 __uses_alloc1_; @@ -208,22 +215,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_construct(__uses_alloc1_, _Tp* __p, _Args&&... __args) { - auto& __outer = __outermost(*this); - typedef typename std::decay::type __outer_type; - typedef allocator_traits<__outer_type> __o_traits; - __o_traits::construct(__outer, __p, allocator_arg, inner_allocator(), - std::forward<_Args>(__args)...); + typedef __outermost_alloc_traits _O_traits; + _O_traits::construct(__outermost(*this), __p, + allocator_arg, inner_allocator(), + std::forward<_Args>(__args)...); } template void _M_construct(__uses_alloc2_, _Tp* __p, _Args&&... __args) { - auto& __outer = __outermost(*this); - typedef typename std::decay::type __outer_type; - typedef allocator_traits<__outer_type> __o_traits; - __o_traits::construct(__outer, __p, std::forward<_Args>(__args)..., - inner_allocator()); + typedef __outermost_alloc_traits _O_traits; + _O_traits::construct(__outermost(*this), __p, + std::forward<_Args>(__args)..., + inner_allocator()); } template @@ -338,15 +343,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); } - // TODO: construct pairs + template + void + construct(pair<_T1, _T2>* __p, piecewise_construct_t, + tuple<_Args1...> __x, tuple<_Args2...> __y) + { + auto& __inner = inner_allocator(); + auto __x_use_tag + = __use_alloc<_T1, inner_allocator_type, _Args1...>(__inner); + auto __y_use_tag + = __use_alloc<_T2, inner_allocator_type, _Args2...>(__inner); + typedef __outermost_alloc_traits _O_traits; + _O_traits::construct(__outermost(*this), __p, piecewise_construct, + _M_construct_p(__x_use_tag, __x), + _M_construct_p(__y_use_tag, __y)); + } + + template + void + construct(pair<_T1, _T2>* __p) + { construct(__p, piecewise_construct, tuple<>(), tuple<>()); } + + template + void + construct(pair<_T1, _T2>* __p, _U&& __u, _V&& __v) + { + construct(__p, piecewise_construct, + std::forward_as_tuple(std::forward<_U>(__u)), + std::forward_as_tuple(std::forward<_V>(__v))); + } + + template + void + construct(pair<_T1, _T2>* __p, const pair<_U, _V>& __x) + { + construct(__p, piecewise_construct, + std::forward_as_tuple(__x.first), + std::forward_as_tuple(__x.second)); + } + + template + void + construct(pair<_T1, _T2>* __p, pair<_U, _V>&& __x) + { + construct(__p, piecewise_construct, + std::forward_as_tuple(std::forward<_U>(__x.first)), + std::forward_as_tuple(std::forward<_V>(__x.second))); + } template void destroy(_Tp* __p) { - auto& __outer = __outermost(*this); - typedef typename std::decay::type __outer_type; - allocator_traits<__outer_type>::destroy(__outer, __p); - } + typedef __outermost_alloc_traits _O_traits; + _O_traits::destroy(__outermost(*this), __p); + } scoped_allocator_adaptor select_on_container_copy_construction() const @@ -360,6 +411,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend bool operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a, const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept; + + private: + template + _Tuple&& + _M_construct_p(__uses_alloc0, _Tuple& __t) + { return std::move(__t); } + + template + std::tuple + _M_construct_p(__uses_alloc1_, std::tuple<_Args...>& __t) + { + typedef std::tuple _Tuple; + return std::tuple_cat(_Tuple(allocator_arg, inner_allocator()), + std::move(__t)); + } + + template + std::tuple<_Args..., inner_allocator_type&> + _M_construct_p(__uses_alloc2_, std::tuple<_Args...>& __t) + { + typedef std::tuple _Tuple; + return std::tuple_cat(std::move(__t), _Tuple(inner_allocator())); + } }; template diff --git a/libstdc++-v3/testsuite/20_util/scoped_allocator/2.cc b/libstdc++-v3/testsuite/20_util/scoped_allocator/2.cc new file mode 100644 index 0000000..6bfa4d7 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/scoped_allocator/2.cc @@ -0,0 +1,308 @@ +// { dg-options "-std=gnu++0x" } + +// Copyright (C) 2012 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 +// . + +#include +#include +#include +#include +#include + +// 20.12.4 Scoped allocator adaptor members [allocator.adaptor.members] +// +// Test piecewise construction of std::pair by scoped_allocator_adaptor + +using __gnu_test::uneq_allocator; +using std::scoped_allocator_adaptor; + +// a DefaultConstructible and CopyConstructible type +struct def +{ + def() : id(999) { } + + int id; +}; + +// a CopyConstructible and non-DefaultConstructible type +struct copyable +{ + copyable(int id) : id(id) { } + + // not constructed with an allocator so nothing to test + bool verify() const { return true; } + + int id; +}; + +// a MoveConstructible and non-DefaultConstructible type +struct move_only +{ + move_only(int id) : id(id) { } + move_only(move_only&&) = default; + + // not constructed with an allocator so nothing to test + bool verify() const { return true; } + + int id; +}; + +// a type for which std::uses_allocator is true +struct uses_alloc_post +{ + typedef uneq_allocator allocator_type; + + uses_alloc_post(const allocator_type& alloc) + : allocator_personality(alloc.get_personality()), id(999) + { } + + uses_alloc_post(copyable arg, const allocator_type& alloc) + : allocator_personality(alloc.get_personality()), id(arg.id) + { } + + uses_alloc_post(move_only arg, const allocator_type& alloc) + : allocator_personality(alloc.get_personality()), id(arg.id) + { } + + // allocator-extended copy ctor + uses_alloc_post(const uses_alloc_post& other, const allocator_type& alloc) + : allocator_personality(alloc.get_personality()), id(other.id) + { } + + // verify we were constructed with right allocator + bool verify() const { return allocator_personality == id; } + + int allocator_personality; + int id; +}; + +// a type for which std::uses_allocator is true +struct uses_alloc_pre : uses_alloc_post +{ + typedef uneq_allocator allocator_type; + + uses_alloc_pre(std::allocator_arg_t, const allocator_type& alloc) + : uses_alloc_post(alloc) + { } + + uses_alloc_pre(std::allocator_arg_t, const allocator_type& alloc, + copyable arg) + : uses_alloc_post(arg, alloc) + { } + + // allocator-extended copy ctor + uses_alloc_pre(std::allocator_arg_t, const allocator_type& alloc, + const uses_alloc_pre& other) + : uses_alloc_post(other, alloc) + { } + + uses_alloc_pre(std::allocator_arg_t, const allocator_type& alloc, + move_only arg) + : uses_alloc_post(std::move(arg), alloc) + { } +}; + +template + void + test_def() + { + bool test __attribute((unused)) = false; + + typedef std::pair test_type; + typedef uneq_allocator alloc_type; + typedef scoped_allocator_adaptor alloc_adaptor; + + int inner_id = 2; + alloc_adaptor a(-1, alloc_type(inner_id)); // outer=-1, inner=2 + + // all pair members that can be constructed with an allocator + // should be constructed with the inner allocator, with personality==2 + + auto p = a.allocate(1); + + // construct(pair* p, piecewise_construct_t, tuple<...>, tuple<...>) + std::tuple<> t; + a.construct(p, std::piecewise_construct, t, t); + VERIFY( p->first.id == 999 ); + VERIFY( p->second.id == 999 ); + a.destroy(p); + + // construct(pair* __p) + a.construct(p); + VERIFY( p->first.id == 999 ); + VERIFY( p->second.id == 999 ); + auto pp = *p; + a.destroy(p); + + // construct(pair* p, const pair& x) + a.construct(p, pp); + VERIFY( p->first.id == 999 ); + VERIFY( p->second.id == 999 ); + a.destroy(p); + + // construct(pair* p, pair&& x) + a.construct(p, std::move(pp)); + VERIFY( p->first.id == 999 ); + VERIFY( p->second.id == 999 ); + a.destroy(p); + + a.deallocate(p, 1); + } + +template + void + test_copying() + { + bool test __attribute((unused)) = false; + + typedef std::pair test_type; + typedef uneq_allocator alloc_type; + typedef scoped_allocator_adaptor alloc_adaptor; + + int inner_id = 2; + alloc_adaptor a(-1, alloc_type(inner_id)); // outer=-1, inner=2 + + // all pair members that can be constructed with an allocator + // should be constructed with the inner allocator, with personality==2 + + auto p = a.allocate(1); + + // construct(pair* p, piecewise_construct_t, tuple<...>, tuple<...>) + auto t = std::make_tuple(copyable(inner_id)); + a.construct(p, std::piecewise_construct, t, t); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + a.destroy(p); + + // construct(pair* __p) + // cannot test this overload using non-DefaultConstructible types + + // construct(pair* p, U&& x, V&& y) + copyable c(inner_id); + a.construct(p, c, c); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + auto pp = *p; + a.destroy(p); + + // construct(pair* p, const pair& x) + a.construct(p, pp); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + a.destroy(p); + + // construct(pair* p, pair&& x) + a.construct(p, std::move(pp)); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + a.destroy(p); + + a.deallocate(p, 1); + } + +template + void + test_moving() + { + bool test __attribute((unused)) = false; + + typedef std::pair test_type; + typedef uneq_allocator alloc_type; + typedef scoped_allocator_adaptor alloc_adaptor; + + int inner_id = 2; + alloc_adaptor a(-1, alloc_type(inner_id)); // outer=-1, inner=2 + + // all pair members that can be constructed with an allocator + // should be constructed with the inner allocator, with personality==2 + + auto p = a.allocate(1); + + // construct(pair* p, piecewise_construct_t, tuple<...>, tuple<...>) + a.construct(p, std::piecewise_construct, + std::make_tuple(move_only(inner_id)), + std::make_tuple(move_only(inner_id))); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + a.destroy(p); + + // construct(pair* __p) + // cannot test this overload using non-DefaultConstructible types + + // construct(pair* p, U&& x, V&& y) + a.construct(p, move_only(inner_id), move_only(inner_id)); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + a.destroy(p); + + // construct(pair* p, const pair& x) + // cannot test this overload using move-only types + + // construct(pair* p, pair&& x) + a.construct(p, std::make_pair(move_only(inner_id), move_only(inner_id))); + VERIFY( p->first.verify() ); + VERIFY( p->second.verify() ); + a.destroy(p); + + a.deallocate(p, 1); + } + +void test01() +{ + test_def(); + test_def(); + test_def(); + test_def(); + test_def(); + test_def(); + test_def(); + test_def(); + test_def(); +} + +void test02() +{ + test_copying(); + test_copying(); + test_copying(); + test_copying(); + test_copying(); + test_copying(); + test_copying(); + test_copying(); + test_copying(); +} + +void test03() +{ + test_moving(); + test_moving(); + test_moving(); + test_moving(); + test_moving(); + test_moving(); + test_moving(); + test_moving(); + test_moving(); +} + +int main() +{ + test01(); + test02(); + test03(); +}