This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Basic exception guarantee testcases (redux)
- From: Stephen M. Webb <stephen dot webb at bregmasoft dot com>
- To: libstdc++ at gcc dot gnu dot org
- Date: Tue, 19 Nov 2002 12:58:25 -0500
- Subject: Basic exception guarantee testcases (redux)
- Organization: Bregmasoft
- Reply-to: stephen dot webb at bregmasoft dot com
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;