From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 107901 invoked by alias); 26 Jun 2017 19:29:52 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 107461 invoked by uid 89); 26 Jun 2017 19:29:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: =?ISO-8859-1?Q?No, score=-24.8 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=franois, 44611, fran=c3=a7ois, 8217?= X-Spam-User: qpsmtpd, 2 recipients X-HELO: mail-wm0-f42.google.com Received: from mail-wm0-f42.google.com (HELO mail-wm0-f42.google.com) (74.125.82.42) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 26 Jun 2017 19:29:48 +0000 Received: by mail-wm0-f42.google.com with SMTP id t129so1366167wmt.1; Mon, 26 Jun 2017 12:29:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:message-id:date:user-agent :mime-version:content-language; bh=nL06OK7iYQLMS6r1fFBdj/MnlkpG5oQc6lbBc3nvZO4=; b=t1q2g2WmTaycuQFw7Wm6hk39AP13TjB5L0T7bdVYgmKtOFK4MQsNCX43IQTDLxh4t1 NB+ABTqQJ5WocMn/qvrRps7VIz0KuDTby0erBUTGm9TZU51X+Hz2bFJvCPo0fRnEyTtb s1RM2a4Fea6s0Q31BoW3g6R0jwnsv3ekevu8R9jt7VbyY7qTx+Z6EL0C4RZlp1yzdOTO 47N6wdAiryXByFsfEbRljOcDVDFC8LGGGPpWphzAR03VJScPJKAECSblCijh1SIM/7xQ +0x9fkc4nA0DOIcBEulUH0z6AtqO1WDjUUoVwL8z3+AqWScsFeOYaC9cMwQPtI+uOwCj /h2A== X-Gm-Message-State: AKS2vOwYBiBELN8DlnFQGauGPbr7VqBmC4tEk/7rVS9R/9hytvq5Cq9N 0eICHcpuFu4uvRLS X-Received: by 10.28.220.212 with SMTP id t203mr795377wmg.13.1498505386325; Mon, 26 Jun 2017 12:29:46 -0700 (PDT) Received: from [192.168.0.23] (arf62-1-82-237-250-248.fbx.proxad.net. [82.237.250.248]) by smtp.googlemail.com with ESMTPSA id c27sm13476607wrb.44.2017.06.26.12.29.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 26 Jun 2017 12:29:45 -0700 (PDT) From: =?UTF-8?Q?Fran=c3=a7ois_Dumont?= Subject: Default std::list default and move constructors To: "libstdc++@gcc.gnu.org" , gcc-patches Message-ID: Date: Mon, 26 Jun 2017 19:29:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.1.1 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------98B112FF59A6E69EE7DB2284" X-SW-Source: 2017-06/txt/msg01958.txt.bz2 This is a multi-part message in MIME format. --------------98B112FF59A6E69EE7DB2284 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-length: 1452 Hi Here is the patch to default implementation of std::list default and move constructors. I introduce _List_node_header to take care of the move implementation and also isolate management of the optional list size storage. I prefer it to usage of _List_node as move constructor seems complicated to implement with an __aligned_membuf. It also avoids to use raw memory as-if it was a size_t without constructing it. Even if size_t constructor is trivial I guess some memory analyser could have complain about it. * include/bits/stl_list.h (_List_node_base()): Define. (_List_node_base(_List_node_base*, _List_node_base*)): New. (struct _List_node_header): New. (_List_impl()): Fix noexcept qualification. (_List_impl(_List_impl&&)): New, default. (_List_impl(_List_impl&&, _Node_alloc_type&&)): New. (_List_base()): Default. (_List_base(_List_base&&)): Default. (_List_base(_List_base&&, _Node_alloc_type&&, true_type)): New. (_List_base(_List_base&&, _Node_alloc_type&&, false_type)): New. (_List_base(_List_base&&, _Node_alloc_type&&)): Use latters. (_List_base::_M_move_nodes): Adapt to use _List_node_header._M_move_nodes. (_List_base::_M_init): Likewise. (list<>()): Default. (list<>(list&&)): Default. (list<>::_M_move_assign(list&&, true_type)): Use _M_move_nodes. Tested under Linux x86_64. Ok to commit ? François --------------98B112FF59A6E69EE7DB2284 Content-Type: text/x-patch; name="list.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="list.patch" Content-length: 12084 diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h index 232885a..7ffffe5 100644 --- a/libstdc++-v3/include/bits/stl_list.h +++ b/libstdc++-v3/include/bits/stl_list.h @@ -82,6 +82,17 @@ namespace std _GLIBCXX_VISIBILITY(default) _List_node_base* _M_next; _List_node_base* _M_prev; +#if __cplusplus >= 201103L + _List_node_base() = default; +#else + _List_node_base() + { } +#endif + + _List_node_base(_List_node_base* __next, _List_node_base* __prev) + : _M_next(__next), _M_prev(__prev) + { } + static void swap(_List_node_base& __x, _List_node_base& __y) _GLIBCXX_USE_NOEXCEPT; @@ -99,6 +110,79 @@ namespace std _GLIBCXX_VISIBILITY(default) _M_unhook() _GLIBCXX_USE_NOEXCEPT; }; + /// The %list node header. + struct _List_node_header : public _List_node_base + { + private: +#if _GLIBCXX_USE_CXX11_ABI + std::size_t _M_size; +#endif + + _List_node_base* _M_base() { return this; } + + public: + _List_node_header() _GLIBCXX_NOEXCEPT + : _List_node_base(this, this) +# if _GLIBCXX_USE_CXX11_ABI + , _M_size(0) +# endif + { } + +#if __cplusplus >= 201103L + _List_node_header(_List_node_header&& __x) noexcept + : _List_node_base(__x._M_next, __x._M_prev) +# if _GLIBCXX_USE_CXX11_ABI + , _M_size(__x._M_size) +# endif + { + if (__x._M_base()->_M_next == __x._M_base()) + this->_M_next = this->_M_prev = this; + else + { + this->_M_next->_M_prev = this->_M_prev->_M_next = this->_M_base(); + __x._M_init(); + } + } + + void + _M_move_nodes(_List_node_header&& __x) + { + _List_node_base* const __xnode = __x._M_base(); + if (__xnode->_M_next == __xnode) + _M_init(); + else + { + _List_node_base* const __node = this->_M_base(); + __node->_M_next = __xnode->_M_next; + __node->_M_prev = __xnode->_M_prev; + __node->_M_next->_M_prev = __node->_M_prev->_M_next = __node; + _M_set_size(__x._M_get_size()); + __x._M_init(); + } + } +#endif + +#if _GLIBCXX_USE_CXX11_ABI + size_t _M_get_size() const { return _M_size; } + void _M_set_size(size_t __n) { _M_size = __n; } + void _M_inc_size(size_t __n) { _M_size += __n; } + void _M_dec_size(size_t __n) { _M_size -= __n; } +#else + // dummy implementations used when the size is not stored + size_t _M_get_size() const { return 0; } + void _M_set_size(size_t) { } + void _M_inc_size(size_t) { } + void _M_dec_size(size_t) { } +#endif + + void + _M_init() _GLIBCXX_NOEXCEPT + { + this->_M_next = this->_M_prev = this; + _M_set_size(0); + } + }; + _GLIBCXX_END_NAMESPACE_VERSION } // namespace detail @@ -323,51 +407,53 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 struct _List_impl : public _Node_alloc_type { -#if _GLIBCXX_USE_CXX11_ABI - _List_node _M_node; -#else - __detail::_List_node_base _M_node; -#endif + __detail::_List_node_header _M_node; - _List_impl() _GLIBCXX_NOEXCEPT - : _Node_alloc_type(), _M_node() + _List_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Node_alloc_type()) ) + : _Node_alloc_type() { } _List_impl(const _Node_alloc_type& __a) _GLIBCXX_NOEXCEPT - : _Node_alloc_type(__a), _M_node() + : _Node_alloc_type(__a) { } #if __cplusplus >= 201103L + _List_impl(_List_impl&&) = default; + + _List_impl(_List_impl&& __x, _Node_alloc_type&& __a) + : _Node_alloc_type(std::move(__a)), _M_node(std::move(__x._M_node)) + { } + _List_impl(_Node_alloc_type&& __a) noexcept - : _Node_alloc_type(std::move(__a)), _M_node() + : _Node_alloc_type(std::move(__a)) { } #endif }; _List_impl _M_impl; -#if _GLIBCXX_USE_CXX11_ABI - size_t _M_get_size() const { return *_M_impl._M_node._M_valptr(); } + size_t + _M_get_size() const { return _M_impl._M_node._M_get_size(); } - void _M_set_size(size_t __n) { *_M_impl._M_node._M_valptr() = __n; } + void + _M_set_size(size_t __n) { _M_impl._M_node._M_set_size(__n); } - void _M_inc_size(size_t __n) { *_M_impl._M_node._M_valptr() += __n; } + void + _M_inc_size(size_t __n) { _M_impl._M_node._M_inc_size(__n); } - void _M_dec_size(size_t __n) { *_M_impl._M_node._M_valptr() -= __n; } + void + _M_dec_size(size_t __n) { _M_impl._M_node._M_dec_size(__n); } +#if _GLIBCXX_USE_CXX11_ABI size_t _M_distance(const __detail::_List_node_base* __first, const __detail::_List_node_base* __last) const { return _S_distance(__first, __last); } // return the stored size - size_t _M_node_count() const { return *_M_impl._M_node._M_valptr(); } + size_t _M_node_count() const { return _M_impl._M_node._M_get_size(); } #else // dummy implementations used when the size is not stored - size_t _M_get_size() const { return 0; } - void _M_set_size(size_t) { } - void _M_inc_size(size_t) { } - void _M_dec_size(size_t) { } size_t _M_distance(const void*, const void*) const { return 0; } // count the number of nodes @@ -397,44 +483,41 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _M_get_Node_allocator() const _GLIBCXX_NOEXCEPT { return _M_impl; } - _List_base() - : _M_impl() - { _M_init(); } +#if __cplusplus >= 201103L + _List_base() = default; +#else + _List_base() { } +#endif _List_base(const _Node_alloc_type& __a) _GLIBCXX_NOEXCEPT : _M_impl(__a) - { _M_init(); } + { } #if __cplusplus >= 201103L - _List_base(_List_base&& __x) noexcept - : _M_impl(std::move(__x._M_get_Node_allocator())) - { _M_move_nodes(std::move(__x)); } + _List_base(_List_base&&) = default; - _List_base(_List_base&& __x, _Node_alloc_type&& __a) + private: + _List_base(_List_base&& __x, _Node_alloc_type&& __a, true_type) + : _M_impl(std::move(__x._M_impl), std::move(__a)) + { } + + _List_base(_List_base&& __x, _Node_alloc_type&& __a, false_type) : _M_impl(std::move(__a)) { if (__x._M_get_Node_allocator() == _M_get_Node_allocator()) _M_move_nodes(std::move(__x)); - else - _M_init(); // Caller must move individual elements. + // else Caller must move individual elements. } + public: + _List_base(_List_base&& __x, _Node_alloc_type&& __a) + : _List_base(std::move(__x), std::move(__a), + typename _Node_alloc_traits::is_always_equal{}) + { } + void _M_move_nodes(_List_base&& __x) - { - auto* const __xnode = std::__addressof(__x._M_impl._M_node); - if (__xnode->_M_next == __xnode) - _M_init(); - else - { - auto* const __node = std::__addressof(_M_impl._M_node); - __node->_M_next = __xnode->_M_next; - __node->_M_prev = __xnode->_M_prev; - __node->_M_next->_M_prev = __node->_M_prev->_M_next = __node; - _M_set_size(__x._M_get_size()); - __x._M_init(); - } - } + { _M_impl._M_node._M_move_nodes(std::move(__x._M_impl._M_node)); } #endif // This is what actually destroys the list. @@ -446,11 +529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 void _M_init() _GLIBCXX_NOEXCEPT - { - this->_M_impl._M_node._M_next = &this->_M_impl._M_node; - this->_M_impl._M_node._M_prev = &this->_M_impl._M_node; - _M_set_size(0); - } + { this->_M_impl._M_node._M_init(); } }; /** @@ -586,11 +665,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 /** * @brief Creates a %list with no elements. */ - list() #if __cplusplus >= 201103L - noexcept(is_nothrow_default_constructible<_Node_alloc_type>::value) + list() = default; +#else + list() { } #endif - : _Base() { } /** * @brief Creates a %list with no elements. @@ -657,13 +736,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #if __cplusplus >= 201103L /** * @brief %List move constructor. - * @param __x A %list of identical element and allocator types. * - * The newly-created %list contains the exact contents of @a __x. - * The contents of @a __x are a valid, but unspecified %list. + * The newly-created %list contains the exact contents of the moved + * instance. The contents of @a __x are a valid, but unspecified %list. */ - list(list&& __x) noexcept - : _Base(std::move(__x)) { } + list(list&&) = default; /** * @brief Builds a %list from an initializer_list @@ -1838,17 +1915,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _M_move_assign(list&& __x, true_type) noexcept { this->_M_clear(); - if (__x.empty()) - this->_M_init(); - else - { - this->_M_impl._M_node._M_next = __x._M_impl._M_node._M_next; - this->_M_impl._M_node._M_next->_M_prev = &this->_M_impl._M_node; - this->_M_impl._M_node._M_prev = __x._M_impl._M_node._M_prev; - this->_M_impl._M_node._M_prev->_M_next = &this->_M_impl._M_node; - this->_M_set_size(__x._M_get_size()); - __x._M_init(); - } + this->_M_move_nodes(std::move(__x)); std::__alloc_on_move(this->_M_get_Node_allocator(), __x._M_get_Node_allocator()); } @@ -1983,12 +2050,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_STD_C::_List_const_iterator<_Tp> __last, input_iterator_tag) { - typedef _GLIBCXX_STD_C::_List_node _Sentinel; + typedef __detail::_List_node_header _Sentinel; _GLIBCXX_STD_C::_List_const_iterator<_Tp> __beyond = __last; ++__beyond; bool __whole = __first == __beyond; if (__builtin_constant_p (__whole) && __whole) - return *static_cast(__last._M_node)->_M_valptr(); + return static_cast(__last._M_node)->_M_get_size(); ptrdiff_t __n = 0; while (__first != __last) diff --git a/libstdc++-v3/testsuite/23_containers/list/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/list/allocator/default_init.cc new file mode 100644 index 0000000..0604e06 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/allocator/default_init.cc @@ -0,0 +1,71 @@ +// Copyright (C) 2017 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-do run { target c++11 } } +// { dg-options "-O0" } +// { dg-xfail-run-if "PR c++/65816" { *-*-* } } + +#include +#include +#include + +#include + +using T = int; + +using __gnu_test::default_init_allocator; + +void test01() +{ + typedef default_init_allocator alloc_type; + typedef std::list test_type; + + __gnu_cxx::__aligned_buffer buf; + __builtin_memset(buf._M_addr(), ~0, sizeof(test_type)); + + VERIFY( buf._M_ptr()->get_allocator().state != 0 ); + + test_type *tmp = ::new(buf._M_addr()) test_type(); + + VERIFY( tmp->get_allocator().state == 0 ); + + tmp->~test_type(); +} + +void test02() +{ + typedef default_init_allocator alloc_type; + typedef std::list test_type; + + __gnu_cxx::__aligned_buffer buf; + __builtin_memset(buf._M_addr(), ~0, sizeof(test_type)); + + VERIFY( buf._M_ptr()->get_allocator().state != 0 ); + + test_type *tmp = ::new(buf._M_addr()) test_type; + + VERIFY( tmp->get_allocator().state == 0 ); + + tmp->~test_type(); +} + +int main() +{ + test01(); + test02(); + return 0; +} --------------98B112FF59A6E69EE7DB2284--