From patchwork Tue Sep 9 17:31:03 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 387408 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 3C27A1400AF for ; Wed, 10 Sep 2014 03:31:32 +1000 (EST) 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=mGu3ICZ/Gbla8PZnWXL8Y/3gSo4+WqbL4/WpuR5w6L/6Yg/BfT2DO J7VdjSekbePezoqkCa/73zrUmLikm5Uz6FUS+O8FdVFylLsXL1GSl53tpKBYLShK Vxi4zjWMR37IRgHssWH5sgjYQ+GpVXTnoB9nz979pWHHeH+1RY3vuk= 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=/zpS4GXEjrWJXGz6Cy3r0JGJUsc=; b=hh+T2Y3KVsx3ci1LILpy 0pg31OtQPrPi+h4Rc9WPpHYNskHk2PK3Q1abJk3RWk8C0P3UUhrqEqvIRgpOXJ72 1hSfoWYKGGI3K8yT4koVrKt3+hsY1XUp7TgB13KVUehLsVqVlHYRcR/M4UOUxVyO jO420E/Rs+pzEQ5eTjZ9HrM= Received: (qmail 14586 invoked by alias); 9 Sep 2014 17:31:13 -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 14564 invoked by uid 89); 9 Sep 2014 17:31:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.3 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS 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; Tue, 09 Sep 2014 17:31:06 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s89HV5x6016483 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 9 Sep 2014 13:31:05 -0400 Received: from localhost (ovpn-116-77.ams2.redhat.com [10.36.116.77]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s89HV3Zi009636; Tue, 9 Sep 2014 13:31:04 -0400 Date: Tue, 9 Sep 2014 18:31:03 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] Make std::deque meet C++11 allocator requirements Message-ID: <20140909173103.GF22778@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) This was a tricky one, because std::deque always has a map of nodes allocated, so needs to re-allocate in its move constructor. That makes move assignment complicated, as the rvalue object must be left in a valid state owning memory that can be freed by its (possibly moved-from) allocator. The _M_replace_map(_Args&&...) function constructs a new deque from its arguments, rips the guts out of that new deque and then destroys it. When the argument to the new deque is an rvalue deque the move constructor takes care of leaving the rvalue in a valid state with memory that can be freed by its allocator. The common case with std::allocator allows move-assignment to be noexcept, because it only involves swapping a few pointers and calling clear(). As an extension we support move assignment of std::deque even if the element types are not assignable, as long as the allocator type propagates (as we do for std::vector, see PR52591). Tested x86_64-linux, normal, debug and profile modes. Committed to trunk. commit 79a3c8ca1c14069e9756350c334bc3ee5e66a61a Author: Jonathan Wakely Date: Fri Nov 23 21:25:07 2012 +0000 Make std::deque meet C++11 allocator requirements. * include/bits/deque.tcc (deque::operator=(const deque&)): Handle allocator propagation. (deque::emplace_front, deque::emplace_back): Use allocator traits. (deque::_M_push_back_aux, deque::_M_push_front_aux): Likewise. (deque::_M_pop_back_aux, deque::_M_pop_front_aux): Likewise. * include/bits/stl_deque.h (__deque_buf_size): Add constexpr. (_Deque_iterator): Handle allocators with custom pointers. (_Deque_base): Likewise. Use allocator traits. (deque): Likewise. Add allocator-extended constructors. (deque::_M_move_assign1, deque::_M_move_assign2): Implement move assignment via tag dispatching. (deque::_M_replace_map): Replace existing data. * include/debug/deque (deque): Add allocator-extended constructors. * include/profile/deque (deque): Likewise. * testsuite/23_containers/deque/allocator/copy.cc: New. * testsuite/23_containers/deque/allocator/copy_assign.cc: New. * testsuite/23_containers/deque/allocator/ext_ptr.cc: New. * testsuite/23_containers/deque/allocator/minimal.cc: New. * testsuite/23_containers/deque/allocator/move.cc: New. * testsuite/23_containers/deque/allocator/move_assign-2.cc: New. * testsuite/23_containers/deque/allocator/move_assign.cc: New. * testsuite/23_containers/deque/allocator/noexcept.cc: New. * testsuite/23_containers/deque/allocator/swap.cc: New. * testsuite/23_containers/deque/requirements/dr438/assign_neg.cc: Adjust dg-error line number. * testsuite/23_containers/deque/requirements/dr438/ constructor_1_neg.cc: Likewise. * testsuite/23_containers/deque/requirements/dr438/ constructor_2_neg.cc: Likewise. * testsuite/23_containers/deque/requirements/dr438/insert_neg.cc: Likewise. * testsuite/23_containers/vector/52591.cc: Test both the propagating and always-equal cases. diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc index ebf5d3a..9c8dd36 100644 --- a/libstdc++-v3/include/bits/deque.tcc +++ b/libstdc++-v3/include/bits/deque.tcc @@ -92,9 +92,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER deque<_Tp, _Alloc>:: operator=(const deque& __x) { - const size_type __len = size(); if (&__x != this) { +#if __cplusplus >= 201103L + if (_Alloc_traits::_S_propagate_on_copy_assign()) + { + if (!_Alloc_traits::_S_always_equal() + && _M_get_Tp_allocator() != __x._M_get_Tp_allocator()) + { + // Replacement allocator cannot free existing storage, + // so deallocate everything and take copy of __x's data. + _M_replace_map(__x, __x.get_allocator()); + std::__alloc_on_copy(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); + return *this; + } + std::__alloc_on_copy(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); + } +#endif + const size_type __len = size(); if (__len >= __x.size()) _M_erase_at_end(std::copy(__x.begin(), __x.end(), this->_M_impl._M_start)); @@ -117,8 +134,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first) { - this->_M_impl.construct(this->_M_impl._M_start._M_cur - 1, - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, + this->_M_impl._M_start._M_cur - 1, + std::forward<_Args>(__args)...); --this->_M_impl._M_start._M_cur; } else @@ -134,8 +152,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (this->_M_impl._M_finish._M_cur != this->_M_impl._M_finish._M_last - 1) { - this->_M_impl.construct(this->_M_impl._M_finish._M_cur, - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, + this->_M_impl._M_finish._M_cur, + std::forward<_Args>(__args)...); ++this->_M_impl._M_finish._M_cur; } else @@ -453,8 +472,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __try { #if __cplusplus >= 201103L - this->_M_impl.construct(this->_M_impl._M_finish._M_cur, - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, + this->_M_impl._M_finish._M_cur, + std::forward<_Args>(__args)...); #else this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __t); #endif @@ -490,8 +510,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER - 1); this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_last - 1; #if __cplusplus >= 201103L - this->_M_impl.construct(this->_M_impl._M_start._M_cur, - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, + this->_M_impl._M_start._M_cur, + std::forward<_Args>(__args)...); #else this->_M_impl.construct(this->_M_impl._M_start._M_cur, __t); #endif @@ -512,7 +533,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_deallocate_node(this->_M_impl._M_finish._M_first); this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node - 1); this->_M_impl._M_finish._M_cur = this->_M_impl._M_finish._M_last - 1; - this->_M_impl.destroy(this->_M_impl._M_finish._M_cur); + _Alloc_traits::destroy(_M_get_Tp_allocator(), + this->_M_impl._M_finish._M_cur); } // Called only if _M_impl._M_start._M_cur == _M_impl._M_start._M_last - 1. @@ -524,7 +546,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void deque<_Tp, _Alloc>:: _M_pop_front_aux() { - this->_M_impl.destroy(this->_M_impl._M_start._M_cur); + _Alloc_traits::destroy(_M_get_Tp_allocator(), + this->_M_impl._M_start._M_cur); _M_deallocate_node(this->_M_impl._M_start._M_first); this->_M_impl._M_start._M_set_node(this->_M_impl._M_start._M_node + 1); this->_M_impl._M_start._M_cur = this->_M_impl._M_start._M_first; diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h index add8742..acb7715 100644 --- a/libstdc++-v3/include/bits/stl_deque.h +++ b/libstdc++-v3/include/bits/stl_deque.h @@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #define _GLIBCXX_DEQUE_BUF_SIZE 512 #endif - inline size_t + _GLIBCXX_CONSTEXPR inline size_t __deque_buf_size(size_t __size) { return (__size < _GLIBCXX_DEQUE_BUF_SIZE ? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1)); } @@ -105,8 +105,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template struct _Deque_iterator { +#if __cplusplus < 201103L typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator; typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator; + typedef _Tp* _Elt_pointer; + typedef _Tp** _Map_pointer; +#else + private: + template + using __ptr_to = typename pointer_traits<_Ptr>::template rebind<_Up>; + template + using __iter = _Deque_iterator<_Tp, _CvTp&, __ptr_to<_CvTp>>; + public: + typedef __iter<_Tp> iterator; + typedef __iter const_iterator; + typedef __ptr_to<_Tp> _Elt_pointer; + typedef __ptr_to<_Elt_pointer> _Map_pointer; +#endif static size_t _S_buffer_size() _GLIBCXX_NOEXCEPT { return __deque_buf_size(sizeof(_Tp)); } @@ -117,20 +132,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef _Ref reference; typedef size_t size_type; typedef ptrdiff_t difference_type; - typedef _Tp** _Map_pointer; typedef _Deque_iterator _Self; - _Tp* _M_cur; - _Tp* _M_first; - _Tp* _M_last; + _Elt_pointer _M_cur; + _Elt_pointer _M_first; + _Elt_pointer _M_last; _Map_pointer _M_node; - _Deque_iterator(_Tp* __x, _Map_pointer __y) _GLIBCXX_NOEXCEPT + _Deque_iterator(_Elt_pointer __x, _Map_pointer __y) _GLIBCXX_NOEXCEPT : _M_cur(__x), _M_first(*__y), _M_last(*__y + _S_buffer_size()), _M_node(__y) { } _Deque_iterator() _GLIBCXX_NOEXCEPT - : _M_cur(0), _M_first(0), _M_last(0), _M_node(0) { } + : _M_cur(), _M_first(), _M_last(), _M_node() { } _Deque_iterator(const iterator& __x) _GLIBCXX_NOEXCEPT : _M_cur(__x._M_cur), _M_first(__x._M_first), @@ -443,15 +457,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template class _Deque_base { + protected: + typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template + rebind<_Tp>::other _Tp_alloc_type; + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits; + +#if __cplusplus < 201103L + typedef _Tp* _Ptr; + typedef const _Tp* _Ptr_const; +#else + typedef typename _Alloc_traits::pointer _Ptr; + typedef typename _Alloc_traits::const_pointer _Ptr_const; +#endif + + typedef typename _Alloc_traits::template rebind<_Ptr>::other + _Map_alloc_type; + typedef __gnu_cxx::__alloc_traits<_Map_alloc_type> _Map_alloc_traits; + public: typedef _Alloc allocator_type; + typedef typename _Alloc_traits::size_type size_type; allocator_type get_allocator() const _GLIBCXX_NOEXCEPT { return allocator_type(_M_get_Tp_allocator()); } - typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator; - typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator; + typedef _Deque_iterator<_Tp, _Tp&, _Ptr> iterator; + typedef _Deque_iterator<_Tp, const _Tp&, _Ptr_const> const_iterator; _Deque_base() : _M_impl() @@ -467,19 +499,43 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Deque_base(const allocator_type& __a) : _M_impl(__a) - { } + { /* Caller must initialize map. */ } #if __cplusplus >= 201103L _Deque_base(_Deque_base&& __x) : _M_impl(std::move(__x._M_get_Tp_allocator())) { - _M_initialize_map(0); if (__x._M_impl._M_map) { - std::swap(this->_M_impl._M_start, __x._M_impl._M_start); - std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish); - std::swap(this->_M_impl._M_map, __x._M_impl._M_map); - std::swap(this->_M_impl._M_map_size, __x._M_impl._M_map_size); + this->_M_impl._M_swap_data(__x._M_impl); + __try + { + // Re-initialize __x using its moved-from allocator. + __x._M_initialize_map(0); + } + __catch (...) + { + this->_M_impl._M_swap_data(__x._M_impl); + __x._M_get_Tp_allocator() = std::move(_M_get_Tp_allocator()); + __throw_exception_again; + } + } + } + + _Deque_base(_Deque_base&& __x, const allocator_type& __a, size_type __n) + : _M_impl(__a) + { + if (__x.get_allocator() == __a) + { + if (__x._M_impl._M_map) + { + _M_initialize_map(0); + this->_M_impl._M_swap_data(__x._M_impl); + } + } + else + { + _M_initialize_map(__n); } } #endif @@ -487,9 +543,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ~_Deque_base() _GLIBCXX_NOEXCEPT; protected: - typedef typename _Alloc::template rebind<_Tp*>::other _Map_alloc_type; - - typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type; + typedef typename iterator::_Map_pointer _Map_pointer; //This struct encapsulates the implementation of the std::deque //standard container and at the same time makes use of the EBO @@ -497,27 +551,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER struct _Deque_impl : public _Tp_alloc_type { - _Tp** _M_map; + _Map_pointer _M_map; size_t _M_map_size; iterator _M_start; iterator _M_finish; _Deque_impl() - : _Tp_alloc_type(), _M_map(0), _M_map_size(0), + : _Tp_alloc_type(), _M_map(), _M_map_size(0), _M_start(), _M_finish() { } _Deque_impl(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT - : _Tp_alloc_type(__a), _M_map(0), _M_map_size(0), + : _Tp_alloc_type(__a), _M_map(), _M_map_size(0), _M_start(), _M_finish() { } #if __cplusplus >= 201103L _Deque_impl(_Tp_alloc_type&& __a) _GLIBCXX_NOEXCEPT - : _Tp_alloc_type(std::move(__a)), _M_map(0), _M_map_size(0), + : _Tp_alloc_type(std::move(__a)), _M_map(), _M_map_size(0), _M_start(), _M_finish() { } #endif + + void _M_swap_data(_Deque_impl& __x) + { + std::swap(this->_M_start, __x._M_start); + std::swap(this->_M_finish, __x._M_finish); + std::swap(this->_M_map, __x._M_map); + std::swap(this->_M_map_size, __x._M_map_size); + } }; _Tp_alloc_type& @@ -532,30 +594,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_get_map_allocator() const _GLIBCXX_NOEXCEPT { return _Map_alloc_type(_M_get_Tp_allocator()); } - _Tp* + _Ptr _M_allocate_node() { - return _M_impl._Tp_alloc_type::allocate(__deque_buf_size(sizeof(_Tp))); + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Traits; + return _Traits::allocate(_M_impl, __deque_buf_size(sizeof(_Tp))); } void - _M_deallocate_node(_Tp* __p) _GLIBCXX_NOEXCEPT + _M_deallocate_node(_Ptr __p) _GLIBCXX_NOEXCEPT { - _M_impl._Tp_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp))); + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Traits; + _Traits::deallocate(_M_impl, __p, __deque_buf_size(sizeof(_Tp))); } - _Tp** + _Map_pointer _M_allocate_map(size_t __n) - { return _M_get_map_allocator().allocate(__n); } + { + _Map_alloc_type __map_alloc = _M_get_map_allocator(); + return _Map_alloc_traits::allocate(__map_alloc, __n); + } void - _M_deallocate_map(_Tp** __p, size_t __n) _GLIBCXX_NOEXCEPT - { _M_get_map_allocator().deallocate(__p, __n); } + _M_deallocate_map(_Map_pointer __p, size_t __n) _GLIBCXX_NOEXCEPT + { + _Map_alloc_type __map_alloc = _M_get_map_allocator(); + _Map_alloc_traits::deallocate(__map_alloc, __p, __n); + } protected: void _M_initialize_map(size_t); - void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish); - void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) _GLIBCXX_NOEXCEPT; + void _M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish); + void _M_destroy_nodes(_Map_pointer __nstart, + _Map_pointer __nfinish) _GLIBCXX_NOEXCEPT; enum { _S_initial_map_size = 8 }; _Deque_impl _M_impl; @@ -576,7 +647,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /** * @brief Layout storage. * @param __num_elements The count of T's for which to allocate space - * at first. + * at first. * @return Nothing. * * The initial underlying memory layout is a bit complicated... @@ -598,16 +669,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // the beginning of _M_map, but for small maps it may be as far in as // _M_map+3. - _Tp** __nstart = (this->_M_impl._M_map - + (this->_M_impl._M_map_size - __num_nodes) / 2); - _Tp** __nfinish = __nstart + __num_nodes; + _Map_pointer __nstart = (this->_M_impl._M_map + + (this->_M_impl._M_map_size - __num_nodes) / 2); + _Map_pointer __nfinish = __nstart + __num_nodes; __try { _M_create_nodes(__nstart, __nfinish); } __catch(...) { _M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size); - this->_M_impl._M_map = 0; + this->_M_impl._M_map = _Map_pointer(); this->_M_impl._M_map_size = 0; __throw_exception_again; } @@ -623,9 +694,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template void _Deque_base<_Tp, _Alloc>:: - _M_create_nodes(_Tp** __nstart, _Tp** __nfinish) + _M_create_nodes(_Map_pointer __nstart, _Map_pointer __nfinish) { - _Tp** __cur; + _Map_pointer __cur; __try { for (__cur = __nstart; __cur < __nfinish; ++__cur) @@ -641,9 +712,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template void _Deque_base<_Tp, _Alloc>:: - _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) _GLIBCXX_NOEXCEPT + _M_destroy_nodes(_Map_pointer __nstart, + _Map_pointer __nfinish) _GLIBCXX_NOEXCEPT { - for (_Tp** __n = __nstart; __n < __nfinish; ++__n) + for (_Map_pointer __n = __nstart; __n < __nfinish; ++__n) _M_deallocate_node(*__n); } @@ -739,15 +811,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __glibcxx_class_requires(_Tp, _SGIAssignableConcept) __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept) - typedef _Deque_base<_Tp, _Alloc> _Base; - typedef typename _Base::_Tp_alloc_type _Tp_alloc_type; + typedef _Deque_base<_Tp, _Alloc> _Base; + typedef typename _Base::_Tp_alloc_type _Tp_alloc_type; + typedef typename _Base::_Alloc_traits _Alloc_traits; + typedef typename _Base::_Map_pointer _Map_pointer; public: typedef _Tp value_type; - typedef typename _Tp_alloc_type::pointer pointer; - typedef typename _Tp_alloc_type::const_pointer const_pointer; - typedef typename _Tp_alloc_type::reference reference; - typedef typename _Tp_alloc_type::const_reference const_reference; + typedef typename _Alloc_traits::pointer pointer; + typedef typename _Alloc_traits::const_pointer const_pointer; + typedef typename _Alloc_traits::reference reference; + typedef typename _Alloc_traits::const_reference const_reference; typedef typename _Base::iterator iterator; typedef typename _Base::const_iterator const_iterator; typedef std::reverse_iterator const_reverse_iterator; @@ -757,8 +831,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef _Alloc allocator_type; protected: - typedef pointer* _Map_pointer; - static size_t _S_buffer_size() _GLIBCXX_NOEXCEPT { return __deque_buf_size(sizeof(_Tp)); } @@ -804,8 +876,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * constructed elements. */ explicit - deque(size_type __n) - : _Base(__n) + deque(size_type __n, const allocator_type& __a = allocator_type()) + : _Base(__a, __n) { _M_default_initialize(); } /** @@ -844,7 +916,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * by @a __x. */ deque(const deque& __x) - : _Base(__x._M_get_Tp_allocator(), __x.size()) + : _Base(_Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()), + __x.size()) { std::__uninitialized_copy_a(__x.begin(), __x.end(), this->_M_impl._M_start, _M_get_Tp_allocator()); } @@ -860,6 +933,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER deque(deque&& __x) : _Base(std::move(__x)) { } + /// Copy constructor with alternative allocator + deque(const deque& __x, const allocator_type& __a) + : _Base(__a, __x.size()) + { std::__uninitialized_copy_a(__x.begin(), __x.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); } + + /// Move constructor with alternative allocator + deque(deque&& __x, const allocator_type& __a) + : _Base(std::move(__x), __a, __x.size()) + { + if (__x.get_allocator() != __a) + { + std::__uninitialized_move_a(__x.begin(), __x.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); + __x.clear(); + } + } + /** * @brief Builds a %deque from an initializer list. * @param __l An initializer_list. @@ -919,7 +1012,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * themselves are pointers, the pointed-to memory is not touched in any * way. Managing the pointer is the user's responsibility. */ - ~deque() _GLIBCXX_NOEXCEPT + ~deque() { _M_destroy_data(begin(), end(), _M_get_Tp_allocator()); } /** @@ -937,16 +1030,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @brief %Deque move assignment operator. * @param __x A %deque of identical element and allocator types. * - * The contents of @a __x are moved into this deque (without copying). + * The contents of @a __x are moved into this deque (without copying, + * if the allocators permit it). * @a __x is a valid, but unspecified %deque. */ deque& - operator=(deque&& __x) noexcept + operator=(deque&& __x) noexcept(_Alloc_traits::_S_always_equal()) { - // NB: DR 1204. - // NB: DR 675. - this->clear(); - this->swap(__x); + constexpr bool __always_equal = _Alloc_traits::_S_always_equal(); + _M_move_assign1(std::move(__x), + integral_constant()); return *this; } @@ -1150,7 +1243,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /** Returns the size() of the largest possible %deque. */ size_type max_size() const _GLIBCXX_NOEXCEPT - { return _M_get_Tp_allocator().max_size(); } + { return _Alloc_traits::max_size(_M_get_Tp_allocator()); } #if __cplusplus >= 201103L /** @@ -1368,7 +1461,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first) { - this->_M_impl.construct(this->_M_impl._M_start._M_cur - 1, __x); + _Alloc_traits::construct(this->_M_impl, + this->_M_impl._M_start._M_cur - 1, + __x); --this->_M_impl._M_start._M_cur; } else @@ -1400,7 +1495,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (this->_M_impl._M_finish._M_cur != this->_M_impl._M_finish._M_last - 1) { - this->_M_impl.construct(this->_M_impl._M_finish._M_cur, __x); + _Alloc_traits::construct(this->_M_impl, + this->_M_impl._M_finish._M_cur, __x); ++this->_M_impl._M_finish._M_cur; } else @@ -1431,7 +1527,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_last - 1) { - this->_M_impl.destroy(this->_M_impl._M_start._M_cur); + _Alloc_traits::destroy(this->_M_impl, + this->_M_impl._M_start._M_cur); ++this->_M_impl._M_start._M_cur; } else @@ -1453,7 +1550,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER != this->_M_impl._M_finish._M_first) { --this->_M_impl._M_finish._M_cur; - this->_M_impl.destroy(this->_M_impl._M_finish._M_cur); + _Alloc_traits::destroy(this->_M_impl, + this->_M_impl._M_finish._M_cur); } else _M_pop_back_aux(); @@ -1659,17 +1757,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * std::swap(d1,d2) will feed to this function. */ void - swap(deque& __x) _GLIBCXX_NOEXCEPT + swap(deque& __x) +#if __cplusplus >= 201103L + noexcept(_Alloc_traits::_S_nothrow_swap()) +#endif { - std::swap(this->_M_impl._M_start, __x._M_impl._M_start); - std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish); - std::swap(this->_M_impl._M_map, __x._M_impl._M_map); - std::swap(this->_M_impl._M_map_size, __x._M_impl._M_map_size); - - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 431. Swapping containers with unequal allocators. - std::__alloc_swap<_Tp_alloc_type>::_S_do_it(_M_get_Tp_allocator(), - __x._M_get_Tp_allocator()); + _M_impl._M_swap_data(__x._M_impl); + _Alloc_traits::_S_on_swap(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); } /** @@ -2011,6 +2106,79 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER void _M_reallocate_map(size_type __nodes_to_add, bool __add_at_front); //@} + +#if __cplusplus >= 201103L + // Constant-time, nothrow move assignment when source object's memory + // can be moved because the allocators are equal. + void + _M_move_assign1(deque&& __x, /* always equal: */ true_type) noexcept + { + this->_M_impl._M_swap_data(__x._M_impl); + __x.clear(); + std::__alloc_on_move(_M_get_Tp_allocator(), __x._M_get_Tp_allocator()); + } + + void + _M_move_assign1(deque&& __x, /* always equal: */ false_type) + { + constexpr bool __move_storage = + _Alloc_traits::_S_propagate_on_move_assign(); + _M_move_assign2(std::move(__x), + integral_constant()); + } + + // Destroy all elements and deallocate all memory, then replace + // with elements created from __args. + template + void + _M_replace_map(_Args&&... __args) + { + // Create new data first, so if allocation fails there are no effects. + deque __newobj(std::forward<_Args>(__args)...); + // Free existing storage using existing allocator. + clear(); + _M_deallocate_node(*begin()._M_node); // one node left after clear() + _M_deallocate_map(this->_M_impl._M_map, this->_M_impl._M_map_size); + this->_M_impl._M_map = nullptr; + this->_M_impl._M_map_size = 0; + // Take ownership of replacement memory. + this->_M_impl._M_swap_data(__newobj._M_impl); + } + + // Do move assignment when the allocator propagates. + void + _M_move_assign2(deque&& __x, /* propagate: */ true_type) + { + // Make a copy of the original allocator state. + auto __alloc = __x._M_get_Tp_allocator(); + // The allocator propagates so storage can be moved from __x, + // leaving __x in a valid empty state with a moved-from allocator. + _M_replace_map(std::move(__x)); + // Move the corresponding allocator state too. + _M_get_Tp_allocator() = std::move(__alloc); + } + + // Do move assignment when it may not be possible to move source + // object's memory, resulting in a linear-time operation. + void + _M_move_assign2(deque&& __x, /* propagate: */ false_type) + { + if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator()) + { + // The allocators are equal so storage can be moved from __x, + // leaving __x in a valid empty state with its current allocator. + _M_replace_map(std::move(__x), __x.get_allocator()); + } + else + { + // The rvalue's allocator cannot be moved and is not equal, + // so we need to individually move each element. + this->assign(std::__make_move_if_noexcept_iterator(__x.begin()), + std::__make_move_if_noexcept_iterator(__x.end())); + __x.clear(); + } + } +#endif }; diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque index 75be748..824cb28 100644 --- a/libstdc++-v3/include/debug/deque +++ b/libstdc++-v3/include/debug/deque @@ -88,6 +88,12 @@ namespace __debug deque(const deque&) = default; deque(deque&&) = default; + deque(const deque& __d, const _Allocator& __a) + : _Base(__d, __a) { } + + deque(deque&& __d, const _Allocator& __a) + : _Safe(std::move(__d)), _Base(std::move(__d), __a) { } + deque(initializer_list __l, const allocator_type& __a = allocator_type()) : _Base(__l, __a) { } @@ -101,8 +107,8 @@ namespace __debug #if __cplusplus >= 201103L explicit - deque(size_type __n) - : _Base(__n) { } + deque(size_type __n, const _Allocator& __a = _Allocator()) + : _Base(__n, __a) { } deque(size_type __n, const _Tp& __value, const _Allocator& __a = _Allocator()) diff --git a/libstdc++-v3/include/profile/deque b/libstdc++-v3/include/profile/deque index 13513f4..c825cbe 100644 --- a/libstdc++-v3/include/profile/deque +++ b/libstdc++-v3/include/profile/deque @@ -60,6 +60,12 @@ namespace __profile deque(const deque&) = default; deque(deque&&) = default; + deque(const deque& __d, const _Allocator& __a) + : _Base(__d, __a) { } + + deque(deque&& __d, const _Allocator& __a) + : _Base(std::move(__d), __a) { } + ~deque() = default; deque(initializer_list __l, @@ -73,8 +79,8 @@ namespace __profile #if __cplusplus >= 201103L explicit - deque(size_type __n) - : _Base(__n) { } + deque(size_type __n, const _Allocator& __a = _Allocator()) + : _Base(__n, __a) { } deque(size_type __n, const _Tp& __value, const _Allocator& __a = _Allocator()) diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc new file mode 100644 index 0000000..f33349c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2014 Free Software Foundation +// +// 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" } + +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::propagating_allocator; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(v1); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(0 == v2.get_allocator().get_personality()); +} + +void test02() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(v1); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); +} + +void test03() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(v1, alloc_type(2)); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(2 == v2.get_allocator().get_personality()); +} + +int main() +{ + test01(); + test02(); + test03(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc new file mode 100644 index 0000000..83ebc7b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2014 Free Software Foundation +// +// 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" } + +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::propagating_allocator; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(1, alloc_type(2)); + v2 = v1; + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(2 == v2.get_allocator().get_personality()); +} + +void test02() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(1, alloc_type(2)); + v2 = v1; + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); +} + +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc new file mode 100644 index 0000000..e17c084 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc @@ -0,0 +1,43 @@ +// Copyright (C) 2014 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" } + +#include +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::CustomPointerAlloc; + +template class std::deque>; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef CustomPointerAlloc alloc_type; + typedef std::deque test_type; + test_type v(1); + VERIFY( ++v.begin() == v.end() ); +} + +int main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc new file mode 100644 index 0000000..70ca09d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc @@ -0,0 +1,45 @@ +// Copyright (C) 2014 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" } + +#include +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::SimpleAllocator; + +template class std::deque>; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef SimpleAllocator alloc_type; + typedef std::allocator_traits traits_type; + typedef std::deque test_type; + test_type v(1, alloc_type{}); + VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc new file mode 100644 index 0000000..1e8d848 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2014 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" } + +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::uneq_allocator; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef uneq_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + auto it = v1.begin(); + test_type v2(std::move(v1)); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); + VERIFY( it == v2.begin() ); +} + +void test02() +{ + bool test __attribute__((unused)) = true; + typedef uneq_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(std::move(v1), alloc_type(2)); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(2 == v2.get_allocator().get_personality()); +} + +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc new file mode 100644 index 0000000..5f337a0 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc @@ -0,0 +1,78 @@ +// Copyright (C) 2012-2014 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 compile } +// { dg-options "-std=gnu++11 -fno-access-control" } + +// libstdc++/52591 + +#include +#include +#include + + +// As an extension we allow move-assignment of std::deque when the element +// type is not MoveAssignable, as long as the allocator type propagates or +// is known to always compare equal. + +struct C +{ + C& operator=(C&&) = delete; +}; + +template +struct A1 : std::allocator +{ + template struct rebind { typedef A1 other; }; + + A1() = default; + template A1(const A1&) { } + + using propagate_on_container_move_assignment = std::true_type; +}; + +void test01() +{ + using test_type = std::deque>; + static_assert(std::is_move_assignable::value, + "deque is move-assignable if allocator propagates"); +} + +template +struct A2 : std::allocator +{ + template struct rebind { typedef A2 other; }; + + A2() = default; + template A2(const A2&) { } + + using propagate_on_container_move_assignment = std::false_type; +}; + +namespace __gnu_cxx +{ + template + struct __allocator_always_compares_equal> : std::true_type + { }; +} + +void test02() +{ + using test_type = std::deque>; + static_assert(std::is_nothrow_move_assignable::value, + "deque is nothrow move-assignable if allocator is always equal"); +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc new file mode 100644 index 0000000..2b5febc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2014 Free Software Foundation +// +// 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" } + +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::propagating_allocator; + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(1, alloc_type(2)); + v2 = std::move(v1); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(2 == v2.get_allocator().get_personality()); +} + +void test02() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + auto it = v1.begin(); + test_type v2(1, alloc_type(2)); + v2 = std::move(v1); + VERIFY( it == v2.begin() ); + VERIFY(0 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); +} + +void test03() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + auto it = v1.begin(); + test_type v2(1, alloc_type(1)); + v2 = std::move(v1); + VERIFY( it == v2.begin() ); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); +} + +int main() +{ + test01(); + test02(); + test03(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc new file mode 100644 index 0000000..6d199cc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2014 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 compile } +// { dg-options "-std=gnu++11" } + +#include +#include + +struct T { int i; }; + +namespace __gnu_test +{ + template + inline void + swap(propagating_allocator& l, propagating_allocator& r) + noexcept(false) + { } +} + +using __gnu_test::propagating_allocator; + +void test01() +{ + typedef std::allocator alloc_type; + typedef std::deque test_type; + test_type v1; + test_type v2; + // this is a GNU extension for std::allocator + // static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" ); + static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" ); +} + +void test02() +{ + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(alloc_type(1)); + test_type v2(alloc_type(2)); + static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" ); + static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" ); +} + +void test03() +{ + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(alloc_type(1)); + test_type v2(alloc_type(2)); + // static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" ); + // noexcept spec of deque::swap depends on swap overload at top of this file + static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" ); +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc new file mode 100644 index 0000000..c504581 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2013 Free Software Foundation +// +// 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" } + +#include +#include +#include + +struct T { int i; }; + +using __gnu_test::propagating_allocator; + +// It is undefined behaviour to swap() containers wth unequal allocators +// if the allocator doesn't propagate, so ensure the allocators compare +// equal, while still being able to test propagation via get_personality(). +bool +operator==(const propagating_allocator&, + const propagating_allocator&) +{ + return true; +} + +bool +operator!=(const propagating_allocator&, + const propagating_allocator&) +{ + return false; +} + + +void test01() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(1, alloc_type(2)); + std::swap(v1, v2); + VERIFY(1 == v1.get_allocator().get_personality()); + VERIFY(2 == v2.get_allocator().get_personality()); + // swap back so assertions in uneq_allocator::deallocate don't fail + std::swap(v1, v2); +} + +void test02() +{ + bool test __attribute__((unused)) = true; + typedef propagating_allocator alloc_type; + typedef std::deque test_type; + test_type v1(1, alloc_type(1)); + test_type v2(1, alloc_type(2)); + std::swap(v1, v2); + VERIFY(2 == v1.get_allocator().get_personality()); + VERIFY(1 == v2.get_allocator().get_personality()); +} + +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc index 4de8f2d..8092ead 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/assign_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1764 } +// { dg-error "no matching" "" { target *-*-* } 1859 } #include diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc index 41f2905..4abdf46 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_1_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1697 } +// { dg-error "no matching" "" { target *-*-* } 1792 } #include diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc index f77b126..61bce4e 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/constructor_2_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1697 } +// { dg-error "no matching" "" { target *-*-* } 1792 } #include #include diff --git a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc index e7d5b1e..a0ca00c 100644 --- a/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/deque/requirements/dr438/insert_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1848 } +// { dg-error "no matching" "" { target *-*-* } 1943 } #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/52591.cc b/libstdc++-v3/testsuite/23_containers/vector/52591.cc index 81a86c5..073d29a 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/52591.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/52591.cc @@ -21,6 +21,8 @@ // libstdc++/52591 #include +#include +#include // As an extension we allow move-assignment of std::vector when the element // type is not MoveAssignable, as long as the allocator type propagates or @@ -31,8 +33,45 @@ struct C C& operator=(C&&) = delete; }; +template +struct A1 : std::allocator +{ + template struct rebind { typedef A1 other; }; + + A1() = default; + template A1(const A1&) { } + + using propagate_on_container_move_assignment = std::true_type; +}; + void test01() { - std::vector a; - a = std::vector(); + using test_type = std::vector>; + static_assert(std::is_nothrow_move_assignable::value, + "vector is nothrow move-assignable if allocator propagates"); +} + +template +struct A2 : std::allocator +{ + template struct rebind { typedef A1 other; }; + + A2() = default; + template A2(const A2&) { } + + using propagate_on_container_move_assignment = std::false_type; +}; + +namespace __gnu_cxx +{ + template + struct __allocator_always_compares_equal> : std::true_type + { }; +} + +void test02() +{ + using test_type = std::vector>; + static_assert(std::is_nothrow_move_assignable::value, + "vector is nothrow move-assignable if allocator is always equal"); }