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