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]

Basic exception guarantee testcases (redux)


I promised yesterday I would deliver better test cases, and here they are.

I redid my changes to testsuite_hooks to integrate with existing test cases 
(hmm, the ones I submitted last year at about this time, maybe it's a 
seasonal thing), made the vector_ctor testcases look like other test cases, 
added a test for vector::operator=(), and threw in my latest deque ctor test 
cases.  All of them.  There's quite a few, but what the heck.  Merry 
Christmas.

I found that std::deque Does the Right Thing regarding honouring the basic 
exception guarantee in its copy constructor, hence that test passes.  
std::vector fails to Do the Right Thing and brings dishonour and shame to the 
Community.

If someone cares to approve and push these changes in to CVS I'll see about 
adding additional test cases for the other containers, as time permits (hah!).

Here's the diffs from the testsuite directory and attached are the same two 
new source files.

Index: 23_containers/deque_ctor.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/23_containers/deque_ctor.cc,v
retrieving revision 1.1
diff -c -3 -p -r1.1 deque_ctor.cc
*** 23_containers/deque_ctor.cc	27 Dec 2001 21:51:28 -0000	1.1
--- 23_containers/deque_ctor.cc	19 Nov 2002 17:20:24 -0000
***************
*** 21,32 ****
  // 23.2.1.1 deque constructors, copy, and assignment
  
  #include <deque>
  #include <testsuite_hooks.h>
  
  typedef std::deque<gnu_counting_struct>   gdeque;
  
  
! // basic alloc/dealloc sanity check
  void
  test01()
  {
--- 21,36 ----
  // 23.2.1.1 deque constructors, copy, and assignment
  
  #include <deque>
+ #include <iterator>
+ #include <sstream>
+ #include <testsuite_allocator.h>
  #include <testsuite_hooks.h>
  
  typedef std::deque<gnu_counting_struct>   gdeque;
  
+ bool test = true;
  
! // see http://gcc.gnu.org/ml/libstdc++/2001-11/msg00139.html
  void
  test01()
  {
*************** test01()
*** 38,46 ****
    assert_count (0);
  }
  
  int main()
  {
    test01();
  
!   return 0;
  }
--- 42,525 ----
    assert_count (0);
  }
  
+ 
+ // 23.2.1     required types
+ //
+ // A missing required type will cause a compile failure.
+ //
+ void
+ requiredTypesCheck()
+ {
+   typedef int             T;
+   typedef std::deque<T>   X;
+ 
+   typedef X::reference              reference;
+   typedef X::const_reference        const_reference;
+   typedef X::iterator               iterator;
+   typedef X::const_iterator         const_iterator;
+   typedef X::size_type              size_type;
+   typedef X::difference_type        difference_type;
+   typedef X::value_type             value_type;
+   typedef X::allocator_type         allocator_type;
+   typedef X::pointer                pointer;
+   typedef X::const_pointer          const_pointer;
+   typedef X::reverse_iterator       reverse_iterator;
+   typedef X::const_reverse_iterator const_reverse_iterator;
+ }
+ 
+ 
+ // @fn defaultConstructorCheck
+ // Explicitly checks the default deque constructor and destructor for both
+ // trivial and non-trivial types.  In addition, the size() and empty()
+ // member functions are explicitly checked here since it should be their
+ // first use. Checking those functions means checking the begin() and
+ // end() and their const brethren functions as well.
+ //
+ // @verbatim
+ // 23.2.1.1   default ctor/dtor
+ //  effects:
+ //    23.2.1.1        constructs an empty deque using the specified 
allocator
+ //  postconditions:
+ //    23.1 table 65   u.size() == 0
+ //  throws:
+ //  complexity:
+ //    23.1 table 65   constant
+ //
+ // 23.2.1.2   bool empty() const
+ //  semantics:
+ //    23.1 table 65   a.size() == 0
+ //    23.1 (7)        a.begin() == a.end()
+ //  throws:
+ //  complexity:
+ //    23.1 table 65   constant
+ //
+ // 23.2.1.2   size_type size() const
+ //  semantics:
+ //    23.1 table 65   a.end() - a.begin()
+ //  throws:
+ //  complexity:
+ //    23.1 table 65(A) should be constant
+ //
+ // 23.2.1     iterator begin()
+ //            const_iterator begin() const
+ //            iterator end() 
+ //            const_iterator end() const
+ //  throws:
+ //    23.1 (10) pt. 4 does not throw
+ //  complexity:
+ //    23.1 table 65   constant
+ // @endverbatim
+ void
+ defaultConstructorCheckPOD()
+ {
+   // setup
+   typedef int             T;
+   typedef std::deque<T>   X;
+ 
+   // run test
+   X u;
+ 
+   // assert postconditions
+   VERIFY(u.empty());
+   VERIFY(0 == u.size());
+   VERIFY(u.begin() == u.end());
+   VERIFY(0 == std::distance(u.begin(), u.end()));
+ 
+   // teardown
+ }
+ 
+ 
+ void
+ defaultConstructorCheck()
+ {
+   // setup
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>     X;
+ 
+   gnu_copy_tracker::reset();
+ 
+   // run test
+   const X u;
+ 
+   // assert postconditions
+   VERIFY(u.empty());
+   VERIFY(0 == u.size());
+   VERIFY(u.begin() == u.end());
+   VERIFY(0 == std::distance(u.begin(), u.end()));
+ 
+   // teardown
+ }
+ 
+ 
+ // @fn copyConstructorCheck()
+ // Explicitly checks the deque copy constructor.  Continues verificaton of
+ // ancillary member functions documented under defaultConstructorCheck().
+ //
+ // This check also tests the push_back() member function.
+ //
+ // @verbatim
+ // 23.2.1     copy constructor
+ //  effects:
+ //  postconditions:
+ //    22.1.1 table 65 a == X(a)
+ //                    u == a
+ //  throws:
+ //  complexity:
+ //    22.1.1 table 65 linear
+ // @endverbatim
+ void
+ copyConstructorCheck()
+ {
+   // setup
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>     X;
+ 
+   const int copyBaseSize = 17;  // arbitrary
+ 
+   X a;
+   for (int i = 0; i < copyBaseSize; ++i)
+     a.push_back(i);
+   gnu_copy_tracker::reset();
+ 
+   // assert preconditions
+   VERIFY(!a.empty());
+   VERIFY(copyBaseSize == a.size());
+   VERIFY(a.begin() != a.end());
+   VERIFY(copyBaseSize == std::distance(a.begin(), a.end()));
+ 
+   // run test
+   X u = a;
+ 
+   // assert postconditions
+   VERIFY(u == a);
+   VERIFY(copyBaseSize == gnu_copy_constructor::count());
+ 
+   // teardown
+ }
+ 
+ 
+ // @fn fillConstructorCheck()
+ // This test explicitly verifies the basic fill constructor.  Like the 
default
+ // constructor, later tests depend on the fill constructor working 
correctly.
+ // That means this explicit test should preceed the later tests so the error
+ // message given on assertion failure can be more helpful n tracking the
+ // problem.
+ // 
+ // 23.2.1.1   fill constructor
+ //  complexity:
+ //    23.2.1.1        linear in N
+ void
+ fillConstructorCheck()
+ {
+   // setup
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>   X;
+ 
+   const X::size_type  n(23);  
+   const X::value_type t(111);
+ 
+   gnu_copy_tracker::reset();
+ 
+   // run test
+   X a(n, t);
+ 
+   // assert postconditions
+   VERIFY(n == a.size());
+   VERIFY(n == gnu_copy_constructor::count());
+ 
+   // teardown
+ }
+ 
+ 
+ // @fn fillConstructorCheck2()
+ // Explicit check for fill constructors masqueraded as range constructors as
+ // elucidated in clause 23.1.1 paragraph 9 of the standard.
+ //
+ // 23.1.1 (9) fill constructor looking like a range constructor
+ void
+ fillConstructorCheck2()
+ {
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>   X;
+ 
+   const int f = 23;  
+   const int l = 111;
+ 
+   gnu_copy_tracker::reset();
+ 
+   X a(f, l);
+ 
+   VERIFY(f == a.size());
+   VERIFY(f == gnu_copy_constructor::count());
+ }
+ 
+ 
+ // @fn rangeConstructorCheckForwardIterator()
+ // This test copies from one deque to another to force the copy
+ // constructor for T to be used because the compiler will kindly
+ // elide copies if the default constructor can be used with
+ // type conversions.  Trust me.
+ //
+ // 23.2.1.1   range constructor, forward iterators
+ void
+ rangeConstructorCheckForwardIterator()
+ {
+   // setup
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>   X;
+ 
+   const X::size_type  n(726); 
+   const X::value_type t(307);
+   X source(n, t);
+   X::iterator i = source.begin();
+   X::iterator j = source.end();
+   X::size_type rangeSize = std::distance(i, j);
+ 
+   gnu_copy_tracker::reset();
+ 
+   // test
+   X a(i, j);
+ 
+   // assert postconditions
+   VERIFY(rangeSize == a.size());
+   VERIFY(gnu_copy_constructor::count() <= rangeSize);
+ }
+ 
+ 
+ // @fn rangeConstructorCheckInputIterator()
+ // An explicit check for range construction on an input iterator
+ // range, which the standard expounds upon as having a different
+ // complexity than forward iterators.
+ //
+ // 23.2.1.1   range constructor, input iterators
+ void
+ rangeConstructorCheckInputIterator()
+ {
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>     X;
+ 
+   std::istringstream ibuf("1234567890123456789");
+   const X::size_type rangeSize = ibuf.str().size();  
+   std::istream_iterator<char>  i(ibuf);
+   std::istream_iterator<char>  j;
+ 
+   gnu_copy_tracker::reset();
+ 
+   X a(i, j);
+ 
+   VERIFY(rangeSize == a.size());
+   VERIFY(gnu_copy_constructor::count() <= (2 * rangeSize));
+ }
+ 
+ 
+ // 23.2.1     copy assignment
+ void
+ copyAssignmentCheck()
+ {
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>     X;
+ 
+   const X::size_type  n(18);  
+   const X::value_type t(1023);
+   X a(n, t);
+   X r;
+ 
+   gnu_copy_tracker::reset();
+ 
+   r = a;
+ 
+   VERIFY(r == a);
+   VERIFY(n == gnu_copy_constructor::count());
+ }
+ 
+ 
+ // 23.2.1.1   fill assignment
+ //
+ // The complexity check must check dtors+copyAssign and copyCtor+copyAssign
+ // because that's the way the SGI implementation works.  Dunno if it's true
+ // standard compliant (which specifies fill assignment in terms of erase and
+ // insert only), but it should work as (most) users expect and is more 
efficient.
+ void
+ fillAssignmentCheck()
+ {
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>   X;
+ 
+   const X::size_type  starting_size(10);  
+   const X::value_type starting_value(66);
+   const X::size_type  n(23);  
+   const X::value_type t(111);
+ 
+   X a(starting_size, starting_value);
+   gnu_copy_tracker::reset();
+ 
+   // preconditions
+   VERIFY(starting_size == a.size());
+ 
+   // test
+   a.assign(n, t);
+ 
+   // postconditions
+   VERIFY(n == a.size());
+   VERIFY(n == (gnu_copy_constructor::count() + 
gnu_assignment_operator::count()));
+   VERIFY(starting_size == (gnu_destructor::count() + 
gnu_assignment_operator::count()));
+ }
+ 
+ 
+ // @verbatim
+ // 23.2.1     range assignment
+ // 23.2.1.1   deque constructors, copy, and assignment
+ //  effects:
+ //    Constructs a deque equal to the range [first, last), using the 
specified allocator.
+ //
+ //      template<typename InputIterator>
+ //        assign(InputIterator first, InputIterator last);
+ //      
+ //    is equivalent to
+ //
+ //      erase(begin(), end());
+ //      insert(begin(), first, last);
+ //
+ //  postconditions:
+ //  throws:
+ //  complexity:
+ //    forward iterators: N calls to the copy constructor, 0 reallocations
+ //    input iterators:   2N calls to the copy constructor, log(N) 
reallocations
+ // @endverbatim
+ void
+ rangeAssignmentCheck()
+ {
+   typedef gnu_copy_tracker  T;
+   typedef std::deque<T>   X;
+ 
+   const X::size_type  source_size(726); 
+   const X::value_type source_value(307);
+   const X::size_type  starting_size(10);  
+   const X::value_type starting_value(66);
+ 
+   X source(source_size, source_value);
+   X::iterator i = source.begin();
+   X::iterator j = source.end();
+   X::size_type rangeSize = std::distance(i, j);
+ 
+   X a(starting_size, starting_value);
+   VERIFY(starting_size == a.size());
+ 
+   gnu_copy_tracker::reset();
+ 
+   a.assign(i, j);
+ 
+   VERIFY(source == a);
+   VERIFY(rangeSize == (gnu_copy_constructor::count() + 
gnu_assignment_operator::count()));
+   VERIFY(starting_size == (gnu_destructor::count() + 
gnu_assignment_operator::count()));
+ }
+ 
+ 
+ // 23.1 (10)  range assignment
+ // 23.2.1.3   with exception
+ // What does "no effects" mean?
+ void
+ rangeAssignmentCheckWithException()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::deque<T>    X;
+ 
+   // test
+ }
+ 
+ 
+ // 23.1.1 (9) fill assignment looking like a range assignment
+ // What does "no effects" mean?
+ void
+ fillAssignmentCheck2()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::deque<T>    X;
+ 
+   // test
+ }
+ 
+ // Verify that the default deque constructor offers the basic exception
+ // guarantee.
+ void
+ test_default_ctor_exception_safety()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::deque<T, gnu_new_allocator<T> > X;
+ 
+   T::reset();
+   gnu_copy_constructor::throw_on(3);
+ 
+   // test
+   try
+   {
+     X a(7);
+     VERIFY(("no exception thrown", false));
+   }
+   catch (...)
+   {
+   }
+ 
+   // assert postconditions
+   VERIFY(gnu_allocator_tracker::allocationTotal() == 
gnu_allocator_tracker::deallocationTotal());
+ 
+   // teardown
+ }
+ 
+ // Verify that the copy constructor offers the basic exception guarantee.
+ void
+ test_copy_ctor_exception_safety()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::deque<T, gnu_new_allocator<T> > X;
+ 
+   X a(7);
+   T::reset();
+   gnu_copy_constructor::throw_on(3);
+ 
+   // test
+   try
+   {
+     X u(a);
+     VERIFY(("no exception thrown", false));
+   }
+   catch (...)
+   {
+     VERIFY(("exception thrown", true));
+   }
+ 
+   // assert postconditions
+   VERIFY(gnu_allocator_tracker::allocationTotal() == 
gnu_allocator_tracker::deallocationTotal());
+ 
+   // teardown
+ }
+ 
+ 
  int main()
  {
+   // basic functionality and standard conformance checks
+   requiredTypesCheck();
+   defaultConstructorCheckPOD();
+   defaultConstructorCheck();
+   copyConstructorCheck();
+   fillConstructorCheck();
+   fillConstructorCheck2();
+   rangeConstructorCheckInputIterator();
+   rangeConstructorCheckForwardIterator();
+   copyAssignmentCheck();
+   fillAssignmentCheck();
+   fillAssignmentCheck2();
+   rangeAssignmentCheck();
+   rangeAssignmentCheckWithException();
+ 
+   // specific bug fix checks
    test01();
  
!   return !test;
  }
+ 
+ // vi:set ts=2 sw=2 et:
Index: 23_containers/vector_ctor.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/23_containers/vector_ctor.cc,v
retrieving revision 1.8
diff -c -3 -p -r1.8 vector_ctor.cc
*** 23_containers/vector_ctor.cc	1 May 2002 02:17:35 -0000	1.8
--- 23_containers/vector_ctor.cc	19 Nov 2002 17:20:24 -0000
***************
*** 22,27 ****
--- 22,28 ----
  
  #include <vector>
  #include <string>
+ #include <testsuite_allocator.h>
  #include <testsuite_hooks.h>
  
  template<typename T>
*************** void test04()
*** 94,105 ****
--- 95,210 ----
  #endif
  }
  
+ 
+ // @fn test_default_ctor_exception_safety
+ // This test verifies that if one of the vector's contained objects throws
+ // an exception from its constructor while the vector is being constructed 
and
+ // filled with default values, all memory is returned to the allocator 
whence
+ // it came.
+ void
+ test_default_ctor_exception_safety()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::vector<T, gnu_new_allocator<T> > X;
+ 
+   T::reset();
+   gnu_copy_constructor::throw_on(3);
+ 
+   // run test
+   try
+   {
+     X a(7);
+     VERIFY(("no exception thrown", false));
+   }
+   catch (...)
+   {
+   }
+ 
+   // assert postconditions
+   VERIFY(("memory leak detected:",
+           gnu_allocator_tracker::allocationTotal() == 
gnu_allocator_tracker::deallocationTotal()));
+ 
+   // teardown
+ }
+ 
+ // @fn test_copy_ctor_exception_safety
+ // This test verifies that if one of the vector's contained objects throws
+ // an exception from its constructor while the vector is being copy
+ // constructed, all memory is returned to the allocator whence it came.
+ void
+ test_copy_ctor_exception_safety()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::vector<T, gnu_new_allocator<T> > X;
+ 
+   X a(7);
+   T::reset();
+   gnu_copy_constructor::throw_on(3);
+ 
+   // run test
+   try
+   {
+     X u(a);
+     VERIFY(("no exception thrown", false));
+   }
+   catch (...)
+   {
+     VERIFY(("exception thrown", true));
+   }
+ 
+   // assert postconditions
+   VERIFY(("memory leak detected:",
+           gnu_allocator_tracker::allocationTotal() == 
gnu_allocator_tracker::deallocationTotal()));
+ 
+   // teardown
+ }
+ 
+ // @fn test_assignment_operator_exception_safety
+ // This test verifies that if one of the vector's contained objects throws
+ // an exception from its constructor while the vector is being copied
+ // through an assignment, all memory is returned to the allocator whence it
+ // came.
+ void
+ test_assignment_operator_exception_safety()
+ {
+   // setup
+   typedef gnu_copy_tracker T;
+   typedef std::vector<T, gnu_new_allocator<T> > X;
+ 
+   X a(7);
+   X u;
+   T::reset();
+   gnu_copy_constructor::throw_on(3);
+ 
+   // run test
+   try
+   {
+     u = a;
+     VERIFY(("no exception thrown", false));
+   }
+   catch (...)
+   {
+     VERIFY(("exception thrown", true));
+   }
+ 
+   // assert postconditions
+   VERIFY(("memory leak detected:",
+           gnu_allocator_tracker::allocationTotal() == 
gnu_allocator_tracker::deallocationTotal()));
+ 
+   // teardown
+ }
+ 
  int main()
  {
    test01();
    test02(); 
    test03();
    test04();
+   test_default_ctor_exception_safety();
+   test_copy_ctor_exception_safety();
+   test_assignment_operator_exception_safety();
  
    return 0;
  }
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/Makefile.am,v
retrieving revision 1.11
diff -c -3 -p -r1.11 Makefile.am
*** Makefile.am	1 Sep 2002 18:09:18 -0000	1.11
--- Makefile.am	19 Nov 2002 17:20:24 -0000
*************** INCLUDES = \
*** 51,57 ****
  
  ## Build support library.
  noinst_LIBRARIES = libv3test.a
! libv3test_a_SOURCES = testsuite_hooks.cc
  
  ## Build support utilities.
  ## Only build this as native, as need to find startup files and libc to 
link.
--- 51,57 ----
  
  ## Build support library.
  noinst_LIBRARIES = libv3test.a
! libv3test_a_SOURCES = testsuite_hooks.cc testsuite_allocator.cc
  
  ## Build support utilities.
  ## Only build this as native, as need to find startup files and libc to 
link.
Index: testsuite_hooks.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/testsuite_hooks.h,v
retrieving revision 1.10
diff -c -3 -p -r1.10 testsuite_hooks.h
*** testsuite_hooks.h	2 Aug 2002 16:04:16 -0000	1.10
--- testsuite_hooks.h	19 Nov 2002 17:20:24 -0000
*************** struct gnu_counting_struct
*** 100,156 ****
  
  #define assert_count(n)   VERIFY(gnu_counting_struct::count == n)
  
  
  class gnu_copy_tracker
  {
    public:
!     // Cannot be explicit.  Conversion ctor used by list_modifiers.cc's
!     // test03(), "range fill at beginning".
!     gnu_copy_tracker (int anId, bool throwOnDemand = false)
!     : itsId(anId), willThrow(throwOnDemand)
!     {}
  
      gnu_copy_tracker (const gnu_copy_tracker& rhs)
!     : itsId(rhs.id()), willThrow(rhs.willThrow)
      {
!       ++itsCopyCount;
!       if (willThrow) 
! 	__throw_exception_again "copy tracker exception";
      }
  
!     gnu_copy_tracker& operator=(const gnu_copy_tracker& rhs)
!     {
!       itsId = rhs.id();
!       // willThrow must obviously already be false to get this far
      }
  
!     ~gnu_copy_tracker() { ++itsDtorCount; }
  
      int
      id() const
!     { return itsId; }
  
    private:
!           int   itsId;
!     const bool  willThrow;
  
    public:
      static void
      reset()
!     { itsCopyCount = 0; itsDtorCount = 0; }
  
      static int
      copyCount() 
!     { return itsCopyCount; }
  
      static int
      dtorCount() 
!     { return itsDtorCount; }
  
    private:
!     static int itsCopyCount;
!     static int itsDtorCount;
  };
  
  struct gnu_char
  {
--- 100,271 ----
  
  #define assert_count(n)   VERIFY(gnu_counting_struct::count == n)
  
+ // A (static) class for counting copy constructors and possibly throwing an
+ // exception on a desired count.
+ class gnu_copy_constructor
+ {
+ public:
+   static unsigned int
+   count()
+   { return count_; }
+ 
+   static void
+   mark_call()
+   {
+     count_++;
+     if (count_ == throw_on_)
+     {
+       __throw_exception_again "copy constructor exception";
+     }
+   }
+ 
+   static void
+   reset()
+   {
+     count_ = 0;
+     throw_on_ = 0;
+   }
+ 
+   static void
+   throw_on(unsigned int count)
+   { throw_on_ = count; }
+ 
+ private:
+   static unsigned int count_;
+   static unsigned int throw_on_;
+ };
  
+ // A (static) class for counting assignment operator calls and possibly
+ // throwing an exception on a desired count.
+ class gnu_assignment_operator
+ {
+ public:
+   static unsigned int
+   count()
+   { return count_; }
+ 
+   static void
+   mark_call()
+   {
+     count_++;
+     if (count_ == throw_on_)
+     {
+       __throw_exception_again "assignment operator exception";
+     }
+   }
+ 
+   static void
+   reset()
+   {
+     count_ = 0;
+     throw_on_ = 0;
+   }
+ 
+   static void
+   throw_on(unsigned int count)
+   { throw_on_ = count; }
+ 
+ private:
+   static unsigned int count_;
+   static unsigned int throw_on_;
+ };
+ 
+ // A (static) class for tracking calls to an object's destructor.
+ class gnu_destructor
+ {
+ public:
+   static unsigned int
+   count()
+   { return count_; }
+ 
+   static void
+   mark_call()
+   { count_++; }
+ 
+   static void
+   reset()
+   { count_ = 0; }
+ 
+ private:
+   static unsigned int count_;
+ };
+ 
+ // An class of objects that can be used for validating various behaviours 
and
+ // guarantees of containers and algorithms defined in the standard library.
  class gnu_copy_tracker
  {
    public:
!     // Creates a copy-tracking object with the given ID number.
!     // If "throw_on_copy" is set, an exception will be thrown if
!     // an attempt is made to copy this object.
!     gnu_copy_tracker(int id = next_id_--, bool throw_on_copy = false)
!     : id_(id)
!     , throw_on_copy_(throw_on_copy)
!     { }
  
+     // Copy-constructs the object, marking a call to the copy
+     // constructor and forcing an exception if indicated.
      gnu_copy_tracker (const gnu_copy_tracker& rhs)
!     : id_(rhs.id()), throw_on_copy_(rhs.throw_on_copy_)
      {
!       if (throw_on_copy_)
!       {
!         gnu_copy_constructor::throw_on(gnu_copy_constructor::count() + 1);
!       }
!       gnu_copy_constructor::mark_call();
      }
  
!     // Assigns the value of another object to this one, tracking the number 
of
!     // times this member function has been called and if the other object is
!     // supposed to throw an exception when it is copied, well, make it so.
!     gnu_copy_tracker&
!     operator=(const gnu_copy_tracker& rhs)
!     { 
!       id_            = rhs.id();
!       if (rhs.throw_on_copy_)
!       {
!         gnu_assignment_operator::throw_on(gnu_assignment_operator::count() 
+ 1);
!       }
!       gnu_assignment_operator::mark_call();
      }
  
!     ~gnu_copy_tracker()
!     { gnu_destructor::mark_call(); }
  
      int
      id() const
!     { return id_; }
  
    private:
!           int   id_;
!     const bool  throw_on_copy_;
  
    public:
      static void
      reset()
!     {
!       gnu_copy_constructor::reset();
!       gnu_assignment_operator::reset();
!       gnu_destructor::reset();
!     }
  
+     // for backwards-compatibility
      static int
      copyCount() 
!     { return gnu_copy_constructor::count(); }
  
+     // for backwards-compatibility
      static int
      dtorCount() 
!     { return gnu_destructor::count(); }
  
    private:
!     static int next_id_;
  };
+ 
+ inline bool
+ operator==(const gnu_copy_tracker& lhs, const gnu_copy_tracker& rhs)
+ { return lhs.id() == rhs.id(); }
  
  struct gnu_char
  {
Index: testsuite_hooks.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/testsuite_hooks.cc,v
retrieving revision 1.4
diff -c -3 -p -r1.4 testsuite_hooks.cc
*** testsuite_hooks.cc	24 Oct 2002 23:27:27 -0000	1.4
--- testsuite_hooks.cc	19 Nov 2002 17:20:24 -0000
*************** __set_testsuite_memlimit(float) { }
*** 78,83 ****
  
  gnu_counting_struct::size_type  gnu_counting_struct::count = 0;
  
! int gnu_copy_tracker::itsCopyCount = 0;
! int gnu_copy_tracker::itsDtorCount = 0;
  
--- 78,87 ----
  
  gnu_counting_struct::size_type  gnu_counting_struct::count = 0;
  
! unsigned int gnu_copy_constructor::count_ = 0;
! unsigned int gnu_copy_constructor::throw_on_ = 0;
! unsigned int gnu_assignment_operator::count_ = 0;
! unsigned int gnu_assignment_operator::throw_on_ = 0;
! unsigned int gnu_destructor::count_ = 0;
!          int gnu_copy_tracker::next_id_ = 0;
  


-- 
Stephen M. Webb
#ifndef SMW_ALLOCATOR_H_
#define SMW_ALLOCATOR_H_

#include <cstddef>
#include <limits>

  class gnu_allocator_tracker {
  public:
    typedef std::size_t    size_type; 

    static void*
    allocate(size_type blocksize)
    {
      allocationTotal_ += blocksize;
      return ::operator new(blocksize);
    }

    static void
    construct()
    { constructCount_++; }

    static void
    destroy()
    { destructCount_++; }

    static void
    deallocate(void* p, size_type blocksize)
    {
      ::operator delete(p);
      deallocationTotal_ += blocksize;
    }

    static size_type
    allocationTotal() 
    { return allocationTotal_; }

    static size_type
    deallocationTotal()
    { return deallocationTotal_; }

    static int
    constructCount() 
    { return constructCount_; }

    static int
    destructCount() 
    { return destructCount_; }
    
    static void
    resetCounts()
    {
      allocationTotal_ = 0;
      deallocationTotal_ = 0;
      constructCount_ = 0;
      destructCount_ = 0;
    }

  private:
    static size_type  allocationTotal_;
    static size_type  deallocationTotal_;
    static int        constructCount_;
    static int        destructCount_;
  };

  // A simple basic allocator that just forwards to the gnu_allocator_tracker
  // to fulfill memory requests.  This class is templated on the target object
  // type, but gnu_allocator_tracker isn't.
  template <class T>
    class gnu_new_allocator
    {
    public:
      typedef T              value_type;
      typedef T*             pointer;
      typedef const T*       const_pointer;
      typedef T&             reference;
      typedef const T&       const_reference;
      typedef std::size_t    size_type; 
      typedef std::ptrdiff_t difference_type; 

      template <class U> struct rebind { typedef gnu_new_allocator<U> other; };

      pointer
      address(reference value) const
      { return &value; }

      const_pointer
      address(const_reference value) const
      { return &value; }

      gnu_new_allocator() throw()
      { }

      gnu_new_allocator(const gnu_new_allocator&) throw()
      { }

      template <class U>
        gnu_new_allocator(const gnu_new_allocator<U>&) throw()
        { }

      ~gnu_new_allocator() throw()
      { }

      size_type
      max_size() const throw()
      { return std::numeric_limits<std::size_t>::max() / sizeof(T); }

      pointer
      allocate(size_type num, const void* = 0)
      { return static_cast<pointer>(gnu_allocator_tracker::allocate(num * sizeof(T))); }

      void
      construct(pointer p, const T& value)
      {
        new (p) T(value);
        gnu_allocator_tracker::construct();
      }

      void
      destroy(pointer p)
      {
        p->~T();
        gnu_allocator_tracker::destroy();
      }

      void
      deallocate(pointer p, size_type num)
      { gnu_allocator_tracker::deallocate(p, num * sizeof(T)); }
    };

  template <class T1, class T2>
    bool
    operator==(const gnu_new_allocator<T1>&, const gnu_new_allocator<T2>&) throw()
    { return true; }

  template <class T1, class T2>
    bool
    operator!=(const gnu_new_allocator<T1>&, const gnu_new_allocator<T2>&) throw()
    { return false; }

#endif // SMW_ALLOCATOR_H_
// vi:set ts=2 sw=2 ai et:
// Utility subroutines for the C++ library testsuite.
//
// Copyright (C) 2002 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.

#include <testsuite_allocator.h>

gnu_allocator_tracker::size_type gnu_allocator_tracker::allocationTotal_   = 0;
gnu_allocator_tracker::size_type gnu_allocator_tracker::deallocationTotal_ = 0;
int                              gnu_allocator_tracker::constructCount_    = 0;
int                              gnu_allocator_tracker::destructCount_     = 0;


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