diff --git a/cast.htm b/cast.htm
new file mode 100644
index 0000000..d64473b
--- /dev/null
+++ b/cast.htm
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+Header boost/cast.hpp Documentation
+
+
+
+
+
+
+The header boost/cast.hpp
+provides polymorphic_cast, polymorphic_downcast,
+and numeric_cast function templates designed
+to complement the C++ built-in casts.
+The program cast_test.cpp can be used to
+verify these function templates work as expected.
+
+Pointers to polymorphic objects (objects of classes which define at least one
+virtual function) are sometimes downcast or crosscast. Downcasting means
+casting from a base class to a derived class. Crosscasting means casting
+across an inheritance hierarchy diagram, such as from one base to the other in a
+Y diagram hierarchy.
+Such casts can be done with old-style casts, but this approach is never to be
+recommended. Old-style casts are sorely lacking in type safety, suffer
+poor readability, and are difficult to locate with search tools.
+The C++ built-in static_cast can be used for efficiently downcasting
+pointers to polymorphic objects, but provides no error detection for the case
+where the pointer being cast actually points to the wrong derived class. The polymorphic_downcast
+template retains the efficiency of static_cast for non-debug
+compilations, but for debug compilations adds safety via an assert() that a dynamic_cast
+succeeds.
+The C++ built-in dynamic_cast can be used for downcasts and crosscasts
+of pointers to polymorphic objects, but error notification in the form of a
+returned value of 0 is inconvenient to test, or worse yet, easy to forget to
+test. The polymorphic_cast template performs a dynamic_cast,
+and throws an exception if the dynamic_cast returns 0.
+A polymorphic_downcast is preferred when debug-mode tests will cover
+100% of the object types possibly cast and when non-debug-mode efficiency is an
+issue. If these two conditions are not present, polymorphic_cast is
+preferred. It must also be used for crosscasts. It does an assert(
+dynamic_cast<Derived>(x) == x ) where x is the base pointer, ensuring that
+not only is a non-zero pointer returned, but also that it correct in the
+presence of multiple inheritance. Warning:: Because polymorphic_downcast
+uses assert(), it violates the one definition rule (ODR) if NDEBUG is inconsistently
+defined across translation units. [See ISO Std 3.2]
+The C++ built-in dynamic_cast must be used to cast references rather
+than pointers. It is also the only cast that can be used to check whether
+a given interface is supported; in that case a return of 0 isn't an error
+condition.
+polymorphic_cast and polymorphic_downcast synopsis
+
+ namespace boost {
+
+template <class Derived, class Base>
+inline Derived polymorphic_cast(Base* x);
+// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
+// Returns: dynamic_cast<Derived>(x)
+
+template <class Derived, class Base>
+inline Derived polymorphic_downcast(Base* x);
+// Effects: assert( dynamic_cast<Derived>(x) == x );
+// Returns: static_cast<Derived>(x)
+
+}
+
+polymorphic_downcast example
+
+ #include <boost/cast.hpp>
+...
+class Fruit { public: virtual ~Fruit(){}; ... };
+class Banana : public Fruit { ... };
+...
+void f( Fruit * fruit ) {
+// ... logic which leads us to believe it is a Banana
+ Banana * banana = boost::polymorphic_downcast<Banana*>(fruit);
+ ...
+
+
+A static_cast or implicit conversion will not
+detect failure to preserve range for numeric casts. The numeric_cast function
+templates are similar to static_cast and certain (dubious)
+implicit conversions in this respect, except that they detect loss of numeric
+range. An exception is thrown when a runtime value-preservation check fails.
+The requirements on the argument and result types are:
+
+
+ - Both argument and result types are CopyConstructible [ISO Std 20.1.3].
+ - Both argument and result types are Numeric, defined by
std::numeric_limits<>::is_specialized
+ being true.
+ - The argument can be converted to the result type using static_cast.
+
+
+numeric_cast synopsis
+
+ namespace boost {
+
+class bad_numeric_cast : public std::bad_cast {...};
+
+template<typename Target, typename Source>
+ inline Target numeric_cast(Source arg);
+ // Throws: bad_numeric_cast unless, in converting arg from Source to Target,
+ // there is no loss of negative range, and no underflow, and no
+ // overflow, as determined by std::numeric_limits
+ // Returns: static_cast<Target>(arg)
+
+}
+
+numeric_cast example
+
+ #include <boost/cast.hpp>
+using namespace boost::cast;
+
+void ariane(double vx)
+{
+ ...
+ unsigned short dx = numeric_cast<unsigned short>(vx);
+ ...
+}
+
+numeric_cast rationale
+The form of the throws condition is specified so that != is not a required
+operation.
+History
+polymorphic_cast was suggested by Bjarne Stroustrup in "The C++
+Programming Language".
+polymorphic_downcast was contributed by Dave
+Abrahams.
+numeric_cast was contributed by Kevlin
+Henney.
+
+Revised 06 January, 2001
+© Copyright boost.org 1999. Permission to copy, use, modify, sell and
+distribute this document is granted provided this copyright notice appears in
+all copies. This document is provided "as is" without express or
+implied warranty, and with no claim as to its suitability for any purpose.
+
+
+
+
diff --git a/cast_test.cpp b/cast_test.cpp
new file mode 100644
index 0000000..1602f16
--- /dev/null
+++ b/cast_test.cpp
@@ -0,0 +1,153 @@
+// boost utility cast test program -----------------------------------------//
+
+// (C) Copyright boost.org 1999. Permission to copy, use, modify, sell
+// and distribute this software is granted provided this copyright
+// notice appears in all copies. This software is provided "as is" without
+// express or implied warranty, and with no claim as to its suitability for
+// any purpose.
+
+// See http://www.boost.org for most recent version including documentation.
+
+// Revision History
+// 28 Jun 00 implicit_cast removed (Beman Dawes)
+// 30 Aug 99 value_cast replaced by numeric_cast
+// 3 Aug 99 Initial Version
+
+#include
+#include
+#include
+#include
+
+# if SCHAR_MAX == LONG_MAX
+# error "This test program doesn't work if SCHAR_MAX == LONG_MAX"
+# endif
+
+using namespace boost;
+using std::cout;
+
+namespace
+{
+ struct Base
+ {
+ virtual char kind() { return 'B'; }
+ };
+
+ struct Base2
+ {
+ virtual char kind2() { return '2'; }
+ };
+
+ struct Derived : public Base, Base2
+ {
+ virtual char kind() { return 'D'; }
+ };
+}
+
+
+int main( int argc, char * argv[] )
+{
+ cout << "Usage: test_casts [n], where n omitted or is:\n"
+ " 1 = execute #1 assert failure (#ifndef NDEBUG)\n"
+ " 2 = execute #2 assert failure (#ifndef NDEBUG)\n"
+ "Example: test_casts 2\n\n";
+
+# ifdef NDEBUG
+ cout << "NDEBUG is defined\n";
+# else
+ cout << "NDEBUG is not defined\n";
+# endif
+
+ cout << "\nBeginning tests...\n";
+
+// test polymorphic_cast ---------------------------------------------------//
+
+ // tests which should succeed
+ Base * base = new Derived;
+ Base2 * base2 = 0;
+ Derived * derived = 0;
+ derived = polymorphic_downcast( base ); // downcast
+ assert( derived->kind() == 'D' );
+
+ derived = 0;
+ derived = polymorphic_cast( base ); // downcast, throw on error
+ assert( derived->kind() == 'D' );
+
+ base2 = polymorphic_cast( base ); // crosscast
+ assert( base2->kind2() == '2' );
+
+ // tests which should result in errors being detected
+ int err_count = 0;
+ base = new Base;
+
+ if ( argc > 1 && *argv[1] == '1' )
+ { derived = polymorphic_downcast( base ); } // #1 assert failure
+
+ bool caught_exception = false;
+ try { derived = polymorphic_cast( base ); }
+ catch (std::bad_cast)
+ { cout<<"caught bad_cast\n"; caught_exception = true; }
+ if ( !caught_exception ) ++err_count;
+ // the following is just so generated code can be inspected
+ if ( derived->kind() == 'B' ) ++err_count;
+
+// test implicit_cast and numeric_cast -------------------------------------//
+
+ // tests which should succeed
+ long small_value = 1;
+ long small_negative_value = -1;
+ long large_value = std::numeric_limits::max();
+ long large_negative_value = std::numeric_limits::min();
+ signed char c = 0;
+
+ c = large_value; // see if compiler generates warning
+
+ c = numeric_cast( small_value );
+ assert( c == 1 );
+ c = 0;
+ c = numeric_cast( small_value );
+ assert( c == 1 );
+ c = 0;
+ c = numeric_cast( small_negative_value );
+ assert( c == -1 );
+
+ // These tests courtesy of Joe R NWP Swatosh
+ assert( 0.0f == numeric_cast( 0.0 ) );
+ assert( 0.0 == numeric_cast( 0.0 ) );
+
+ // tests which should result in errors being detected
+
+ caught_exception = false;
+ try { c = numeric_cast( large_value ); }
+ catch (bad_numeric_cast)
+ { cout<<"caught bad_numeric_cast #1\n"; caught_exception = true; }
+ if ( !caught_exception ) ++err_count;
+
+ caught_exception = false;
+ try { c = numeric_cast( large_negative_value ); }
+ catch (bad_numeric_cast)
+ { cout<<"caught bad_numeric_cast #2\n"; caught_exception = true; }
+ if ( !caught_exception ) ++err_count;
+
+ unsigned long ul;
+ caught_exception = false;
+ try { ul = numeric_cast( large_negative_value ); }
+ catch (bad_numeric_cast)
+ { cout<<"caught bad_numeric_cast #3\n"; caught_exception = true; }
+ if ( !caught_exception ) ++err_count;
+
+ caught_exception = false;
+ try { ul = numeric_cast( small_negative_value ); }
+ catch (bad_numeric_cast)
+ { cout<<"caught bad_numeric_cast #4\n"; caught_exception = true; }
+ if ( !caught_exception ) ++err_count;
+
+ caught_exception = false;
+ try { numeric_cast( std::numeric_limits::max() ); }
+ catch (bad_numeric_cast)
+ { cout<<"caught bad_numeric_cast #5\n"; caught_exception = true; }
+ if ( !caught_exception ) ++err_count;
+
+ cout << err_count << " errors detected\nTest "
+ << (err_count==0 ? "passed\n" : "failed\n");
+ return err_count;
+} // main
diff --git a/index.htm b/index.htm
new file mode 100644
index 0000000..3833736
--- /dev/null
+++ b/index.htm
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+Boost Cast Library
+
+
+
+
+
Boost
+Conversion Library
+
+The Conversion Library improves program safety and clarity by performing
+otherwise messy conversions. It includes cast-style function templates designed to complement the C++
+Standard's built-in casts.
+To reduce coupling, particularly to standard library IOStreams, the Boost
+Conversion Library is
+supplied by several headers:
+
+ - The boost/cast header provides polymorphic_cast<>
+ and polymorphic_downcast<> to perform safe casting between
+ polymorphic types, and numeric_cast<> to perform safe casting
+ between numeric types.
+
+ - The boost/lexical_cast header provides lexical_cast<>
+ general literal text conversions, such as an
int
represented as
+ a string
, or vice-versa.
+
+
+Revised 06 January, 2001
+
+
+
+
+
diff --git a/lexical_cast.htm b/lexical_cast.htm
new file mode 100644
index 0000000..2a4af6d
--- /dev/null
+++ b/lexical_cast.htm
@@ -0,0 +1,242 @@
+
+
+
+ lexical_cast
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sometimes a value must be converted to a literal text form, such as an
+int
represented as a string
, or vice-versa, when
+a string
is interpreted as an int
. Such examples
+are common when converting between data types internal to a program and
+representation external to a program, such as windows and configuration files.
+
+The standard C and C++ libraries offer a number of facilities for performing
+such conversions. However, they vary with their ease of use, extensibility,
+and safety.
+
+For instance, there are a number of limitations with the family of standard C
+functions typified by atoi
:
+
+ -
+ Conversion is supported in one direction only: from text to
+ internal data type. Converting the other way using the C library
+ requires either the inconvenience and compromised safety of the
+
sprintf
function, or the loss of portability associated
+ with non-standard functions such as itoa
.
+
+ -
+ The range of types supported is only a subset of the built-in numeric
+ types, namely
int
, long
,
+ and double
.
+
+ -
+ The range of types cannot be extended in a uniform manner. For
+ instance, conversion from string representation to
+
complex
or rational
.
+
+
+The standard C functions typified by strtol
have the same basic
+limitations, but offer finer control over the conversion process. However, for
+the common case such control is often either not required or not used. The
+scanf
family of functions offer even greater control, but also
+lack safety and ease of use.
+
+The standard C++ library offers stringstream
for the kind of
+in-core formatting being discussed. It offers a great deal of control over the
+formatting and conversion of I/O to and from arbitrary types through text.
+However, for simple conversions direct use of stringstream
can be
+either clumsy (with the introduction of extra local variables and the loss of
+infix-expression convenience) or obscure (where stringstream
+objects are created as temporary objects in an expression). Facets provide a
+comprehensive concept and facility for controlling textual representation, but
+their relatively high entry level requires an extreme degree of involvement
+for simple conversions.
+
+The lexical_cast
template function offers a convenient and consistent
+form for supporting common conversions to and from arbitrary types when they are
+represented as text. The simplification it offers is in expression-level
+convenience for such conversions. For more involved conversions, such as where
+precision or formatting need tighter control than is offered by the default
+behavior of lexical_cast
, the conventional
+stringstream
approach is recommended. Where the conversions are
+numeric to numeric, numeric_cast
may offer more reasonable
+behavior than lexical_cast
.
+
+
+
+
+
+The following example treats command line arguments as a sequence of numeric data:
+
+
+int main(int argc, char * argv[])
+{
+ using boost::lexical_cast;
+ using boost::bad_lexical_cast;
+
+ std::vector<short> args;
+
+ while(*++argv)
+ {
+ try
+ {
+ args.push_back(lexical_cast<short>(*argv));
+ }
+ catch(bad_lexical_cast &)
+ {
+ args.push_back(0);
+ }
+ }
+ ...
+}
+
+
+
+The following example uses numeric data in a string expression:
+
+
+void log_message(const std::string &);
+
+void log_errno(int yoko)
+{
+ log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
+}
+
+
+
+
+
+
+Library features defined in "boost/lexical_cast.hpp"
:
+
+
+
+namespace boost
+{
+ class bad_lexical_cast;
+ template<typename Target, typename Source>
+ Target lexical_cast(Source arg);
+}
+
+
+
+Test harness defined in "lexical_cast_test.cpp"
.
+
+
+
+
+
+
+
+template<typename Target, typename Source>
+ Target lexical_cast(Source arg);
+
+
+
+Returns the result of streaming arg
into a std::stringstream
and then
+out as a Target
object. The conversion is parameterized by the current
+lexical_context
, if set. If the conversion is
+unsuccessful, a bad_lexical_cast
exception is thrown
+if the current lexical_context
is set for throwing or
+if there is no current lexical_context
set, otherwise a
+Target()
is returned.
+
+The requirements on the argument and result types are:
+
+ -
+
Source
is OutputStreamable, meaning that an
+ operator<<
is defined that takes a
+ std::ostream
object on the left hand side and an instance
+ of the argument type on the right.
+
+ -
+ Both
Source
and Target
are CopyConstructible [20.1.3].
+
+ -
+
Target
is InputStreamable, meaning that an
+ operator>>
is defined that takes a
+ std::istream
object on the left hand side and an instance
+ of the result type on the right.
+
+ -
+
Target
is DefaultConstructible, meaning that it is
+ possible to default-initialize an object of that type [8.5, 20.1.3].
+
+ -
+
Target
is Assignable [23.1].
+
+
+
+
+
+
+
+
+
+class bad_lexical_cast : public std::bad_cast
+{
+public:
+ virtual const char * what() const throw();
+};
+
+
+
+Exception used to indicate runtime lexical_cast
failure.
+
+
+
+
+
+To date the code and test harness have been compiled successfully using
+Microsoft Visual C++ 6.0, Borland C++ 5.5, and GNU g++ 2.91. Tests have run successfully for
+Microsoft Visual C++ 6.0 and Borland C++ 5.5. For g++ streams interpret any integer, rather than
+just 0
and 1
, as valid for bool
; the other tests pass
+without problem. The deprecated standard header <strstream>
is used in
+preference to the standard <sstream>
header for out-of-the-box g++ support.
+
+
+
+
+
+
+ -
+ A mechanism for providing quality-of-service control is needed, e.g. formatting and exception
+ behavior. In the name of simplicity (and release), the current version strips out an earlier
+ experimental version.
+
+ -
+ Wide character and incompatible
std::basic_string
issues need to be catered for.
+
+ -
+ An
interpret_cast
that performs a do-something-reasonable conversion between
+ types. It would, for instance, select between numeric_cast
and lexical_cast
+ based on std::numeric_limits<>::is_specialized
.
+
+
+
+
+
+© Copyright Kevlin Henney, 2000
+
+
+
diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp
new file mode 100644
index 0000000..c19cf08
--- /dev/null
+++ b/lexical_cast_test.cpp
@@ -0,0 +1,149 @@
+// boost lexical_cast_test.cpp program -------------------------------------//
+
+// See http://www.boost.org for most recent version including documentation.
+
+// what: lexical_cast custom keyword cast tests
+// who: contributed by Kevlin Henney
+// when: October 2000
+// where: tested with MSVC 6.0 and BCC 5.5
+
+#include
+#include "test.hpp"
+#include
+#include
+#include
+
+using namespace boost;
+using namespace std;
+
+typedef test::test test_case;
+typedef const test_case * test_case_iterator;
+
+extern const test_case_iterator begin, end;
+
+int main()
+{
+ test::tester test_suite(begin, end);
+ return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+void test_to_string()
+{
+ test::check_equal(
+ lexical_cast(2001), "2001",
+ "2001 -> \"2001\"");
+ test::check_equal(
+ lexical_cast(2001.0), "2001",
+ "2001.0 ->\"2001\"");
+ test::check_equal(
+ lexical_cast(complex(2000,1)), "(2000,1)",
+ "complex(2000,1) -> \"(2000,1)\"");
+}
+
+void test_to_int()
+{
+ test::check_equal(
+ lexical_cast("2001"), 2001,
+ "\"2001\" -> 2001");
+ test::check_equal(
+ lexical_cast(" 2001"), 2001,
+ "\" 2001\" -> 2001");
+ test::check_equal(
+ lexical_cast("2001 "), 2001,
+ "\"2001 \" -> 2001");
+ TEST_CHECK_THROW(
+ lexical_cast("Two thousand and one"),
+ bad_lexical_cast,
+ "\"Two thousand and one\"");
+ TEST_CHECK_THROW(
+ lexical_cast("2001: A Space Odyssey"),
+ bad_lexical_cast,
+ "\"2001: A Space Odyssey\"");
+ TEST_CHECK_THROW(
+ lexical_cast(200.1),
+ bad_lexical_cast,
+ "200.1");
+ TEST_CHECK_THROW(
+ lexical_cast("200e1"),
+ bad_lexical_cast,
+ "\"200e1\"");
+}
+
+void test_to_char()
+{
+ test::check_equal(
+ lexical_cast("2"), '2',
+ "\"2\" -> '2'");
+ test::check_equal(
+ lexical_cast(" 2"), '2',
+ "\" 2\" -> '2'");
+ test::check_equal(
+ lexical_cast("2 "), '2',
+ "\"2 \" -> '2'");
+ test::check_equal(
+ lexical_cast(2), '2',
+ "2 -> '2'");
+ TEST_CHECK_THROW(
+ lexical_cast("2001"),
+ bad_lexical_cast,
+ "\"2001\"");
+ TEST_CHECK_THROW(
+ lexical_cast(2001),
+ bad_lexical_cast,
+ "2001");
+}
+
+void test_to_double()
+{
+ test::check_equal(
+ lexical_cast("1e6"), 1e6,
+ "\"1e6\" -> 1e6");
+ test::check_equal(
+ lexical_cast("1e-2"), 1e-2,
+ "\"1e-2\" -> 1e-2");
+}
+
+void test_to_bool()
+{
+ test::check_equal(
+ lexical_cast(1), true,
+ "1 -> true");
+ test::check_equal(
+ lexical_cast('0'), false,
+ "'0' -> false");
+ TEST_CHECK_THROW(
+ lexical_cast(2001),
+ bad_lexical_cast,
+ "2001");
+ TEST_CHECK_THROW(
+ lexical_cast(2),
+ bad_lexical_cast,
+ "2");
+ TEST_CHECK_THROW(
+ lexical_cast("true thousand and one"),
+ bad_lexical_cast,
+ "\"true thousand and one\"");
+}
+
+const test_case test_cases[] =
+{
+ { "lexical_cast", test_to_string },
+ { "lexical_cast", test_to_int },
+ { "lexical_cast", test_to_char },
+ { "lexical_cast", test_to_double },
+ { "lexical_cast", test_to_bool }
+};
+
+const test_case_iterator begin = test_cases;
+const test_case_iterator end =
+ test_cases + (sizeof test_cases / sizeof *test_cases);
+
+// Copyright Kevlin Henney, 2000. All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose is hereby granted without fee, provided that this copyright and
+// permissions notice appear in all copies and derivatives, and that no
+// charge may be made for the software and its documentation except to cover
+// cost of distribution.
+//
+// This software is provided "as is" without express or implied warranty.
diff --git a/test.hpp b/test.hpp
new file mode 100644
index 0000000..ba183ef
--- /dev/null
+++ b/test.hpp
@@ -0,0 +1,302 @@
+// what: simple unit test framework
+// who: developed by Kevlin Henney
+// when: November 2000
+// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.91
+
+#ifndef TEST_INCLUDED
+#define TEST_INCLUDED
+
+#include
+#include
+#include // for out-of-the-box g++
+#include
+
+namespace test // test tuple comprises name and nullary function (object)
+{
+ template
+ struct test
+ {
+ string_type name;
+ function_type action;
+
+ static test make(string_type name, function_type action)
+ {
+ test result; // MSVC aggreggate initializer bugs
+ result.name = name;
+ result.action = action;
+ return result;
+ }
+ };
+}
+
+namespace test // failure exception used to indicate checked test failures
+{
+ class failure : public std::exception
+ {
+ public: // struction (default cases are OK)
+
+ failure(const std::string & why)
+ : reason(why)
+ {
+ }
+
+ public: // usage
+
+ virtual const char * what() const throw()
+ {
+ return reason.c_str();
+ }
+
+ private: // representation
+
+ std::string reason;
+
+ };
+}
+
+namespace test // not_implemented exception used to mark unimplemented tests
+{
+ class not_implemented : public std::exception
+ {
+ public: // usage (default ctor and dtor are OK)
+
+ virtual const char * what() const throw()
+ {
+ return "not implemented";
+ }
+
+ };
+}
+
+namespace test // test utilities
+{
+ inline void check(bool condition, const std::string & description)
+ {
+ if(!condition)
+ {
+ throw failure(description);
+ }
+ }
+
+ inline void check_true(bool value, const std::string & description)
+ {
+ check(value, "expected true: " + description);
+ }
+
+ inline void check_false(bool value, const std::string & description)
+ {
+ check(!value, "expected false: " + description);
+ }
+
+ template
+ void check_equal(
+ const lhs_type & lhs, const rhs_type & rhs,
+ const std::string & description)
+ {
+ check(lhs == rhs, "expected equal values: " + description);
+ }
+
+ template
+ void check_unequal(
+ const lhs_type & lhs, const rhs_type & rhs,
+ const std::string & description)
+ {
+ check(lhs != rhs, "expected unequal values: " + description);
+ }
+
+ inline void check_null(const void * ptr, const std::string & description)
+ {
+ check(!ptr, "expected null pointer: " + description);
+ }
+
+ inline void check_non_null(const void * ptr, const std::string & description)
+ {
+ check(ptr, "expected non-null pointer: " + description);
+ }
+}
+
+#define TEST_CHECK_THROW(expression, exception, description) \
+ try \
+ { \
+ expression; \
+ throw ::test::failure(description); \
+ } \
+ catch(exception &) \
+ { \
+ }
+
+namespace test // memory tracking (enabled if test new and delete linked in)
+{
+ class allocations
+ {
+ public: // singleton access
+
+ static allocations & instance()
+ {
+ static allocations singleton;
+ return singleton;
+ }
+
+ public: // logging
+
+ void clear()
+ {
+ alloc_count = dealloc_count = 0;
+ }
+
+ void allocation()
+ {
+ ++alloc_count;
+ }
+
+ void deallocation()
+ {
+ ++dealloc_count;
+ }
+
+ public: // reporting
+
+ unsigned long allocated() const
+ {
+ return alloc_count;
+ }
+
+ unsigned long deallocated() const
+ {
+ return dealloc_count;
+ }
+
+ bool balanced() const
+ {
+ return alloc_count == dealloc_count;
+ }
+
+ private: // structors (default dtor is fine)
+
+ allocations()
+ : alloc_count(0), dealloc_count(0)
+ {
+ }
+
+ private: // prevention
+
+ allocations(const allocations &);
+ allocations & operator=(const allocations &);
+
+ private: // state
+
+ unsigned long alloc_count, dealloc_count;
+
+ };
+}
+
+namespace test // tester is the driver class for a sequence of tests
+{
+ template
+ class tester
+ {
+ public: // structors (default destructor is OK)
+
+ tester(test_iterator first_test, test_iterator after_last_test)
+ : begin(first_test), end(after_last_test)
+ {
+ }
+
+ public: // usage
+
+ bool operator()(); // returns true if all tests passed
+
+ private: // representation
+
+ test_iterator begin, end;
+
+ private: // prevention
+
+ tester(const tester &);
+ tester &operator=(const tester &);
+
+ };
+
+ template
+ bool tester::operator()()
+ {
+ using namespace std;
+
+ unsigned long passed = 0, failed = 0, unimplemented = 0;
+
+ for(test_iterator current = begin; current != end; ++current)
+ {
+ cerr << "[" << current->name << "] " << flush;
+ string result = "passed"; // optimistic
+
+ try
+ {
+ allocations::instance().clear();
+ current->action();
+
+ if(!allocations::instance().balanced())
+ {
+ unsigned long allocated = allocations::instance().allocated();
+ unsigned long deallocated = allocations::instance().deallocated();
+ ostrstream report;
+ report << "new/delete ("
+ << allocated << " allocated, "
+ << deallocated << " deallocated)"
+ << ends;
+ const char * text = report.str();
+ report.freeze(false);
+ throw failure(text);
+ }
+
+ ++passed;
+ }
+ catch(const failure & caught)
+ {
+ (result = "failed: ") += caught.what();
+ ++failed;
+ }
+ catch(const not_implemented &)
+ {
+ result = "not implemented";
+ ++unimplemented;
+ }
+ catch(const exception & caught)
+ {
+ (result = "exception: ") += caught.what();
+ ++failed;
+ }
+ catch(...)
+ {
+ result = "failed with unknown exception";
+ ++failed;
+ }
+
+ cerr << result << endl;
+ }
+
+ cerr << passed + failed << " tests: "
+ << passed << " passed, "
+ << failed << " failed";
+
+ if(unimplemented)
+ {
+ cerr << " (" << unimplemented << " not implemented)";
+ }
+
+ cerr << endl;
+
+ return failed == 0;
+ }
+}
+
+#endif
+
+// Copyright Kevlin Henney, 2000. All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose is hereby granted without fee, provided that this copyright and
+// permissions notice appear in all copies and derivatives, and that no
+// charge may be made for the software and its documentation except to cover
+// cost of distribution.
+//
+// This software is provided "as is" without express or implied warranty.