mirror of
https://github.com/boostorg/conversion.git
synced 2026-08-06 13:34:14 +02:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 053f330b0a | |||
| 6c5f31e7a5 | |||
| 1f7147d24b | |||
| a385c3ec99 | |||
| 701d5f0bf0 | |||
| b5583b88fa | |||
| 5b6e39b2b8 | |||
| 04f73e5a89 | |||
| 65328d9716 | |||
| dc151d2b5a | |||
| 23949682c1 | |||
| 5055e842cf | |||
| 9e764f3e49 | |||
| a3e690da32 | |||
| fb681bb0ea | |||
| 98a67d93f3 | |||
| 0c54d6a037 | |||
| 39329bc5b9 | |||
| 2ce20c872e | |||
| 49c0b2f333 | |||
| e9a5ac6d7a | |||
| ee3f643c5e | |||
| d44a6fcf8b | |||
| ac6e41d676 | |||
| 4224fa5deb |
@@ -120,10 +120,10 @@ void f( Fruit * fruit ) {
|
||||
<p><code>polymorphic_cast</code> was suggested by Bjarne Stroustrup in "The C++
|
||||
Programming Language".<br>
|
||||
<code>polymorphic_downcast</code> was contributed by <a href=
|
||||
"../../people/dave_abrahams.htm">Dave Abrahams</a>.<code><br>
|
||||
"http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams</a>.<code><br>
|
||||
An old
|
||||
numeric_cast</code> that was contributed by <a href=
|
||||
"../../people/kevlin_henney.htm">Kevlin Henney</a> is now superseeded by the <a href="../numeric/conversion/doc/index.html">Boost Numeric Conversion Library</a></p>
|
||||
"http://www.boost.org/people/kevlin_henney.htm">Kevlin Henney</a> is now superseeded by the <a href="../numeric/conversion/doc/html/index.html">Boost Numeric Conversion Library</a></p>
|
||||
<hr>
|
||||
|
||||
<p>Revised
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
// Copyright Alexander Nasonov & Paul A. Bristow 2006.
|
||||
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED
|
||||
#define BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED
|
||||
|
||||
#include <climits>
|
||||
#include <ios>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/integer_traits.hpp>
|
||||
|
||||
#ifndef BOOST_NO_IS_ABSTRACT
|
||||
// Fix for SF:1358600 - lexical_cast & pure virtual functions & VC 8 STL
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/type_traits/is_abstract.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || \
|
||||
(defined(BOOST_MSVC) && (BOOST_MSVC<1310))
|
||||
|
||||
#define BOOST_LCAST_NO_COMPILE_TIME_PRECISION
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
|
||||
#include <boost/assert.hpp>
|
||||
#else
|
||||
#include <boost/static_assert.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace detail {
|
||||
|
||||
class lcast_abstract_stub {};
|
||||
|
||||
#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
|
||||
// Calculate an argument to pass to std::ios_base::precision from
|
||||
// lexical_cast. See alternative implementation for broken standard
|
||||
// libraries in lcast_get_precision below. Keep them in sync, please.
|
||||
template<class T>
|
||||
struct lcast_precision
|
||||
{
|
||||
#ifdef BOOST_NO_IS_ABSTRACT
|
||||
typedef std::numeric_limits<T> limits; // No fix for SF:1358600.
|
||||
#else
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_<
|
||||
boost::is_abstract<T>
|
||||
, std::numeric_limits<lcast_abstract_stub>
|
||||
, std::numeric_limits<T>
|
||||
>::type limits;
|
||||
#endif
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, use_default_precision =
|
||||
!limits::is_specialized || limits::is_exact
|
||||
);
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, is_specialized_bin =
|
||||
!use_default_precision &&
|
||||
limits::radix == 2 && limits::digits > 0
|
||||
);
|
||||
|
||||
BOOST_STATIC_CONSTANT(bool, is_specialized_dec =
|
||||
!use_default_precision &&
|
||||
limits::radix == 10 && limits::digits10 > 0
|
||||
);
|
||||
|
||||
BOOST_STATIC_CONSTANT(std::streamsize, streamsize_max =
|
||||
boost::integer_traits<std::streamsize>::const_max
|
||||
);
|
||||
|
||||
BOOST_STATIC_CONSTANT(unsigned int, precision_dec = limits::digits10 + 1U);
|
||||
|
||||
BOOST_STATIC_ASSERT(!is_specialized_dec ||
|
||||
precision_dec <= streamsize_max + 0UL
|
||||
);
|
||||
|
||||
BOOST_STATIC_CONSTANT(unsigned long, precision_bin =
|
||||
2UL + limits::digits * 30103UL / 100000UL
|
||||
);
|
||||
|
||||
BOOST_STATIC_ASSERT(!is_specialized_bin ||
|
||||
(limits::digits + 0UL < ULONG_MAX / 30103UL &&
|
||||
precision_bin > limits::digits10 + 0UL &&
|
||||
precision_bin <= streamsize_max + 0UL)
|
||||
);
|
||||
|
||||
BOOST_STATIC_CONSTANT(std::streamsize, value =
|
||||
is_specialized_bin ? precision_bin
|
||||
: is_specialized_dec ? precision_dec : 6
|
||||
);
|
||||
};
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
inline std::streamsize lcast_get_precision(T* = 0)
|
||||
{
|
||||
#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
|
||||
return lcast_precision<T>::value;
|
||||
#else // Follow lcast_precision algorithm at run-time:
|
||||
|
||||
#ifdef BOOST_NO_IS_ABSTRACT
|
||||
typedef std::numeric_limits<T> limits; // No fix for SF:1358600.
|
||||
#else
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_<
|
||||
boost::is_abstract<T>
|
||||
, std::numeric_limits<lcast_abstract_stub>
|
||||
, std::numeric_limits<T>
|
||||
>::type limits;
|
||||
#endif
|
||||
|
||||
bool const use_default_precision =
|
||||
!limits::is_specialized || limits::is_exact;
|
||||
|
||||
if(!use_default_precision)
|
||||
{ // Includes all built-in floating-point types, float, double ...
|
||||
// and UDT types for which digits (significand bits) is defined (not zero)
|
||||
|
||||
bool const is_specialized_bin =
|
||||
limits::radix == 2 && limits::digits > 0;
|
||||
bool const is_specialized_dec =
|
||||
limits::radix == 10 && limits::digits10 > 0;
|
||||
std::streamsize const streamsize_max =
|
||||
(boost::integer_traits<std::streamsize>::max)();
|
||||
|
||||
if(is_specialized_bin)
|
||||
{ // Floating-point types with
|
||||
// limits::digits defined by the specialization.
|
||||
|
||||
unsigned long const digits = limits::digits;
|
||||
unsigned long const precision = 2UL + digits * 30103UL / 100000UL;
|
||||
// unsigned long is selected because it is at least 32-bits
|
||||
// and thus ULONG_MAX / 30103UL is big enough for all types.
|
||||
BOOST_ASSERT(
|
||||
digits < ULONG_MAX / 30103UL &&
|
||||
precision > limits::digits10 + 0UL &&
|
||||
precision <= streamsize_max + 0UL
|
||||
);
|
||||
return precision;
|
||||
}
|
||||
else if(is_specialized_dec)
|
||||
{ // Decimal Floating-point type, most likely a User Defined Type
|
||||
// rather than a real floating-point hardware type.
|
||||
unsigned int const precision = limits::digits10 + 1U;
|
||||
BOOST_ASSERT(precision <= streamsize_max + 0UL);
|
||||
return precision;
|
||||
}
|
||||
}
|
||||
|
||||
// Integral type (for which precision has no effect)
|
||||
// or type T for which limits is NOT specialized,
|
||||
// so assume stream precision remains the default 6 decimal digits.
|
||||
// Warning: if your User-defined Floating-point type T is NOT specialized,
|
||||
// then you may lose accuracy by only using 6 decimal digits.
|
||||
// To avoid this, you need to specialize T with either
|
||||
// radix == 2 and digits == the number of significand bits,
|
||||
// OR
|
||||
// radix = 10 and digits10 == the number of decimal digits.
|
||||
|
||||
return 6;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void lcast_set_precision(std::ios_base& stream, T*)
|
||||
{
|
||||
stream.precision(lcast_get_precision<T>());
|
||||
}
|
||||
|
||||
template<class Source, class Target>
|
||||
inline void lcast_set_precision(std::ios_base& stream, Source*, Target*)
|
||||
{
|
||||
std::streamsize const s = lcast_get_precision(static_cast<Source*>(0));
|
||||
std::streamsize const t = lcast_get_precision(static_cast<Target*>(0));
|
||||
stream.precision(s > t ? s : t);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif // BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED
|
||||
|
||||
Executable → Regular
+1
-1
@@ -23,7 +23,7 @@ inline T implicit_cast (typename mpl::identity<T>::type x) {
|
||||
//template <typename T>
|
||||
//void implicit_cast (...);
|
||||
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // IMPLICIT_CAST_DWA200356_HPP
|
||||
|
||||
+1637
-40
File diff suppressed because it is too large
Load Diff
+124
-7
@@ -20,8 +20,14 @@
|
||||
<a href="#lexical_cast"><code>lexical_cast</code></a></li>
|
||||
<li>
|
||||
<a href="#bad_lexical_cast"><code>bad_lexical_cast</code></a></li>
|
||||
<li>
|
||||
<a href="#faq">Frequently Asked Questions</a></li>
|
||||
<li>
|
||||
<a href="#references">References</a></li>
|
||||
<li>
|
||||
<a href="#changes">Changes</a></li>
|
||||
<li>
|
||||
<a href="#performance">Performance</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2><a name="motivation">Motivation</a></h2>
|
||||
@@ -77,13 +83,13 @@
|
||||
conversions, such as where precision or formatting need tighter control than is
|
||||
offered by the default behavior of <code>lexical_cast</code>, the conventional <code>
|
||||
stringstream</code> approach is recommended. Where the conversions are
|
||||
numeric to numeric, <code><a href="../numeric/conversion/doc/numeric_cast.html">numeric_cast</a></code>
|
||||
numeric to numeric, <code><a href="../numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html">numeric_cast</a></code>
|
||||
may offer more reasonable behavior than <code>lexical_cast</code>.
|
||||
<p>
|
||||
For a good discussion of the options and issues involved in string-based
|
||||
formatting, including comparison of <code>stringstream</code>, <code>lexical_cast</code>,
|
||||
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>. Also, take a look at the <a href="#performance">Performance</a> section.
|
||||
<p>
|
||||
<hr>
|
||||
<h2><a name="examples">Examples</a></h2>
|
||||
@@ -160,7 +166,7 @@ void log_errno(int yoko)
|
||||
and an instance of the result type on the right.
|
||||
</li>
|
||||
<li>
|
||||
Both <code>Source</code> and <code>Target</code> are <i>CopyConstructible</i> [20.1.3].
|
||||
<code>Target</code> is <i>CopyConstructible</i> [20.1.3].
|
||||
</li>
|
||||
<li>
|
||||
<code>Target</code> is <i>DefaultConstructible</i>, meaning that it is possible
|
||||
@@ -190,9 +196,91 @@ public:
|
||||
</pre>
|
||||
</blockquote>Exception used to indicate runtime <a href="#lexical_cast"><code>lexical_cast</code></a>
|
||||
failure.
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
<!--
|
||||
The original design of lexical_cast library does not supports throwing/nonthrowing behaviour, default values,
|
||||
locales... BOOST_LEXICAL_CAST_ASSUME_C_LOCALE is a good optimization, but it breaks down the original design.
|
||||
-->
|
||||
<!--
|
||||
<h2><a name="BOOST_LEXICAL_CAST_ASSUME_C_LOCALE"><code>BOOST_LEXICAL_CAST_ASSUME_C_LOCALE</code></a></h2>
|
||||
<blockquote><pre>#define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE</blockquote></pre>
|
||||
or,
|
||||
<blockquote><pre>g++ -DBOOST_LEXICAL_CAST_ASSUME_C_LOCALE ... (gcc on Linux/Unix)</blockquote></pre>
|
||||
<blockquote><pre>cl.exe /DBOOST_LEXICAL_CAST_ASSUME_C_LOCALE ... (Visual C++ on Windows)</blockquote></pre>
|
||||
</pre>
|
||||
Eliminate an overhead of <code>std::locale</code> if your program runs in the "C" locale. If the option is set but a program runs in other locale, <code>lexical_cast</code> result is unspecified.
|
||||
<hr>
|
||||
-->
|
||||
|
||||
<h2><a name="faq">Frequently Asked Questions</a></h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top"><b>Question:</b></td>
|
||||
<td>Why does <code>lexical_cast<int8_t>("127")</code> throw <code>bad_lexical_cast</code>?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Answer:</b></td>
|
||||
<td>The type <code>int8_t</code> is a typedef to <code>char</code> or <code>signed char</code>.
|
||||
Lexical conversion to these types is simply reading a byte from source but since the source has
|
||||
more than one byte, the exception is thrown.
|
||||
Please use other integer types such as <code>int</code> or <code>short int</code>. If bounds checking
|
||||
is important, you can also call <a href="../../libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html">numeric_cast</a>:
|
||||
<pre><a href="../../libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html">numeric_cast</a><int8_t>(lexical_cast<int>("127"));</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Question:</b></td><td>What does <code>lexical_cast<std::string></code> of an <code>int8_t</code> or <code>uint8_t</code> not do what I expect?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Answer:</b></td><td>As above, note that <code>int8_t</code> and <code>uint8_t</code> are actually chars and are formatted as such. To avoid this, cast to an integer type first:
|
||||
<pre>lexical_cast<std::string>(static_cast<int>(n));</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Question:</b></td>
|
||||
<td>The implementation always resets the <code>ios_base::skipws</code> flag of an underlying stream object. It breaks my <code>operator>></code> that works only in presence of this flag. Can you remove code that resets the flag?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Answer:</b></td>
|
||||
<td>May be in a future version. There is no requirement in <a href="#n1973">[N1973]</a> to reset the flag but remember that <a href="#n1973">[N1973]</a> is not yet accepted by the committee. By the way, it's a great opportunity to make your <code>operator>></code> conform to the standard. Read a good C++ book, study <code>std::sentry</code> and <a href="../../libs/io/doc/ios_state.html">ios_state_saver</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Question:</b></td>
|
||||
<td>Why <code>std::cout << boost::lexical_cast<unsigned int>("-1");</code> does not throw, but outputs 4294967295?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><b>Answer:</b></td>
|
||||
<td><code>boost::lexical_cast</code> has the behavior of <code>stringstream</code>, which uses <code>num_get</code> functions of <code>std::locale</code> to convert numbers. If we look at the [22.2.2.1.2] of Programming languages — C++, we'll see, that <code>num_get</code> uses the rules of <code>scanf</code> for conversions. And in the C99 standard for unsigned input value minus sign is optional, so if a negative number is read, no errors will arise and the result will be the two's complement.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2><a name="references">References</a></h2>
|
||||
<ul type="square">
|
||||
<li><a name="n1973"></a>[N1973] Kevlin Henney, Beman Dawes, Lexical Conversion Library Proposal for TR2,
|
||||
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html">N1973</a>.
|
||||
<a name="tuning"></a><li> [Tuning] Alexander Nasonov, Fine Tuning for lexical_cast,
|
||||
<a href="http://accu.org/index.php/journals/1375">Overload #74</a> (<a href="http://www.accu.org/var/uploads/journals/overload74.pdf">PDF</a>),
|
||||
August 2006.</li>
|
||||
</ul>
|
||||
<h2><a name="changes">Changes</a></h2>
|
||||
<h3>May 2011:</h3>
|
||||
<ul type="square">
|
||||
<li>Optimizations for "C" and other locales without number grouping.</li>
|
||||
<li>Better performance and less memory usage for unsigned char and signed char conversions.</li>
|
||||
<li>Better performance and less memory usage for conversions to arithmetic types.</li>
|
||||
<li>Better performance and less memory usage for conversions from arithmetic type to arithmetic type.</li>
|
||||
<li>Directly construct <code>Target</code> from <code>Source</code> on some conversions (like conversions from string to string, from char array to string, from char to char and others).</li>
|
||||
</ul>
|
||||
<h3>August, October 2006:</h3>
|
||||
<ul type="square">
|
||||
<li>Better performance for many combinations of <code>Source</code> and <code>Target</code>
|
||||
types. Refer to <a href="#tuning">[Tuning]</a> for more details.
|
||||
</li>
|
||||
</ul>
|
||||
<h3>June 2005:</h3>
|
||||
<ul type="square">
|
||||
<li>Call-by-const reference for the parameters. This requires partial specialization
|
||||
@@ -228,7 +316,36 @@ public:
|
||||
</ul>
|
||||
<p>
|
||||
<hr>
|
||||
|
||||
<div align="right"><small><i>© Copyright Kevlin Henney, 2000–2005</i></small></div>
|
||||
|
||||
<h2><a name="performance">Performance</a></h2>
|
||||
This table shows the execution time in milliseconds for 100000 calls of the following string formatters:
|
||||
|
||||
<table border="1" width="100%">
|
||||
<tr>
|
||||
<tr><td>From->To</td><td> <code>lexical_cast</code> </td><td><code>std::stringstream</code><br>with construction</td><td><code>std::stringstream</code><br>without construction</td><td><code>sscanf</code>/<code>sprintf</code></td></tr>
|
||||
<tr><td>string->char</td><td bgcolor="#00C000"><1</td><td>91</td><td>7</td><td>10</td></tr>
|
||||
<tr><td>string->int</td><td bgcolor="#00C000">7</td><td>115</td><td>23</td><td>18</td></tr>
|
||||
<tr><td>string->unsigned int</td><td bgcolor="#00C000">7</td><td>117</td><td>22</td><td>17</td></tr>
|
||||
<tr><td>string->bool</td><td bgcolor="#00C000"><1</td><td>104</td><td>19</td><td>10</td></tr>
|
||||
<tr><td>string->float</td><td>85</td><td>172</td><td>60</td><td bgcolor="#00C000">33</td></tr>
|
||||
<tr><td>char->string</td><td bgcolor="#00C000">7</td><td>105</td><td>16</td><td>12</td></tr>
|
||||
<tr><td>int->string</td><td bgcolor="#00C000">15</td><td>131</td><td>21</td><td>17</td></tr>
|
||||
<tr><td>unsigned int->string</td><td bgcolor="#00C000">14</td><td>125</td><td>21</td><td>17</td></tr>
|
||||
<tr><td>bool->string</td><td bgcolor="#00C000">7</td><td>122</td><td>24</td><td>12</td></tr>
|
||||
<tr><td>float->string</td><td>124</td><td>223</td><td>115</td><td bgcolor="#00C000">48</td></tr>
|
||||
<tr><td>char*->string</td><td bgcolor="#00C000">9</td><td>123</td><td>20</td><td>---</td></tr>
|
||||
<tr><td>int->int</td><td bgcolor="#00C000"><1</td><td>120</td><td>26</td><td>---</td></tr>
|
||||
<tr><td>float->float</td><td bgcolor="#00C000"><1</td><td>262</td><td>142</td><td>---</td></tr>
|
||||
</table>
|
||||
|
||||
Fastest results are highlitened with green.
|
||||
<hr>
|
||||
<div align="right"><small><i>Copyright © Kevlin Henney, 2000-2005</i></small></div>
|
||||
<div align="right"><small><i>Copyright © Alexander Nasonov, 2006-2010</i></small></div>
|
||||
<div align="right"><small><i>Copyright © Antony Polukhin, 2011</i></small></div>
|
||||
<div align="right"><small><i>
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at <a href="../../LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</i></small>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+678
-17
@@ -2,7 +2,9 @@
|
||||
//
|
||||
// See http://www.boost.org for most recent version, including documentation.
|
||||
//
|
||||
// Copyright Terje Slettebø and Kevlin Henney, 2005.
|
||||
// Copyright Terje Sletteb and Kevlin Henney, 2005.
|
||||
// Copyright Alexander Nasonov, 2006.
|
||||
// Copyright Antony Polukhin, 2011.
|
||||
//
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
@@ -10,6 +12,13 @@
|
||||
//
|
||||
// Note: The unit test no longer compile on MSVC 6, but lexical_cast itself works for it.
|
||||
|
||||
//
|
||||
// We need this #define before any #includes: otherwise msvc will emit warnings
|
||||
// deep within std::string, resulting from our (perfectly legal) use of basic_string
|
||||
// with a custom traits class:
|
||||
//
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
@@ -20,15 +29,36 @@
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/floating_point_comparison.hpp>
|
||||
|
||||
#if defined(BOOST_NO_STRINGSTREAM) || \
|
||||
defined(BOOST_NO_STD_WSTRING) || \
|
||||
defined(BOOST_NO_STD_LOCALE)
|
||||
#define DISABLE_WIDE_CHAR_SUPPORT
|
||||
#include <boost/type_traits/integral_promotion.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \
|
||||
&& !(defined(BOOST_MSVC) && BOOST_MSVC < 1300)
|
||||
#define LCAST_TEST_LONGLONG
|
||||
#endif
|
||||
|
||||
template<class CharT>
|
||||
struct my_traits : std::char_traits<CharT>
|
||||
{
|
||||
};
|
||||
|
||||
template<class CharT>
|
||||
struct my_allocator : std::allocator<CharT>
|
||||
{
|
||||
};
|
||||
|
||||
// Test all 65536 values if true:
|
||||
bool const lcast_test_small_integral_types_completely = false;
|
||||
|
||||
// lcast_integral_test_counter: use when testing all values of an integral
|
||||
// types is not possible. Max. portable value is 32767.
|
||||
int const lcast_integral_test_counter=1000;
|
||||
|
||||
using namespace boost;
|
||||
|
||||
void test_conversion_to_char();
|
||||
@@ -44,6 +74,28 @@ void test_conversion_from_wstring();
|
||||
void test_conversion_to_wstring();
|
||||
void test_bad_lexical_cast();
|
||||
void test_no_whitespace_stripping();
|
||||
void test_conversion_from_to_short();
|
||||
void test_conversion_from_to_ushort();
|
||||
void test_conversion_from_to_int();
|
||||
void test_conversion_from_to_uint();
|
||||
void test_conversion_from_to_long();
|
||||
void test_conversion_from_to_ulong();
|
||||
void test_conversion_from_to_intmax_t();
|
||||
void test_conversion_from_to_uintmax_t();
|
||||
#ifdef LCAST_TEST_LONGLONG
|
||||
void test_conversion_from_to_longlong();
|
||||
void test_conversion_from_to_ulonglong();
|
||||
#endif
|
||||
void test_conversion_from_to_float();
|
||||
void test_conversion_from_to_double();
|
||||
void test_conversion_from_to_long_double();
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
void test_traits();
|
||||
void test_wtraits();
|
||||
void test_allocator();
|
||||
void test_wallocator();
|
||||
#endif
|
||||
void test_char_types_conversions();
|
||||
|
||||
unit_test::test_suite *init_unit_test_suite(int, char *[])
|
||||
{
|
||||
@@ -56,14 +108,38 @@ unit_test::test_suite *init_unit_test_suite(int, char *[])
|
||||
suite->add(BOOST_TEST_CASE(test_conversion_from_to_wchar_t_alias));
|
||||
suite->add(BOOST_TEST_CASE(test_conversion_to_pointer));
|
||||
suite->add(BOOST_TEST_CASE(test_conversion_to_string));
|
||||
#ifndef DISABLE_WIDE_CHAR_SUPPORT
|
||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||
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
|
||||
#endif
|
||||
suite->add(BOOST_TEST_CASE(test_bad_lexical_cast));
|
||||
suite->add(BOOST_TEST_CASE(test_no_whitespace_stripping));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t));
|
||||
#ifdef LCAST_TEST_LONGLONG
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong));
|
||||
#endif
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_float));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_double));
|
||||
suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long_double));
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
suite->add(BOOST_TEST_CASE(&test_traits));
|
||||
suite->add(BOOST_TEST_CASE(&test_wtraits));
|
||||
suite->add(BOOST_TEST_CASE(&test_allocator));
|
||||
suite->add(BOOST_TEST_CASE(&test_wallocator));
|
||||
#endif
|
||||
|
||||
suite->add(BOOST_TEST_CASE(&test_char_types_conversions));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
@@ -95,10 +171,15 @@ void test_conversion_to_int()
|
||||
BOOST_CHECK_EQUAL(0, lexical_cast<int>('0'));
|
||||
BOOST_CHECK_THROW(lexical_cast<int>('A'), bad_lexical_cast);
|
||||
BOOST_CHECK_EQUAL(1, lexical_cast<int>(1));
|
||||
BOOST_CHECK_EQUAL(1, lexical_cast<int>(1.0));
|
||||
|
||||
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_EQUAL(
|
||||
(std::numeric_limits<int>::min)(),
|
||||
lexical_cast<int>((std::numeric_limits<int>::min)()));
|
||||
|
||||
BOOST_CHECK_THROW(lexical_cast<int>(1.23), bad_lexical_cast);
|
||||
|
||||
@@ -159,14 +240,31 @@ void test_conversion_to_bool()
|
||||
BOOST_CHECK_EQUAL(false, lexical_cast<bool>("0"));
|
||||
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>(1.0001L), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(2), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(2u), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(-1), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(-2), bad_lexical_cast);
|
||||
|
||||
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<bool>(std::string("")), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<bool>(std::string("Test")), bad_lexical_cast);
|
||||
|
||||
BOOST_CHECK(lexical_cast<bool>("+1") == true );
|
||||
BOOST_CHECK(lexical_cast<bool>("+0") == false );
|
||||
BOOST_CHECK(lexical_cast<bool>("-0") == false );
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>("--0"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>("-+-0"), bad_lexical_cast);
|
||||
}
|
||||
|
||||
void test_conversion_to_string()
|
||||
{
|
||||
char buf[] = "hello";
|
||||
char* str = buf;
|
||||
BOOST_CHECK_EQUAL(str, lexical_cast<std::string>(str));
|
||||
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));
|
||||
@@ -196,14 +294,14 @@ void test_conversion_from_to_wchar_t_alias()
|
||||
void test_conversion_to_pointer()
|
||||
{
|
||||
BOOST_CHECK_THROW(lexical_cast<char *>("Test"), bad_lexical_cast);
|
||||
#ifndef DISABLE_WIDE_CHAR_SUPPORT
|
||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||
BOOST_CHECK_THROW(lexical_cast<wchar_t *>("Test"), bad_lexical_cast);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_conversion_from_wchar_t()
|
||||
{
|
||||
#ifndef DISABLE_WIDE_CHAR_SUPPORT
|
||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
BOOST_CHECK_EQUAL(1, lexical_cast<int>(L'1'));
|
||||
BOOST_CHECK_THROW(lexical_cast<int>(L'A'), bad_lexical_cast);
|
||||
@@ -236,9 +334,11 @@ void test_conversion_from_wchar_t()
|
||||
|
||||
void test_conversion_to_wchar_t()
|
||||
{
|
||||
#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
BOOST_CHECK_EQUAL(L'1', lexical_cast<wchar_t>(1));
|
||||
BOOST_CHECK_EQUAL(L'0', lexical_cast<wchar_t>(0));
|
||||
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), 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));
|
||||
@@ -256,12 +356,12 @@ void test_conversion_to_wchar_t()
|
||||
lexical_cast<wchar_t>(std::wstring(L"")), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<wchar_t>(std::wstring(L"Test")), bad_lexical_cast);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_conversion_from_wstring()
|
||||
{
|
||||
#ifndef DISABLE_WIDE_CHAR_SUPPORT
|
||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||
BOOST_CHECK_EQUAL(123, lexical_cast<int>(std::wstring(L"123")));
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<int>(std::wstring(L"")), bad_lexical_cast);
|
||||
@@ -274,12 +374,15 @@ void test_conversion_from_wstring()
|
||||
lexical_cast<bool>(std::wstring(L"")), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<bool>(std::wstring(L"Test")), bad_lexical_cast);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_conversion_to_wstring()
|
||||
{
|
||||
#ifndef DISABLE_WIDE_CHAR_SUPPORT
|
||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||
wchar_t buf[] = L"hello";
|
||||
wchar_t* str = buf;
|
||||
BOOST_CHECK(str == lexical_cast<std::wstring>(str));
|
||||
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));
|
||||
@@ -288,6 +391,7 @@ void test_conversion_to_wstring()
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
BOOST_CHECK(L"A" == lexical_cast<std::wstring>(L'A'));
|
||||
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L' '));
|
||||
BOOST_CHECK(L"A" == lexical_cast<std::wstring>('A'));
|
||||
#endif
|
||||
BOOST_CHECK(L"Test" == lexical_cast<std::wstring>(L"Test"));
|
||||
BOOST_CHECK(L" " == lexical_cast<std::wstring>(L" "));
|
||||
@@ -295,7 +399,7 @@ void test_conversion_to_wstring()
|
||||
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
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_bad_lexical_cast()
|
||||
@@ -318,3 +422,560 @@ void test_no_whitespace_stripping()
|
||||
BOOST_CHECK_THROW(lexical_cast<int>(" 123"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<int>("123 "), bad_lexical_cast);
|
||||
}
|
||||
|
||||
// Replace "-,999" with "-999".
|
||||
template<class CharT>
|
||||
std::basic_string<CharT> to_str_gcc_workaround(std::basic_string<CharT> str)
|
||||
{
|
||||
std::locale loc;
|
||||
std::numpunct<CharT> const& np = BOOST_USE_FACET(std::numpunct<CharT>, loc);
|
||||
std::ctype<CharT> const& ct = BOOST_USE_FACET(std::ctype<CharT>, loc);
|
||||
|
||||
if(np.grouping().empty())
|
||||
return str;
|
||||
|
||||
CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() };
|
||||
|
||||
if(str.find(prefix) != 0)
|
||||
return str;
|
||||
|
||||
prefix[1] = CharT();
|
||||
str.replace(0, 2, prefix);
|
||||
return str;
|
||||
}
|
||||
|
||||
template<class CharT, class T>
|
||||
std::basic_string<CharT> to_str(T t)
|
||||
{
|
||||
std::basic_ostringstream<CharT> o;
|
||||
o << t;
|
||||
return to_str_gcc_workaround(o.str());
|
||||
}
|
||||
|
||||
template<class T, class CharT>
|
||||
void test_conversion_from_integral_to_char(CharT zero)
|
||||
{
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(0)) == zero + 0);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(1)) == zero + 1);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(2)) == zero + 2);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(3)) == zero + 3);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(4)) == zero + 4);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(5)) == zero + 5);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(6)) == zero + 6);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(7)) == zero + 7);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(8)) == zero + 8);
|
||||
BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(9)) == zero + 9);
|
||||
|
||||
BOOST_CHECK_THROW(lexical_cast<CharT>(static_cast<T>(10)), bad_lexical_cast);
|
||||
|
||||
T t = (std::numeric_limits<T>::max)();
|
||||
BOOST_CHECK_THROW(lexical_cast<CharT>(t), bad_lexical_cast);
|
||||
}
|
||||
|
||||
template<class T, class CharT>
|
||||
void test_conversion_from_char_to_integral(CharT zero)
|
||||
{
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 0)) == static_cast<T>(0) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 1)) == static_cast<T>(1) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 2)) == static_cast<T>(2) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 3)) == static_cast<T>(3) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 4)) == static_cast<T>(4) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 5)) == static_cast<T>(5) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 6)) == static_cast<T>(6) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 7)) == static_cast<T>(7) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 8)) == static_cast<T>(8) );
|
||||
BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 9)) == static_cast<T>(9) );
|
||||
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( static_cast<CharT>(zero + 10)), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( static_cast<CharT>(zero - 1)), bad_lexical_cast);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void test_conversion_from_integral_to_integral()
|
||||
{
|
||||
T t = 0;
|
||||
BOOST_CHECK(lexical_cast<T>(t) == t);
|
||||
|
||||
// Next two variables are used to supress warnings.
|
||||
int st = 32767; unsigned int ut = st;
|
||||
t = st;
|
||||
BOOST_CHECK(lexical_cast<short>(t) == st);
|
||||
BOOST_CHECK(lexical_cast<unsigned short>(t) == ut);
|
||||
BOOST_CHECK(lexical_cast<int>(t) == st);
|
||||
BOOST_CHECK(lexical_cast<unsigned int>(t) == ut);
|
||||
BOOST_CHECK(lexical_cast<long>(t) == st);
|
||||
BOOST_CHECK(lexical_cast<unsigned long>(t) == ut);
|
||||
|
||||
t = (std::numeric_limits<T>::max)();
|
||||
BOOST_CHECK(lexical_cast<T>(t) == t);
|
||||
|
||||
t = (std::numeric_limits<T>::min)();
|
||||
BOOST_CHECK(lexical_cast<T>(t) == t);
|
||||
}
|
||||
|
||||
template<class T, class CharT>
|
||||
void test_conversion_from_integral_to_string(CharT)
|
||||
{
|
||||
typedef std::numeric_limits<T> limits;
|
||||
typedef std::basic_string<CharT> string_type;
|
||||
|
||||
T t;
|
||||
|
||||
t = (limits::min)();
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
|
||||
t = (limits::max)();
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
|
||||
if(limits::digits <= 16 && lcast_test_small_integral_types_completely)
|
||||
// min and max have already been tested.
|
||||
for(t = 1 + (limits::min)(); t != (limits::max)(); ++t)
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
else
|
||||
{
|
||||
T const min_val = (limits::min)();
|
||||
T const max_val = (limits::max)();
|
||||
T const half_max_val = max_val / 2;
|
||||
T const cnt = lcast_integral_test_counter; // to supress warnings
|
||||
unsigned int const counter = cnt < half_max_val ? cnt : half_max_val;
|
||||
|
||||
unsigned int i;
|
||||
|
||||
// Test values around min:
|
||||
t = min_val;
|
||||
for(i = 0; i < counter; ++i, ++t)
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
|
||||
// Test values around max:
|
||||
t = max_val;
|
||||
for(i = 0; i < counter; ++i, --t)
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
|
||||
// Test values around zero:
|
||||
if(limits::is_signed)
|
||||
for(t = -counter; t < static_cast<T>(counter); ++t)
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
|
||||
// Test values around 100, 1000, 10000, ...
|
||||
T ten_power = 100;
|
||||
for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10)
|
||||
{
|
||||
// ten_power + 100 probably never overflows
|
||||
for(t = ten_power - 100; t != ten_power + 100; ++t)
|
||||
BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class CharT>
|
||||
void test_conversion_from_string_to_integral(CharT)
|
||||
{
|
||||
typedef std::numeric_limits<T> limits;
|
||||
typedef std::basic_string<CharT> string_type;
|
||||
|
||||
string_type s;
|
||||
string_type const zero = to_str<CharT>(0);
|
||||
string_type const nine = to_str<CharT>(9);
|
||||
T const min_val = (limits::min)();
|
||||
T const max_val = (limits::max)();
|
||||
|
||||
s = to_str<CharT>(min_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(s), min_val);
|
||||
if(limits::is_signed)
|
||||
{
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast);
|
||||
}
|
||||
|
||||
s = to_str<CharT>(max_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(s), max_val);
|
||||
{
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast);
|
||||
|
||||
s = to_str<CharT>(max_val);
|
||||
for (int i =1; i <=10; ++i) {
|
||||
s[s.size()-1] += 1;
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( s ), bad_lexical_cast);
|
||||
}
|
||||
|
||||
s = to_str<CharT>(max_val);
|
||||
std::locale loc;
|
||||
typedef std::numpunct<char> numpunct;
|
||||
if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) {
|
||||
// Following tests work well for locale C
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+s), max_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+to_str<CharT>(0)+s), max_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+to_str<CharT>(0)+to_str<CharT>(0)+s), max_val);
|
||||
}
|
||||
|
||||
for (int i =1; i <=256; ++i) {
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(i)+s ), bad_lexical_cast);
|
||||
}
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion<T>::type promoted;
|
||||
if ( !(boost::is_same<T, promoted>::value) )
|
||||
{
|
||||
promoted prom = max_val;
|
||||
s = to_str<CharT>(max_val);
|
||||
for (int i =1; i <=256; ++i) {
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(prom+i) ), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(i)+s ), bad_lexical_cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(limits::digits <= 16 && lcast_test_small_integral_types_completely)
|
||||
// min and max have already been tested.
|
||||
for(T t = 1 + min_val; t != max_val; ++t)
|
||||
BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t);
|
||||
else
|
||||
{
|
||||
T const half_max_val = max_val / 2;
|
||||
T const cnt = lcast_integral_test_counter; // to supress warnings
|
||||
unsigned int const counter = cnt < half_max_val ? cnt : half_max_val;
|
||||
|
||||
T t;
|
||||
unsigned int i;
|
||||
|
||||
// Test values around min:
|
||||
t = min_val;
|
||||
for(i = 0; i < counter; ++i, ++t)
|
||||
BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t);
|
||||
|
||||
// Test values around max:
|
||||
t = max_val;
|
||||
for(i = 0; i < counter; ++i, --t)
|
||||
BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t);
|
||||
|
||||
// Test values around zero:
|
||||
if(limits::is_signed)
|
||||
for(t = -counter; t < static_cast<T>(counter); ++t)
|
||||
BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t);
|
||||
|
||||
// Test values around 100, 1000, 10000, ...
|
||||
T ten_power = 100;
|
||||
for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10)
|
||||
{
|
||||
// ten_power + 100 probably never overflows
|
||||
for(t = ten_power - 100; t != ten_power + 100; ++t)
|
||||
BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void test_conversion_from_to_integral_for_locale()
|
||||
{
|
||||
std::locale current_locale;
|
||||
typedef std::numpunct<char> numpunct;
|
||||
numpunct const& np = BOOST_USE_FACET(numpunct, current_locale);
|
||||
if ( !np.grouping().empty() )
|
||||
{
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<T>( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" )
|
||||
, bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( std::string("100") + np.thousands_sep() ), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( np.thousands_sep() + std::string("100") ), bad_lexical_cast);
|
||||
|
||||
// Exception must not be thrown, when we are using no separators at all
|
||||
BOOST_CHECK( lexical_cast<T>("10000") == static_cast<T>(10000) );
|
||||
}
|
||||
|
||||
test_conversion_from_integral_to_integral<T>();
|
||||
test_conversion_from_integral_to_string<T>('0');
|
||||
test_conversion_from_string_to_integral<T>('0');
|
||||
#if !defined(BOOST_LCAST_NO_WCHAR_T)
|
||||
test_conversion_from_integral_to_string<T>(L'0');
|
||||
test_conversion_from_string_to_integral<T>(L'0');
|
||||
#endif
|
||||
}
|
||||
|
||||
struct restore_oldloc
|
||||
{
|
||||
std::locale oldloc;
|
||||
~restore_oldloc() { std::locale::global(oldloc); }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void test_conversion_from_to_integral()
|
||||
{
|
||||
char const zero = '0';
|
||||
signed char const szero = '0';
|
||||
unsigned char const uzero = '0';
|
||||
test_conversion_from_integral_to_char<T>(zero);
|
||||
test_conversion_from_char_to_integral<T>(zero);
|
||||
test_conversion_from_integral_to_char<T>(szero);
|
||||
test_conversion_from_char_to_integral<T>(szero);
|
||||
test_conversion_from_integral_to_char<T>(uzero);
|
||||
test_conversion_from_char_to_integral<T>(uzero);
|
||||
#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
wchar_t const wzero = L'0';
|
||||
test_conversion_from_integral_to_char<T>(wzero);
|
||||
test_conversion_from_char_to_integral<T>(wzero);
|
||||
#endif
|
||||
|
||||
BOOST_CHECK(lexical_cast<T>("-1") == static_cast<T>(-1));
|
||||
BOOST_CHECK(lexical_cast<T>("-9") == static_cast<T>(-9));
|
||||
BOOST_CHECK(lexical_cast<T>(-1) == static_cast<T>(-1));
|
||||
BOOST_CHECK(lexical_cast<T>(-9) == static_cast<T>(-9));
|
||||
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("-1.0"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("-9.0"), bad_lexical_cast);
|
||||
BOOST_CHECK(lexical_cast<T>(-1.0) == static_cast<T>(-1));
|
||||
BOOST_CHECK(lexical_cast<T>(-9.0) == static_cast<T>(-9));
|
||||
|
||||
BOOST_CHECK(lexical_cast<T>(static_cast<T>(1)) == static_cast<T>(1));
|
||||
BOOST_CHECK(lexical_cast<T>(static_cast<T>(9)) == static_cast<T>(9));
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(1.1f), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(1.1), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(1.1L), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(1.0001f), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(1.0001), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(1.0001L), bad_lexical_cast);
|
||||
|
||||
BOOST_CHECK(lexical_cast<T>("+1") == static_cast<T>(1) );
|
||||
BOOST_CHECK(lexical_cast<T>("+9") == static_cast<T>(9) );
|
||||
BOOST_CHECK(lexical_cast<T>("+10") == static_cast<T>(10) );
|
||||
BOOST_CHECK(lexical_cast<T>("+90") == static_cast<T>(90) );
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("++1"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("-+9"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("--1"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("+-9"), bad_lexical_cast);
|
||||
// test_conversion_from_to_integral_for_locale
|
||||
|
||||
typedef std::numpunct<char> numpunct;
|
||||
|
||||
restore_oldloc guard;
|
||||
std::locale const& oldloc = guard.oldloc;
|
||||
|
||||
std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping();
|
||||
std::string grouping2(grouping1);
|
||||
|
||||
test_conversion_from_to_integral_for_locale<T>();
|
||||
|
||||
try
|
||||
{
|
||||
std::locale newloc("");
|
||||
std::locale::global(newloc);
|
||||
|
||||
grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping();
|
||||
}
|
||||
catch(std::exception const& ex)
|
||||
{
|
||||
std::string msg("Failed to set system locale: ");
|
||||
msg += ex.what();
|
||||
BOOST_TEST_MESSAGE(msg);
|
||||
}
|
||||
|
||||
if(grouping1 != grouping2)
|
||||
test_conversion_from_to_integral_for_locale<T>();
|
||||
|
||||
if(grouping1.empty() && grouping2.empty())
|
||||
BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested");
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void test_conversion_from_to_float()
|
||||
{
|
||||
char const zero = '0';
|
||||
signed char const szero = '0';
|
||||
unsigned char const uzero = '0';
|
||||
test_conversion_from_integral_to_char<T>(zero);
|
||||
test_conversion_from_char_to_integral<T>(zero);
|
||||
test_conversion_from_integral_to_char<T>(szero);
|
||||
test_conversion_from_char_to_integral<T>(szero);
|
||||
test_conversion_from_integral_to_char<T>(uzero);
|
||||
test_conversion_from_char_to_integral<T>(uzero);
|
||||
#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
wchar_t const wzero = L'0';
|
||||
test_conversion_from_integral_to_char<T>(wzero);
|
||||
test_conversion_from_char_to_integral<T>(wzero);
|
||||
#endif
|
||||
|
||||
test_conversion_from_integral_to_integral<T>();
|
||||
|
||||
BOOST_CHECK_CLOSE(lexical_cast<T>("+1"), 1, std::numeric_limits<T>::epsilon() );
|
||||
BOOST_CHECK_CLOSE(lexical_cast<T>("+9"), 9, std::numeric_limits<T>::epsilon()*9 );
|
||||
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("++1"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("-+9"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("--1"), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>("+-9"), bad_lexical_cast);
|
||||
}
|
||||
|
||||
void test_conversion_from_to_short()
|
||||
{
|
||||
test_conversion_from_to_integral<short>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_ushort()
|
||||
{
|
||||
test_conversion_from_to_integral<unsigned short>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_int()
|
||||
{
|
||||
test_conversion_from_to_integral<int>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_uint()
|
||||
{
|
||||
test_conversion_from_to_integral<unsigned int>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_long()
|
||||
{
|
||||
test_conversion_from_to_integral<long>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_ulong()
|
||||
{
|
||||
test_conversion_from_to_integral<unsigned long>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_intmax_t()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::intmax_t>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_uintmax_t()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::uintmax_t>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_float()
|
||||
{
|
||||
test_conversion_from_to_float<float>();
|
||||
}
|
||||
void test_conversion_from_to_double()
|
||||
{
|
||||
test_conversion_from_to_float<double>();
|
||||
}
|
||||
void test_conversion_from_to_long_double()
|
||||
{
|
||||
test_conversion_from_to_float<long double>();
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_LONG_LONG)
|
||||
|
||||
void test_conversion_from_to_longlong()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::long_long_type>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_ulonglong()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::ulong_long_type>();
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
|
||||
void test_conversion_from_to_longlong()
|
||||
{
|
||||
test_conversion_from_to_integral<__int64>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_ulonglong()
|
||||
{
|
||||
test_conversion_from_to_integral<unsigned __int64>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
void test_traits()
|
||||
{
|
||||
typedef std::basic_string<char, my_traits<char> > my_string;
|
||||
|
||||
my_string const s("s");
|
||||
BOOST_CHECK(boost::lexical_cast<char>(s) == s[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(s) == s);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(-1) == "-1");
|
||||
}
|
||||
|
||||
void test_wtraits()
|
||||
{
|
||||
typedef std::basic_string<wchar_t, my_traits<wchar_t> > my_string;
|
||||
|
||||
my_string const s(L"s");
|
||||
BOOST_CHECK(boost::lexical_cast<wchar_t>(s) == s[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(s) == s);
|
||||
//BOOST_CHECK(boost::lexical_cast<my_string>(-1) == L"-1");
|
||||
// Commented out because gcc 3.3 doesn't support this:
|
||||
// basic_ostream<wchar_t, my_traits<wchar_t> > o; o << -1;
|
||||
}
|
||||
|
||||
void test_allocator()
|
||||
{
|
||||
typedef std::basic_string< char
|
||||
, std::char_traits<char>
|
||||
, my_allocator<char>
|
||||
> my_string;
|
||||
|
||||
my_string s("s");
|
||||
BOOST_CHECK(boost::lexical_cast<char>(s) == s[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<std::string>(s) == "s");
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(s) == s);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(1) == "1");
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>("s") == s);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(std::string("s")) == s);
|
||||
}
|
||||
|
||||
void test_wallocator()
|
||||
{
|
||||
typedef std::basic_string< wchar_t
|
||||
, std::char_traits<wchar_t>
|
||||
, my_allocator<wchar_t>
|
||||
> my_string;
|
||||
|
||||
my_string s(L"s");
|
||||
BOOST_CHECK(boost::lexical_cast<wchar_t>(s) == s[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<std::wstring>(s) == L"s");
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(s) == s);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(1) == L"1");
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(L"s") == s);
|
||||
BOOST_CHECK(boost::lexical_cast<my_string>(std::wstring(L"s")) == s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void test_char_types_conversions()
|
||||
{
|
||||
const char c_arr[] = "Test array of chars";
|
||||
const unsigned char uc_arr[] = "Test array of chars";
|
||||
const signed char sc_arr[] = "Test array of chars";
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<std::string>(c_arr) == std::string(c_arr));
|
||||
BOOST_CHECK(boost::lexical_cast<std::string>(uc_arr) == std::string(c_arr));
|
||||
BOOST_CHECK(boost::lexical_cast<std::string>(sc_arr) == std::string(c_arr));
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<char>(c_arr[0]) == c_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<char>(uc_arr[0]) == c_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<char>(sc_arr[0]) == c_arr[0]);
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<unsigned char>(c_arr[0]) == uc_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<unsigned char>(uc_arr[0]) == uc_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<unsigned char>(sc_arr[0]) == uc_arr[0]);
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<signed char>(c_arr[0]) == sc_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<signed char>(uc_arr[0]) == sc_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<signed char>(sc_arr[0]) == sc_arr[0]);
|
||||
|
||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||
const wchar_t wc_arr[]=L"Test array of chars";
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<std::wstring>(wc_arr) == std::wstring(wc_arr));
|
||||
BOOST_CHECK(boost::lexical_cast<std::wstring>(c_arr) == std::wstring(wc_arr));
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<std::wstring>(sc_arr) != std::wstring(wc_arr) );
|
||||
BOOST_CHECK(boost::lexical_cast<std::wstring>(uc_arr) != std::wstring(wc_arr) );
|
||||
|
||||
BOOST_CHECK(boost::lexical_cast<wchar_t>(c_arr[0]) == wc_arr[0]);
|
||||
BOOST_CHECK(boost::lexical_cast<wchar_t>(wc_arr[0]) == wc_arr[0]);
|
||||
|
||||
BOOST_CHECK_THROW(boost::lexical_cast<wchar_t>(uc_arr[0]), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(boost::lexical_cast<wchar_t>(sc_arr[0]), bad_lexical_cast);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ test-suite conversion
|
||||
[ run ../cast_test.cpp ]
|
||||
[ run ../numeric_cast_test.cpp ]
|
||||
[ run ../lexical_cast_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
|
||||
[ run lexical_cast_loopback_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
|
||||
[ run lexical_cast_abstract_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
|
||||
[ run lexical_cast_noncopyable_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
|
||||
[ run lexical_cast_vc8_bug_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
|
||||
;
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Unit test for boost::lexical_cast.
|
||||
//
|
||||
// See http://www.boost.org for most recent version, including documentation.
|
||||
//
|
||||
// Copyright Sergey Shandar 2005, Alexander Nasonov, 2007.
|
||||
//
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// Test abstract class. Bug 1358600:
|
||||
// http://sf.net/tracker/?func=detail&aid=1358600&group_id=7586&atid=107586
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#pragma warning(disable: 193 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/unit_test.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
void test_abstract();
|
||||
|
||||
unit_test::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_abstract));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
virtual void out(std::ostream &) const = 0;
|
||||
};
|
||||
|
||||
class B: public A
|
||||
{
|
||||
public:
|
||||
virtual void out(std::ostream &O) const { O << "B"; }
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &O, const A &a)
|
||||
{
|
||||
a.out(O);
|
||||
return O;
|
||||
}
|
||||
|
||||
void test_abstract()
|
||||
{
|
||||
const A &a = B();
|
||||
BOOST_CHECK(boost::lexical_cast<std::string>(a) == "B");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Unit test for boost::lexical_cast.
|
||||
//
|
||||
// See http://www.boost.org for most recent version, including documentation.
|
||||
//
|
||||
// Copyright Alexander Nasonov, 2006.
|
||||
//
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// Test round-tripping conversion FPT -> string -> FPT,
|
||||
// where FPT is Floating Point Type.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#pragma warning(disable: 193 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/unit_test.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
void test_round_conversion_float();
|
||||
void test_round_conversion_double();
|
||||
void test_round_conversion_long_double();
|
||||
|
||||
unit_test::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_round_conversion_float));
|
||||
suite->add(BOOST_TEST_CASE(&test_round_conversion_double));
|
||||
suite->add(BOOST_TEST_CASE(&test_round_conversion_long_double));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void test_round_conversion()
|
||||
{
|
||||
T epsilon = std::numeric_limits<T>::epsilon();
|
||||
std::string const epsilon_s = boost::lexical_cast<std::string>(epsilon);
|
||||
BOOST_CHECK(epsilon == lexical_cast<T>(epsilon_s));
|
||||
|
||||
T max_ = (std::numeric_limits<T>::max)();
|
||||
std::string const max_s = boost::lexical_cast<std::string>(max_);
|
||||
BOOST_CHECK(max_ == lexical_cast<T>(max_s));
|
||||
|
||||
T min_ = (std::numeric_limits<T>::min)();
|
||||
std::string const min_s = boost::lexical_cast<std::string>(min_);
|
||||
BOOST_CHECK(min_ == lexical_cast<T>(min_s));
|
||||
|
||||
T max_div137 = max_ / 137;
|
||||
std::string max_div137_s = boost::lexical_cast<std::string>(max_div137);
|
||||
BOOST_CHECK(max_div137 == lexical_cast<T>(max_div137_s));
|
||||
|
||||
T epsilon_mult137 = epsilon * 137;
|
||||
std::string epsilon_mult137_s(lexical_cast<std::string>(epsilon_mult137));
|
||||
BOOST_CHECK(epsilon_mult137 == lexical_cast<T>(epsilon_mult137_s));
|
||||
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
// See bug http://tinyurl.com/vhpvo
|
||||
template<class T>
|
||||
void test_msvc_magic_values()
|
||||
{
|
||||
T magic_msvc = 0.00010000433948393407;
|
||||
std::string magic_msvc_s = boost::lexical_cast<std::string>(magic_msvc);
|
||||
BOOST_CHECK(magic_msvc == lexical_cast<T>(magic_msvc_s));
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_round_conversion_float()
|
||||
{
|
||||
test_round_conversion<float>();
|
||||
}
|
||||
|
||||
void test_round_conversion_double()
|
||||
{
|
||||
test_round_conversion<double>();
|
||||
#if defined(BOOST_MSVC)
|
||||
test_msvc_magic_values<double>();
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_round_conversion_long_double()
|
||||
{
|
||||
test_round_conversion<long double>();
|
||||
#if defined(BOOST_MSVC)
|
||||
test_msvc_magic_values<long double>();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Unit test for boost::lexical_cast.
|
||||
//
|
||||
// See http://www.boost.org for most recent version, including documentation.
|
||||
//
|
||||
// Copyright Alexander Nasonov, 2007.
|
||||
//
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// Test that Source can be non-copyable.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#pragma warning(disable: 193 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/noncopyable.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
void test_noncopyable();
|
||||
|
||||
unit_test::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_noncopyable));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
class Noncopyable : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
Noncopyable() {}
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, const Noncopyable&)
|
||||
{
|
||||
return out << "Noncopyable";
|
||||
}
|
||||
|
||||
void test_noncopyable()
|
||||
{
|
||||
Noncopyable x;
|
||||
BOOST_CHECK(boost::lexical_cast<std::string>(x) == "Noncopyable");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Unit test for boost::lexical_cast.
|
||||
//
|
||||
// See http://www.boost.org for most recent version, including documentation.
|
||||
//
|
||||
// Copyright Alexander Nasonov, 2007.
|
||||
//
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
|
||||
//
|
||||
// This tests now must pass on vc8, because lexical_cast
|
||||
// implementation has changed and it does not use stringstream for casts
|
||||
// to integral types
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
// See also test_conversion_from_string_to_integral(CharT)
|
||||
// in libs/conversion/lexical_cast_test.cpp
|
||||
template<class T, class CharT>
|
||||
void test_too_long_number(CharT zero)
|
||||
{
|
||||
typedef std::numeric_limits<T> limits;
|
||||
|
||||
std::basic_string<CharT> s;
|
||||
|
||||
std::basic_ostringstream<CharT> o;
|
||||
o << (limits::max)() << zero;
|
||||
s = o.str();
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s), bad_lexical_cast);
|
||||
s[s.size()-1] += 9; // '0' -> '9'
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s), bad_lexical_cast);
|
||||
|
||||
if(limits::is_signed)
|
||||
{
|
||||
std::basic_ostringstream<CharT> o;
|
||||
o << (limits::min)() << zero;
|
||||
s = o.str();
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s), bad_lexical_cast);
|
||||
s[s.size()-1] += 9; // '0' -> '9'
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s), bad_lexical_cast);
|
||||
}
|
||||
}
|
||||
|
||||
void test_vc8_bug()
|
||||
{
|
||||
test_too_long_number<boost::intmax_t>('0');
|
||||
test_too_long_number<boost::uintmax_t>('0');
|
||||
#if !defined(BOOST_LCAST_NO_WCHAR_T)
|
||||
test_too_long_number<boost::intmax_t>(L'0');
|
||||
test_too_long_number<boost::uintmax_t>(L'0');
|
||||
#endif
|
||||
}
|
||||
|
||||
unit_test::test_suite *init_unit_test_suite(int, char *[])
|
||||
{
|
||||
unit_test_framework::test_suite *suite =
|
||||
BOOST_TEST_SUITE("lexical_cast vc8 bug unit test");
|
||||
suite->add(BOOST_TEST_CASE(test_vc8_bug));
|
||||
return suite;
|
||||
}
|
||||
Reference in New Issue
Block a user