update from Kevlin and Terje

[SVN r17861]
This commit is contained in:
Beman Dawes
2003-03-12 21:33:16 +00:00
parent 0d7e048f06
commit 42639f120a
3 changed files with 607 additions and 392 deletions

View File

@@ -1,67 +1,176 @@
// boost lexical_cast.hpp header -------------------------------------------//
// See http://www.boost.org/libs/conversion for documentation.
#ifndef BOOST_LEXICAL_CAST_INCLUDED #ifndef BOOST_LEXICAL_CAST_INCLUDED
#define BOOST_LEXICAL_CAST_INCLUDED #define BOOST_LEXICAL_CAST_INCLUDED
// boost lexical_cast.hpp header --------------------------------------------//
// See http://www.boost.org/libs/conversion for documentation.
// See end of this header for rights and permissions.
//
// what: lexical_cast custom keyword cast // what: lexical_cast custom keyword cast
// who: contributed by Kevlin Henney, with alternative naming, behaviors // who: contributed by Kevlin Henney,
// and fixes contributed by Dave Abrahams, Daryle Walker and other // enhanced with contributions from Terje Sletteb<65>,
// Boosters on the list // with additional fixes and suggestions from Gennaro Prota,
// when: November 2000 // Dave Abrahams, Daryle Walker, and other Boosters on the list
// where: tested with MSVC 6.0, BCC 5.5, and g++ 2.91 // when: November 2000, March 2003
#include <string>
#include <typeinfo>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/type_traits.hpp>
// Some sstream implementations are broken for the purposes of lexical cast. #ifdef BOOST_NO_STRINGSTREAM
# if defined(BOOST_NO_STRINGSTREAM)
# define BOOST_LEXICAL_CAST_USE_STRSTREAM
# endif
#ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM
#include <strstream> #include <strstream>
#else #else
#include <sstream> #include <sstream>
#endif #endif
#include <typeinfo>
namespace boost namespace boost
{ {
// exception used to indicate runtime lexical_cast failure // exception used to indicate runtime lexical_cast failure
class bad_lexical_cast : public std::bad_cast class bad_lexical_cast : public std::bad_cast
{ {
public: public:
// constructors, destructors, and assignment operator defaulted virtual ~bad_lexical_cast() throw()
// function inlined for brevity and consistency with rest of library
virtual const char * what() const throw()
{ {
return "bad lexical cast: "
"source type value could not be interpreted as target";
} }
}; };
namespace detail // actual underlying concrete exception type
{
template<typename Target, typename Source>
class no_lexical_conversion : public bad_lexical_cast
{
public:
no_lexical_conversion()
: description(
std::string() + "bad lexical cast: " +
"source type value could not be interpreted as target, Target=" +
typeid(Target).name() + ", Source=" + typeid(Source).name())
{
}
virtual ~no_lexical_conversion() throw()
{
}
virtual const char *what() const throw()
{
return description.c_str();
}
private:
const std::string description; // static initialization fails on MSVC6
};
}
namespace detail // selectors for choosing stream character type
{
template<typename Type>
struct stream_char
{
typedef char type;
};
#ifndef BOOST_NO_STRINGSTREAM
template<>
struct stream_char<wchar_t>
{
typedef wchar_t type;
};
template<>
struct stream_char<wchar_t *>
{
typedef wchar_t type;
};
template<>
struct stream_char<const wchar_t *>
{
typedef wchar_t type;
};
template<>
struct stream_char<std::wstring>
{
typedef wchar_t type;
};
#endif
template<typename TargetChar, typename SourceChar>
struct widest_char
{
typedef TargetChar type;
};
template<>
struct widest_char<char, wchar_t>
{
typedef wchar_t type;
};
}
namespace detail // stream wrapper for handling lexical conversions
{
template<typename Target, typename Source>
class lexical_stream
{
public:
lexical_stream()
{
stream.unsetf(std::ios::skipws);
if(std::numeric_limits<Target>::is_specialized)
stream.precision(std::numeric_limits<Target>::digits10 + 1);
else if(std::numeric_limits<Source>::is_specialized)
stream.precision(std::numeric_limits<Source>::digits10 + 1);
}
~lexical_stream()
{
#if defined(BOOST_NO_STRINGSTREAM)
stream.freeze(false);
#endif
}
bool operator<<(const Source &input)
{
return stream << input;
}
template<typename InputStreamable>
bool operator>>(InputStreamable &output)
{
return !is_pointer<InputStreamable>::value &&
stream >> output &&
(stream >> std::ws).eof();
}
template<typename Char, typename Traits, typename Allocator>
bool operator>>(std::basic_string<Char, Traits, Allocator> &output)
{
return std::getline(stream, output, char_type()).eof();
}
private:
typedef typename widest_char<
typename stream_char<Target>::type,
typename stream_char<Source>::type>::type char_type;
#if defined(BOOST_NO_STRINGSTREAM)
std::strstream stream;
#else
std::basic_stringstream<char_type> stream;
#endif
};
}
template<typename Target, typename Source> template<typename Target, typename Source>
Target lexical_cast(Source arg) Target lexical_cast(Source arg)
{ {
# ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM detail::lexical_stream<Target, Source> interpreter;
std::strstream interpreter; // for out-of-the-box g++ 2.95.2
# else
std::stringstream interpreter;
# endif
Target result; Target result;
if(!(interpreter << arg) || !(interpreter >> result) || if(!(interpreter << arg && interpreter >> result))
!(interpreter >> std::ws).eof()) throw detail::no_lexical_conversion<Target, Source>();
throw bad_lexical_cast();
return result; return result;
} }
} }
// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. // Copyright Kevlin Henney, 2000-2003. All rights reserved.
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and // purpose is hereby granted without fee, provided that this copyright and
@@ -69,8 +178,4 @@ namespace boost
// //
// This software is provided "as is" without express or implied warranty. // This software is provided "as is" without express or implied warranty.
#ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM
# undef BOOST_LEXICAL_CAST_USE_STRSTREAM
#endif
#endif #endif

View File

@@ -5,61 +5,56 @@
<meta name="author" content="Kevlin Henney, mailto:kevlin@curbralan.com"> <meta name="author" content="Kevlin Henney, mailto:kevlin@curbralan.com">
<meta name="generator" content="Microsoft FrontPage 4.0"> <meta name="generator" content="Microsoft FrontPage 4.0">
</head> </head>
<body bgcolor="#FFFFFF" text="#000000"> <body bgcolor="#FFFFFF" text="#000000">
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header <h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
<a href="../../boost/lexical_cast.hpp">boost/lexical_cast.hpp</a></h1> <a href="../../boost/lexical_cast.hpp">boost/lexical_cast.hpp</a></h1>
<ul> <ul>
<li><a href="#motivation">Motivation</a></li> <li>
<li><a href="#examples">Examples</a></li> <a href="#motivation">Motivation</a></li>
<li><a href="#synopsis">Synopsis</a></li> <li>
<li><a href="#lexical_cast"><code>lexical_cast</code></a></li> <a href="#examples">Examples</a></li>
<li><a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a></li> <li>
<li><a href="#portability">Portability</a></li> <a href="#synopsis">Synopsis</a></li>
<li><a href="#future">Future directions</a></li> <li>
<a href="#lexical_cast"><code>lexical_cast</code></a></li>
<li>
<a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a></li>
</ul> </ul>
<hr> <hr>
<h2><a name="motivation">Motivation</a></h2> <h2><a name="motivation">Motivation</a></h2>
Sometimes a value must be converted to a literal text form, such as an <code>int</code>
Sometimes a value must be converted to a literal text form, such as an represented as a <code>string</code>, or vice-versa, when a <code>string</code>
<code>int</code> represented as a <code>string</code>, or vice-versa, when is interpreted as an <code>int</code>. Such examples are common when converting
a <code>string</code> is interpreted as an <code>int</code>. Such examples between data types internal to a program and representation external to a
are common when converting between data types internal to a program and program, such as windows and configuration files.
representation external to a program, such as windows and configuration files.
<p> <p>
The standard C and C++ libraries offer a number of facilities for performing The standard C and C++ libraries offer a number of facilities for performing
such conversions. However, they vary with their ease of use, extensibility, such conversions. However, they vary with their ease of use, extensibility, and
and safety. safety.
<p> <p>
For instance, there are a number of limitations with the family of standard C For instance, there are a number of limitations with the family of standard C
functions typified by <code>atoi</code>: functions typified by <code>atoi</code>:
<ul> <ul>
<li> <li>
Conversion is supported in one direction only: from text to Conversion is supported in one direction only: from text to internal data type.
internal data type. Converting the other way using the C library Converting the other way using the C library requires either the inconvenience
requires either the inconvenience and compromised safety of the and compromised safety of the <code>sprintf</code> function, or the loss of
<code>sprintf</code> function, or the loss of portability associated portability associated with non-standard functions such as <code>itoa</code>.
with non-standard functions such as <code>itoa</code>.
</li> </li>
<li> <li>
The range of types supported is only a subset of the built-in numeric The range of types supported is only a subset of the built-in numeric types,
types, namely <code>int</code>, <code>long</code>, namely <code>int</code>, <code>long</code>, and <code>double</code>.
and <code>double</code>.
</li> </li>
<li> <li>
The range of types cannot be extended in a uniform manner. For The range of types cannot be extended in a uniform manner. For instance,
instance, conversion from string representation to conversion from string representation to <code>complex</code> or <code>rational</code>.
<code>complex</code> or <code>rational</code>.
</li> </li>
</ul> </ul>
The standard C functions typified by <code>strtol</code> have the same basic The standard C functions typified by <code>strtol</code> have the same basic
limitations, but offer finer control over the conversion process. However, for limitations, but offer finer control over the conversion process. However, for
the common case such control is often either not required or not used. The the common case such control is often either not required or not used. The <code>scanf</code>
<code>scanf</code> family of functions offer even greater control, but also family of functions offer even greater control, but also lack safety and ease
lack safety and ease of use. of use.
<p> <p>
The standard C++ library offers <code>stringstream</code> for the kind of The standard C++ library offers <code>stringstream</code> for the kind of
in-core formatting being discussed. It offers a great deal of control over the in-core formatting being discussed. It offers a great deal of control over the
@@ -69,30 +64,30 @@ either clumsy (with the introduction of extra local variables and the loss of
infix-expression convenience) or obscure (where <code>stringstream</code> infix-expression convenience) or obscure (where <code>stringstream</code>
objects are created as temporary objects in an expression). Facets provide a objects are created as temporary objects in an expression). Facets provide a
comprehensive concept and facility for controlling textual representation, but comprehensive concept and facility for controlling textual representation, but
their relatively high entry level requires an extreme degree of involvement their perceived complexity and high entry level requires an extreme degree of
for simple conversions. involvement for simple conversions, and excludes all but a few programmers.
<p> <p>
The <code>lexical_cast</code> template function offers a convenient and consistent The <code>lexical_cast</code> function template offers a convenient and
form for supporting common conversions to and from arbitrary types when they are consistent form for supporting common conversions to and from arbitrary types
represented as text. The simplification it offers is in expression-level when they are represented as text. The simplification it offers is in
convenience for such conversions. For more involved conversions, such as where expression-level convenience for such conversions. For more involved
precision or formatting need tighter control than is offered by the default conversions, such as where precision or formatting need tighter control than is
behavior of <code>lexical_cast</code>, the conventional offered by the default behavior of <code>lexical_cast</code>, the conventional <code>
<code>stringstream</code> approach is recommended. Where the conversions are stringstream</code> approach is recommended. Where the conversions are
numeric to numeric, <code><a href="cast.htm#numeric_cast">numeric_cast</a></code> numeric to numeric, <code><a href="cast.htm#numeric_cast">numeric_cast</a></code>
may offer more reasonable behavior than <code>lexical_cast</code>. may offer more reasonable behavior than <code>lexical_cast</code>
.
<p> <p>
For a good discussion of the options and issues involved in string-based formatting, For a good discussion of the options and issues involved in string-based
including comparison of <code>stringstream</code>, <code>lexical_cast</code>, and formatting, including comparison of <code>stringstream</code>, <code>lexical_cast</code>,
others, see Herb Sutter's article, <a href="http://www.gotw.ca/publications/mill19.htm"> and others, see Herb Sutter's article, <a href="http://www.gotw.ca/publications/mill19.htm">
<i>The String Formatters of Manor Farm</i></a>. <i>The String Formatters of Manor Farm</i></a>
.
<p> <p>
<hr> <hr>
<h2><a name="examples">Examples</a></h2> <h2><a name="examples">Examples</a></h2>
The following example treats command line arguments as a sequence of numeric
The following example treats command line arguments as a sequence of numeric data: data: <blockquote>
<blockquote>
<pre> <pre>
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
@@ -115,10 +110,7 @@ int main(int argc, char * argv[])
... ...
} }
</pre> </pre>
</blockquote> </blockquote>The following example uses numeric data in a string expression: <blockquote>
The following example uses numeric data in a string expression:
<blockquote>
<pre> <pre>
void log_message(const std::string &amp;); void log_message(const std::string &amp;);
@@ -128,12 +120,9 @@ void log_errno(int yoko)
} }
</pre> </pre>
</blockquote> </blockquote>
<hr> <hr>
<h2><a name="synopsis">Synopsis</a></h2> <h2><a name="synopsis">Synopsis</a></h2>
Library features defined in <a href="../../boost/lexical_cast.hpp"><code>&quot;boost/lexical_cast.hpp&quot;</code></a>: Library features defined in <a href="../../boost/lexical_cast.hpp"><code>&quot;boost/lexical_cast.hpp&quot;</code></a>:
<blockquote> <blockquote>
<pre> <pre>
namespace boost namespace boost
@@ -143,110 +132,65 @@ namespace boost
Target <a href="#lexical_cast">lexical_cast</a>(Source arg); Target <a href="#lexical_cast">lexical_cast</a>(Source arg);
} }
</pre> </pre>
</blockquote> </blockquote>Unit test defined in <a href="lexical_cast_test.cpp"><code>&quot;lexical_cast_test.cpp&quot;</code></a>.
Test harness defined in <a href="lexical_cast_test.cpp"><code>&quot;lexical_cast_test.cpp&quot;</code></a>.
<p> <p>
<hr> <hr>
<h2><a name="lexical_cast"><code>lexical_cast</code></a></h2> <h2><a name="lexical_cast"><code>lexical_cast</code></a></h2>
<blockquote> <blockquote>
<pre> <pre>
template&lt;typename Target, typename Source&gt; template&lt;typename Target, typename Source&gt;
Target lexical_cast(Source arg); Target lexical_cast(Source arg);
</pre> </pre>
</blockquote> </blockquote>Returns the result of streaming <code>arg</code> into a <code>std::stringstream</code>
and then out as a <code>Target</code> object. Note that spaces are significant
Returns the result of streaming <code>arg</code> into a <code>std::stringstream</code> and then in any conversion and are not skipped. If the conversion is unsuccessful, a <a href="#bad_lexical_cast">
out as a <code>Target</code> object. If the conversion is unsuccessful, a <code>bad_lexical_cast</code></a>
<a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a> exception is thrown. exception is thrown.
<p> <p>
The requirements on the argument and result types are: The requirements on the argument and result types are:
<ul> <ul>
<li> <li>
<code>Source</code> is <i>OutputStreamable</i>, meaning that an <code>Source</code> is <i>OutputStreamable</i>, meaning that an <code>operator&lt;&lt;</code>
<code>operator&lt;&lt;</code> is defined that takes a is defined that takes a <code>std::ostream</code> or <code>std::wostream</code> object on the
<code>std::ostream</code> object on the left hand side and an instance left hand side and an instance of the argument type on the right.
of the argument type on the right.
</li> </li>
<li> <li>
Both <code>Source</code> and <code>Target</code> are <i>CopyConstructible</i> [20.1.3]. Both <code>Source</code> and <code>Target</code> are <i>CopyConstructible</i> [20.1.3].
</li> </li>
<li> <li>
<code>Target</code> is <i>InputStreamable</i>, meaning that an <code>Target</code> is <i>InputStreamable</i>, meaning that an <code>operator&gt;&gt;</code>
<code>operator&gt;&gt;</code> is defined that takes a is defined that takes a <code>std::istream</code> or <code>std::wistream</code> object on the left hand side
<code>std::istream</code> object on the left hand side and an instance and an instance of the result type on the right.
of the result type on the right.
</li> </li>
<li> <li>
<code>Target</code> is <i>DefaultConstructible</i>, meaning that it is <code>Target</code> is <i>DefaultConstructible</i>, meaning that it is possible
possible to <i>default-initialize</i> an object of that type [8.5, 20.1.3]. to <i>default-initialize</i> an object of that type [8.5, 20.1.4].
</li>
<li>
<code>Target</code> is <i>Assignable</i> [23.1].
</li> </li>
</ul> </ul>
The character type of the underlying stream is assumed to be <code>char</code> unless
the either the <code>Source</code> or the <code>Target</code> type is <code>wchar_t</code>
or a wide-character string type &#151; either <code>wchar_t *</code> or <code>std::wstring</code> &#151;
in which case <code>wchar_t</code> is used.
<p>
Where a higher degree of control is required over conversions, <code>std::stringstream</code>
and <code>std::wstringstream</code> offer a more appropriate path. Where non-stream-based conversions are
required, <code>lexical_cast</code>
is the wrong tool for the job, and is not special-cased for such scenarios.
<p> <p>
<hr> <hr>
<h2><a name="bad_lexical_cast"><code>bad_lexical_cast</code></a></h2> <h2><a name="bad_lexical_cast"><code>bad_lexical_cast</code></a></h2>
<blockquote> <blockquote>
<pre> <pre>
class bad_lexical_cast : public std::bad_cast class bad_lexical_cast : public std::bad_cast
{ {
public: public:
virtual const char * what() const throw(); ... // <i>same member function interface as</i> std::exception
}; };
</pre> </pre>
</blockquote> </blockquote>Exception used to indicate runtime <a href="#lexical_cast"><code>lexical_cast</code></a>
failure.
Exception used to indicate runtime <a href="#lexical_cast"><code>lexical_cast</code></a> failure.
<p> <p>
<hr> <hr>
<h2><a name="portability">Portability</a></h2> <div align="right"><small><i>&copy; Copyright Kevlin Henney, 2000&#150;2003</i></small></div>
To date the code and test harness have been compiled successfully using
Microsoft Visual C++ 6.0, Borland C++ 5.5, and GNU g++ 2.91. Tests have run successfully for
Microsoft Visual C++ 6.0 and Borland C++ 5.5. For g++ streams interpret any integer, rather than
just <code>0</code> and <code>1</code>, as valid for <code>bool</code>; the other tests pass
without problem. The deprecated standard header <code>&lt;strstream&gt;</code> is used in
preference to the standard <code>&lt;sstream&gt;</code> header for out-of-the-box g++ support.
<p>
<hr>
<h2><a name="future">Future directions</a></h2>
<ul>
<li>
Improved string handling, correctly accommodating wide character strings, incompatible
<code>basic_string</code> types, and empty strings.
</li>
<li>
Optimize the use of a stream away for identity conversions.
</li>
<li>
An <code>interpret_cast</code> that performs a <i>do-something-reasonable</i> conversion between
types. It would, for instance, select between <code>numeric_cast</code> and <code>lexical_cast</code>
based on <code>std::numeric_limits&lt;&gt;::is_specialized</code>. This would be an interesting
project, but there are no concrete plans to pursue this at the moment.
</li>
<li>
It is also worth mentioning future <i>non-directions</i>: anything that involves adding extra
arguments for a conversion operation is not being considered. A custom keyword cast, such as
<code>lexical_cast</code>, is intended to look like a built-in cast operator: built-in cast operators
take only a single operand. Where a higher degree of control is required over conversions, the
standard <code>stringstream</code> offers a more appropriate path. Where non-stream-based conversions
are required, <code>lexical_cast</code> is the wrong tool for the job, and so it won't be special-cased
for such scenarios.
</li>
</ul>
<hr>
<div align="right"><small><i>&copy; Copyright Kevlin Henney, 2000, 2002</i></small></div>
</body> </body>
</html> </html>

View File

@@ -1,149 +1,315 @@
// boost lexical_cast_test.cpp program -------------------------------------// // Unit test for boost::lexical_cast.
//
// See http://www.boost.org for most recent version including documentation. // See http://www.boost.org for most recent version, including documentation.
//
// what: lexical_cast custom keyword cast tests // Copyright Terje Sletteb<65> and Kevlin Henney, 2003.
// who: contributed by Kevlin Henney
// when: October 2000
// where: tested with MSVC 6.0 and BCC 5.5
#include <boost/lexical_cast.hpp>
#include "test.hpp"
#include <complex>
#include <iostream>
#include <string>
using namespace boost;
using namespace std;
typedef test::test<const char *, void (*)()> test_case;
typedef const test_case * test_case_iterator;
extern const test_case_iterator begin, end;
int main()
{
test::tester<test_case_iterator> test_suite(begin, end);
return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
}
void test_to_string()
{
test::check_equal(
lexical_cast<string>(2001), "2001",
"2001 -> \"2001\"");
test::check_equal(
lexical_cast<string>(2001.0), "2001",
"2001.0 ->\"2001\"");
test::check_equal(
lexical_cast<string>(complex<double>(2000,1)), "(2000,1)",
"complex<double>(2000,1) -> \"(2000,1)\"");
}
void test_to_int()
{
test::check_equal(
lexical_cast<int>("2001"), 2001,
"\"2001\" -> 2001");
test::check_equal(
lexical_cast<int>(" 2001"), 2001,
"\" 2001\" -> 2001");
test::check_equal(
lexical_cast<int>("2001 "), 2001,
"\"2001 \" -> 2001");
TEST_CHECK_THROW(
lexical_cast<int>("Two thousand and one"),
bad_lexical_cast,
"\"Two thousand and one\"");
TEST_CHECK_THROW(
lexical_cast<int>("2001: A Space Odyssey"),
bad_lexical_cast,
"\"2001: A Space Odyssey\"");
TEST_CHECK_THROW(
lexical_cast<int>(200.1),
bad_lexical_cast,
"200.1");
TEST_CHECK_THROW(
lexical_cast<int>("200e1"),
bad_lexical_cast,
"\"200e1\"");
}
void test_to_char()
{
test::check_equal(
lexical_cast<char>("2"), '2',
"\"2\" -> '2'");
test::check_equal(
lexical_cast<char>(" 2"), '2',
"\" 2\" -> '2'");
test::check_equal(
lexical_cast<char>("2 "), '2',
"\"2 \" -> '2'");
test::check_equal(
lexical_cast<char>(2), '2',
"2 -> '2'");
TEST_CHECK_THROW(
lexical_cast<char>("2001"),
bad_lexical_cast,
"\"2001\"");
TEST_CHECK_THROW(
lexical_cast<char>(2001),
bad_lexical_cast,
"2001");
}
void test_to_double()
{
test::check_equal(
lexical_cast<double>("1e6"), 1e6,
"\"1e6\" -> 1e6");
test::check_equal(
lexical_cast<double>("1e-2"), 1e-2,
"\"1e-2\" -> 1e-2");
}
void test_to_bool()
{
test::check_equal(
lexical_cast<bool>(1), true,
"1 -> true");
test::check_equal(
lexical_cast<bool>('0'), false,
"'0' -> false");
TEST_CHECK_THROW(
lexical_cast<bool>(2001),
bad_lexical_cast,
"2001");
TEST_CHECK_THROW(
lexical_cast<bool>(2),
bad_lexical_cast,
"2");
TEST_CHECK_THROW(
lexical_cast<bool>("true thousand and one"),
bad_lexical_cast,
"\"true thousand and one\"");
}
const test_case test_cases[] =
{
{ "lexical_cast<std::string>", test_to_string },
{ "lexical_cast<int>", test_to_int },
{ "lexical_cast<char>", test_to_char },
{ "lexical_cast<double>", test_to_double },
{ "lexical_cast<bool>", test_to_bool }
};
const test_case_iterator begin = test_cases;
const test_case_iterator end =
test_cases + (sizeof test_cases / sizeof *test_cases);
// Copyright Kevlin Henney, 2000. All rights reserved.
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and // purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives, and that no // permissions notice appear in all copies and derivatives.
// 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. // This software is provided "as is" without express or implied warranty.
#include <boost/config.hpp>
#if defined(__INTEL_COMPILER)
#pragma warning(disable: 383 488 981 1418 1419)
#elif defined(BOOST_MSVC)
#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800)
#endif
#include <boost/lexical_cast.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/included/unit_test_framework.hpp>
// If BOOST_NO_STRINGSTREAM is defined wide character support is unavailable,
// and all wide character tests are disabled.
#ifdef BOOST_NO_STRINGSTREAM
#define NO_WIDE_CHAR_SUPPORT
#endif
using namespace boost;
void test_conversion_to_char();
void test_conversion_to_int();
void test_conversion_to_double();
void test_conversion_to_bool();
void test_conversion_to_string();
void test_conversion_to_pointer();
void test_conversion_from_wchar_t();
void test_conversion_to_wchar_t();
void test_conversion_from_wstring();
void test_conversion_to_wstring();
unit_test_framework::test_suite *init_unit_test_suite(int, char **)
{
unit_test_framework::test_suite *suite =
BOOST_TEST_SUITE("lexical_cast unit test");
suite->add(BOOST_TEST_CASE(test_conversion_to_char));
suite->add(BOOST_TEST_CASE(test_conversion_to_int));
suite->add(BOOST_TEST_CASE(test_conversion_to_double));
suite->add(BOOST_TEST_CASE(test_conversion_to_bool));
suite->add(BOOST_TEST_CASE(test_conversion_to_pointer));
suite->add(BOOST_TEST_CASE(test_conversion_to_string));
#ifndef NO_WIDE_CHAR_SUPPORT
suite->add(BOOST_TEST_CASE(test_conversion_from_wchar_t));
suite->add(BOOST_TEST_CASE(test_conversion_to_wchar_t));
suite->add(BOOST_TEST_CASE(test_conversion_from_wstring));
suite->add(BOOST_TEST_CASE(test_conversion_to_wstring));
#endif
return suite;
}
void test_conversion_to_char()
{
BOOST_CHECK_EQUAL('A', lexical_cast<char>('A'));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(' '));
BOOST_CHECK_EQUAL('1', lexical_cast<char>(1));
BOOST_CHECK_EQUAL('0', lexical_cast<char>(0));
BOOST_CHECK_THROW(lexical_cast<char>(123), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL('1', lexical_cast<char>(1.0));
BOOST_CHECK_EQUAL('1', lexical_cast<char>(true));
BOOST_CHECK_EQUAL('0', lexical_cast<char>(false));
BOOST_CHECK_EQUAL('A', lexical_cast<char>("A"));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(" "));
BOOST_CHECK_THROW(lexical_cast<char>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<char>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL('A', lexical_cast<char>("A"));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(" "));
BOOST_CHECK_THROW(lexical_cast<char>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<char>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL('A', lexical_cast<char>(std::string("A")));
BOOST_CHECK_EQUAL(' ', lexical_cast<char>(std::string(" ")));
BOOST_CHECK_THROW(
lexical_cast<char>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<char>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_int()
{
BOOST_CHECK_EQUAL(1,lexical_cast<int>('1'));
BOOST_CHECK_EQUAL(0,lexical_cast<int>('0'));
BOOST_CHECK_THROW(lexical_cast<int>('A'),boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1,lexical_cast<int>(1));
BOOST_CHECK_EQUAL(
std::numeric_limits<int>::max(),
lexical_cast<int>(std::numeric_limits<int>::max()));
BOOST_CHECK_EQUAL(1,lexical_cast<int>(1.0));
BOOST_CHECK_THROW(lexical_cast<int>(1.23), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(1e20), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1, lexical_cast<int>(true));
BOOST_CHECK_EQUAL(0, lexical_cast<int>(false));
BOOST_CHECK_EQUAL(123, lexical_cast<int>("123"));
BOOST_CHECK_THROW(
lexical_cast<int>(" 123"), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(123, lexical_cast<int>("123"));
BOOST_CHECK_THROW(lexical_cast<int>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(123,lexical_cast<int>(std::string("123")));
BOOST_CHECK_THROW(
lexical_cast<int>(std::string(" 123")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<int>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<int>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_double()
{
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>('1'));
BOOST_CHECK_THROW(lexical_cast<double>('A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>(1));
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(1.23));
BOOST_CHECK_CLOSE(
std::numeric_limits<double>::max() / 2,
lexical_cast<double>(std::numeric_limits<double>::max() / 2),
std::numeric_limits<double>::epsilon());
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>(true));
BOOST_CHECK_EQUAL(0.0, lexical_cast<double>(false));
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>("1.23"));
BOOST_CHECK_THROW(lexical_cast<double>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>("1.23"));
BOOST_CHECK_THROW(lexical_cast<double>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(std::string("1.23")));
BOOST_CHECK_THROW(
lexical_cast<double>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<double>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_bool()
{
BOOST_CHECK_EQUAL(true, lexical_cast<bool>('1'));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>('0'));
BOOST_CHECK_THROW(lexical_cast<bool>('A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(1));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(0));
BOOST_CHECK_THROW(lexical_cast<bool>(123), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(1.0));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(0.0));
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(true));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(false));
BOOST_CHECK_EQUAL(true, lexical_cast<bool>("1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>("0"));
BOOST_CHECK_THROW(lexical_cast<bool>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<bool>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>("1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>("0"));
BOOST_CHECK_THROW(lexical_cast<bool>(""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<bool>("Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(std::string("1")));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(std::string("0")));
BOOST_CHECK_THROW(
lexical_cast<bool>(std::string("")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<bool>(std::string("Test")), boost::bad_lexical_cast);
}
void test_conversion_to_string()
{
// *** All the following gives compilation error (ambiguity) on MSVC 6
BOOST_CHECK_EQUAL("A", lexical_cast<std::string>('A'));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(' '));
BOOST_CHECK_EQUAL("123", lexical_cast<std::string>(123));
BOOST_CHECK_EQUAL("1.23", lexical_cast<std::string>(1.23));
BOOST_CHECK_EQUAL("1.111111111", lexical_cast<std::string>(1.111111111));
BOOST_CHECK_EQUAL("1",lexical_cast<std::string>(true));
BOOST_CHECK_EQUAL("0",lexical_cast<std::string>(false));
BOOST_CHECK_EQUAL("Test", lexical_cast<std::string>("Test"));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(" "));
BOOST_CHECK_EQUAL("", lexical_cast<std::string>(""));
BOOST_CHECK_EQUAL("Test", lexical_cast<std::string>("Test"));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(" "));
BOOST_CHECK_EQUAL("", lexical_cast<std::string>(""));
BOOST_CHECK_EQUAL("Test", lexical_cast<std::string>(std::string("Test")));
BOOST_CHECK_EQUAL(" ", lexical_cast<std::string>(std::string(" ")));
BOOST_CHECK_EQUAL("", lexical_cast<std::string>(std::string("")));
}
void test_conversion_to_pointer()
{
BOOST_CHECK_THROW(lexical_cast<char *>("Test"), boost::bad_lexical_cast);
#ifndef NO_WIDE_CHAR_SUPPORT
BOOST_CHECK_THROW(lexical_cast<wchar_t *>("Test"), boost::bad_lexical_cast);
#endif
}
void test_conversion_from_wchar_t()
{
#ifndef NO_WIDE_CHAR_SUPPORT
BOOST_CHECK_EQUAL(1, lexical_cast<int>(L'1'));
BOOST_CHECK_THROW(lexical_cast<int>(L'A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(123, lexical_cast<int>(L"123"));
BOOST_CHECK_THROW(lexical_cast<int>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(123, lexical_cast<int>(L"123"));
BOOST_CHECK_THROW(lexical_cast<int>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<int>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.0, lexical_cast<double>(L'1'));
BOOST_CHECK_THROW(lexical_cast<double>(L'A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(L"1.23"));
BOOST_CHECK_THROW(lexical_cast<double>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(L"1.23"));
BOOST_CHECK_THROW(lexical_cast<double>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(L'1'));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(L'0'));
BOOST_CHECK_THROW(lexical_cast<bool>(L'A'), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(L"1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(L"0"));
BOOST_CHECK_THROW(lexical_cast<bool>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<bool>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(L"1"));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(L"0"));
BOOST_CHECK_THROW(lexical_cast<bool>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<bool>(L"Test"), boost::bad_lexical_cast);
#endif
}
void test_conversion_to_wchar_t()
{
#ifndef NO_WIDE_CHAR_SUPPORT
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(1));
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(0));
BOOST_CHECK_THROW(lexical_cast<wchar_t>(123), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(1.0));
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(0.0));
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(true));
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(false));
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(L'A'));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(L' '));
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(L"A"));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(L" "));
BOOST_CHECK_THROW(lexical_cast<wchar_t>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<wchar_t>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(L"A"));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(L" "));
BOOST_CHECK_THROW(lexical_cast<wchar_t>(L""), boost::bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<wchar_t>(L"Test"), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(L'A', lexical_cast<wchar_t>(std::wstring(L"A")));
BOOST_CHECK_EQUAL(L' ', lexical_cast<wchar_t>(std::wstring(L" ")));
BOOST_CHECK_THROW(
lexical_cast<wchar_t>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<wchar_t>(std::wstring(L"Test")), boost::bad_lexical_cast);
#endif
}
void test_conversion_from_wstring()
{
#ifndef NO_WIDE_CHAR_SUPPORT
BOOST_CHECK_EQUAL(123, lexical_cast<int>(std::wstring(L"123")));
BOOST_CHECK_THROW(
lexical_cast<int>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<int>(std::wstring(L"Test")), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(1.23, lexical_cast<double>(std::wstring(L"1.23")));
BOOST_CHECK_THROW(
lexical_cast<double>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<double>(std::wstring(L"Test")), boost::bad_lexical_cast);
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(std::wstring(L"1")));
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(std::wstring(L"0")));
BOOST_CHECK_THROW(
lexical_cast<bool>(std::wstring(L"")), boost::bad_lexical_cast);
BOOST_CHECK_THROW(
lexical_cast<bool>(std::wstring(L"Test")), boost::bad_lexical_cast);
#endif
}
void test_conversion_to_wstring()
{
#ifndef NO_WIDE_CHAR_SUPPORT
BOOST_CHECK(L"123" == lexical_cast<std::wstring>(123));
BOOST_CHECK(L"1.23" == lexical_cast<std::wstring>(1.23));
BOOST_CHECK(L"1.111111111" == lexical_cast<std::wstring>(1.111111111));
BOOST_CHECK(L"1" == lexical_cast<std::wstring>(true));
BOOST_CHECK(L"0" == lexical_cast<std::wstring>(false));
BOOST_CHECK(L"A" == lexical_cast<std::wstring>(L'A'));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L' '));
BOOST_CHECK(L"Test" == lexical_cast<std::wstring>(L"Test"));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L" "));
BOOST_CHECK(L"" == lexical_cast<std::wstring>(L""));
BOOST_CHECK(L"Test" == lexical_cast<std::wstring>(L"Test"));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L" "));
BOOST_CHECK(L"" == lexical_cast<std::wstring>(L""));
BOOST_CHECK(L"Test" == lexical_cast<std::wstring>(std::wstring(L"Test")));
BOOST_CHECK(L" " == lexical_cast<std::wstring>(std::wstring(L" ")));
BOOST_CHECK(L"" == lexical_cast<std::wstring>(std::wstring(L"")));
#endif
}