From bd8485dc9f89c0eff0a548a6ba210e75be6f419c Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Sat, 9 Jul 2011 13:06:29 +0000 Subject: [PATCH] stl_vector.h: Use new allocator model in C++0x mode. 2011-07-09 Jonathan Wakely * include/bits/stl_vector.h: Use new allocator model in C++0x mode. * include/bits/vector.tcc: Likewise. * testsuite/util/testsuite_allocator.h (propagating_allocator): Define. * testsuite/23_containers/vector/allocator/copy_assign.cc: New. * testsuite/23_containers/vector/allocator/noexcept.cc: New. * testsuite/23_containers/vector/allocator/copy.cc: New. * testsuite/23_containers/vector/allocator/swap.cc: New. * testsuite/23_containers/vector/allocator/move_assign.cc: New. * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc: Adjust dg-error line numbers. * testsuite/23_containers/vector/requirements/dr438/insert_neg.cc: Likewise. * testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc: Likewise. * testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc: Likewise. From-SVN: r176078 --- libstdc++-v3/ChangeLog | 19 +++ libstdc++-v3/include/bits/stl_vector.h | 145 +++++++++++++----- libstdc++-v3/include/bits/vector.tcc | 44 ++++-- .../23_containers/vector/allocator/copy.cc | 55 +++++++ .../vector/allocator/copy_assign.cc | 57 +++++++ .../vector/allocator/move_assign.cc | 57 +++++++ .../vector/allocator/noexcept.cc | 76 +++++++++ .../23_containers/vector/allocator/swap.cc | 57 +++++++ .../vector/requirements/dr438/assign_neg.cc | 2 +- .../requirements/dr438/constructor_1_neg.cc | 2 +- .../requirements/dr438/constructor_2_neg.cc | 2 +- .../vector/requirements/dr438/insert_neg.cc | 2 +- .../testsuite/util/testsuite_allocator.h | 62 ++++++++ 13 files changed, 521 insertions(+), 59 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/allocator/copy_assign.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/allocator/move_assign.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/allocator/noexcept.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index bd2a0cd9f51..1304b9241e2 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,22 @@ +2011-07-09 Jonathan Wakely + + * include/bits/stl_vector.h: Use new allocator model in C++0x mode. + * include/bits/vector.tcc: Likewise. + * testsuite/util/testsuite_allocator.h (propagating_allocator): Define. + * testsuite/23_containers/vector/allocator/copy_assign.cc: New. + * testsuite/23_containers/vector/allocator/noexcept.cc: New. + * testsuite/23_containers/vector/allocator/copy.cc: New. + * testsuite/23_containers/vector/allocator/swap.cc: New. + * testsuite/23_containers/vector/allocator/move_assign.cc: New. + * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc: + Adjust dg-error line numbers. + * testsuite/23_containers/vector/requirements/dr438/insert_neg.cc: + Likewise. + * testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc: + Likewise. + * testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc: + Likewise. + 2011-07-09 Jonathan Wakely * include/ext/alloc_traits.h (__allocator_always_compares_equal): New diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 929bcbe7ba1..0211033a456 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -71,13 +71,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER struct _Vector_base { typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type; + typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer + pointer; struct _Vector_impl : public _Tp_alloc_type { - typename _Tp_alloc_type::pointer _M_start; - typename _Tp_alloc_type::pointer _M_finish; - typename _Tp_alloc_type::pointer _M_end_of_storage; + pointer _M_start; + pointer _M_finish; + pointer _M_end_of_storage; _Vector_impl() : _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0) @@ -93,6 +95,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #endif + + void _M_swap_data(_Vector_impl& __x) + { + std::swap(_M_start, __x._M_start); + std::swap(_M_finish, __x._M_finish); + std::swap(_M_end_of_storage, __x._M_end_of_storage); + } }; public: @@ -118,30 +127,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Vector_base(size_t __n) : _M_impl() - { - this->_M_impl._M_start = this->_M_allocate(__n); - this->_M_impl._M_finish = this->_M_impl._M_start; - this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; - } + { _M_create_storage(__n); } _Vector_base(size_t __n, const allocator_type& __a) : _M_impl(__a) - { - this->_M_impl._M_start = this->_M_allocate(__n); - this->_M_impl._M_finish = this->_M_impl._M_start; - this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; - } + { _M_create_storage(__n); } #ifdef __GXX_EXPERIMENTAL_CXX0X__ + _Vector_base(_Tp_alloc_type&& __a) + : _M_impl(std::move(__a)) { } + _Vector_base(_Vector_base&& __x) : _M_impl(std::move(__x._M_get_Tp_allocator())) + { this->_M_impl._M_swap_data(__x._M_impl); } + + _Vector_base(_Vector_base&& __x, const allocator_type& __a) + : _M_impl(__a) { - this->_M_impl._M_start = __x._M_impl._M_start; - this->_M_impl._M_finish = __x._M_impl._M_finish; - this->_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage; - __x._M_impl._M_start = 0; - __x._M_impl._M_finish = 0; - __x._M_impl._M_end_of_storage = 0; + if (__x.get_allocator() == __a) + this->_M_impl._M_swap_data(__x._M_impl); + else + { + size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start; + _M_create_storage(__n); + } } #endif @@ -152,16 +161,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER public: _Vector_impl _M_impl; - typename _Tp_alloc_type::pointer + pointer _M_allocate(size_t __n) { return __n != 0 ? _M_impl.allocate(__n) : 0; } void - _M_deallocate(typename _Tp_alloc_type::pointer __p, size_t __n) + _M_deallocate(pointer __p, size_t __n) { if (__p) _M_impl.deallocate(__p, __n); } + + private: + void + _M_create_storage(size_t __n) + { + this->_M_impl._M_start = this->_M_allocate(__n); + this->_M_impl._M_finish = this->_M_impl._M_start; + this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; + } }; @@ -196,10 +214,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER 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 _Base::pointer pointer; + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits; + typedef typename _Alloc_traits::const_pointer const_pointer; + typedef typename _Alloc_traits::reference reference; + typedef typename _Alloc_traits::const_reference const_reference; typedef __gnu_cxx::__normal_iterator iterator; typedef __gnu_cxx::__normal_iterator const_iterator; @@ -283,7 +302,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @a x (for fast expansion) will not be copied. */ vector(const vector& __x) - : _Base(__x.size(), __x._M_get_Tp_allocator()) + : _Base(__x.size(), + _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator())) { this->_M_impl._M_finish = std::__uninitialized_copy_a(__x.begin(), __x.end(), this->_M_impl._M_start, @@ -301,6 +321,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector(vector&& __x) noexcept : _Base(std::move(__x)) { } + /// Copy constructor with alternative allocator + vector(const vector& __x, const allocator_type& __a) + : _Base(__x.size(), __a) + { this->_M_impl._M_finish = + std::__uninitialized_copy_a(__x.begin(), __x.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); + } + + /// Move constructor with alternative allocator + vector(vector&& __rv, const allocator_type& __m) + : _Base(std::move(__rv), __m) + { + if (__rv.get_allocator() != __m) + { + this->_M_impl._M_finish = + std::__uninitialized_move_a(__rv.begin(), __rv.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); + __rv.clear(); + } + } + /** * @brief Builds a %vector from an initializer list. * @param l An initializer_list. @@ -377,12 +420,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @a x is a valid, but unspecified %vector. */ vector& - operator=(vector&& __x) + operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()) { - // NB: DR 1204. - // NB: DR 675. - this->clear(); - this->swap(__x); + if (_Alloc_traits::_S_propagate_on_move_assign()) + { + // We're moving the rvalue's allocator so can move the data too. + const vector __tmp(std::move(*this)); // discard existing data + this->_M_impl._M_swap_data(__x._M_impl); + std::__alloc_on_move(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); + } + else if (_Alloc_traits::_S_always_equal() + || __x._M_get_Tp_allocator() == this->_M_get_Tp_allocator()) + { + // The rvalue's allocator can free our storage and vice versa, + // so can swap the data storage after destroying our contents. + this->clear(); + this->_M_impl._M_swap_data(__x._M_impl); + } + else + { + // The rvalue's allocator cannot be moved, or 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(); + } return *this; } @@ -834,7 +897,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { - this->_M_impl.construct(this->_M_impl._M_finish, __x); + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + __x); ++this->_M_impl._M_finish; } else @@ -864,7 +928,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER pop_back() { --this->_M_impl._M_finish; - this->_M_impl.destroy(this->_M_impl._M_finish); + _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish); } #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -1024,16 +1088,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ void swap(vector& __x) +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + 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_end_of_storage, - __x._M_impl._M_end_of_storage); - - // _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()); + this->_M_impl._M_swap_data(__x._M_impl); + _Alloc_traits::_S_on_swap(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); } /** diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index fd576dbd2df..85b514b561b 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -94,8 +94,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { - this->_M_impl.construct(this->_M_impl._M_finish, - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + std::forward<_Args>(__args)...); ++this->_M_impl._M_finish; } else @@ -112,7 +112,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage && __position == end()) { - this->_M_impl.construct(this->_M_impl._M_finish, __x); + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, __x); ++this->_M_impl._M_finish; } else @@ -138,7 +138,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (__position + 1 != end()) _GLIBCXX_MOVE3(__position + 1, end(), __position); --this->_M_impl._M_finish; - this->_M_impl.destroy(this->_M_impl._M_finish); + _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish); return __position; } @@ -160,6 +160,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (&__x != this) { +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + 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 + this->clear(); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + } + std::__alloc_on_copy(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); + } +#endif const size_type __xlen = __x.size(); if (__xlen > capacity()) { @@ -277,8 +293,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage && __position == end()) { - this->_M_impl.construct(this->_M_impl._M_finish, - std::forward<_Args>(__args)...); + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + std::forward<_Args>(__args)...); ++this->_M_impl._M_finish; } else @@ -300,9 +316,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) { - this->_M_impl.construct(this->_M_impl._M_finish, - _GLIBCXX_MOVE(*(this->_M_impl._M_finish - - 1))); + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + _GLIBCXX_MOVE(*(this->_M_impl._M_finish + - 1))); ++this->_M_impl._M_finish; #ifndef __GXX_EXPERIMENTAL_CXX0X__ _Tp __x_copy = __x; @@ -329,11 +345,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // case, where the moves could alter a new element belonging // to the existing vector. This is an issue only for callers // taking the element by const lvalue ref (see 23.1/13). - this->_M_impl.construct(__new_start + __elems_before, + _Alloc_traits::construct(this->_M_impl, + __new_start + __elems_before, #ifdef __GXX_EXPERIMENTAL_CXX0X__ - std::forward<_Args>(__args)...); + std::forward<_Args>(__args)...); #else - __x); + __x); #endif __new_finish = 0; @@ -352,7 +369,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __catch(...) { if (!__new_finish) - this->_M_impl.destroy(__new_start + __elems_before); + _Alloc_traits::destroy(this->_M_impl, + __new_start + __elems_before); else std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator()); _M_deallocate(__new_start, __len); diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc new file mode 100644 index 00000000000..bcd521efe18 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/copy.cc @@ -0,0 +1,55 @@ +// Copyright (C) 2011 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++0x" } + +#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::vector test_type; + test_type v1(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::vector test_type; + test_type v1(alloc_type(1)); + test_type 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/vector/allocator/copy_assign.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/copy_assign.cc new file mode 100644 index 00000000000..0e2050e0e3c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/copy_assign.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2011 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++0x" } + +#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::vector test_type; + test_type v1(alloc_type(1)); + test_type v2(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::vector test_type; + test_type v1(alloc_type(1)); + test_type v2(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/vector/allocator/move_assign.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/move_assign.cc new file mode 100644 index 00000000000..2a792c61c89 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/move_assign.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2011 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++0x" } + +#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::vector test_type; + test_type v1(alloc_type(1)); + test_type v2(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::vector test_type; + test_type v1(alloc_type(1)); + test_type v2(alloc_type(2)); + v2 = std::move(v1); + VERIFY(0 == 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/vector/allocator/noexcept.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/noexcept.cc new file mode 100644 index 00000000000..8bde430e239 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/noexcept.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2011 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++0x" } + +#include +#include +#include + +struct T { int i; }; + +namespace __gnu_test +{ + inline void + swap(propagating_allocator& l, propagating_allocator& r) + noexcept(false) + { + typedef uneq_allocator base_alloc; + swap(static_cast(l), static_cast(r)); + } +} + +using __gnu_test::propagating_allocator; + +void test01() +{ + typedef std::allocator alloc_type; + typedef std::vector 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::vector 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::vector 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" ); + static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" ); +} + +int main() +{ + test01(); + test02(); + test03(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc new file mode 100644 index 00000000000..808753e7520 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/swap.cc @@ -0,0 +1,57 @@ +// Copyright (C) 2011 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++0x" } + +#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::vector test_type; + test_type v1(alloc_type(1)); + test_type v2(alloc_type(2)); + std::swap(v1, v2); + 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::vector test_type; + test_type v1(alloc_type(1)); + test_type v2(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/vector/requirements/dr438/assign_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc index eba024c0c8c..8ff85455db7 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/assign_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1157 } +// { dg-error "no matching" "" { target *-*-* } 1218 } #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc index 24c14ce6bba..344f1a68170 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_1_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1087 } +// { dg-error "no matching" "" { target *-*-* } 1148 } #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc index b765096d9d4..7f3c52e8058 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/constructor_2_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1087 } +// { dg-error "no matching" "" { target *-*-* } 1148 } #include #include diff --git a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc index 083f2e0d26c..c2337c82c65 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/requirements/dr438/insert_neg.cc @@ -18,7 +18,7 @@ // . // { dg-do compile } -// { dg-error "no matching" "" { target *-*-* } 1198 } +// { dg-error "no matching" "" { target *-*-* } 1259 } #include diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h index 95e8d0dbaac..3b9fb28b901 100644 --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h @@ -371,6 +371,68 @@ namespace __gnu_test int personality; }; + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + // An uneq_allocator which can be used to test allocator propagation. + template + class propagating_allocator : public uneq_allocator + { + typedef uneq_allocator base_alloc; + base_alloc& base() { return *this; } + const base_alloc& base() const { return *this; } + void swap_base(base_alloc& b) { swap(b, this->base()); } + + typedef std::integral_constant trait_type; + + public: + template + struct rebind { typedef propagating_allocator other; }; + + propagating_allocator(int i) noexcept + : base_alloc(i) + { } + + template + propagating_allocator(const propagating_allocator& a) + noexcept + : base_alloc(a) + { } + + propagating_allocator() noexcept = default; + + propagating_allocator(const propagating_allocator&) noexcept = default; + + template + propagating_allocator& + operator=(const propagating_allocator& a) noexcept + { + static_assert(P2, "assigning propagating_allocator"); + propagating_allocator(a).swap_base(*this); + } + + // postcondition: a.get_personality() == 0 + propagating_allocator(propagating_allocator&& a) noexcept + : base_alloc() + { swap_base(a); } + + // postcondition: a.get_personality() == 0 + propagating_allocator& + operator=(propagating_allocator&& a) noexcept + { + propagating_allocator(std::move(a)).swap_base(*this); + return *this; + } + + typedef trait_type propagate_on_container_copy_assignment; + typedef trait_type propagate_on_container_move_assignment; + typedef trait_type propagate_on_container_swap; + + propagating_allocator select_on_container_copy_construction() const + { return Propagate ? *this : propagating_allocator(); } + }; + +#endif + } // namespace __gnu_test #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H