From fd18c76ac8c85976bd7fe413aca2c26296ca6d54 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 9 Sep 2014 18:29:32 +0100 Subject: [PATCH] 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. From-SVN: r215090 --- libstdc++-v3/ChangeLog | 36 ++ libstdc++-v3/include/bits/deque.tcc | 45 ++- libstdc++-v3/include/bits/stl_deque.h | 316 ++++++++++++++---- libstdc++-v3/include/debug/deque | 10 +- libstdc++-v3/include/profile/deque | 10 +- .../23_containers/deque/allocator/copy.cc | 67 ++++ .../deque/allocator/copy_assign.cc | 57 ++++ .../23_containers/deque/allocator/ext_ptr.cc | 43 +++ .../23_containers/deque/allocator/minimal.cc | 45 +++ .../23_containers/deque/allocator/move.cc | 57 ++++ .../deque/allocator/move_assign-2.cc | 78 +++++ .../deque/allocator/move_assign.cc | 74 ++++ .../23_containers/deque/allocator/noexcept.cc | 67 ++++ .../23_containers/deque/allocator/swap.cc | 77 +++++ .../deque/requirements/dr438/assign_neg.cc | 2 +- .../requirements/dr438/constructor_1_neg.cc | 2 +- .../requirements/dr438/constructor_2_neg.cc | 2 +- .../deque/requirements/dr438/insert_neg.cc | 2 +- .../testsuite/23_containers/vector/52591.cc | 43 ++- 19 files changed, 938 insertions(+), 95 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign-2.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/allocator/swap.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index bf3f48db3fb..a5acf92b2dc 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,39 @@ +2014-09-09 Jonathan Wakely + + * 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. + 2014-09-06 François Dumont * include/bits/hashtable_policy.h (_Prime_rehash_policy): Constructor diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc index ebf5d3a0ab9..9c8dd36f1f5 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 add8742a102..acb7715f717 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 75be7489b1a..824cb289112 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 13513f4bdc7..c825cbe2ad9 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 00000000000..f33349c796a --- /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 00000000000..83ebc7b8fca --- /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 00000000000..e17c08474f1 --- /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 00000000000..70ca09ddb3d --- /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 00000000000..1e8d848c6eb --- /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 00000000000..5f337a07099 --- /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 00000000000..2b5febc0d03 --- /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 00000000000..6d199cc37ef --- /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 00000000000..c504581c44e --- /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 4de8f2d0fb9..8092ead6d41 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 41f29056198..4abdf4682be 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 f77b1267890..61bce4eb049 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 e7d5b1ee654..a0ca00caf8a 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 81a86c5c3c7..073d29adb90 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"); } -- 2.30.2