diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index bd37e9a..924d6ac 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1,31 +1,29 @@ -// boost lexical_cast.hpp header -------------------------------------------// - -// See http://www.boost.org/libs/conversion for documentation. - #ifndef 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 -// who: contributed by Kevlin Henney, with alternative naming, behaviors -// and fixes contributed by Dave Abrahams, Daryle Walker and other -// Boosters on the list -// when: November 2000 -// where: tested with MSVC 6.0, BCC 5.5, and g++ 2.91 - -#include - -// Some sstream implementations are broken for the purposes of lexical cast. -# if defined(BOOST_NO_STRINGSTREAM) -# define BOOST_LEXICAL_CAST_USE_STRSTREAM -# endif - -#ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM -# include -#else -# include -#endif +// who: contributed by Kevlin Henney, +// enhanced with contributions from Terje Slettebų, +// with additional fixes and suggestions from Gennaro Prota, +// Dave Abrahams, Daryle Walker, and other Boosters on the list +// when: November 2000, March 2003 +#include #include +#include +#include +#include + +#ifdef BOOST_NO_STRINGSTREAM +#include +#else +#include +#endif namespace boost { @@ -33,35 +31,146 @@ namespace boost class bad_lexical_cast : public std::bad_cast { public: - // constructors, destructors, and assignment operator defaulted - - // function inlined for brevity and consistency with rest of library - virtual const char * what() const throw() + virtual ~bad_lexical_cast() throw() { - return "bad lexical cast: " - "source type value could not be interpreted as target"; } }; + namespace detail // actual underlying concrete exception type + { + template + 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 + struct stream_char + { + typedef char type; + }; + + #ifndef BOOST_NO_STRINGSTREAM + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + #endif + + template + struct widest_char + { + typedef TargetChar type; + }; + + template<> + struct widest_char + { + typedef wchar_t type; + }; + } + + namespace detail // stream wrapper for handling lexical conversions + { + template + class lexical_stream + { + public: + lexical_stream() + { + stream.unsetf(std::ios::skipws); + + if(std::numeric_limits::is_specialized) + stream.precision(std::numeric_limits::digits10 + 1); + else if(std::numeric_limits::is_specialized) + stream.precision(std::numeric_limits::digits10 + 1); + } + ~lexical_stream() + { + #if defined(BOOST_NO_STRINGSTREAM) + stream.freeze(false); + #endif + } + bool operator<<(const Source &input) + { + return stream << input; + } + template + bool operator>>(InputStreamable &output) + { + return !is_pointer::value && + stream >> output && + (stream >> std::ws).eof(); + } + template + bool operator>>(std::basic_string &output) + { + return std::getline(stream, output, char_type()).eof(); + } + private: + typedef typename widest_char< + typename stream_char::type, + typename stream_char::type>::type char_type; + + #if defined(BOOST_NO_STRINGSTREAM) + std::strstream stream; + #else + std::basic_stringstream stream; + #endif + }; + } + template Target lexical_cast(Source arg) { -# ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM - std::strstream interpreter; // for out-of-the-box g++ 2.95.2 -# else - std::stringstream interpreter; -# endif + detail::lexical_stream interpreter; Target result; - if(!(interpreter << arg) || !(interpreter >> result) || - !(interpreter >> std::ws).eof()) - throw bad_lexical_cast(); - + if(!(interpreter << arg && interpreter >> result)) + throw detail::no_lexical_conversion(); 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 // 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. -#ifdef BOOST_LEXICAL_CAST_USE_STRSTREAM -# undef BOOST_LEXICAL_CAST_USE_STRSTREAM -#endif - #endif diff --git a/lexical_cast.htm b/lexical_cast.htm index 870068d..6b52fb5 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -1,99 +1,94 @@ - - lexical_cast - - - - - - -

c++boost.gif (8819 bytes)Header -boost/lexical_cast.hpp

- - - -
-

Motivation

- -Sometimes a value must be converted to a literal text form, such as an -int represented as a string, or vice-versa, when -a string is interpreted as an int. Such examples -are common when converting between data types internal to a program and -representation external to a program, such as windows and configuration files. -

-The standard C and C++ libraries offer a number of facilities for performing -such conversions. However, they vary with their ease of use, extensibility, -and safety. -

-For instance, there are a number of limitations with the family of standard C -functions typified by atoi: -

    -
  • - Conversion is supported in one direction only: from text to - internal data type. Converting the other way using the C library - requires either the inconvenience and compromised safety of the - sprintf function, or the loss of portability associated - with non-standard functions such as itoa. -
  • -
  • - The range of types supported is only a subset of the built-in numeric - types, namely int, long, - and double. -
  • -
  • - The range of types cannot be extended in a uniform manner. For - instance, conversion from string representation to - complex or rational. -
  • -
-The standard C functions typified by strtol have the same basic -limitations, but offer finer control over the conversion process. However, for -the common case such control is often either not required or not used. The -scanf family of functions offer even greater control, but also -lack safety and ease of use. -

-The standard C++ library offers stringstream for the kind of -in-core formatting being discussed. It offers a great deal of control over the -formatting and conversion of I/O to and from arbitrary types through text. -However, for simple conversions direct use of stringstream can be -either clumsy (with the introduction of extra local variables and the loss of -infix-expression convenience) or obscure (where stringstream -objects are created as temporary objects in an expression). Facets provide a -comprehensive concept and facility for controlling textual representation, but -their relatively high entry level requires an extreme degree of involvement -for simple conversions. -

-The lexical_cast template function offers a convenient and consistent -form for supporting common conversions to and from arbitrary types when they are -represented as text. The simplification it offers is in expression-level -convenience for such conversions. For more involved conversions, such as where -precision or formatting need tighter control than is offered by the default -behavior of lexical_cast, the conventional -stringstream approach is recommended. Where the conversions are -numeric to numeric, numeric_cast -may offer more reasonable behavior than lexical_cast. -

-For a good discussion of the options and issues involved in string-based formatting, -including comparison of stringstream, lexical_cast, and -others, see Herb Sutter's article, -The String Formatters of Manor Farm. -

- -


-

Examples

- -The following example treats command line arguments as a sequence of numeric data: -
-
+	
+		lexical_cast
+		
+		
+	
+	
+		

c++boost.gif (8819 bytes)Header + boost/lexical_cast.hpp

+ +
+

Motivation

+ Sometimes a value must be converted to a literal text form, such as an int + represented as a string, or vice-versa, when a string + is interpreted as an int. Such examples are common when converting + between data types internal to a program and representation external to a + program, such as windows and configuration files. +

+ The standard C and C++ libraries offer a number of facilities for performing + such conversions. However, they vary with their ease of use, extensibility, and + safety. +

+ For instance, there are a number of limitations with the family of standard C + functions typified by atoi: +

    +
  • + Conversion is supported in one direction only: from text to internal data type. + Converting the other way using the C library requires either the inconvenience + and compromised safety of the sprintf function, or the loss of + portability associated with non-standard functions such as itoa. +
  • +
  • + The range of types supported is only a subset of the built-in numeric types, + namely int, long, and double. +
  • +
  • + The range of types cannot be extended in a uniform manner. For instance, + conversion from string representation to complex or rational. +
  • +
+ The standard C functions typified by strtol have the same basic + limitations, but offer finer control over the conversion process. However, for + the common case such control is often either not required or not used. The scanf + family of functions offer even greater control, but also lack safety and ease + of use. +

+ The standard C++ library offers stringstream for the kind of + in-core formatting being discussed. It offers a great deal of control over the + formatting and conversion of I/O to and from arbitrary types through text. + However, for simple conversions direct use of stringstream can be + either clumsy (with the introduction of extra local variables and the loss of + infix-expression convenience) or obscure (where stringstream + objects are created as temporary objects in an expression). Facets provide a + comprehensive concept and facility for controlling textual representation, but + their perceived complexity and high entry level requires an extreme degree of + involvement for simple conversions, and excludes all but a few programmers. +

+ The lexical_cast function template offers a convenient and + consistent form for supporting common conversions to and from arbitrary types + when they are represented as text. The simplification it offers is in + expression-level convenience for such conversions. For more involved + conversions, such as where precision or formatting need tighter control than is + offered by the default behavior of lexical_cast, the conventional + stringstream approach is recommended. Where the conversions are + numeric to numeric, numeric_cast + may offer more reasonable behavior than lexical_cast + . +

+ For a good discussion of the options and issues involved in string-based + formatting, including comparison of stringstream, lexical_cast, + and others, see Herb Sutter's article, + The String Formatters of Manor Farm + . +

+


+

Examples

+ The following example treats command line arguments as a sequence of numeric + data:
+
 int main(int argc, char * argv[])
 {
     using boost::lexical_cast;
@@ -115,11 +110,8 @@ int main(int argc, char * argv[])
     ...
 }
 
-
- -The following example uses numeric data in a string expression: -
-
+			
The following example uses numeric data in a string expression:
+
 void log_message(const std::string &);
 
 void log_errno(int yoko)
@@ -127,15 +119,12 @@ void log_errno(int yoko)
     log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
 }
 
-
- -
-

Synopsis

- -Library features defined in "boost/lexical_cast.hpp": - -
-
+			
+
+

Synopsis

+ Library features defined in "boost/lexical_cast.hpp": +
+
 namespace boost
 {
     class bad_lexical_cast;
@@ -143,110 +132,65 @@ namespace boost
       Target lexical_cast(Source arg);
 }
 
-
- -Test harness defined in "lexical_cast_test.cpp". -

- -


-

lexical_cast

- -
-
+			
Unit test defined in "lexical_cast_test.cpp". +

+


+

lexical_cast

+
+
 template<typename Target, typename Source>
   Target lexical_cast(Source arg);
 
-
- -Returns the result of streaming arg into a std::stringstream and then -out as a Target object. If the conversion is unsuccessful, a -bad_lexical_cast exception is thrown. -

-The requirements on the argument and result types are: -

    -
  • - Source is OutputStreamable, meaning that an - operator<< is defined that takes a - std::ostream object on the left hand side and an instance - of the argument type on the right. -
  • -
  • - Both Source and Target are CopyConstructible [20.1.3]. -
  • -
  • - Target is InputStreamable, meaning that an - operator>> is defined that takes a - std::istream object on the left hand side and an instance - of the result type on the right. -
  • -
  • - Target is DefaultConstructible, meaning that it is - possible to default-initialize an object of that type [8.5, 20.1.3]. -
  • -
  • - Target is Assignable [23.1]. -
  • -
-

- -


-

bad_lexical_cast

- -
-
+			
Returns the result of streaming arg into a std::stringstream + and then out as a Target object. Note that spaces are significant + in any conversion and are not skipped. If the conversion is unsuccessful, a + bad_lexical_cast + exception is thrown. +

+ The requirements on the argument and result types are: +

    +
  • + Source is OutputStreamable, meaning that an operator<< + is defined that takes a std::ostream or std::wostream object on the + left hand side and an instance of the argument type on the right. +
  • +
  • + Both Source and Target are CopyConstructible [20.1.3]. +
  • +
  • + Target is InputStreamable, meaning that an operator>> + is defined that takes a std::istream or std::wistream object on the left hand side + and an instance of the result type on the right. +
  • +
  • + Target is DefaultConstructible, meaning that it is possible + to default-initialize an object of that type [8.5, 20.1.4]. +
  • +
+ The character type of the underlying stream is assumed to be char unless + the either the Source or the Target type is wchar_t + or a wide-character string type — either wchar_t * or std::wstring — + in which case wchar_t is used. +

+ Where a higher degree of control is required over conversions, std::stringstream + and std::wstringstream offer a more appropriate path. Where non-stream-based conversions are + required, lexical_cast + is the wrong tool for the job, and is not special-cased for such scenarios. +

+


+

bad_lexical_cast

+
+
 class bad_lexical_cast : public std::bad_cast
 {
 public:
-    virtual const char * what() const throw();
+    ... // same member function interface as std::exception
 };
 
-
- -Exception used to indicate runtime lexical_cast failure. -

- -


-

Portability

- -To date the code and test harness have been compiled successfully using -Microsoft Visual C++ 6.0, Borland C++ 5.5, and GNU g++ 2.91. Tests have run successfully for -Microsoft Visual C++ 6.0 and Borland C++ 5.5. For g++ streams interpret any integer, rather than -just 0 and 1, as valid for bool; the other tests pass -without problem. The deprecated standard header <strstream> is used in -preference to the standard <sstream> header for out-of-the-box g++ support. -

- -


-

Future directions

- -
    -
  • - Improved string handling, correctly accommodating wide character strings, incompatible - basic_string types, and empty strings. -
  • -
  • - Optimize the use of a stream away for identity conversions. -
  • -
  • - An interpret_cast that performs a do-something-reasonable conversion between - types. It would, for instance, select between numeric_cast and lexical_cast - based on std::numeric_limits<>::is_specialized. This would be an interesting - project, but there are no concrete plans to pursue this at the moment. -
  • -
  • - It is also worth mentioning future non-directions: anything that involves adding extra - arguments for a conversion operation is not being considered. A custom keyword cast, such as - lexical_cast, 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 stringstream offers a more appropriate path. Where non-stream-based conversions - are required, lexical_cast is the wrong tool for the job, and so it won't be special-cased - for such scenarios. -
  • -
- -
- -
© Copyright Kevlin Henney, 2000, 2002
- - +
Exception used to indicate runtime lexical_cast + failure. +

+


+
© Copyright Kevlin Henney, 2000–2003
+ diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index c19cf08..1d3c631 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -1,149 +1,315 @@ -// boost lexical_cast_test.cpp program -------------------------------------// - -// See http://www.boost.org for most recent version including documentation. - -// what: lexical_cast custom keyword cast tests -// who: contributed by Kevlin Henney -// when: October 2000 -// where: tested with MSVC 6.0 and BCC 5.5 - -#include -#include "test.hpp" -#include -#include -#include - -using namespace boost; -using namespace std; - -typedef test::test test_case; -typedef const test_case * test_case_iterator; - -extern const test_case_iterator begin, end; - -int main() -{ - test::tester test_suite(begin, end); - return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE; -} - -void test_to_string() -{ - test::check_equal( - lexical_cast(2001), "2001", - "2001 -> \"2001\""); - test::check_equal( - lexical_cast(2001.0), "2001", - "2001.0 ->\"2001\""); - test::check_equal( - lexical_cast(complex(2000,1)), "(2000,1)", - "complex(2000,1) -> \"(2000,1)\""); -} - -void test_to_int() -{ - test::check_equal( - lexical_cast("2001"), 2001, - "\"2001\" -> 2001"); - test::check_equal( - lexical_cast(" 2001"), 2001, - "\" 2001\" -> 2001"); - test::check_equal( - lexical_cast("2001 "), 2001, - "\"2001 \" -> 2001"); - TEST_CHECK_THROW( - lexical_cast("Two thousand and one"), - bad_lexical_cast, - "\"Two thousand and one\""); - TEST_CHECK_THROW( - lexical_cast("2001: A Space Odyssey"), - bad_lexical_cast, - "\"2001: A Space Odyssey\""); - TEST_CHECK_THROW( - lexical_cast(200.1), - bad_lexical_cast, - "200.1"); - TEST_CHECK_THROW( - lexical_cast("200e1"), - bad_lexical_cast, - "\"200e1\""); -} - -void test_to_char() -{ - test::check_equal( - lexical_cast("2"), '2', - "\"2\" -> '2'"); - test::check_equal( - lexical_cast(" 2"), '2', - "\" 2\" -> '2'"); - test::check_equal( - lexical_cast("2 "), '2', - "\"2 \" -> '2'"); - test::check_equal( - lexical_cast(2), '2', - "2 -> '2'"); - TEST_CHECK_THROW( - lexical_cast("2001"), - bad_lexical_cast, - "\"2001\""); - TEST_CHECK_THROW( - lexical_cast(2001), - bad_lexical_cast, - "2001"); -} - -void test_to_double() -{ - test::check_equal( - lexical_cast("1e6"), 1e6, - "\"1e6\" -> 1e6"); - test::check_equal( - lexical_cast("1e-2"), 1e-2, - "\"1e-2\" -> 1e-2"); -} - -void test_to_bool() -{ - test::check_equal( - lexical_cast(1), true, - "1 -> true"); - test::check_equal( - lexical_cast('0'), false, - "'0' -> false"); - TEST_CHECK_THROW( - lexical_cast(2001), - bad_lexical_cast, - "2001"); - TEST_CHECK_THROW( - lexical_cast(2), - bad_lexical_cast, - "2"); - TEST_CHECK_THROW( - lexical_cast("true thousand and one"), - bad_lexical_cast, - "\"true thousand and one\""); -} - -const test_case test_cases[] = -{ - { "lexical_cast", test_to_string }, - { "lexical_cast", test_to_int }, - { "lexical_cast", test_to_char }, - { "lexical_cast", test_to_double }, - { "lexical_cast", test_to_bool } -}; - -const test_case_iterator begin = test_cases; -const test_case_iterator end = - test_cases + (sizeof test_cases / sizeof *test_cases); - -// Copyright Kevlin Henney, 2000. All rights reserved. +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Terje Slettebų and Kevlin Henney, 2003. // // 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. +// permissions notice appear in all copies and derivatives. // // This software is provided "as is" without express or implied warranty. + +#include + +#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 +#include +#include + +// 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('A')); + BOOST_CHECK_EQUAL(' ', lexical_cast(' ')); + BOOST_CHECK_EQUAL('1', lexical_cast(1)); + BOOST_CHECK_EQUAL('0', lexical_cast(0)); + BOOST_CHECK_THROW(lexical_cast(123), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL('1', lexical_cast(1.0)); + BOOST_CHECK_EQUAL('1', lexical_cast(true)); + BOOST_CHECK_EQUAL('0', lexical_cast(false)); + BOOST_CHECK_EQUAL('A', lexical_cast("A")); + BOOST_CHECK_EQUAL(' ', lexical_cast(" ")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL('A', lexical_cast("A")); + BOOST_CHECK_EQUAL(' ', lexical_cast(" ")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL('A', lexical_cast(std::string("A"))); + BOOST_CHECK_EQUAL(' ', lexical_cast(std::string(" "))); + BOOST_CHECK_THROW( + lexical_cast(std::string("")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(std::string("Test")), boost::bad_lexical_cast); +} + +void test_conversion_to_int() +{ + BOOST_CHECK_EQUAL(1,lexical_cast('1')); + BOOST_CHECK_EQUAL(0,lexical_cast('0')); + BOOST_CHECK_THROW(lexical_cast('A'),boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(1,lexical_cast(1)); + BOOST_CHECK_EQUAL( + std::numeric_limits::max(), + lexical_cast(std::numeric_limits::max())); + BOOST_CHECK_EQUAL(1,lexical_cast(1.0)); + + BOOST_CHECK_THROW(lexical_cast(1.23), boost::bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast(1e20), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(1, lexical_cast(true)); + BOOST_CHECK_EQUAL(0, lexical_cast(false)); + BOOST_CHECK_EQUAL(123, lexical_cast("123")); + BOOST_CHECK_THROW( + lexical_cast(" 123"), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(123, lexical_cast("123")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(123,lexical_cast(std::string("123"))); + BOOST_CHECK_THROW( + lexical_cast(std::string(" 123")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(std::string("")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(std::string("Test")), boost::bad_lexical_cast); +} + +void test_conversion_to_double() +{ + BOOST_CHECK_EQUAL(1.0, lexical_cast('1')); + BOOST_CHECK_THROW(lexical_cast('A'), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(1.0, lexical_cast(1)); + BOOST_CHECK_EQUAL(1.23, lexical_cast(1.23)); + BOOST_CHECK_CLOSE( + std::numeric_limits::max() / 2, + lexical_cast(std::numeric_limits::max() / 2), + std::numeric_limits::epsilon()); + BOOST_CHECK_EQUAL(1.0, lexical_cast(true)); + BOOST_CHECK_EQUAL(0.0, lexical_cast(false)); + BOOST_CHECK_EQUAL(1.23, lexical_cast("1.23")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(1.23, lexical_cast("1.23")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(1.23, lexical_cast(std::string("1.23"))); + BOOST_CHECK_THROW( + lexical_cast(std::string("")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(std::string("Test")), boost::bad_lexical_cast); +} + +void test_conversion_to_bool() +{ + BOOST_CHECK_EQUAL(true, lexical_cast('1')); + BOOST_CHECK_EQUAL(false, lexical_cast('0')); + BOOST_CHECK_THROW(lexical_cast('A'), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(true, lexical_cast(1)); + BOOST_CHECK_EQUAL(false, lexical_cast(0)); + BOOST_CHECK_THROW(lexical_cast(123), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(true, lexical_cast(1.0)); + BOOST_CHECK_EQUAL(false, lexical_cast(0.0)); + BOOST_CHECK_EQUAL(true, lexical_cast(true)); + BOOST_CHECK_EQUAL(false, lexical_cast(false)); + BOOST_CHECK_EQUAL(true, lexical_cast("1")); + BOOST_CHECK_EQUAL(false, lexical_cast("0")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(true, lexical_cast("1")); + BOOST_CHECK_EQUAL(false, lexical_cast("0")); + BOOST_CHECK_THROW(lexical_cast(""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(true, lexical_cast(std::string("1"))); + BOOST_CHECK_EQUAL(false, lexical_cast(std::string("0"))); + BOOST_CHECK_THROW( + lexical_cast(std::string("")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(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('A')); + BOOST_CHECK_EQUAL(" ", lexical_cast(' ')); + BOOST_CHECK_EQUAL("123", lexical_cast(123)); + BOOST_CHECK_EQUAL("1.23", lexical_cast(1.23)); + BOOST_CHECK_EQUAL("1.111111111", lexical_cast(1.111111111)); + BOOST_CHECK_EQUAL("1",lexical_cast(true)); + BOOST_CHECK_EQUAL("0",lexical_cast(false)); + BOOST_CHECK_EQUAL("Test", lexical_cast("Test")); + BOOST_CHECK_EQUAL(" ", lexical_cast(" ")); + BOOST_CHECK_EQUAL("", lexical_cast("")); + BOOST_CHECK_EQUAL("Test", lexical_cast("Test")); + BOOST_CHECK_EQUAL(" ", lexical_cast(" ")); + BOOST_CHECK_EQUAL("", lexical_cast("")); + BOOST_CHECK_EQUAL("Test", lexical_cast(std::string("Test"))); + BOOST_CHECK_EQUAL(" ", lexical_cast(std::string(" "))); + BOOST_CHECK_EQUAL("", lexical_cast(std::string(""))); +} + +void test_conversion_to_pointer() +{ + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + #ifndef NO_WIDE_CHAR_SUPPORT + BOOST_CHECK_THROW(lexical_cast("Test"), boost::bad_lexical_cast); + #endif +} + +void test_conversion_from_wchar_t() +{ + #ifndef NO_WIDE_CHAR_SUPPORT + BOOST_CHECK_EQUAL(1, lexical_cast(L'1')); + BOOST_CHECK_THROW(lexical_cast(L'A'), boost::bad_lexical_cast); + + BOOST_CHECK_EQUAL(123, lexical_cast(L"123")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(123, lexical_cast(L"123")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + + BOOST_CHECK_EQUAL(1.0, lexical_cast(L'1')); + BOOST_CHECK_THROW(lexical_cast(L'A'), boost::bad_lexical_cast); + + BOOST_CHECK_EQUAL(1.23, lexical_cast(L"1.23")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(1.23, lexical_cast(L"1.23")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + + BOOST_CHECK_EQUAL(true, lexical_cast(L'1')); + BOOST_CHECK_EQUAL(false, lexical_cast(L'0')); + BOOST_CHECK_THROW(lexical_cast(L'A'), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(true, lexical_cast(L"1")); + BOOST_CHECK_EQUAL(false, lexical_cast(L"0")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(true, lexical_cast(L"1")); + BOOST_CHECK_EQUAL(false, lexical_cast(L"0")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(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(1)); + BOOST_CHECK_EQUAL(L'0', lexical_cast(0)); + BOOST_CHECK_THROW(lexical_cast(123), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(L'1', lexical_cast(1.0)); + BOOST_CHECK_EQUAL(L'0', lexical_cast(0.0)); + BOOST_CHECK_EQUAL(L'1', lexical_cast(true)); + BOOST_CHECK_EQUAL(L'0', lexical_cast(false)); + BOOST_CHECK_EQUAL(L'A', lexical_cast(L'A')); + BOOST_CHECK_EQUAL(L' ', lexical_cast(L' ')); + BOOST_CHECK_EQUAL(L'A', lexical_cast(L"A")); + BOOST_CHECK_EQUAL(L' ', lexical_cast(L" ")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(L'A', lexical_cast(L"A")); + BOOST_CHECK_EQUAL(L' ', lexical_cast(L" ")); + BOOST_CHECK_THROW(lexical_cast(L""), boost::bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(L"Test"), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(L'A', lexical_cast(std::wstring(L"A"))); + BOOST_CHECK_EQUAL(L' ', lexical_cast(std::wstring(L" "))); + BOOST_CHECK_THROW( + lexical_cast(std::wstring(L"")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(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(std::wstring(L"123"))); + BOOST_CHECK_THROW( + lexical_cast(std::wstring(L"")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(std::wstring(L"Test")), boost::bad_lexical_cast); + + BOOST_CHECK_EQUAL(1.23, lexical_cast(std::wstring(L"1.23"))); + BOOST_CHECK_THROW( + lexical_cast(std::wstring(L"")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(std::wstring(L"Test")), boost::bad_lexical_cast); + + BOOST_CHECK_EQUAL(true, lexical_cast(std::wstring(L"1"))); + BOOST_CHECK_EQUAL(false, lexical_cast(std::wstring(L"0"))); + BOOST_CHECK_THROW( + lexical_cast(std::wstring(L"")), boost::bad_lexical_cast); + BOOST_CHECK_THROW( + lexical_cast(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(123)); + BOOST_CHECK(L"1.23" == lexical_cast(1.23)); + BOOST_CHECK(L"1.111111111" == lexical_cast(1.111111111)); + BOOST_CHECK(L"1" == lexical_cast(true)); + BOOST_CHECK(L"0" == lexical_cast(false)); + BOOST_CHECK(L"A" == lexical_cast(L'A')); + BOOST_CHECK(L" " == lexical_cast(L' ')); + BOOST_CHECK(L"Test" == lexical_cast(L"Test")); + BOOST_CHECK(L" " == lexical_cast(L" ")); + BOOST_CHECK(L"" == lexical_cast(L"")); + BOOST_CHECK(L"Test" == lexical_cast(L"Test")); + BOOST_CHECK(L" " == lexical_cast(L" ")); + BOOST_CHECK(L"" == lexical_cast(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""))); + #endif +}