mirror of
https://github.com/boostorg/any.git
synced 2026-07-21 13:03:30 +00:00
Initial commit
[SVN r10512]
This commit is contained in:
@@ -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
@@ -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>(©),
|
||||
"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>(©),
|
||||
"comparing address in copy against original");
|
||||
check_equal(assign_result, ©, "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
@@ -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 <<a href="../../boost/any.hpp">boost/any.hpp</a>></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 <list>
|
||||
#include <boost/any.hpp>
|
||||
|
||||
typedef std::list<boost::any> many;
|
||||
|
||||
void append_int(many & values, int value)
|
||||
{
|
||||
boost::any to_append = value;
|
||||
values.push_back(to_append);
|
||||
}
|
||||
|
||||
void append_string(many & values, const std::string & value)
|
||||
{
|
||||
values.push_back(value);
|
||||
}
|
||||
|
||||
void append_char_ptr(many & values, const char * value)
|
||||
{
|
||||
values.push_back(value);
|
||||
}
|
||||
|
||||
void append_any(many & values, const boost::any & value)
|
||||
{
|
||||
values.push_back(value);
|
||||
}
|
||||
|
||||
void append_nothing(many & 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 & operand)
|
||||
{
|
||||
return operand.empty();
|
||||
}
|
||||
|
||||
bool is_int(const boost::any & operand)
|
||||
{
|
||||
return operand.type() == typeid(int);
|
||||
}
|
||||
|
||||
bool is_char_ptr(const boost::any & operand)
|
||||
{
|
||||
try
|
||||
{
|
||||
any_ptr<const char *>(operand);
|
||||
return true;
|
||||
}
|
||||
catch(const boost::bad_any_cast &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_string(const boost::any & operand)
|
||||
{
|
||||
return any_ptr<std::string>(&operand);
|
||||
}
|
||||
|
||||
void count_all(many & values, std::ostream & out)
|
||||
{
|
||||
out << "#empty == "
|
||||
<< std::count_if(values.begin(), values.end(), is_empty) << std::endl;
|
||||
out << "#int == "
|
||||
<< std::count_if(values.begin(), values.end(), is_int) << std::endl;
|
||||
out << "#const char * == "
|
||||
<< std::count_if(values.begin(), values.end(), is_char_ptr) << std::endl;
|
||||
out << "#string == "
|
||||
<< std::count_if(values.begin(), values.end(), is_string) << std::endl;
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
The following type, patterned after the OMG's Property Service, defines name–value
|
||||
pairs for arbitrary value types:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
struct property
|
||||
{
|
||||
property();
|
||||
property(const std::string &, const boost::any &);
|
||||
|
||||
std::string name;
|
||||
boost::any value;
|
||||
};
|
||||
|
||||
typedef std::list<property> 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 &) = 0;
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
<h2><a name="synopsis">Synopsis</a></h2>
|
||||
|
||||
Dependencies and library features defined in <a href="../../boost/any.hpp"><code>"boost/any.hpp"</code></a>:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class <a href="#any">any</a>;
|
||||
class <a href="#bad_any_cast">bad_any_cast</a>;
|
||||
template<typename <a href="#ValueType">ValueType</a>>
|
||||
<a href="#ValueType">ValueType</a> <a href="#any_cast">any_cast</a>(const <a href="#any">any</a> &);
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
Test harness defined in <a href="any_test.cpp"><code>"any_test.cpp"</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 &);
|
||||
template<typename <a href="#ValueType">ValueType</a>>
|
||||
<a href="#template-ctor">any</a>(const <a href="#ValueType">ValueType</a> &);
|
||||
<a href="#dtor">~any</a>();
|
||||
|
||||
public: // <a href="#modifiers"><i>modifiers</i></a>
|
||||
|
||||
any & <a href="#swap">swap</a>(any &);
|
||||
any & <a href="#copy-assign">operator=</a>(const any &);
|
||||
template<typename <a href="#ValueType">ValueType</a>>
|
||||
any & <a href="#template-assign">operator=</a>(const <a href="#ValueType">ValueType</a> &);
|
||||
|
||||
public: // <a href="#queries"><i>queries</i></a>
|
||||
|
||||
bool <a href="#empty">empty</a>() const;
|
||||
const std::type_info & <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 & 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<typename </a><a href="#ValueType">ValueType</a>>
|
||||
any::any(const <a href="#ValueType">ValueType</a> & 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 & swap(any & 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 & operator=(const any & 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<typename </a><a href="#ValueType">ValueType</a>>
|
||||
any & operator=(const <a href="#ValueType">ValueType</a> & 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 & 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<typename <a href="#ValueType">ValueType</a>>
|
||||
<a href="#ValueType">ValueType</a> any_cast(const <a href="#any">any</a> & operand);
|
||||
template<typename <a href="#ValueType">ValueType</a>>
|
||||
const <a href="#ValueType">ValueType</a> * any_cast(const <a href="#any">any</a> * operand);
|
||||
template<typename <a href="#ValueType">ValueType</a>>
|
||||
<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>© Copyright Kevlin Henney, 2001</i></small></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user