This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
WIP: C++11 allocator support for std::deque
- From: Jonathan Wakely <jwakely dot gcc at gmail dot com>
- To: "libstdc++" <libstdc++ at gcc dot gnu dot org>
- Date: Wed, 20 Nov 2013 20:00:59 +0000
- Subject: WIP: C++11 allocator support for std::deque
- Authentication-results: sourceware.org; auth=none
This is an incomplete patch to add allocator support to std::deque.
Excuse the ugly code and inevitable bugs, it was coded at 5am because
I couldn't sleep. I'm not going to finish it for stage1, so here it
is just for fun (and to show why we should change std::deque's
invariant).
The new 23_containers/deque/allocator/noexcept.cc test is XFAIL'd
because moving and swapping doesn't meet the noexcept guarantees we
provide for the other containers. std::deque has an invariant that
it's never empty, so it needs to allocate memory in its move
constructor. Eurgh.
The pre-existing 23_containers/deque/requirements/exception/basic.cc
exception safety test also fails now. I haven't figured out where the
problem is yet, but it's probably in
deque::_M_move_assign(deque&&, true_type), is truly horrible code ,.
The complexity there is that when
propagate_on_container_move_assignment is true we will leave __x with
a moved-from allocator, so its memory has to be allocated by an
allocator that compares equal to that same moved-from state, but to be
exception-safe we want to allocate first, before destroying the
existing data. Eurgh. I'll try to improve it another time.
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index 9c33ad9..6dfff77 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -92,9 +92,33 @@ _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
+ deque __newobj(__x.size(), __x._M_get_Tp_allocator());
+ this->clear();
+ _M_destroy_nodes(this->_M_impl._M_start._M_node,
+ this->_M_impl._M_finish._M_node + 1);
+ _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;
+ std::__alloc_on_copy(_M_get_Tp_allocator(),
+ __x._M_get_Tp_allocator());
+ this->_M_impl._M_swap_data(__newobj._M_impl);
+ }
+ else
+ 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 +141,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 +159,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,10 +479,12 @@ _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);
+ _Alloc_traits::construct(this->_M_impl,
+ this->_M_impl._M_finish._M_cur, __t);
#endif
this->_M_impl._M_finish._M_set_node(this->_M_impl._M_finish._M_node
+ 1);
@@ -490,10 +518,12 @@ _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);
+ _Alloc_traits::construct(this->_M_impl,
+ this->_M_impl._M_start._M_cur, __t);
#endif
}
__catch(...)
@@ -512,7 +542,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 +555,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_finish._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;
@@ -878,6 +910,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
deque<_Tp, _Alloc>::
_M_reallocate_map(size_type __nodes_to_add, bool __add_at_front)
{
+#if 0
+ if (__builtin_expect(_M_impl._M_map == _Map_pointer(), 0)) // TODO improve
+ this->_M_initialize_map(0);
+#endif
+
const size_type __old_num_nodes
= this->_M_impl._M_finish._M_node - this->_M_impl._M_start._M_node + 1;
const size_type __new_num_nodes = __old_num_nodes + __nodes_to_add;
diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h
index ca9e417..e0c9055 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<typename _Tp, typename _Ref, typename _Ptr>
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<typename _Up>
+ using __ptr_to = typename pointer_traits<_Ptr>::template rebind<_Up>;
+ template<typename _CvTp>
+ using __iter = _Deque_iterator<_Tp, _CvTp&, __ptr_to<_CvTp>>;
+ public:
+ typedef __iter<_Tp> iterator;
+ typedef __iter<const _Tp> 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,15 +132,14 @@ _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) { }
@@ -443,15 +457,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
template<typename _Tp, typename _Alloc>
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()
@@ -473,13 +505,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_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);
+ // re-initialize __x using its moved-from allocator
+ __x._M_initialize_map(0); // TODO remove somehow?
+ }
+ }
+
+ _Deque_base(_Deque_base&& __x, const allocator_type& __a, size_type __n)
+ : _M_impl(__a)
+ {
+ if (__x.get_allocator() == __a)
+ {
+ _M_initialize_map(0); // TODO remove somehow?
+ if (__x._M_impl._M_map)
+ this->_M_impl._M_swap_data(__x._M_impl);
+ }
+ else
+ {
+ _M_initialize_map(__n);
}
}
#endif
@@ -487,37 +532,43 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
~_Deque_base() _GLIBCXX_NOEXCEPT;
protected:
+ 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
//for empty allocators.
- typedef typename _Alloc::template rebind<_Tp*>::other _Map_alloc_type;
-
- typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
-
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 +583,38 @@ _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 +635,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,9 +657,9 @@ _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); }
@@ -623,9 +682,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
template<typename _Tp, typename _Alloc>
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 +700,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
template<typename _Tp, typename _Alloc>
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);
}
@@ -672,6 +732,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* - size_t _M_map_size
* - iterator _M_start, _M_finish
*
+ * // TODO unless moved-from, ...
* map_size is at least 8. %map is an array of map_size
* pointers-to-@a nodes. (The name %map has nothing to do with the
* std::map class, and @b nodes should not be confused with
@@ -739,15 +800,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_iterator> const_reverse_iterator;
@@ -757,8 +820,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)); }
@@ -798,8 +859,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(); }
/**
@@ -838,7 +899,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()); }
@@ -851,9 +913,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* The newly-created %deque contains the exact contents of @a __x.
* The contents of @a __x are a valid, but unspecified %deque.
*/
- deque(deque&& __x)
+ deque(deque&& __x) // TODO noexcept
: _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) // TODO noexcept(_S_)
+ : _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.
@@ -935,15 +1017,61 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* @a __x is a valid, but unspecified %deque.
*/
deque&
- operator=(deque&& __x) noexcept
+ operator=(deque&& __x) // TODO cond noexcept
{
- // NB: DR 1204.
- // NB: DR 675.
- this->clear();
- this->swap(__x);
+ constexpr bool __move_storage =
+ _Alloc_traits::_S_propagate_on_move_assign()
+ || _Alloc_traits::_S_always_equal();
+ _M_move_assign(std::move(__x),
+ integral_constant<bool, __move_storage>());
return *this;
}
+ // TODO make private and put later in file
+ // Constant-time move assignment when source object's memory can be
+ // moved, either because the source's allocator will move too
+ // or because the allocators are equal.
+ void
+ _M_move_assign(deque&& __x, true_type)
+ {
+ _Tp_alloc_type __alloc =
+ _Alloc_traits::_S_propagate_on_move_assign()
+ ? _Tp_alloc_type(std::move(__x._M_get_Tp_allocator()))
+ : __x._M_get_Tp_allocator();
+ // initialize empty deque using maybe-moved-from allocator
+ deque __empty(__x._M_get_Tp_allocator()); // XXX can throw
+ // free existing storage
+ this->clear();
+ _M_destroy_nodes(this->_M_impl._M_start._M_node,
+ this->_M_impl._M_finish._M_node + 1);
+ _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 __x's storage
+ this->_M_impl._M_swap_data(__x._M_impl);
+ // and maybe its allocator
+ std::__alloc_on_move(_M_get_Tp_allocator(), __alloc);
+ // swap __x storage with "empty" deque created using same alloc
+ __empty._M_impl._M_swap_data(__x._M_impl);
+ }
+
+ // Do move assignment when it might not be possible to move source
+ // object's memory, resulting in a linear-time operation.
+ void
+ _M_move_assign(deque&& __x, false_type)
+ {
+ if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
+ _M_move_assign(std::move(__x), std::true_type());
+ 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();
+ }
+ }
+
/**
* @brief Assigns an initializer list to a %deque.
* @param __l An initializer_list.
@@ -1144,7 +1272,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
/**
@@ -1362,7 +1490,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
@@ -1394,7 +1524,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
@@ -1425,7 +1556,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
@@ -1447,7 +1579,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();
@@ -1653,7 +1786,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* std::swap(d1,d2) will feed to this function.
*/
void
- swap(deque& __x) _GLIBCXX_NOEXCEPT
+ swap(deque& __x) _GLIBCXX_NOEXCEPT // TODO cond noexcept?
{
std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 5c8c161..c945a44 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -1435,9 +1435,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
const vector __tmp(std::move(*this));
this->_M_impl._M_swap_data(__x._M_impl);
- if (_Alloc_traits::_S_propagate_on_move_assign())
- std::__alloc_on_move(_M_get_Tp_allocator(),
- __x._M_get_Tp_allocator());
+ std::__alloc_on_move(_M_get_Tp_allocator(), __x._M_get_Tp_allocator());
}
// Do move assignment when it might not be possible to move source
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..9e4fb34
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy.cc
@@ -0,0 +1,67 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::deque<T, alloc_type> 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<T, true> alloc_type;
+ typedef std::deque<T, alloc_type> 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<T, true> alloc_type;
+ typedef std::deque<T, alloc_type> 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..c2cc55d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/copy_assign.cc
@@ -0,0 +1,57 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::deque<T, alloc_type> 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<T, true> alloc_type;
+ typedef std::deque<T, alloc_type> 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..69b11d2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/ext_ptr.cc
@@ -0,0 +1,43 @@
+// Copyright (C) 2013 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::CustomPointerAlloc;
+
+template class std::deque<T, CustomPointerAlloc<T>>;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef CustomPointerAlloc<T> alloc_type;
+ typedef std::deque<T, alloc_type> 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..cd5ea66
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/minimal.cc
@@ -0,0 +1,45 @@
+// Copyright (C) 2011-2013 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::SimpleAllocator;
+
+template class std::deque<T, SimpleAllocator<T>>;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef SimpleAllocator<T> alloc_type;
+ typedef std::allocator_traits<alloc_type> traits_type;
+ typedef std::deque<T, alloc_type> 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..244a7e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2013 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::uneq_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef uneq_allocator<T> alloc_type;
+ typedef std::deque<T, alloc_type> test_type;
+ test_type v1(1, alloc_type(1));
+ test_type v2(std::move(v1));
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+ bool test __attribute__((unused)) = true;
+ typedef uneq_allocator<T> alloc_type;
+ typedef std::deque<T, alloc_type> 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.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc
new file mode 100644
index 0000000..ee7c65f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/move_assign.cc
@@ -0,0 +1,57 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::deque<T, alloc_type> 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<T, true> alloc_type;
+ typedef std::deque<T, alloc_type> test_type;
+ test_type v1(1, alloc_type(1));
+ test_type v2(1, 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/deque/allocator/noexcept.cc b/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc
new file mode 100644
index 0000000..7bd65e3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/deque/allocator/noexcept.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2013 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
+// <http://www.gnu.org/licenses/>.
+
+// XFAIL while std::deque allocates memory in move constructor
+// { dg-do compile { xfail *-*-* } }
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+namespace __gnu_test
+{
+ template<typename U>
+ inline void
+ swap(propagating_allocator<U, true>& l, propagating_allocator<U, true>& r)
+ noexcept(false)
+ { }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+ typedef std::allocator<T> alloc_type;
+ typedef std::deque<T, alloc_type> 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" ); // { dg-error "throw" }
+ static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::deque<T, alloc_type> 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<T, true> alloc_type;
+ typedef std::deque<T, alloc_type> 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" ); // { dg-error "throw" }
+ static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" ); // { dg-error "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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <deque>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+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<T, false>&,
+ const propagating_allocator<T, false>&)
+{
+ return true;
+}
+
+bool
+operator!=(const propagating_allocator<T, false>&,
+ const propagating_allocator<T, false>&)
+{
+ return false;
+}
+
+
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ typedef propagating_allocator<T, false> alloc_type;
+ typedef std::deque<T, alloc_type> 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<T, true> alloc_type;
+ typedef std::deque<T, alloc_type> 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;
+}