From patchwork Sat Jan 17 00:23:50 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 430075 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id B4FC61401EF for ; Sat, 17 Jan 2015 11:24:13 +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=ZsdnBtCb+7CEEZVEtoAJj8xGL4nZw/Dnh5BfC595vdDGzUwZEWt2f zT+cwj70zc2Aff1jyUsrLDDWKaNHypm8DDr5opmLMSiWmeBc/zZlBOuxq16rQdMZ iheVmcTqA/obL+3v8Icqfg9QgUmzu4sa9RWYNRAw+vs9UvRUbO1rDs= 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=+iMpzYaxOq+RFugj59Dks9qulv0=; b=Krt2oMD6ImZpDmFhLjAv g+G1eoxbEkmINqayeoxf/v0HapiszwxpQTRctkZ4zOYja06QJfRo2Inw694LN7kS s7z4fnh/zsG5Y3WS3/CDIJj8YpGIyRuvdGiiax3Qv00t0SxPYLKwV1ZiPR2Udmjz Ujn0uo4ICM7Fv9rqKgXt4mY= Received: (qmail 22872 invoked by alias); 17 Jan 2015 00:23:56 -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 22732 invoked by uid 89); 17 Jan 2015 00:23:55 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-Spam-User: qpsmtpd, 2 recipients 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 (AES256-GCM-SHA384 encrypted) ESMTPS; Sat, 17 Jan 2015 00:23:52 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t0H0NpT2021820 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 16 Jan 2015 19:23:51 -0500 Received: from localhost (ovpn-116-25.ams2.redhat.com [10.36.116.25]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t0H0No2C003165; Fri, 16 Jan 2015 19:23:51 -0500 Date: Sat, 17 Jan 2015 00:23:50 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] libstdc++/56785 reduce space overhead of nested tuples Message-ID: <20150117002350.GN3360@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) This replaces the current empty _Tuple_impl that terminates the recursive inheritance hierarchy, instead adding the extra code to the last base class that holds data so that the recursion terminates there instead. The purpose of this is to avoid nested tuples having two instances of the same _Tuple_impl base class, which cannot be placed at the same address and so take up space despite being empty. Tested x86_64-linux, committed to trunk. commit 65e06eb5b8ee42fb024307538380f8a375aba7ca Author: Jonathan Wakely Date: Mon Jun 23 23:41:08 2014 +0100 PR libstdc++/56785 * include/std/tuple (_Tuple_impl): Remove zero-element specialization and define one-element specialization. * testsuite/20_util/tuple/56785.cc: New. diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index b710049..e500a76 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -158,30 +158,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct _Tuple_impl; - /** - * Zero-element tuple implementation. This is the basis case for the - * inheritance recursion. - */ - template - struct _Tuple_impl<_Idx> - { - template friend class _Tuple_impl; - - _Tuple_impl() = default; - - template - _Tuple_impl(allocator_arg_t, const _Alloc&) { } - - template - _Tuple_impl(allocator_arg_t, const _Alloc&, const _Tuple_impl&) { } - - template - _Tuple_impl(allocator_arg_t, const _Alloc&, _Tuple_impl&&) { } - - protected: - void _M_swap(_Tuple_impl&) noexcept { /* no-op */ } - }; - template struct __is_empty_non_tuple : is_empty<_Tp> { }; @@ -358,6 +334,130 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + // Basis case of inheritance recursion. + template + struct _Tuple_impl<_Idx, _Head> + : private _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> + { + template friend class _Tuple_impl; + + typedef _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> _Base; + + static constexpr _Head& + _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + static constexpr const _Head& + _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + constexpr _Tuple_impl() + : _Base() { } + + explicit + constexpr _Tuple_impl(const _Head& __head) + : _Base(__head) { } + + template + explicit + constexpr _Tuple_impl(_UHead&& __head) + : _Base(std::forward<_UHead>(__head)) { } + + constexpr _Tuple_impl(const _Tuple_impl&) = default; + + constexpr + _Tuple_impl(_Tuple_impl&& __in) + noexcept(is_nothrow_move_constructible<_Head>::value) + : _Base(std::forward<_Head>(_M_head(__in))) { } + + template + constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template + constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in) + : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) + : _Base(__tag, __use_alloc<_Head>(__a)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Head& __head) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _UHead&& __head) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(__head)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl&& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + std::forward<_Head>(_M_head(__in))) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead>&& __in) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + _Tuple_impl& + operator=(const _Tuple_impl& __in) + { + _M_head(*this) = _M_head(__in); + return *this; + } + + _Tuple_impl& + operator=(_Tuple_impl&& __in) + noexcept(is_nothrow_move_assignable<_Head>::value) + { + _M_head(*this) = std::forward<_Head>(_M_head(__in)); + return *this; + } + + template + _Tuple_impl& + operator=(const _Tuple_impl<_Idx, _UHead>& __in) + { + _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); + return *this; + } + + template + _Tuple_impl& + operator=(_Tuple_impl<_Idx, _UHead>&& __in) + { + _M_head(*this) + = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); + return *this; + } + + protected: + void + _M_swap(_Tuple_impl& __in) + noexcept(noexcept(swap(std::declval<_Head&>(), std::declval<_Head&>()))) + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + } + }; + /// Primary class template, tuple template class tuple : public _Tuple_impl<0, _Elements...> diff --git a/libstdc++-v3/testsuite/20_util/tuple/56785.cc b/libstdc++-v3/testsuite/20_util/tuple/56785.cc new file mode 100644 index 0000000..504ab0a --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/56785.cc @@ -0,0 +1,32 @@ +// Copyright (C) 2015 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++11" } +// { dg-do compile } + +#include + +class Empty { }; + +using std::tuple; +using char_pair = tuple; + +static_assert( sizeof(tuple) == sizeof(char_pair), + "Nested tuple tuple> is too big"); + +static_assert( sizeof(tuple) == (2 * sizeof(char_pair)), + "Nested tuple> is too big" );