Initial commit

[SVN r10512]
This commit is contained in:
Beman Dawes
2001-07-03 14:07:01 +00:00
commit d3609ba51f
4 changed files with 1028 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain
+199
View File
@@ -0,0 +1,199 @@
// what: unit tests for variant type boost::any
// who: contributed by Kevlin Henney
// when: July 2001
// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
#include <cstdlib>
#include <string>
#include <utility>
#include "boost/any.hpp"
#include "test.hpp"
namespace any_tests
{
typedef test::test<const char *, void (*)()> test_case;
typedef const test_case * test_case_iterator;
extern const test_case_iterator begin, end;
}
int main()
{
using namespace any_tests;
test::tester<test_case_iterator> test_suite(begin, end);
return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
}
namespace any_tests // test suite
{
void test_default_ctor();
void test_converting_ctor();
void test_copy_ctor();
void test_copy_assign();
void test_converting_assign();
void test_bad_cast();
void test_swap();
void test_null_copying();
const test_case test_cases[] =
{
{ "default construction", test_default_ctor },
{ "single argument construction", test_converting_ctor },
{ "copy construction", test_copy_ctor },
{ "copy assignment operator", test_copy_assign },
{ "converting assignment operator", test_converting_assign },
{ "failed custom keyword cast", test_bad_cast },
{ "swap member function", test_swap },
{ "copying operations on a null", test_null_copying }
};
const test_case_iterator begin = test_cases;
const test_case_iterator end =
test_cases + (sizeof test_cases / sizeof *test_cases);
}
namespace any_tests // test definitions
{
using namespace test;
using namespace boost;
void test_default_ctor()
{
const any value;
check_true(value.empty(), "empty");
check_null(any_cast<int>(&value), "any_cast<int>");
check_equal(value.type(), typeid(void), "type");
}
void test_converting_ctor()
{
std::string text = "test message";
any value = text;
check_false(value.empty(), "empty");
check_equal(value.type(), typeid(std::string), "type");
check_null(any_cast<int>(&value), "any_cast<int>");
check_non_null(any_cast<std::string>(&value), "any_cast<std::string>");
check_equal(
any_cast<std::string>(value), text,
"comparing cast copy against original text");
check_unequal(
any_cast<std::string>(&value), &text,
"comparing address in copy against original text");
}
void test_copy_ctor()
{
std::string text = "test message";
any original = text, copy = original;
check_false(copy.empty(), "empty");
check_equal(original.type(), copy.type(), "type");
check_equal(
any_cast<std::string>(original), any_cast<std::string>(copy),
"comparing cast copy against original");
check_equal(
text, any_cast<std::string>(copy),
"comparing cast copy against original text");
check_unequal(
any_cast<std::string>(&original),
any_cast<std::string>(&copy),
"comparing address in copy against original");
}
void test_copy_assign()
{
std::string text = "test message";
any original = text, copy;
any * assign_result = &(copy = original);
check_false(copy.empty(), "empty");
check_equal(original.type(), copy.type(), "type");
check_equal(
any_cast<std::string>(original), any_cast<std::string>(copy),
"comparing cast copy against cast original");
check_equal(
text, any_cast<std::string>(copy),
"comparing cast copy against original text");
check_unequal(
any_cast<std::string>(&original),
any_cast<std::string>(&copy),
"comparing address in copy against original");
check_equal(assign_result, &copy, "address of assignment result");
}
void test_converting_assign()
{
std::string text = "test message";
any value;
any * assign_result = &(value = text);
check_false(value.empty(), "type");
check_equal(value.type(), typeid(std::string), "type");
check_null(any_cast<int>(&value), "any_cast<int>");
check_non_null(any_cast<std::string>(&value), "any_cast<std::string>");
check_equal(
any_cast<std::string>(value), text,
"comparing cast copy against original text");
check_unequal(
any_cast<std::string>(&value),
&text,
"comparing address in copy against original text");
check_equal(assign_result, &value, "address of assignment result");
}
void test_bad_cast()
{
std::string text = "test message";
any value = text;
TEST_CHECK_THROW(
any_cast<const char *>(value),
bad_any_cast,
"any_cast to incorrect type");
}
void test_swap()
{
std::string text = "test message";
any original = text, swapped;
std::string * original_ptr = any_cast<std::string>(&original);
any * swap_result = &original.swap(swapped);
check_true(original.empty(), "empty on original");
check_false(swapped.empty(), "empty on swapped");
check_equal(swapped.type(), typeid(std::string), "type");
check_equal(
text, any_cast<std::string>(swapped),
"comparing swapped copy against original text");
check_non_null(original_ptr, "address in pre-swapped original");
check_equal(
original_ptr,
any_cast<std::string>(&swapped),
"comparing address in swapped against original");
check_equal(swap_result, &original, "address of swap result");
}
void test_null_copying()
{
const any null;
any copied = null, assigned;
assigned = null;
check_true(null.empty(), "empty on null");
check_true(copied.empty(), "empty on copied");
check_true(assigned.empty(), "empty on copied");
}
}
// Copyright Kevlin Henney, 2000, 2001. 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.
+431
View File
@@ -0,0 +1,431 @@
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>any</title>
<meta name="author" content="Kevlin Henney, mailto:kevlin@curbralan.com">
<meta name="generator" content="Microsoft FrontPage 4.0">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h1><img border="0" src="../../c++boost.gif" align="center" width="277" height="86">Header &lt;<a href="../../boost/any.hpp">boost/any.hpp</a>&gt;</h1>
<ul>
<li><a href="#motivation">Motivation</li>
<li><a href="#examples">Examples</li>
<li><a href="#synopsis">Synopsis</li>
<li><a href="#ValueType"><i>ValueType</i> requirements</li>
<li><a href="#any"><code>any</code></li>
<li><a href="#bad_any_cast"><code>bad_any_cast</code></li>
<li><a href="#any_cast"><code>any_cast</code></li>
<li><a href="#portability">Portability</li>
</ul>
<hr>
<h2><a name="motivation">Motivation</a></h2>
There are times when a generic (in the sense of <i>general</i> as opposed to
<i>template-based programming</i>) type is needed: variables that are truly variable,
accommodating values of many other more specific types rather than C++'s normal strict
and static types. We can distinguish three basic kinds of generic type:
<ol>
<li>
Converting types that can hold one of a number of possible value types,
e.g. <code>int</code> and <code>string</code>, and freely convert between them,
for instance interpreting <code>5</code> as <code>"5"</code> or vice-versa.
Such types are common in scripting and other interpreted languages.
<a href="../conversion/lexical_cast.htm">
<code>boost::lexical_cast</code></a> supports such conversion functionality.
</li>
<li>
Discriminated types that contain values of different types but do not attempt conversion between
them, i.e. <code>5</code> is held strictly as an <code>int</code> and is not implicitly
convertible either to <code>"5"</code> or to <code>5.0</code>. Their indifference to
interpretation but awareness of type effectively makes them safe, generic containers of single
values, with no scope for surprises from ambiguous conversions.
</li>
<li>
Indiscriminate types that can refer to anything but are oblivious to the actual underlying type,
entrusting all forms of access and interpretation to the programmer. This niche is dominated by
<code>void *</code>, which offers plenty of scope for surprising, undefined behavior.
</li>
</ol>
The <code>any</code> class (based on the class of the same name described in
<a href="http://www.two-sdg.demon.co.uk/curbralan/papers/ValuedConversions.pdf">"Valued Conversions"</a>
by Kevlin Henney, <i>C++ Report</i> 12(7), July/August 2000) is a variant value type based on the second
category. It supports copying of any value type and safe checked extraction of that value strictly
against its type. A similar design, offering more appropriate operators, can be used for a generalized
function adaptor, <code>any_function</code>, a generalized iterator adaptor, <code>any_iterator</code>,
and other object types that need uniform runtime treatment but support only compile-time template
parameter conformance.
<p>
<hr>
<h2><a name="examples">Examples</a></h2>
The following code demonstrates the syntax for using implicit conversions to and copying of
<code>any</code> objects:
<blockquote>
<pre>
#include &lt;list&gt;
#include &lt;boost/any.hpp&gt;
typedef std::list&lt;boost::any&gt; many;
void append_int(many &amp; values, int value)
{
boost::any to_append = value;
values.push_back(to_append);
}
void append_string(many &amp; values, const std::string &amp; value)
{
values.push_back(value);
}
void append_char_ptr(many &amp; values, const char * value)
{
values.push_back(value);
}
void append_any(many &amp; values, const boost::any &amp; value)
{
values.push_back(value);
}
void append_nothing(many &amp; values)
{
values.push_back(boost::any());
}
</pre>
</blockquote>
The following predicates follow on from the previous definitions and demonstrate
the use of queries on <code>any</code> objects:
<blockquote>
<pre>
bool is_empty(const boost::any &amp; operand)
{
return operand.empty();
}
bool is_int(const boost::any &amp; operand)
{
return operand.type() == typeid(int);
}
bool is_char_ptr(const boost::any &amp; operand)
{
try
{
any_ptr&lt;const char *&gt;(operand);
return true;
}
catch(const boost::bad_any_cast &amp;)
{
return false;
}
}
bool is_string(const boost::any &amp; operand)
{
return any_ptr&lt;std::string&gt;(&amp;operand);
}
void count_all(many &amp; values, std::ostream &amp; out)
{
out &lt;&lt; &quot;#empty == &quot;
&lt;&lt; std::count_if(values.begin(), values.end(), is_empty) &lt;&lt; std::endl;
out &lt;&lt; &quot;#int == &quot;
&lt;&lt; std::count_if(values.begin(), values.end(), is_int) &lt;&lt; std::endl;
out &lt;&lt; &quot;#const char * == &quot;
&lt;&lt; std::count_if(values.begin(), values.end(), is_char_ptr) &lt;&lt; std::endl;
out &lt;&lt; &quot;#string == &quot;
&lt;&lt; std::count_if(values.begin(), values.end(), is_string) &lt;&lt; std::endl;
}
</pre>
</blockquote>
The following type, patterned after the OMG's Property Service, defines name&#150;value
pairs for arbitrary value types:
<blockquote>
<pre>
struct property
{
property();
property(const std::string &amp;, const boost::any &amp;);
std::string name;
boost::any value;
};
typedef std::list&lt;property&gt; properties;
</pre>
</blockquote>
The following base class demonstrates one approach to runtime polymorphism based callbacks that also
require arbitrary argument types. The absence of <code>virtual</code> member templates requires that
different solutions have different trade-offs in terms of efficiency, safety, and generality. Using
a checked variant type offers one approach:
<blockquote>
<pre>
class consumer
{
public:
virtual void notify(const any &amp;) = 0;
...
};
</pre>
</blockquote>
<hr>
<h2><a name="synopsis">Synopsis</a></h2>
Dependencies and library features defined in <a href="../../boost/any.hpp"><code>&quot;boost/any.hpp&quot;</code></a>:
<blockquote>
<pre>
#include &lt;typeinfo&gt;
namespace boost
{
class <a href="#any">any</a>;
class <a href="#bad_any_cast">bad_any_cast</a>;
template&lt;typename <a href="#ValueType">ValueType</a>&gt;
<a href="#ValueType">ValueType</a> <a href="#any_cast">any_cast</a>(const <a href="#any">any</a> &amp;);
}
</pre>
</blockquote>
Test harness defined in <a href="any_test.cpp"><code>&quot;any_test.cpp&quot;</code></a>.
<p>
<hr>
<h2><a name="ValueType"><i>ValueType</i> requirements</a></h2>
Values are strongly informational objects for which identity is not significant,
i.e. the focus is principally on their state content and any behavior organized around that.
Another distinguishing feature of values is their granularity: normally fine-grained
objects representing simple concepts in the system such as quantities.
<p>
As the emphasis of a value lies in its state not its identity, values can be copied and
typically assigned one to another, requiring the explicit or implicit definition of a
public copy constructor and public assignment operator. Values typically live within
other scopes, i.e. within objects or blocks, rather than on the heap. Values are therefore
normally passed around and manipulated directly as variables or through references, but not
as pointers that emphasize identity and indirection.
<p>
The specific requirements on value types to be used in an <a href="#any"><code>any</code></a> are:
<ul>
<li>
A <i>ValueType</i> is <i>CopyConstructible</i> [20.1.3].
</li>
<li>
A <i>ValueType</i> is optionally <i>Assignable</i> [23.1]. The strong exception-safety
guarantee is required for all forms of assignment.
</li>
<li>
The destructor for a <i>ValueType</i> upholds the no-throw exception-safety guarantee.
</li>
</ul>
<p>
<hr>
<h2><a name="any"><code>any</code></a></h2>
<blockquote>
<pre>
class any
{
public: // <a href="#structors"><i>structors</i></a>
<a href="#default-ctor">any</a>();
<a href="#copy-ctor">any</a>(const any &amp;);
template&lt;typename <a href="#ValueType">ValueType</a>&gt;
<a href="#template-ctor">any</a>(const <a href="#ValueType">ValueType</a> &amp;);
<a href="#dtor">~any</a>();
public: // <a href="#modifiers"><i>modifiers</i></a>
any &amp; <a href="#swap">swap</a>(any &amp;);
any &amp; <a href="#copy-assign">operator=</a>(const any &amp;);
template&lt;typename <a href="#ValueType">ValueType</a>&gt;
any &amp; <a href="#template-assign">operator=</a>(const <a href="#ValueType">ValueType</a> &amp;);
public: // <a href="#queries"><i>queries</i></a>
bool <a href="#empty">empty</a>() const;
const std::type_info &amp; <a href="#type">type</a>() const;
private: // <i>representation</i>
...
};
</pre>
</blockquote>
A class whose instances can hold instances of any type that satisfies
<a href="#ValueType"><i>ValueType</i></a> requirements: effectively an unbounded <code>union</code> type.
Note that <code>any</code> itself satisfies <a href="#ValueType"><i>ValueType</i></a> requirements with
assignment.
<p>
<ul>
<hr>
<h3><a name="structors">Structors</a></h3>
<blockquote>
<pre>
<a name="default-ctor">any::any();</a>
</pre>
</blockquote>
Default constructor that sets new instance to empty.
<blockquote>
<pre>
<a name="copy-ctor">any::any(const any &amp; other);</a>
</pre>
</blockquote>
Copy constructor that copies content of <code>other</code> into new instance, so that
any content is equivalent in both type and value to the content of <code>other</code>,
or empty if <code>other</code> is empty. May fail with a <code>std::bad_alloc</code> exception
or any exceptions arising from the copy constructor of the contained type.
<blockquote>
<pre>
<a name="template-ctor">template&lt;typename </a><a href="#ValueType">ValueType</a>&gt;
any::any(const <a href="#ValueType">ValueType</a> &amp; value);
</pre>
</blockquote>
Templated converting constructor makes a copy of <code>value</code>, so that the initial
content of the new instance is equivalent in both type and value to <code>value</code>.
May fail with a <code>std::bad_alloc</code> exception or any exceptions arising from the
copy constructor of
the contained type.
<blockquote>
<pre>
<a name="dtor">any::~any();</a>
</pre>
</blockquote>
Non-throwing destructor that releases any and all resources used in management of instance.
<p>
<hr>
<h3><a name="modifiers">Modifiers</a></h3>
<blockquote>
<pre>
<a name="swap">any &amp; swap(any &amp; rhs);</a>
</pre>
</blockquote>
Non-throwing exchange of the contents of <code>*this</code> and <code>rhs</code>.
<blockquote>
<pre>
<a name="copy-assign">any &amp; operator=(const any &amp; rhs);</a>
</pre>
</blockquote>
Copy assignment operator that copies content of <code>rhs</code> into current instance, discarding
previous content, so that the new content is equivalent in both type and value to the content of
<code>rhs</code>, or empty if <code>rhs.empty()</code>. May fail with a <code>std::bad_alloc</code>
exception or any exceptions arising from the copy constructor of the contained type.
Assignment satisfies the strong guarantee of exception safety.
<blockquote>
<pre>
<a name="template-assign">template&lt;typename </a><a href="#ValueType">ValueType</a>&gt;
any &amp; operator=(const <a href="#ValueType">ValueType</a> &amp; rhs);
</pre>
</blockquote>
Templated assignment operator makes a copy of <code>rhs</code>, discarding previous content,
so that the new content of is equivalent in both type and value to <code>rhs</code>. May fail with a
<code>std::bad_alloc</code> exception or any exceptions arising from the copy constructor of
the contained type. Assignment satisfies the strong guarantee of exception safety.
<p>
<hr>
<h3><a name="queries">Queries</a></h3>
<blockquote>
<pre>
<a name="empty">bool empty() const;</a>
</pre>
</blockquote>
Test for emptiness, returning <code>true</code> if instance is empty, otherwise <code>false</code>.
<blockquote>
<pre>
<a name="type">const std::type_info &amp; type() const;</a>
</pre>
</blockquote>
Returns the <code>typeid</code> of the contained value if instance is non-empty, otherwise
<code>typeid(void)</code> returned. Useful for querying against types known either at
compile time or only at runtime.
</ul>
<hr>
<h2><a name="bad_any_cast"><code>bad_any_cast</code></a></h2>
<blockquote>
<pre>
class bad_any_cast : public std::bad_cast
{
public:
virtual const char * what() const;
};
</pre>
</blockquote>
The exception thrown in the event of a failed <a href="#any_cast"><code>any_cast</code></a> of
an <a href="#any"><code>any</code></a> value.
<p>
<hr>
<h2><a name="any_cast"><code>any_cast</code></a></h2>
<blockquote>
<pre>
template&lt;typename <a href="#ValueType">ValueType</a>&gt;
<a href="#ValueType">ValueType</a> any_cast(const <a href="#any">any</a> &amp; operand);
template&lt;typename <a href="#ValueType">ValueType</a>&gt;
const <a href="#ValueType">ValueType</a> * any_cast(const <a href="#any">any</a> * operand);
template&lt;typename <a href="#ValueType">ValueType</a>&gt;
<a href="#ValueType">ValueType</a> * any_cast(<a href="#any">any</a> * operand);
</pre>
</blockquote>
Custom keyword cast for extracting a value of a given type from an
<a href="#any"><code>any</code></a>. If passed a pointer, it returns a similarly qualified
pointer to the value content if successful, otherwise null is returned. If passed a value or
reference, it returns a copy of the value content if successful, otherwise a
<a href="#bad_any_cast"><code>bad_any_cast</code></a> exception is thrown.
<p>
<hr>
<h2><a name="portability">Portability</a></h2>
To date the code and test harness have been compiled and tested successfully using Borland C++ 5.5,
Microsoft Visual C++ 6.0, and GNU g++ 2.95.
<p>
<hr>
<div align="right"><small><i>&copy; Copyright Kevlin Henney, 2001</i></small></div>
</body>
</html>
+302
View File
@@ -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 <exception>
#include <iostream>
#include <strstream> // for out-of-the-box g++
#include <string>
namespace test // test tuple comprises name and nullary function (object)
{
template<typename string_type, typename function_type>
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<typename lhs_type, typename rhs_type>
void check_equal(
const lhs_type & lhs, const rhs_type & rhs,
const std::string & description)
{
check(lhs == rhs, "expected equal values: " + description);
}
template<typename lhs_type, typename rhs_type>
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<typename test_iterator>
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<typename test_iterator>
bool tester<test_iterator>::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.