2014-09-24 François Dumont <fdumont@gcc.gnu.org>
authorfdumont <fdumont@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 24 Sep 2014 19:55:35 +0000 (19:55 +0000)
committerfdumont <fdumont@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 24 Sep 2014 19:55:35 +0000 (19:55 +0000)
PR libstdc++/29988
* include/bits/stl_tree.h (_Rb_tree_reuse_or_alloc_node<>): New.
(_Rb_tree_alloc_node<>): New.
(_Rb_tree<>::operator=(_Rb_tree<>&&)): New.
(_Rb_tree<>::_M_assign_unique): New.
(_Rb_tree<>::_M_assign_equal): New.
(_Rb_tree<>): Adapt to reuse allocated nodes as much as possible.
* include/bits/stl_map.h
(std::map<>::operator=(std::map<>&&)): Default implementation.
(std::map<>::operator=(initializer_list<>)): Adapt to use
_Rb_tree::_M_assign_unique.
* include/bits/stl_multimap.h
(std::multimap<>::operator=(std::multimap<>&&)): Default implementation.
(std::multimap<>::operator=(initializer_list<>)): Adapt to use
_Rb_tree::_M_assign_equal.
* include/bits/stl_set.h
(std::set<>::operator=(std::set<>&&)): Default implementation.
(std::set<>::operator=(initializer_list<>)): Adapt to use
_Rb_tree::_M_assign_unique.
* include/bits/stl_multiset.h
(std::multiset<>::operator=(std::multiset<>&&)): Default implementation.
(std::multiset<>::operator=(initializer_list<>)): Adapt to use
_Rb_tree::_M_assign_equal.
* testsuite/23_containers/map/allocator/copy_assign.cc (test03): New.
* testsuite/23_containers/map/allocator/init-list.cc: New.
* testsuite/23_containers/map/allocator/move_assign.cc (test03): New.
* testsuite/23_containers/multimap/allocator/copy_assign.cc
(test03): New.
* testsuite/23_containers/multimap/allocator/init-list.cc: New.
* testsuite/23_containers/multimap/allocator/move_assign.cc
(test03): New.
* testsuite/23_containers/multiset/allocator/copy_assign.cc
(test03): New.
* testsuite/23_containers/multiset/allocator/init-list.cc: New.
* testsuite/23_containers/multiset/allocator/move_assign.cc
(test03): New.
* testsuite/23_containers/set/allocator/copy_assign.cc (test03): New.
* testsuite/23_containers/set/allocator/init-list.cc: New.
* testsuite/23_containers/set/allocator/move_assign.cc (test03): New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@215568 138bc75d-0d04-0410-961f-82ee72b054a4

18 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_map.h
libstdc++-v3/include/bits/stl_multimap.h
libstdc++-v3/include/bits/stl_multiset.h
libstdc++-v3/include/bits/stl_set.h
libstdc++-v3/include/bits/stl_tree.h
libstdc++-v3/testsuite/23_containers/map/allocator/copy_assign.cc
libstdc++-v3/testsuite/23_containers/map/allocator/init-list.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/map/allocator/move_assign.cc
libstdc++-v3/testsuite/23_containers/multimap/allocator/copy_assign.cc
libstdc++-v3/testsuite/23_containers/multimap/allocator/init-list.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/multimap/allocator/move_assign.cc
libstdc++-v3/testsuite/23_containers/multiset/allocator/copy_assign.cc
libstdc++-v3/testsuite/23_containers/multiset/allocator/init-list.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/multiset/allocator/move_assign.cc
libstdc++-v3/testsuite/23_containers/set/allocator/copy_assign.cc
libstdc++-v3/testsuite/23_containers/set/allocator/init-list.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/set/allocator/move_assign.cc

index 2f8abd7..630b116 100644 (file)
@@ -1,3 +1,45 @@
+2014-09-24  François Dumont  <fdumont@gcc.gnu.org>
+
+       PR libstdc++/29988
+       * include/bits/stl_tree.h (_Rb_tree_reuse_or_alloc_node<>): New.
+       (_Rb_tree_alloc_node<>): New.
+       (_Rb_tree<>::operator=(_Rb_tree<>&&)): New.
+       (_Rb_tree<>::_M_assign_unique): New.
+       (_Rb_tree<>::_M_assign_equal): New.
+       (_Rb_tree<>): Adapt to reuse allocated nodes as much as possible.
+       * include/bits/stl_map.h
+       (std::map<>::operator=(std::map<>&&)): Default implementation.
+       (std::map<>::operator=(initializer_list<>)): Adapt to use
+       _Rb_tree::_M_assign_unique.
+       * include/bits/stl_multimap.h
+       (std::multimap<>::operator=(std::multimap<>&&)): Default implementation.
+       (std::multimap<>::operator=(initializer_list<>)): Adapt to use
+       _Rb_tree::_M_assign_equal.
+       * include/bits/stl_set.h
+       (std::set<>::operator=(std::set<>&&)): Default implementation.
+       (std::set<>::operator=(initializer_list<>)): Adapt to use
+       _Rb_tree::_M_assign_unique.
+       * include/bits/stl_multiset.h
+       (std::multiset<>::operator=(std::multiset<>&&)): Default implementation.
+       (std::multiset<>::operator=(initializer_list<>)): Adapt to use
+       _Rb_tree::_M_assign_equal.
+       * testsuite/23_containers/map/allocator/copy_assign.cc (test03): New.
+       * testsuite/23_containers/map/allocator/init-list.cc: New.
+       * testsuite/23_containers/map/allocator/move_assign.cc (test03): New.
+       * testsuite/23_containers/multimap/allocator/copy_assign.cc
+       (test03): New.
+       * testsuite/23_containers/multimap/allocator/init-list.cc: New.
+       * testsuite/23_containers/multimap/allocator/move_assign.cc
+       (test03): New.
+       * testsuite/23_containers/multiset/allocator/copy_assign.cc
+       (test03): New.
+       * testsuite/23_containers/multiset/allocator/init-list.cc: New.
+       * testsuite/23_containers/multiset/allocator/move_assign.cc
+       (test03): New.
+       * testsuite/23_containers/set/allocator/copy_assign.cc (test03): New.
+       * testsuite/23_containers/set/allocator/init-list.cc: New.
+       * testsuite/23_containers/set/allocator/move_assign.cc (test03): New.
+
 2014-09-24  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/63353
index 405d4b8..899f063 100644 (file)
@@ -297,28 +297,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }
 
 #if __cplusplus >= 201103L
-      /**
-       *  @brief  %Map move assignment operator.
-       *  @param  __x  A %map of identical element and allocator types.
-       *
-       *  The contents of @a __x are moved into this map (without copying
-       *  if the allocators compare equal or get moved on assignment).
-       *  Afterwards @a __x is in a valid, but unspecified state.
-       */
+      /// Move assignment operator.
       map&
-      operator=(map&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
-      {
-       if (!_M_t._M_move_assign(__x._M_t))
-         {
-           // The rvalue's allocator cannot be moved and is not equal,
-           // so we need to individually move each element.
-           clear();
-           insert(std::__make_move_if_noexcept_iterator(__x.begin()),
-                  std::__make_move_if_noexcept_iterator(__x.end()));
-           __x.clear();
-         }
-       return *this;
-      }
+      operator=(map&&) = default;
 
       /**
        *  @brief  %Map list assignment operator.
@@ -334,8 +315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       map&
       operator=(initializer_list<value_type> __l)
       {
-       this->clear();
-       this->insert(__l.begin(), __l.end());
+       _M_t._M_assign_unique(__l.begin(), __l.end());
        return *this;
       }
 #endif
index a73164e..ab0c59b 100644 (file)
@@ -292,28 +292,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }
 
 #if __cplusplus >= 201103L
-      /**
-       *  @brief  %Multimap move assignment operator.
-       *  @param  __x  A %multimap of identical element and allocator types.
-       *
-       *  The contents of @a __x are moved into this multimap (without copying
-       *  if the allocators compare equal or get moved on assignment).
-       *  Afterwards @a __x is in a valid, but unspecified state.
-       */
+      /// Move assignment operator.
       multimap&
-      operator=(multimap&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
-      {
-       if (!_M_t._M_move_assign(__x._M_t))
-         {
-           // The rvalue's allocator cannot be moved and is not equal,
-           // so we need to individually move each element.
-           clear();
-           insert(std::__make_move_if_noexcept_iterator(__x.begin()),
-                  std::__make_move_if_noexcept_iterator(__x.end()));
-           __x.clear();
-         }
-       return *this;
-      }
+      operator=(multimap&&) = default;
 
       /**
        *  @brief  %Multimap list assignment operator.
@@ -329,8 +310,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       multimap&
       operator=(initializer_list<value_type> __l)
       {
-       this->clear();
-       this->insert(__l.begin(), __l.end());
+       _M_t._M_assign_equal(__l.begin(), __l.end());
        return *this;
       }
 #endif
index f379aef..8b0dba1 100644 (file)
@@ -263,28 +263,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }
 
 #if __cplusplus >= 201103L
-      /**
-       *  @brief  %Multiset move assignment operator.
-       *  @param  __x  A %multiset of identical element and allocator types.
-       *
-       *  The contents of @a __x are moved into this %multiset (without
-       *  copying if the allocators compare equal or get moved on assignment).
-       *  Afterwards @a __x is in a valid, but unspecified state.
-       */
+      /// Move assignment operator.
       multiset&
-      operator=(multiset&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
-      {
-       if (!_M_t._M_move_assign(__x._M_t))
-         {
-           // The rvalue's allocator cannot be moved and is not equal,
-           // so we need to individually move each element.
-           clear();
-           insert(std::__make_move_if_noexcept_iterator(__x._M_t.begin()),
-                  std::__make_move_if_noexcept_iterator(__x._M_t.end()));
-           __x.clear();
-         }
-       return *this;
-      }
+      operator=(multiset&&) = default;
 
       /**
        *  @brief  %Multiset list assignment operator.
@@ -300,8 +281,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       multiset&
       operator=(initializer_list<value_type> __l)
       {
-       this->clear();
-       this->insert(__l.begin(), __l.end());
+       _M_t._M_assign_equal(__l.begin(), __l.end());
        return *this;
       }
 #endif
index 48dc761..53938ea 100644 (file)
@@ -267,28 +267,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       }
 
 #if __cplusplus >= 201103L
-      /**
-       *  @brief %Set move assignment operator.
-       *  @param __x  A %set of identical element and allocator types.
-       *
-       *  The contents of @a __x are moved into this %set (without copying
-       *  if the allocators compare equal or get moved on assignment).
-       *  Afterwards @a __x is in a valid, but unspecified state.
-       */
+      /// Move assignment operator.
       set&
-      operator=(set&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
-      {
-       if (!_M_t._M_move_assign(__x._M_t))
-         {
-           // The rvalue's allocator cannot be moved and is not equal,
-           // so we need to individually move each element.
-           clear();
-           insert(std::__make_move_if_noexcept_iterator(__x._M_t.begin()),
-                  std::__make_move_if_noexcept_iterator(__x._M_t.end()));
-           __x.clear();
-         }
-       return *this;
-      }
+      operator=(set&&) = default;
 
       /**
        *  @brief  %Set list assignment operator.
@@ -304,8 +285,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       set&
       operator=(initializer_list<value_type> __l)
       {
-       this->clear();
-       this->insert(__l.begin(), __l.end());
+       _M_t._M_assign_unique(__l.begin(), __l.end());
        return *this;
       }
 #endif
index cc9bf94..258579d 100644 (file)
@@ -355,6 +355,106 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     protected:
       typedef _Rb_tree_node_base*              _Base_ptr;
       typedef const _Rb_tree_node_base*        _Const_Base_ptr;
+      typedef _Rb_tree_node<_Val>*             _Link_type;
+      typedef const _Rb_tree_node<_Val>*       _Const_Link_type;
+
+    private:
+      // Functor recycling a pool of nodes and using allocation once the pool is
+      // empty.
+      struct _Reuse_or_alloc_node
+      {
+       _Reuse_or_alloc_node(const _Rb_tree_node_base& __header,
+                            _Rb_tree& __t)
+         : _M_root(__header._M_parent), _M_nodes(__header._M_right), _M_t(__t)
+       {
+         if (_M_root)
+           _M_root->_M_parent = 0;
+         else
+           _M_nodes = 0;
+       }
+
+#if __cplusplus >= 201103L
+       _Reuse_or_alloc_node(const _Reuse_or_alloc_node&) = delete;
+#endif
+
+       ~_Reuse_or_alloc_node()
+       { _M_t._M_erase(static_cast<_Link_type>(_M_root)); }
+
+       template<typename _Arg>
+         _Link_type
+#if __cplusplus < 201103L
+         operator()(const _Arg& __arg)
+#else
+         operator()(_Arg&& __arg)
+#endif
+         {
+           _Link_type __node = static_cast<_Link_type>(_M_extract());
+           if (__node)
+             {
+               _M_t._M_destroy_node(__node);
+               _M_t._M_construct_node(__node, _GLIBCXX_FORWARD(_Arg, __arg));
+               return __node;
+             }
+
+           return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg));
+         }
+
+      private:
+       _Base_ptr
+       _M_extract()
+       {
+         if (!_M_nodes)
+           return _M_nodes;
+
+         _Base_ptr __node = _M_nodes;
+         _M_nodes = _M_nodes->_M_parent;
+         if (_M_nodes)
+           {
+             if (_M_nodes->_M_right == __node)
+               {
+                 _M_nodes->_M_right = 0;
+
+                 if (_M_nodes->_M_left)
+                   {
+                     _M_nodes = _M_nodes->_M_left;
+
+                     while (_M_nodes->_M_right)
+                       _M_nodes = _M_nodes->_M_right;
+                   }
+               }
+             else // __node is on the left.
+               _M_nodes->_M_left = 0;
+           }
+         else
+           _M_root = 0;
+
+         return __node;
+       }
+
+       _Base_ptr _M_root;
+       _Base_ptr _M_nodes;
+       _Rb_tree& _M_t;
+      };
+
+      // Functor similar to the previous one but without any pool of node to
+      // recycle.
+      struct _Alloc_node
+      {
+       _Alloc_node(_Rb_tree& __t)
+         : _M_t(__t) { }
+
+       template<typename _Arg>
+         _Link_type
+#if __cplusplus < 201103L
+         operator()(const _Arg& __arg) const
+#else
+         operator()(_Arg&& __arg) const
+#endif
+         { return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg)); }
+
+      private:
+       _Rb_tree& _M_t;
+      };
 
     public:
       typedef _Key                             key_type;
@@ -363,8 +463,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef const value_type*                const_pointer;
       typedef value_type&                      reference;
       typedef const value_type&                const_reference;
-      typedef _Rb_tree_node<_Val>*             _Link_type;
-      typedef const _Rb_tree_node<_Val>*       _Const_Link_type;
       typedef size_t                           size_type;
       typedef ptrdiff_t                        difference_type;
       typedef _Alloc                           allocator_type;
@@ -391,44 +489,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { _Alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1); }
 
 #if __cplusplus < 201103L
-      _Link_type
-      _M_create_node(const value_type& __x)
+      void
+      _M_construct_node(_Link_type __node, const value_type& __x)
       {
-       _Link_type __tmp = _M_get_node();
        __try
-         { get_allocator().construct(__tmp->_M_valptr(), __x); }
+         { get_allocator().construct(__node->_M_valptr(), __x); }
        __catch(...)
          {
-           _M_put_node(__tmp);
+           _M_put_node(__node);
            __throw_exception_again;
          }
+      }
+
+      _Link_type
+      _M_create_node(const value_type& __x)
+      {
+       _Link_type __tmp = _M_get_node();
+       _M_construct_node(__tmp, __x);
        return __tmp;
       }
 
       void
       _M_destroy_node(_Link_type __p)
-      {
-       get_allocator().destroy(__p->_M_valptr());
-       _M_put_node(__p);
-      }
+      { get_allocator().destroy(__p->_M_valptr()); }
 #else
       template<typename... _Args>
-        _Link_type
-        _M_create_node(_Args&&... __args)
+       void
+       _M_construct_node(_Link_type __node, _Args&&... __args)
        {
-         _Link_type __tmp = _M_get_node();
          __try
            {
-             ::new(__tmp) _Rb_tree_node<_Val>;
+             ::new(__node) _Rb_tree_node<_Val>;
              _Alloc_traits::construct(_M_get_Node_allocator(),
-                                      __tmp->_M_valptr(),
+                                      __node->_M_valptr(),
                                       std::forward<_Args>(__args)...);
            }
          __catch(...)
            {
-             _M_put_node(__tmp);
+             __node->~_Rb_tree_node<_Val>();
+             _M_put_node(__node);
              __throw_exception_again;
            }
+       }
+
+      template<typename... _Args>
+        _Link_type
+        _M_create_node(_Args&&... __args)
+       {
+         _Link_type __tmp = _M_get_node();
+         _M_construct_node(__tmp, std::forward<_Args>(__args)...);
          return __tmp;
        }
 
@@ -437,23 +546,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
        _Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr());
        __p->~_Rb_tree_node<_Val>();
-       _M_put_node(__p);
       }
 #endif
 
-      _Link_type
-      _M_clone_node(_Const_Link_type __x)
+      void
+      _M_drop_node(_Link_type __p) _GLIBCXX_NOEXCEPT
       {
-       _Link_type __tmp = _M_create_node(*__x->_M_valptr());
-       __tmp->_M_color = __x->_M_color;
-       __tmp->_M_left = 0;
-       __tmp->_M_right = 0;
-       return __tmp;
+       _M_destroy_node(__p);
+       _M_put_node(__p);
       }
 
+      template<typename _NodeGen>
+       _Link_type
+       _M_clone_node(_Const_Link_type __x, _NodeGen& __node_gen)
+       {
+         _Link_type __tmp = __node_gen(*__x->_M_valptr());
+         __tmp->_M_color = __x->_M_color;
+         __tmp->_M_left = 0;
+         __tmp->_M_right = 0;
+         return __tmp;
+       }
+
     protected:
-      template<typename _Key_compare, 
-              bool _Is_pod_comparator = __is_pod(_Key_compare)>
+      // Unused _Is_pod_comparator is kept as it is part of mangled name.
+      template<typename _Key_compare,
+              bool /* _Is_pod_comparator */ = __is_pod(_Key_compare)>
         struct _Rb_tree_impl : public _Node_allocator
         {
          _Key_compare          _M_key_compare;
@@ -477,6 +594,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          { _M_initialize(); }
 #endif
 
+         void
+         _M_reset()
+         {
+           this->_M_header._M_parent = 0;
+           this->_M_header._M_left = &this->_M_header;
+           this->_M_header._M_right = &this->_M_header;
+           this->_M_node_count = 0;
+         }
+
        private:
          void
          _M_initialize()
@@ -605,9 +731,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                   const key_type& __k);
 
 #if __cplusplus >= 201103L
-      template<typename _Arg>
+      template<typename _Arg, typename _NodeGen>
         iterator
-        _M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v);
+       _M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v, _NodeGen&);
 
       iterator
       _M_insert_node(_Base_ptr __x, _Base_ptr __y, _Link_type __z);
@@ -626,9 +752,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       iterator
       _M_insert_equal_lower_node(_Link_type __z);
 #else
-      iterator
-      _M_insert_(_Base_ptr __x, _Base_ptr __y,
-                const value_type& __v);
+      template<typename _NodeGen>
+       iterator
+       _M_insert_(_Base_ptr __x, _Base_ptr __y,
+                  const value_type& __v, _NodeGen&);
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 233. Insertion hints in associative containers.
@@ -639,8 +766,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_insert_equal_lower(const value_type& __x);
 #endif
 
+      template<typename _NodeGen>
+       _Link_type
+       _M_copy(_Const_Link_type __x, _Link_type __p, _NodeGen&);
+
       _Link_type
-      _M_copy(_Const_Link_type __x, _Link_type __p);
+      _M_copy(_Const_Link_type __x, _Link_type __p)
+      {
+       _Alloc_node __an(*this);
+       return _M_copy(__x, __p, __an);
+      }
 
       void
       _M_erase(_Link_type __x);
@@ -690,7 +825,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Rb_tree(const _Rb_tree& __x, const allocator_type& __a)
       : _M_impl(__x._M_impl._M_key_compare, _Node_allocator(__a))
       {
-       if (__x._M_root() != 0)
+       if (__x._M_root() != nullptr)
          {
            _M_root() = _M_copy(__x._M_begin(), _M_end());
            _M_leftmost() = _S_minimum(_M_root());
@@ -794,13 +929,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         iterator
         _M_insert_equal(_Arg&& __x);
 
-      template<typename _Arg>
+      template<typename _Arg, typename _NodeGen>
         iterator
-        _M_insert_unique_(const_iterator __position, _Arg&& __x);
+       _M_insert_unique_(const_iterator __pos, _Arg&& __x, _NodeGen&);
 
       template<typename _Arg>
-        iterator
-        _M_insert_equal_(const_iterator __position, _Arg&& __x);
+       iterator
+       _M_insert_unique_(const_iterator __pos, _Arg&& __x)
+       {
+         _Alloc_node __an(*this);
+         return _M_insert_unique_(__pos, std::forward<_Arg>(__x), __an);
+       }
+
+      template<typename _Arg, typename _NodeGen>
+       iterator
+       _M_insert_equal_(const_iterator __pos, _Arg&& __x, _NodeGen&);
+
+      template<typename _Arg>
+       iterator
+       _M_insert_equal_(const_iterator __pos, _Arg&& __x)
+       {
+         _Alloc_node __an(*this);
+         return _M_insert_equal_(__pos, std::forward<_Arg>(__x), __an);
+       }
 
       template<typename... _Args>
        pair<iterator, bool>
@@ -824,11 +975,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       iterator
       _M_insert_equal(const value_type& __x);
 
+      template<typename _NodeGen>
+       iterator
+       _M_insert_unique_(const_iterator __pos, const value_type& __x,
+                         _NodeGen&);
+
       iterator
-      _M_insert_unique_(const_iterator __position, const value_type& __x);
+      _M_insert_unique_(const_iterator __pos, const value_type& __x)
+      {
+       _Alloc_node __an(*this);
+       return _M_insert_unique_(__pos, __x, __an);
+      }
 
+      template<typename _NodeGen>
+       iterator
+       _M_insert_equal_(const_iterator __pos, const value_type& __x,
+                        _NodeGen&);
       iterator
-      _M_insert_equal_(const_iterator __position, const value_type& __x);
+      _M_insert_equal_(const_iterator __pos, const value_type& __x)
+      {
+       _Alloc_node __an(*this);
+       return _M_insert_equal_(__pos, __x, __an);
+      }
 #endif
 
       template<typename _InputIterator>
@@ -908,10 +1076,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       clear() _GLIBCXX_NOEXCEPT
       {
         _M_erase(_M_begin());
-        _M_leftmost() = _M_end();
-        _M_root() = 0;
-        _M_rightmost() = _M_end();
-        _M_impl._M_node_count = 0;
+       _M_impl._M_reset();
       }
 
       // Set operations.
@@ -951,8 +1116,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __rb_verify() const;
 
 #if __cplusplus >= 201103L
-      bool
-      _M_move_assign(_Rb_tree&);
+      _Rb_tree&
+      operator=(_Rb_tree&&) noexcept(_Alloc_traits::_S_nothrow_move());
+
+      template<typename _Iterator>
+       void
+       _M_assign_unique(_Iterator, _Iterator);
+
+      template<typename _Iterator>
+       void
+       _M_assign_equal(_Iterator, _Iterator);
 
     private:
       // Move elements from container with equal allocator.
@@ -1029,7 +1202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : _M_impl(__x._M_impl._M_key_compare, std::move(__a))
     {
       using __eq = integral_constant<bool, _Alloc_traits::_S_always_equal()>;
-      if (__x._M_root() != 0)
+      if (__x._M_root() != nullptr)
        _M_move_data(__x, __eq());
     }
 
@@ -1062,7 +1235,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_move_data(__x, std::true_type());
       else
        {
-         _M_root() = _M_copy(__x._M_begin(), _M_end());
+         _Alloc_node __an(*this);
+         auto __lbd =
+           [&__an](const value_type& __cval)
+           {
+             auto& __val = const_cast<value_type&>(__cval);
+             return __an(std::move_if_noexcept(__val));
+           };
+         _M_root() = _M_copy(__x._M_begin(), _M_end(), __lbd);
          _M_leftmost() = _S_minimum(_M_root());
          _M_rightmost() = _S_maximum(_M_root());
          _M_impl._M_node_count = __x._M_impl._M_node_count;
@@ -1071,9 +1251,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
-    bool
+    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&
     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
-    _M_move_assign(_Rb_tree& __x)
+    operator=(_Rb_tree&& __x)
+    noexcept(_Alloc_traits::_S_nothrow_move())
     {
       _M_impl._M_key_compare = __x._M_impl._M_key_compare;
       if (_Alloc_traits::_S_propagate_on_move_assign()
@@ -1081,14 +1262,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          || _M_get_Node_allocator() == __x._M_get_Node_allocator())
        {
          clear();
-         if (__x._M_root() != 0)
+         if (__x._M_root() != nullptr)
            _M_move_data(__x, std::true_type());
          std::__alloc_on_move(_M_get_Node_allocator(),
                               __x._M_get_Node_allocator());
-         return true;
+         return *this;
+       }
+
+      // Try to move each node reusing existing nodes and copying __x nodes
+      // structure.
+      _Reuse_or_alloc_node __roan(_M_impl._M_header, *this);
+      _M_impl._M_reset();
+      if (__x._M_root() != nullptr)
+       {
+         auto __lbd =
+           [&__roan](const value_type& __cval)
+           {
+             auto& __val = const_cast<value_type&>(__cval);
+             return __roan(std::move_if_noexcept(__val));
+           };
+         _M_root() = _M_copy(__x._M_begin(), _M_end(), __lbd);
+         _M_leftmost() = _S_minimum(_M_root());
+         _M_rightmost() = _S_maximum(_M_root());
+         _M_impl._M_node_count = __x._M_impl._M_node_count;
+         __x.clear();
        }
-      return false;
+      return *this;
     }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+           typename _Compare, typename _Alloc>
+    template<typename _Iterator>
+      void
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_assign_unique(_Iterator __first, _Iterator __last)
+      {
+       _Reuse_or_alloc_node __roan(this->_M_impl._M_header, *this);
+       _M_impl._M_reset();
+       for (; __first != __last; ++__first)
+         _M_insert_unique_(end(), *__first, __roan);
+      }
+
+  template<typename _Key, typename _Val, typename _KeyOfValue,
+           typename _Compare, typename _Alloc>
+    template<typename _Iterator>
+      void
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_assign_equal(_Iterator __first, _Iterator __last)
+      {
+       _Reuse_or_alloc_node __roan(this->_M_impl._M_header, *this);
+       _M_impl._M_reset();
+       for (; __first != __last; ++__first)
+         _M_insert_equal_(end(), *__first, __roan);
+      }
 #endif
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1100,7 +1326,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (this != &__x)
        {
          // Note that _Key may be a constant type.
-         clear();
 #if __cplusplus >= 201103L
          if (_Alloc_traits::_S_propagate_on_copy_assign())
            {
@@ -1109,46 +1334,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              if (!_Alloc_traits::_S_always_equal()
                  && __this_alloc != __that_alloc)
                {
+                 // Replacement allocator cannot free existing storage, we need
+                 // to erase nodes first.
+                 clear();
                  std::__alloc_on_copy(__this_alloc, __that_alloc);
                }
            }
 #endif
+
+         _Reuse_or_alloc_node __roan(this->_M_impl._M_header, *this);
+         _M_impl._M_reset();
          _M_impl._M_key_compare = __x._M_impl._M_key_compare;
          if (__x._M_root() != 0)
            {
-             _M_root() = _M_copy(__x._M_begin(), _M_end());
+             _M_root() = _M_copy(__x._M_begin(), _M_end(), __roan);
              _M_leftmost() = _S_minimum(_M_root());
              _M_rightmost() = _S_maximum(_M_root());
              _M_impl._M_node_count = __x._M_impl._M_node_count;
            }
        }
+
       return *this;
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
-    template<typename _Arg>
+    template<typename _Arg, typename _NodeGen>
+#else
+    template<typename _NodeGen>
 #endif
-    typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_insert_(_Base_ptr __x, _Base_ptr __p,
 #if __cplusplus >= 201103L
-    _M_insert_(_Base_ptr __x, _Base_ptr __p, _Arg&& __v)
+                _Arg&& __v,
 #else
-    _M_insert_(_Base_ptr __x, _Base_ptr __p, const _Val& __v)
+                const _Val& __v,
 #endif
-    {
-      bool __insert_left = (__x != 0 || __p == _M_end()
-                           || _M_impl._M_key_compare(_KeyOfValue()(__v),
-                                                     _S_key(__p)));
+                _NodeGen& __node_gen)
+      {
+       bool __insert_left = (__x != 0 || __p == _M_end()
+                             || _M_impl._M_key_compare(_KeyOfValue()(__v),
+                                                       _S_key(__p)));
 
-      _Link_type __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v));
+       _Link_type __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v));
 
-      _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
-                                   this->_M_impl._M_header);
-      ++_M_impl._M_node_count;
-      return iterator(__z);
-    }
+       _Rb_tree_insert_and_rebalance(__insert_left, __z, __p,
+                                     this->_M_impl._M_header);
+       ++_M_impl._M_node_count;
+       return iterator(__z);
+      }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
@@ -1200,40 +1436,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Key, typename _Val, typename _KoV,
-           typename _Compare, typename _Alloc>
-    typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Link_type
-    _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::
-    _M_copy(_Const_Link_type __x, _Link_type __p)
-    {
-      // Structural copy.  __x and __p must be non-null.
-      _Link_type __top = _M_clone_node(__x);
-      __top->_M_parent = __p;
-
-      __try
-       {
-         if (__x->_M_right)
-           __top->_M_right = _M_copy(_S_right(__x), __top);
-         __p = __top;
-         __x = _S_left(__x);
+          typename _Compare, typename _Alloc>
+    template<typename _NodeGen>
+      typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Link_type
+      _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::
+      _M_copy(_Const_Link_type __x, _Link_type __p, _NodeGen& __node_gen)
+      {
+       // Structural copy. __x and __p must be non-null.
+       _Link_type __top = _M_clone_node(__x, __node_gen);
+       __top->_M_parent = __p;
 
-         while (__x != 0)
-           {
-             _Link_type __y = _M_clone_node(__x);
-             __p->_M_left = __y;
-             __y->_M_parent = __p;
-             if (__x->_M_right)
-               __y->_M_right = _M_copy(_S_right(__x), __y);
-             __p = __y;
-             __x = _S_left(__x);
-           }
-       }
-      __catch(...)
-       {
-         _M_erase(__top);
-         __throw_exception_again;
-       }
-      return __top;
-    }
+       __try
+         {
+           if (__x->_M_right)
+             __top->_M_right = _M_copy(_S_right(__x), __top, __node_gen);
+           __p = __top;
+           __x = _S_left(__x);
+
+           while (__x != 0)
+             {
+               _Link_type __y = _M_clone_node(__x, __node_gen);
+               __p->_M_left = __y;
+               __y->_M_parent = __p;
+               if (__x->_M_right)
+                 __y->_M_right = _M_copy(_S_right(__x), __y, __node_gen);
+               __p = __y;
+               __x = _S_left(__x);
+             }
+         }
+       __catch(...)
+         {
+           _M_erase(__top);
+           __throw_exception_again;
+         }
+       return __top;
+      }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
@@ -1246,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        {
          _M_erase(_S_right(__x));
          _Link_type __y = _S_left(__x);
-         _M_destroy_node(__x);
+         _M_drop_node(__x);
          __x = __y;
        }
     }
@@ -1394,10 +1631,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              _M_leftmost() = __t._M_leftmost();
              _M_rightmost() = __t._M_rightmost();
              _M_root()->_M_parent = _M_end();
+             _M_impl._M_node_count = __t._M_impl._M_node_count;
              
-             __t._M_root() = 0;
-             __t._M_leftmost() = __t._M_end();
-             __t._M_rightmost() = __t._M_end();
+             __t._M_impl._M_reset();
            }
        }
       else if (__t._M_root() == 0)
@@ -1406,10 +1642,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          __t._M_leftmost() = _M_leftmost();
          __t._M_rightmost() = _M_rightmost();
          __t._M_root()->_M_parent = __t._M_end();
+         __t._M_impl._M_node_count = _M_impl._M_node_count;
          
-         _M_root() = 0;
-         _M_leftmost() = _M_end();
-         _M_rightmost() = _M_end();
+         _M_impl._M_reset();
        }
       else
        {
@@ -1419,9 +1654,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          
          _M_root()->_M_parent = _M_end();
          __t._M_root()->_M_parent = __t._M_end();
+         std::swap(this->_M_impl._M_node_count, __t._M_impl._M_node_count);
        }
       // No need to swap header's color as it does not change.
-      std::swap(this->_M_impl._M_node_count, __t._M_impl._M_node_count);
       std::swap(this->_M_impl._M_key_compare, __t._M_impl._M_key_compare);
 
       _Alloc_traits::_S_on_swap(_M_get_Node_allocator(),
@@ -1500,9 +1735,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        = _M_get_insert_unique_pos(_KeyOfValue()(__v));
 
       if (__res.second)
-       return _Res(_M_insert_(__res.first, __res.second,
-                              _GLIBCXX_FORWARD(_Arg, __v)),
-                   true);
+       {
+         _Alloc_node __an(*this);
+         return _Res(_M_insert_(__res.first, __res.second,
+                                _GLIBCXX_FORWARD(_Arg, __v), __an),
+                     true);
+       }
 
       return _Res(iterator(static_cast<_Link_type>(__res.first)), false);
     }
@@ -1522,7 +1760,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       pair<_Base_ptr, _Base_ptr> __res
        = _M_get_insert_equal_pos(_KeyOfValue()(__v));
-      return _M_insert_(__res.first, __res.second, _GLIBCXX_FORWARD(_Arg, __v));
+      _Alloc_node __an(*this);
+      return _M_insert_(__res.first, __res.second,
+                       _GLIBCXX_FORWARD(_Arg, __v), __an);
     }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1587,22 +1827,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
-    template<typename _Arg>
+    template<typename _Arg, typename _NodeGen>
+#else
+    template<typename _NodeGen>
 #endif
-    typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_insert_unique_(const_iterator __position,
 #if __cplusplus >= 201103L
-    _M_insert_unique_(const_iterator __position, _Arg&& __v)
+                       _Arg&& __v,
 #else
-    _M_insert_unique_(const_iterator __position, const _Val& __v)
+                       const _Val& __v,
 #endif
+                       _NodeGen& __node_gen)
     {
       pair<_Base_ptr, _Base_ptr> __res
        = _M_get_insert_hint_unique_pos(__position, _KeyOfValue()(__v));
 
       if (__res.second)
        return _M_insert_(__res.first, __res.second,
-                         _GLIBCXX_FORWARD(_Arg, __v));
+                         _GLIBCXX_FORWARD(_Arg, __v),
+                         __node_gen);
       return iterator(static_cast<_Link_type>(__res.first));
     }
 
@@ -1664,25 +1909,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Key, typename _Val, typename _KeyOfValue,
            typename _Compare, typename _Alloc>
 #if __cplusplus >= 201103L
-    template<typename _Arg>
+    template<typename _Arg, typename _NodeGen>
+#else
+    template<typename _NodeGen>
 #endif
-    typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
-    _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
+      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
+      _M_insert_equal_(const_iterator __position,
 #if __cplusplus >= 201103L
-    _M_insert_equal_(const_iterator __position, _Arg&& __v)
+                      _Arg&& __v,
 #else
-    _M_insert_equal_(const_iterator __position, const _Val& __v)
+                      const _Val& __v,
 #endif
-    {
-      pair<_Base_ptr, _Base_ptr> __res
-       = _M_get_insert_hint_equal_pos(__position, _KeyOfValue()(__v));
+                      _NodeGen& __node_gen)
+      {
+       pair<_Base_ptr, _Base_ptr> __res
+         = _M_get_insert_hint_equal_pos(__position, _KeyOfValue()(__v));
 
-      if (__res.second)
-       return _M_insert_(__res.first, __res.second,
-                         _GLIBCXX_FORWARD(_Arg, __v));
+       if (__res.second)
+         return _M_insert_(__res.first, __res.second,
+                           _GLIBCXX_FORWARD(_Arg, __v),
+                           __node_gen);
 
-      return _M_insert_equal_lower(_GLIBCXX_FORWARD(_Arg, __v));
-    }
+       return _M_insert_equal_lower(_GLIBCXX_FORWARD(_Arg, __v));
+      }
 
 #if __cplusplus >= 201103L
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1751,12 +2001,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            if (__res.second)
              return _Res(_M_insert_node(__res.first, __res.second, __z), true);
        
-           _M_destroy_node(__z);
+           _M_drop_node(__z);
            return _Res(iterator(static_cast<_Link_type>(__res.first)), false);
          }
        __catch(...)
          {
-           _M_destroy_node(__z);
+           _M_drop_node(__z);
            __throw_exception_again;
          }
       }
@@ -1777,7 +2027,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          }
        __catch(...)
          {
-           _M_destroy_node(__z);
+           _M_drop_node(__z);
            __throw_exception_again;
          }
       }
@@ -1798,12 +2048,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            if (__res.second)
              return _M_insert_node(__res.first, __res.second, __z);
 
-           _M_destroy_node(__z);
+           _M_drop_node(__z);
            return iterator(static_cast<_Link_type>(__res.first));
          }
        __catch(...)
          {
-           _M_destroy_node(__z);
+           _M_drop_node(__z);
            __throw_exception_again;
          }
       }
@@ -1828,7 +2078,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          }
        __catch(...)
          {
-           _M_destroy_node(__z);
+           _M_drop_node(__z);
            __throw_exception_again;
          }
       }
@@ -1841,8 +2091,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Rb_tree<_Key, _Val, _KoV, _Cmp, _Alloc>::
       _M_insert_unique(_II __first, _II __last)
       {
+       _Alloc_node __an(*this);
        for (; __first != __last; ++__first)
-         _M_insert_unique_(end(), *__first);
+         _M_insert_unique_(end(), *__first, __an);
       }
 
   template<typename _Key, typename _Val, typename _KoV,
@@ -1852,8 +2103,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Rb_tree<_Key, _Val, _KoV, _Cmp, _Alloc>::
       _M_insert_equal(_II __first, _II __last)
       {
+       _Alloc_node __an(*this);
        for (; __first != __last; ++__first)
-         _M_insert_equal_(end(), *__first);
+         _M_insert_equal_(end(), *__first, __an);
       }
 
   template<typename _Key, typename _Val, typename _KeyOfValue,
@@ -1866,7 +2118,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        static_cast<_Link_type>(_Rb_tree_rebalance_for_erase
                                (const_cast<_Base_ptr>(__position._M_node),
                                 this->_M_impl._M_header));
-      _M_destroy_node(__y);
+      _M_drop_node(__y);
       --_M_impl._M_node_count;
     }
 
index 2dc69ea..ea914cb 100644 (file)
@@ -59,9 +59,33 @@ void test02()
   VERIFY(1 == v2.get_allocator().get_personality());
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<std::pair<const int, int>> alloc_type;
+  typedef std::map<int, int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1 = { { 0, 0 }, { 1, 1 } };
+  test_type v2 = { { 2, 2 }, { 3, 3 } };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  v1 = v2;
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/map/allocator/init-list.cc b/libstdc++-v3/testsuite/23_containers/map/allocator/init-list.cc
new file mode 100644 (file)
index 0000000..d33d10d
--- /dev/null
@@ -0,0 +1,55 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+//
+
+// { dg-options "-std=gnu++11" }
+
+#include <map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<std::pair<const int, int>> alloc_type;
+  typedef std::map<int, int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1;
+  v1 = { { 0, 0 }, { 1, 1 } };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  VERIFY( allocs != 0 );
+  VERIFY( constructs != 0 );
+
+  // Check no allocation on list initialization.
+  v1 = { { 4, 4 }, { 5, 5 } };
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
+int main()
+{
+  test01();
+}
index 3a8f1f1..167e87d 100644 (file)
@@ -43,8 +43,8 @@ void test01()
   v2 = { test_type::value_type{} };
   v2 = std::move(v1);
 
-  VERIFY(1 == v1.get_allocator().get_personality());
-  VERIFY(2 == v2.get_allocator().get_personality());
+  VERIFY( 1 == v1.get_allocator().get_personality() );
+  VERIFY( 2 == v2.get_allocator().get_personality() );
 }
 
 void test02()
@@ -60,14 +60,47 @@ void test02()
   v2 = { test_type::value_type{} };
   v2 = std::move(v1);
 
-  VERIFY(0 == v1.get_allocator().get_personality());
-  VERIFY(1 == v2.get_allocator().get_personality());
+  VERIFY( 0 == v1.get_allocator().get_personality() );
+  VERIFY( 1 == v2.get_allocator().get_personality() );
   VERIFY( it == v2.begin() );
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef propagating_allocator<std::pair<const int, int>, false,
+                               tracker_allocator<std::pair<const int, int>>>
+    alloc_type;
+  typedef std::map<int, int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1(alloc_type(1));
+  v1 = { { 0, 0 }, { 1, 1 } };
+
+  test_type v2(alloc_type(2));
+  v2 = { { 2, 2 }, { 3, 3 } };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  // Check no allocation on move assignment with non propagating allocators.
+  v1 = std::move(v2);
+
+  VERIFY( 1 == v1.get_allocator().get_personality() );
+  VERIFY( 2 == v2.get_allocator().get_personality() );
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
index 4c9c371..ee841a3 100644 (file)
@@ -59,9 +59,33 @@ void test02()
   VERIFY(1 == v2.get_allocator().get_personality());
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<std::pair<const int, int>> alloc_type;
+  typedef std::multimap<int, int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1 = { { 1, 1 }, { 1, 1 } };
+  test_type v2 = { { 2, 2 }, { 2, 2 } };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  v1 = v2;
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/allocator/init-list.cc b/libstdc++-v3/testsuite/23_containers/multimap/allocator/init-list.cc
new file mode 100644 (file)
index 0000000..c2241b4
--- /dev/null
@@ -0,0 +1,55 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+//
+
+// { dg-options "-std=gnu++11" }
+
+#include <map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<std::pair<const int, int>> alloc_type;
+  typedef std::multimap<int, int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1;
+  v1 = { { 0, 0 }, { 0, 0 } };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  VERIFY( allocs != 0 );
+  VERIFY( constructs != 0 );
+
+  // Check no allocation on list initialization.
+  v1 = { { 1, 1 }, { 1, 1 } };
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
+int main()
+{
+  test01();
+}
index 6b13861..11b5e35 100644 (file)
@@ -61,9 +61,42 @@ void test02()
   VERIFY( it == v2.begin()  );
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef propagating_allocator<std::pair<const int, int>, false,
+                               tracker_allocator<std::pair<const int, int>>>
+    alloc_type;
+  typedef std::multimap<int, int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1(alloc_type(1));
+  v1 = { { 1, 1 }, { 1, 1 } };
+
+  test_type v2(alloc_type(2));
+  v2 = { { 2, 2 }, { 2, 2 } };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  // Check no allocation on move assignment with non propagating allocators.
+  v1 = std::move(v2);
+
+  VERIFY( 1 == v1.get_allocator().get_personality() );
+  VERIFY( 2 == v2.get_allocator().get_personality() );
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
index 140af8c..f5921ab 100644 (file)
@@ -57,9 +57,33 @@ void test02()
   VERIFY(1 == v2.get_allocator().get_personality());
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<int> alloc_type;
+  typedef std::multiset<int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1 = { 0, 0 };
+  test_type v2 = { 1, 1 };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  v1 = v2;
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/allocator/init-list.cc b/libstdc++-v3/testsuite/23_containers/multiset/allocator/init-list.cc
new file mode 100644 (file)
index 0000000..a657ae0
--- /dev/null
@@ -0,0 +1,55 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+//
+
+// { dg-options "-std=gnu++11" }
+
+#include <set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<int> alloc_type;
+  typedef std::multiset<int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1;
+  v1 = { 0, 0 };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  VERIFY( allocs != 0 );
+  VERIFY( constructs != 0 );
+
+  // Check no allocation on list initialization.
+  v1 = { 1, 1 };
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
+int main()
+{
+  test01();
+}
index 956f885..405aff1 100644 (file)
@@ -59,9 +59,40 @@ void test02()
   VERIFY( it == v2.begin() );
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef propagating_allocator<int, false, tracker_allocator<int>> alloc_type;
+  typedef std::multiset<int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1(alloc_type(1));
+  v1 = { 0, 0 };
+
+  test_type v2(alloc_type(2));
+  v2 = { 2, 2 };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  // Check no allocation on move assignment with non propagating allocators.
+  v1 = std::move(v2);
+
+  VERIFY( 1 == v1.get_allocator().get_personality() );
+  VERIFY( 2 == v2.get_allocator().get_personality() );
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
index 0e13d15..1176a70 100644 (file)
@@ -57,9 +57,33 @@ void test02()
   VERIFY(1 == v2.get_allocator().get_personality());
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<int> alloc_type;
+  typedef std::set<int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1 = { 0, 1 };
+  test_type v2 = { 2, 3 };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  v1 = v2;
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/23_containers/set/allocator/init-list.cc b/libstdc++-v3/testsuite/23_containers/set/allocator/init-list.cc
new file mode 100644 (file)
index 0000000..1c39da2
--- /dev/null
@@ -0,0 +1,55 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+//
+
+// { dg-options "-std=gnu++11" }
+
+#include <set>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef tracker_allocator<int> alloc_type;
+  typedef std::set<int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1;
+  v1 = { 0, 1 };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  VERIFY( allocs != 0 );
+  VERIFY( constructs != 0 );
+
+  // Check no allocation on list initialization.
+  v1 = { 4, 5 };
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
+int main()
+{
+  test01();
+}
index 416e0b4..f4d02e8 100644 (file)
@@ -59,9 +59,40 @@ void test02()
   VERIFY( it == v2.begin() );
 }
 
+void test03()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace __gnu_test;
+
+  typedef propagating_allocator<int, false, tracker_allocator<int>> alloc_type;
+  typedef std::set<int, std::less<int>, alloc_type> test_type;
+
+  tracker_allocator_counter::reset();
+
+  test_type v1(alloc_type(1));
+  v1 = { 0, 1 };
+
+  test_type v2(alloc_type(2));
+  v2 = { 2, 3 };
+
+  auto allocs = tracker_allocator_counter::get_allocation_count();
+  auto constructs = tracker_allocator_counter::get_construct_count();
+
+  // Check no allocation on move assignment with non propagating allocators.
+  v1 = std::move(v2);
+
+  VERIFY( 1 == v1.get_allocator().get_personality() );
+  VERIFY( 2 == v2.get_allocator().get_personality() );
+
+  VERIFY( tracker_allocator_counter::get_allocation_count() == allocs );
+  VERIFY( tracker_allocator_counter::get_construct_count() == constructs + 2 );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }