This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Deque... (Re: [Patch] libstdc++/23425)


Howard Hinnant wrote:

>>> FYI, I'm working on this. It looks like, we are already using the
>>> optimization for deque::clear() and we are not for
>>> deque::erase(iterator, iterator). It seems to me that we should just
>>> take out the code in clear() which implements the double loop pattern
>>> and call it from both. Which in fact would be _M_erase_at_end or
>>> _M_erase_at_begin ;) ...
>>
>> ... and of course, going to loops over plain pointers, instead of
>> deque::iterators means that _Destroy will be optimized very, very well
>> by the compiler, similarly to what happens for vector! (especially 
>> so if
>> we overload it for random access iterators)
>>
>> :-)
>
> Thanks Paolo!

So, finally... Here is what I have, taking shape... Exactly as per
Howard's suggestions, the basic ideas are:
1- Consistently use _M_erase_at_begin/_M_erase_at_end and avoid calling
move/copy unnecessarily.
2- Consistently use the "segmented iterator" optimization, when nothing
better is available, that is, when _Destroy(iterator, iterator) doesn't
boil down for sure to nothing (see _M_destroy_data_aux).

I have verified from dumps that the loops over pointers produced by 2-
are optimized to empty loops as expected, even to nothing if _Destroy is
overloaded for random access iterators (but probably the additional
overloads can wait because the loop optimizer will be improved and we
have a PR about that opened by Chris, 23361). And of course that
otherwise the dumps are as good or better than current mainline ;)

Testcases ran through valgrind.

Anyone can spot something wrong? Otherwise I will probably go ahead for v7.

Paolo.

//////////////////
2005-11-26  Paolo Carlini  <pcarlini@suse.de>

	* include/bits/stl_deque.h (deque<>::_M_erase_at_end,
	_M_erase_at_begin, _M_destroy_data, _M_destroy_data_dispatch,
	_M_destroy_data_aux): New, optimize erase at begin() / end() and
	consistently use the "segmented iterator" optimization.
	(deque<>::~deque(), resize, clear, _M_assign_aux, _M_fill_assign):
	Use the above.
	* include/bits/deque.tcc (deque<>::operator=, _M_assign_aux): Same.
	(erase(iterator, iterator)): Likewise, clean-up.
	(erase(iterator)): Tweak, don't call __move unnecessarily. 
	(_M_destroy_data_aux): Define.
	* testsuite/23_containers/deque/modifiers/erase/1.cc: New.
	* testsuite/23_containers/deque/modifiers/erase/2.cc: Likewise.

	* testsuite/23_containers/vector/modifiers/erase/1.cc: Extend.
Index: include/bits/stl_deque.h
===================================================================
--- include/bits/stl_deque.h	(revision 106945)
+++ include/bits/stl_deque.h	(working copy)
@@ -735,8 +735,7 @@
        *  way.  Managing the pointer is the user's responsibilty.
        */
       ~deque()
-      { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-		      _M_get_Tp_allocator()); }
+      { _M_destroy_data(begin(), end(), _M_get_Tp_allocator()); }
 
       /**
        *  @brief  %Deque assignment operator.
@@ -901,7 +900,7 @@
       {
 	const size_type __len = size();
 	if (__new_size < __len)
-	  erase(this->_M_impl._M_start + __new_size, this->_M_impl._M_finish);
+	  _M_erase_at_end(this->_M_impl._M_start + __new_size);
 	else
 	  insert(this->_M_impl._M_finish, __new_size - __len, __x);
       }
@@ -1268,7 +1267,9 @@
        *  pointed-to memory is not touched in any way.  Managing the pointer is
        *  the user's responsibilty.
        */
-      void clear();
+      void
+      clear()
+      { _M_erase_at_end(begin()); }
 
     protected:
       // Internal constructor functions follow.
@@ -1378,7 +1379,7 @@
 	      insert(end(), __mid, __last);
 	    }
 	  else
-	    erase(std::copy(__first, __last, begin()), end());
+	    _M_erase_at_end(std::copy(__first, __last, begin()));
 	}
 
       // Called by assign(n,t), and the range assign when it turns out
@@ -1393,7 +1394,7 @@
 	  }
 	else
 	  {
-	    erase(begin() + __n, end());
+	    _M_erase_at_end(begin() + __n);
 	    std::fill(begin(), end(), __val);
 	  }
       }
@@ -1406,9 +1407,12 @@
        */
       template<typename _Value_type>
 	void _M_push_back_aux(const _Value_type&);
+
       template<typename _Value_type>
 	void _M_push_front_aux(const _Value_type&);
+
       void _M_pop_back_aux();
+
       void _M_pop_front_aux();
       //@}
 
@@ -1470,6 +1474,54 @@
 		      _ForwardIterator __first, _ForwardIterator __last,
 		      size_type __n);
 
+
+      // Internal erase functions follow.
+
+      void
+      _M_destroy_data_aux(iterator __first, iterator __last);
+
+      void
+      _M_destroy_data_dispatch(iterator, iterator, __true_type) { }
+      
+      void
+      _M_destroy_data_dispatch(iterator __first, iterator __last, __false_type)
+      { _M_destroy_data_aux(__first, __last); }
+
+      // Called by ~deque().
+      // NB: Doesn't deallocate the nodes.
+      template<typename _Alloc1>
+        void
+        _M_destroy_data(iterator __first, iterator __last, _Alloc1)
+        { _M_destroy_data_aux(__first, __last); }
+
+      void
+      _M_destroy_data(iterator __first, iterator __last, std::allocator<_Tp>)
+      {
+	typedef typename std::__is_scalar<value_type>::__type
+	  _Has_trivial_destructor;
+	_M_destroy_data_dispatch(__first, __last, _Has_trivial_destructor());
+      }
+
+      // Called by erase(q1, q2).
+      void
+      _M_erase_at_begin(iterator __pos)
+      {
+	_M_destroy_data(begin(), __pos, _M_get_Tp_allocator());
+	_M_destroy_nodes(this->_M_impl._M_start._M_node, __pos._M_node);
+	this->_M_impl._M_start = __pos;
+      }
+
+      // Called by erase(q1, q2), resize(), clear(), _M_assign_aux,
+      // _M_fill_assign, operator=.
+      void
+      _M_erase_at_end(iterator __pos)
+      {
+	_M_destroy_data(__pos, end(), _M_get_Tp_allocator());
+	_M_destroy_nodes(__pos._M_node + 1,
+			 this->_M_impl._M_finish._M_node + 1);
+	this->_M_impl._M_finish = __pos;
+      }
+
       //@{
       /**
        *  @if maint
Index: include/bits/deque.tcc
===================================================================
--- include/bits/deque.tcc	(revision 106945)
+++ include/bits/deque.tcc	(working copy)
@@ -72,8 +72,8 @@
       if (&__x != this)
 	{
 	  if (__len >= __x.size())
-	    erase(std::copy(__x.begin(), __x.end(), this->_M_impl._M_start),
-		  this->_M_impl._M_finish);
+	    _M_erase_at_end(std::copy(__x.begin(), __x.end(),
+				      this->_M_impl._M_start));
 	  else
 	    {
 	      const_iterator __mid = __x.begin() + difference_type(__len);
@@ -112,18 +112,20 @@
     {
       iterator __next = __position;
       ++__next;
-      const size_type __index = __position - this->_M_impl._M_start;
+      const size_type __index = __position - begin();
       if (__index < (size() >> 1))
 	{
-	  std::__move_backward(this->_M_impl._M_start, __position, __next);
+	  if (__position != begin())
+	    std::__move_backward(begin(), __position, __next);
 	  pop_front();
 	}
       else
 	{
-	  std::__move(__next, this->_M_impl._M_finish, __position);
+	  if (__next != end())
+	    std::__move(__next, end(), __position);
 	  pop_back();
 	}
-      return this->_M_impl._M_start + __index;
+      return begin() + __index;
     }
 
   template<typename _Tp, typename _Alloc>
@@ -131,73 +133,31 @@
     deque<_Tp, _Alloc>::
     erase(iterator __first, iterator __last)
     {
-      if (__first == this->_M_impl._M_start
-	  && __last == this->_M_impl._M_finish)
+      if (__first == begin() && __last == end())
 	{
 	  clear();
-	  return this->_M_impl._M_finish;
+	  return end();
 	}
       else
 	{
 	  const difference_type __n = __last - __first;
-	  const difference_type __elems_before = (__first
-						  - this->_M_impl._M_start);
+	  const difference_type __elems_before = __first - begin();
 	  if (static_cast<size_type>(__elems_before) < (size() - __n) / 2)
 	    {
-	      std::__move_backward(this->_M_impl._M_start, __first, __last);
-	      iterator __new_start = this->_M_impl._M_start + __n;
-	      std::_Destroy(this->_M_impl._M_start, __new_start,
-			    _M_get_Tp_allocator());
-	      _M_destroy_nodes(this->_M_impl._M_start._M_node,
-			       __new_start._M_node);
-	      this->_M_impl._M_start = __new_start;
+	      if (__first != begin())
+		std::__move_backward(begin(), __first, __last);
+	      _M_erase_at_begin(begin() + __n);
 	    }
 	  else
 	    {
-	      std::__move(__last, this->_M_impl._M_finish, __first);
-	      iterator __new_finish = this->_M_impl._M_finish - __n;
-	      std::_Destroy(__new_finish, this->_M_impl._M_finish,
-			    _M_get_Tp_allocator());
-	      _M_destroy_nodes(__new_finish._M_node + 1,
-			       this->_M_impl._M_finish._M_node + 1);
-	      this->_M_impl._M_finish = __new_finish;
+	      if (__last != end())
+		std::__move(__last, end(), __first);
+	      _M_erase_at_end(end() - __n);
 	    }
-	  return this->_M_impl._M_start + __elems_before;
+	  return begin() + __elems_before;
 	}
     }
 
-  template<typename _Tp, typename _Alloc>
-    void
-    deque<_Tp, _Alloc>::
-    clear()
-    {
-      for (_Map_pointer __node = this->_M_impl._M_start._M_node + 1;
-           __node < this->_M_impl._M_finish._M_node;
-           ++__node)
-	{
-	  std::_Destroy(*__node, *__node + _S_buffer_size(),
-			_M_get_Tp_allocator());
-	  _M_deallocate_node(*__node);
-	}
-
-      if (this->_M_impl._M_start._M_node != this->_M_impl._M_finish._M_node)
-	{
-	  std::_Destroy(this->_M_impl._M_start._M_cur,
-			this->_M_impl._M_start._M_last,
-			_M_get_Tp_allocator());
-	  std::_Destroy(this->_M_impl._M_finish._M_first,
-			this->_M_impl._M_finish._M_cur,
-			_M_get_Tp_allocator());
-	  _M_deallocate_node(this->_M_impl._M_finish._M_first);
-	}
-      else
-        std::_Destroy(this->_M_impl._M_start._M_cur,
-		      this->_M_impl._M_finish._M_cur,
-		      _M_get_Tp_allocator());
-
-      this->_M_impl._M_finish = this->_M_impl._M_start;
-    }
-
   template<typename _Tp, class _Alloc>
     template<typename _InputIterator>
       void
@@ -209,7 +169,7 @@
         for (; __first != __last && __cur != end(); ++__cur, ++__first)
           *__cur = *__first;
         if (__first == __last)
-          erase(__cur, end());
+          _M_erase_at_end(__cur);
         else
           insert(end(), __first, __last);
       }
@@ -682,6 +642,28 @@
   template<typename _Tp, typename _Alloc>
     void
     deque<_Tp, _Alloc>::
+    _M_destroy_data_aux(iterator __first, iterator __last)
+    {
+      for (_Map_pointer __node = __first._M_node + 1;
+           __node < __last._M_node; ++__node)
+	std::_Destroy(*__node, *__node + _S_buffer_size(),
+		      _M_get_Tp_allocator());
+
+      if (__first._M_node != __last._M_node)
+	{
+	  std::_Destroy(__first._M_cur, __first._M_last,
+			_M_get_Tp_allocator());
+	  std::_Destroy(__last._M_first, __last._M_cur,
+			_M_get_Tp_allocator());
+	}
+      else
+        std::_Destroy(__first._M_cur, __last._M_cur,
+		      _M_get_Tp_allocator());
+    }
+
+  template<typename _Tp, typename _Alloc>
+    void
+    deque<_Tp, _Alloc>::
     _M_new_elements_at_front(size_type __new_elems)
     {
       const size_type __new_nodes
Index: testsuite/23_containers/vector/modifiers/erase/1.cc
===================================================================
--- testsuite/23_containers/vector/modifiers/erase/1.cc	(revision 106945)
+++ testsuite/23_containers/vector/modifiers/erase/1.cc	(working copy)
@@ -27,10 +27,14 @@
 const int A1[] = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
 const int A2[] = {0, 2, 3, 4, 10, 11, 12, 13, 14, 15};
 const int A3[] = {0, 2, 3, 4, 10, 11};
+const int A4[] = {4, 10, 11};
+const int A5[] = {4, 10};
 const int  N = sizeof(A)  / sizeof(int);
 const int N1 = sizeof(A1) / sizeof(int);
 const int N2 = sizeof(A2) / sizeof(int);
 const int N3 = sizeof(A3) / sizeof(int);
+const int N4 = sizeof(A4) / sizeof(int);
+const int N5 = sizeof(A4) / sizeof(int);
 
 void
 test01()
@@ -54,8 +58,16 @@
   VERIFY( it3 == v.begin() + 6 );
   VERIFY( std::equal(v.begin(), v.end(), A3) );
 
-  iterator_type it4 = v.erase(v.begin(), v.end());
+  iterator_type it4 = v.erase(v.begin(), v.begin() + 3);
   VERIFY( it4 == v.begin() );
+  VERIFY( std::equal(v.begin(), v.end(), A4) );
+
+  iterator_type it5 = v.erase(v.begin() + 2);
+  VERIFY( it5 == v.begin() + 2 );
+  VERIFY( std::equal(v.begin(), v.end(), A5) );
+
+  iterator_type it6 = v.erase(v.begin(), v.end());
+  VERIFY( it6 == v.begin() );
   VERIFY( v.empty() );
 }
 
@@ -67,7 +79,7 @@
   typedef std::vector<std::vector<int> >   vec_type;
   typedef vec_type::iterator          iterator_type;
 
-  vec_type v, v1, v2, v3;
+  vec_type v, v1, v2, v3, v4, v5;
   for (int i = 0; i < N; ++i)
     v.push_back(std::vector<int>(1, A[i]));
   for (int i = 0; i < N1; ++i)
@@ -76,6 +88,10 @@
     v2.push_back(std::vector<int>(1, A2[i]));
   for (int i = 0; i < N3; ++i)
     v3.push_back(std::vector<int>(1, A3[i]));
+  for (int i = 0; i < N2; ++i)
+    v4.push_back(std::vector<int>(1, A4[i]));
+  for (int i = 0; i < N3; ++i)
+    v5.push_back(std::vector<int>(1, A5[i]));
   
   iterator_type it1 = v.erase(v.begin() + 1);
   VERIFY( it1 == v.begin() + 1 );
@@ -89,8 +105,16 @@
   VERIFY( it3 == v.begin() + 6 );
   VERIFY( std::equal(v.begin(), v.end(), v3.begin()) );
 
-  iterator_type it4 = v.erase(v.begin(), v.end());
+  iterator_type it4 = v.erase(v.begin(), v.begin() + 3);
   VERIFY( it4 == v.begin() );
+  VERIFY( std::equal(v.begin(), v.end(), v4.begin()) );
+
+  iterator_type it5 = v.erase(v.begin() + 2);
+  VERIFY( it5 == v.begin() + 2 );
+  VERIFY( std::equal(v.begin(), v.end(), v5.begin()) );
+
+  iterator_type it6 = v.erase(v.begin(), v.end());
+  VERIFY( it6 == v.begin() );
   VERIFY( v.empty() );
 }
 
Index: testsuite/23_containers/deque/modifiers/erase/1.cc
===================================================================
--- testsuite/23_containers/deque/modifiers/erase/1.cc	(revision 0)
+++ testsuite/23_containers/deque/modifiers/erase/1.cc	(revision 0)
@@ -0,0 +1,126 @@
+// 2005-11-25  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2005 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 2, 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 COPYING.  If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 23.2.1.3 deque modifiers
+
+#include <deque>
+#include <testsuite_hooks.h>
+
+const int  A[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+const int A1[] = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+const int A2[] = {0, 2, 3, 4, 10, 11, 12, 13, 14, 15};
+const int A3[] = {0, 2, 3, 4, 10, 11};
+const int A4[] = {4, 10, 11};
+const int A5[] = {4, 10};
+const int  N = sizeof(A)  / sizeof(int);
+const int N1 = sizeof(A1) / sizeof(int);
+const int N2 = sizeof(A2) / sizeof(int);
+const int N3 = sizeof(A3) / sizeof(int);
+const int N4 = sizeof(A4) / sizeof(int);
+const int N5 = sizeof(A4) / sizeof(int);
+
+void
+test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  typedef std::deque<int>                deque_type;
+  typedef deque_type::iterator        iterator_type;
+
+  deque_type v(A, A + N);
+
+  iterator_type it1 = v.erase(v.begin() + 1);
+  VERIFY( it1 == v.begin() + 1 );
+  VERIFY( std::equal(v.begin(), v.end(), A1) );
+  
+  iterator_type it2 = v.erase(v.begin() + 4, v.begin() + 9);
+  VERIFY( it2 == v.begin() + 4 );
+  VERIFY( std::equal(v.begin(), v.end(), A2) );
+  
+  iterator_type it3 = v.erase(v.begin() + 6, v.end());
+  VERIFY( it3 == v.begin() + 6 );
+  VERIFY( std::equal(v.begin(), v.end(), A3) );
+
+  iterator_type it4 = v.erase(v.begin(), v.begin() + 3);
+  VERIFY( it4 == v.begin() );
+  VERIFY( std::equal(v.begin(), v.end(), A4) );
+
+  iterator_type it5 = v.erase(v.begin() + 2);
+  VERIFY( it5 == v.begin() + 2 );
+  VERIFY( std::equal(v.begin(), v.end(), A5) );
+
+  iterator_type it6 = v.erase(v.begin(), v.end());
+  VERIFY( it6 == v.begin() );
+  VERIFY( v.empty() );
+}
+
+void
+test02()
+{
+  bool test __attribute__((unused)) = true;
+
+  typedef std::deque<std::deque<int> >   deque_type;
+  typedef deque_type::iterator        iterator_type;
+
+  deque_type v, v1, v2, v3, v4, v5;
+  for (int i = 0; i < N; ++i)
+    v.push_back(std::deque<int>(1, A[i]));
+  for (int i = 0; i < N1; ++i)
+    v1.push_back(std::deque<int>(1, A1[i]));
+  for (int i = 0; i < N2; ++i)
+    v2.push_back(std::deque<int>(1, A2[i]));
+  for (int i = 0; i < N3; ++i)
+    v3.push_back(std::deque<int>(1, A3[i]));
+  for (int i = 0; i < N4; ++i)
+    v4.push_back(std::deque<int>(1, A4[i]));
+  for (int i = 0; i < N5; ++i)
+    v5.push_back(std::deque<int>(1, A5[i]));
+  
+  iterator_type it1 = v.erase(v.begin() + 1);
+  VERIFY( it1 == v.begin() + 1 );
+  VERIFY( std::equal(v.begin(), v.end(), v1.begin()) );
+  
+  iterator_type it2 = v.erase(v.begin() + 4, v.begin() + 9);
+  VERIFY( it2 == v.begin() + 4 );
+  VERIFY( std::equal(v.begin(), v.end(), v2.begin()) );
+  
+  iterator_type it3 = v.erase(v.begin() + 6, v.end());
+  VERIFY( it3 == v.begin() + 6 );
+  VERIFY( std::equal(v.begin(), v.end(), v3.begin()) );
+
+  iterator_type it4 = v.erase(v.begin(), v.begin() + 3);
+  VERIFY( it4 == v.begin() );
+  VERIFY( std::equal(v.begin(), v.end(), v4.begin()) );
+
+  iterator_type it5 = v.erase(v.begin() + 2);
+  VERIFY( it5 == v.begin() + 2 );
+  VERIFY( std::equal(v.begin(), v.end(), v5.begin()) );
+
+  iterator_type it6 = v.erase(v.begin(), v.end());
+  VERIFY( it6 == v.begin() );
+  VERIFY( v.empty() );
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
Index: testsuite/23_containers/deque/modifiers/erase/2.cc
===================================================================
--- testsuite/23_containers/deque/modifiers/erase/2.cc	(revision 0)
+++ testsuite/23_containers/deque/modifiers/erase/2.cc	(revision 0)
@@ -0,0 +1,108 @@
+// 2005-11-25  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2005 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 2, 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 COPYING.  If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 23.2.1.3 deque modifiers
+
+#include <deque>
+#include <testsuite_hooks.h>
+
+const int  A[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+		  13, 14, 15};
+const int A0[] = {-5, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+const int A1[] = {-5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+const int A2[] = {-5, 0, 1, 2, 8, 9, 10, 11, 12, 13, 14, 15};
+const int A3[] = {-5, 0, 1, 2, 8, 9, 10, 11};
+const int A4[] = {2, 8, 9, 10, 11};
+const int A5[] = {2, 8, 10, 11};
+const int A6[] = {2, 8, 10};
+const int  N = sizeof(A)  / sizeof(int);
+const int N0 = sizeof(A0) / sizeof(int);
+const int N1 = sizeof(A1) / sizeof(int);
+const int N2 = sizeof(A2) / sizeof(int);
+const int N3 = sizeof(A3) / sizeof(int);
+const int N4 = sizeof(A4) / sizeof(int);
+const int N5 = sizeof(A5) / sizeof(int);
+const int N6 = sizeof(A6) / sizeof(int);
+
+template<int Size>
+  class My_class
+  {
+    double dummy[Size];
+    int data;
+    
+  public:
+    My_class(int num)
+    : data(num) { }
+    
+    operator int() const
+    { return data; }
+  };
+
+template<typename T>
+  void
+  test01()
+  {
+    bool test __attribute__((unused)) = true;
+    
+    typedef std::deque<T>                         deque_type;
+    typedef typename deque_type::iterator      iterator_type;
+
+    deque_type v(A, A + N);
+
+    iterator_type it0 = v.erase(v.begin() + 1, v.begin() + 4);
+    VERIFY( it0 == v.begin() + 1 );
+    VERIFY( std::equal(v.begin(), v.end(), A0) );
+    
+    iterator_type it1 = v.erase(v.begin() + 1);
+    VERIFY( it1 == v.begin() + 1 );
+    VERIFY( std::equal(v.begin(), v.end(), A1) );
+    
+    iterator_type it2 = v.erase(v.begin() + 4, v.begin() + 9);
+    VERIFY( it2 == v.begin() + 4 );
+    VERIFY( std::equal(v.begin(), v.end(), A2) );
+  
+    iterator_type it3 = v.erase(v.begin() + 8, v.end());
+    VERIFY( it3 == v.begin() + 8 );
+    VERIFY( std::equal(v.begin(), v.end(), A3) );
+
+    iterator_type it4 = v.erase(v.begin(), v.begin() + 3);
+    VERIFY( it4 == v.begin() );
+    VERIFY( std::equal(v.begin(), v.end(), A4) );
+    
+    iterator_type it5 = v.erase(v.begin() + 2);
+    VERIFY( it5 == v.begin() + 2 );
+    VERIFY( std::equal(v.begin(), v.end(), A5) );
+
+    iterator_type it6 = v.erase(v.begin() + 3, v.end());
+    VERIFY( it6 == v.begin() + 3 );
+    VERIFY( std::equal(v.begin(), v.end(), A6) );
+
+    iterator_type it7 = v.erase(v.begin(), v.end());
+    VERIFY( it7 == v.begin() );
+    VERIFY( v.empty() );
+  }
+
+int main()
+{
+  test01<My_class<1> >();
+  test01<My_class<8> >();
+  test01<My_class<32> >();
+  return 0;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]