|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r73851 - in branches/release: boost doc/html libs/conversion libs/conversion/doc libs/conversion/test
From: antoshkka_at_[hidden]
Date: 2011-08-17 14:43:12
Author: apolukhin
Date: 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
New Revision: 73851
URL: http://svn.boost.org/trac/boost/changeset/73851
Log:
Merge from trunk r73850
* Compile time optimizations
* Float types optimizations
* Source code refactoring
* Parsing and writing inf and nan values according to the standart
* Fixed some bugs and warnings
* New tests
* New documentation
Added:
branches/release/doc/html/boost_lexical_cast.html (contents, props changed)
branches/release/libs/conversion/doc/
branches/release/libs/conversion/test/lexical_cast_float_types_test.cpp (contents, props changed)
branches/release/libs/conversion/test/lexical_cast_inf_nan_test.cpp (contents, props changed)
branches/release/libs/conversion/test/lexical_cast_wchars_test.cpp (contents, props changed)
Text files modified:
branches/release/boost/lexical_cast.hpp | 1685 +++++++++++++++++++++------------------
branches/release/libs/conversion/index.html | 2
branches/release/libs/conversion/lexical_cast.htm | 357 --------
branches/release/libs/conversion/lexical_cast_test.cpp | 141 +-
branches/release/libs/conversion/test/Jamfile.v2 | 3
branches/release/libs/conversion/test/lexical_cast_loopback_test.cpp | 6
6 files changed, 992 insertions(+), 1202 deletions(-)
Modified: branches/release/boost/lexical_cast.hpp
==============================================================================
--- branches/release/boost/lexical_cast.hpp (original)
+++ branches/release/boost/lexical_cast.hpp 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -1,6 +1,12 @@
#ifndef BOOST_LEXICAL_CAST_INCLUDED
#define BOOST_LEXICAL_CAST_INCLUDED
+// MS compatible compilers support #pragma once
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
// Boost lexical_cast.hpp header -------------------------------------------//
//
// See http://www.boost.org/libs/conversion for documentation.
@@ -18,6 +24,8 @@
#include <cstddef>
#include <istream>
#include <string>
+#include <cstring>
+#include <cstdio>
#include <typeinfo>
#include <exception>
#include <cmath>
@@ -28,17 +36,26 @@
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits/ice.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/is_signed.hpp>
-#include <boost/call_traits.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/lcast_precision.hpp>
#include <boost/detail/workaround.hpp>
+#include <cwchar>
+
#ifndef BOOST_NO_STD_LOCALE
-#include <locale>
+# include <locale>
+#else
+# ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
+# warning "Unable to use <locale> header. boost::lexical_cast will use the 'C' locale."
+# define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
+# endif
#endif
#ifdef BOOST_NO_STRINGSTREAM
@@ -214,156 +231,17 @@
namespace detail // lcast_src_length
{
// Return max. length of string representation of Source;
- // 0 if unlimited (with exceptions for some types, see below).
- // Values with limited string representation are placed to
- // the buffer locally defined in lexical_cast function.
- // 1 is returned for few types such as CharT const* or
- // std::basic_string<CharT> that already have an internal
- // buffer ready to be reused by lexical_stream_limited_src.
- // Each specialization should have a correspondent operator<<
- // defined in lexical_stream_limited_src.
template< class CharT // A result of widest_char transformation.
, class Source // Source type of lexical_cast.
>
struct lcast_src_length
{
- BOOST_STATIC_CONSTANT(std::size_t, value = 0);
+ BOOST_STATIC_CONSTANT(std::size_t, value = 1);
// To check coverage, build the test with
// bjam --v2 profile optimization=off
static void check_coverage() {}
};
- template<>
- struct lcast_src_length<char, bool>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
- template<>
- struct lcast_src_length<char, char>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
- template<>
- struct lcast_src_length<char, signed char>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
- template<>
- struct lcast_src_length<char, unsigned char>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
- template<>
- struct lcast_src_length<char, signed char*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
- template<>
- struct lcast_src_length<char, unsigned char*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
- template<>
- struct lcast_src_length<char, signed char const*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
- template<>
- struct lcast_src_length<char, unsigned char const*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- template<>
- struct lcast_src_length<wchar_t, bool>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
- template<>
- struct lcast_src_length<wchar_t, char>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
-#ifndef BOOST_NO_INTRINSIC_WCHAR_T
- template<>
- struct lcast_src_length<wchar_t, wchar_t>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-#endif
-#endif
-
- template<>
- struct lcast_src_length<char, char const*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
- template<>
- struct lcast_src_length<char, char*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- template<>
- struct lcast_src_length<wchar_t, wchar_t const*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
- template<>
- struct lcast_src_length<wchar_t, wchar_t*>
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-#endif
-
-#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
- template<class CharT, class Traits, class Alloc>
- struct lcast_src_length< CharT, std::basic_string<CharT,Traits,Alloc> >
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-#else
- template<>
- struct lcast_src_length< char, std::basic_string<char> >
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- template<>
- struct lcast_src_length< wchar_t, std::basic_string<wchar_t> >
- {
- BOOST_STATIC_CONSTANT(std::size_t, value = 1);
- static void check_coverage() {}
- };
-#endif
-#endif
-
// Helper for integral types.
// Notes on length calculation:
// Max length for 32bit int with grouping "\1" and thousands_sep ',':
@@ -383,7 +261,7 @@
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
BOOST_STATIC_CONSTANT(std::size_t, value =
std::numeric_limits<Source>::is_signed +
- std::numeric_limits<Source>::is_specialized + // == 1
+ std::numeric_limits<Source>::is_specialized + /* == 1 */
std::numeric_limits<Source>::digits10 * 2
);
#else
@@ -502,6 +380,9 @@
BOOST_STATIC_CONSTANT(char, zero = '0');
BOOST_STATIC_CONSTANT(char, minus = '-');
BOOST_STATIC_CONSTANT(char, plus = '+');
+ BOOST_STATIC_CONSTANT(char, lowercase_e = 'e');
+ BOOST_STATIC_CONSTANT(char, capital_e = 'E');
+ BOOST_STATIC_CONSTANT(char, c_decimal_separator = '.');
};
#ifndef BOOST_LCAST_NO_WCHAR_T
@@ -511,17 +392,13 @@
BOOST_STATIC_CONSTANT(wchar_t, zero = L'0');
BOOST_STATIC_CONSTANT(wchar_t, minus = L'-');
BOOST_STATIC_CONSTANT(wchar_t, plus = L'+');
+ BOOST_STATIC_CONSTANT(wchar_t, lowercase_e = L'e');
+ BOOST_STATIC_CONSTANT(wchar_t, capital_e = L'E');
+ BOOST_STATIC_CONSTANT(wchar_t, c_decimal_separator = L'.');
};
#endif
}
- namespace detail // lexical_streambuf_fake
- {
- struct lexical_streambuf_fake
- {
- };
- }
-
namespace detail // lcast_to_unsigned
{
#if (defined _MSC_VER)
@@ -560,7 +437,6 @@
int_type const zero = Traits::to_int_type(czero);
#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
- // TODO: use BOOST_NO_STD_LOCALE
std::locale loc;
typedef std::numpunct<CharT> numpunct;
numpunct const& np = BOOST_USE_FACET(numpunct, loc);
@@ -639,14 +515,13 @@
T multiplier = 1;
#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
- // TODO: use BOOST_NO_STD_LOCALE
std::locale loc;
typedef std::numpunct<CharT> numpunct;
numpunct const& np = BOOST_USE_FACET(numpunct, loc);
std::string const& grouping = np.grouping();
std::string::size_type const grouping_size = grouping.size();
- /* According to [22.2.2.1.2] of Programming languages - C++
+ /* According to Programming languages - C++
* we MUST check for correct grouping
*/
if (grouping_size && grouping[0] > 0)
@@ -719,158 +594,613 @@
}
}
- namespace detail // stream wrapper for handling lexical conversions
+ namespace detail
{
- template<typename Target, typename Source, typename Traits>
- class lexical_stream
- {
- private:
- typedef typename widest_char<
- typename stream_char<Target>::type,
- typename stream_char<Source>::type>::type char_type;
-
- typedef Traits traits_type;
-
- public:
- lexical_stream(char_type* = 0, char_type* = 0)
- {
- stream.unsetf(std::ios::skipws);
- lcast_set_precision(stream, static_cast<Source*>(0), static_cast<Target*>(0) );
- }
- ~lexical_stream()
- {
- #if defined(BOOST_NO_STRINGSTREAM)
- stream.freeze(false);
- #endif
+ /* Returns true and sets the correct value if found NaN or Inf. */
+ template <class CharT, class T>
+ inline bool parse_inf_nan_impl(const CharT* begin, const CharT* end, T& value
+ , const CharT* lc_NAN, const CharT* lc_nan
+ , const CharT* lc_INFINITY, const CharT* lc_infinity
+ , const CharT opening_brace, const CharT closing_brace)
+ {
+ using namespace std;
+ const wchar_t minus = lcast_char_constants<wchar_t>::minus;
+ const wchar_t plus = lcast_char_constants<wchar_t>::plus;
+ const int inifinity_size = 8;
+
+ bool has_minus = false;
+ /* Parsing +/- */
+ if( *begin == minus)
+ {
+ ++ begin;
+ has_minus = true;
}
- bool operator<<(const Source &input)
+ else if( *begin == plus ) ++begin;
+
+ if( end-begin < 3 ) return false;
+ if( !memcmp(begin, lc_nan, 3*sizeof(CharT)) || !memcmp(begin, lc_NAN, 3*sizeof(CharT)) )
{
- return !(stream << input).fail();
- }
- template<typename InputStreamable>
- bool operator>>(InputStreamable &output)
+ begin += 3;
+ if (end != begin) /* It is 'nan(...)' or some bad input*/
+ {
+ if(end-begin<2) return false; // bad input
+ -- end;
+ if( *begin != opening_brace || *end != closing_brace) return false; // bad input
+ }
+
+ if( !has_minus ) value = std::numeric_limits<T>::quiet_NaN();
+ else value = (boost::math::changesign) (std::numeric_limits<T>::quiet_NaN());
+ return true;
+ } else
+ if (( /* 'INF' or 'inf' */
+ end-begin==3
+ &&
+ (!memcmp(begin, lc_infinity, 3*sizeof(CharT)) || !memcmp(begin, lc_INFINITY, 3*sizeof(CharT)))
+ )
+ ||
+ ( /* 'INFINITY' or 'infinity' */
+ end-begin==inifinity_size
+ &&
+ (!memcmp(begin, lc_infinity, inifinity_size)|| !memcmp(begin, lc_INFINITY, inifinity_size))
+ )
+ )
{
- return !is_pointer<InputStreamable>::value &&
- stream >> output &&
- stream.get() ==
-#if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING)
-// GCC 2.9x lacks std::char_traits<>::eof().
-// We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3
-// configurations, which do provide std::char_traits<>::eof().
-
- EOF;
-#else
- traits_type::eof();
-#endif
+ if( !has_minus ) value = std::numeric_limits<T>::infinity();
+ else value = (boost::math::changesign) (std::numeric_limits<T>::infinity());
+ return true;
}
-#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ return false;
+ }
- bool operator>>(std::string &output)
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ template <class T>
+ bool parse_inf_nan(const wchar_t* begin, const wchar_t* end, T& value)
+ {
+ return parse_inf_nan_impl(begin, end, value
+ , L"NAN", L"nan"
+ , L"INFINITY", L"infinity"
+ , L'(', L')');
+ }
+#endif
+
+ template <class CharT, class T>
+ bool parse_inf_nan(const CharT* begin, const CharT* end, T& value)
+ {
+ return parse_inf_nan_impl(begin, end, value
+ , "NAN", "nan"
+ , "INFINITY", "infinity"
+ , '(', ')');
+ }
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ template <class T>
+ bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value)
+ {
+ using namespace std;
+ if ( (boost::math::isnan)(value) )
{
- #if defined(BOOST_NO_STRINGSTREAM)
- stream << '\0';
- #endif
- stream.str().swap(output);
+ if ( (boost::math::signbit)(value) )
+ {
+ memcpy(begin,L"-nan", sizeof(L"-nan"));
+ end = begin + 4;
+ } else
+ {
+ memcpy(begin,L"nan", sizeof(L"nan"));
+ end = begin + 3;
+ }
return true;
- }
- #ifndef BOOST_LCAST_NO_WCHAR_T
- bool operator>>(std::wstring &output)
+ } else if ( (boost::math::isinf)(value) )
{
- stream.str().swap(output);
+ if ( (boost::math::signbit)(value) )
+ {
+ memcpy(begin,L"-inf", sizeof(L"-inf"));
+ end = begin + 4;
+ } else
+ {
+ memcpy(begin,L"inf", sizeof(L"inf"));
+ end = begin + 3;
+ }
return true;
}
- #endif
-#else
- bool operator>>(std::basic_string<char_type,traits_type>& output)
+ return false;
+ }
+#endif
+ template <class CharT, class T>
+ bool put_inf_nan(CharT* begin, CharT*& end, const T& value)
+ {
+ using namespace std;
+ if ( (boost::math::isnan)(value) )
{
- stream.str().swap(output);
+ if ( (boost::math::signbit)(value) )
+ {
+ memcpy(begin,"-nan", sizeof("-nan"));
+ end = begin + 4;
+ } else
+ {
+ memcpy(begin,"nan", sizeof("nan"));
+ end = begin + 3;
+ }
return true;
- }
-
- template<class Alloc>
- bool operator>>(std::basic_string<char_type,traits_type,Alloc>& out)
+ } else if ( (boost::math::isinf)(value) )
{
- std::basic_string<char_type,traits_type> str(stream.str());
- out.assign(str.begin(), str.end());
+ if ( (boost::math::signbit)(value) )
+ {
+ memcpy(begin,"-inf", sizeof("-inf"));
+ end = begin + 4;
+ } else
+ {
+ memcpy(begin,"inf", sizeof("inf"));
+ end = begin + 3;
+ }
return true;
}
-#endif
- private:
- #if defined(BOOST_NO_STRINGSTREAM)
- std::strstream stream;
- #elif defined(BOOST_NO_STD_LOCALE)
- std::stringstream stream;
- #else
- std::basic_stringstream<char_type,traits_type> stream;
- #endif
- };
- }
- namespace detail // optimized stream wrapper
- {
- // String representation of Source has an upper limit.
- template< class CharT // a result of widest_char transformation
- , class Base // lexical_streambuf_fake or basic_streambuf<CharT>
- , class Traits // usually char_traits<CharT>
- >
- class lexical_stream_limited_src : public Base
- {
- // A string representation of Source is written to [start, finish).
- // Currently, it is assumed that [start, finish) is big enough
- // to hold a string representation of any Source value.
- CharT* start;
- CharT* finish;
+ return false;
+ }
- private:
+ }
- static void widen_and_assign(char*p, char ch)
- {
- Traits::assign(*p, ch);
- }
-#ifndef BOOST_LCAST_NO_WCHAR_T
- static void widen_and_assign(wchar_t* p, char ch)
- {
- // TODO: use BOOST_NO_STD_LOCALE
- std::locale loc;
- wchar_t w = BOOST_USE_FACET(std::ctype<wchar_t>, loc).widen(ch);
- Traits::assign(*p, w);
- }
+ namespace detail // lcast_ret_float
+ {
+ template <class T>
+ struct mantissa_holder_type
+ {
+ /* Can not be used with this type */
+ };
- static void widen_and_assign(wchar_t* p, wchar_t ch)
- {
- Traits::assign(*p, ch);
- }
+ template <>
+ struct mantissa_holder_type<float>
+ {
+ typedef unsigned int type;
+ };
- static void widen_and_assign(char*, wchar_t ch); // undefined
+ template <>
+ struct mantissa_holder_type<double>
+ {
+#if defined(BOOST_HAS_LONG_LONG)
+ typedef boost::ulong_long_type type;
+#elif defined(BOOST_HAS_MS_INT64)
+ typedef unsigned __int64 type;
#endif
+ };
- template<class OutputStreamable>
- bool lcast_put(const OutputStreamable& input)
- {
- this->setp(start, finish);
- std::basic_ostream<CharT> stream(static_cast<Base*>(this));
- lcast_set_precision(stream, static_cast<OutputStreamable*>(0));
- bool const result = !(stream << input).fail();
- finish = this->pptr();
- return result;
+ template<class Traits, class T, class CharT>
+ inline bool lcast_ret_float(T& value, const CharT* begin, const CharT* end)
+ {
+
+#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
+ std::locale loc;
+ typedef std::numpunct<CharT> numpunct;
+ numpunct const& np = BOOST_USE_FACET(numpunct, loc);
+ std::string const& grouping = np.grouping();
+ std::string::size_type const grouping_size = grouping.size();
+ CharT const thousands_sep = grouping_size ? np.thousands_sep() : 0;
+ CharT const decimal_point = np.decimal_point();
+ bool found_grouping = false;
+ unsigned int last_grouping_pos = grouping_size - 1;
+#else
+ CharT const decimal_point = lcast_char_constants<CharT>::c_decimal_separator;
+#endif
+
+ CharT const czero = lcast_char_constants<CharT>::zero;
+ CharT const minus = lcast_char_constants<CharT>::minus;
+ CharT const plus = lcast_char_constants<CharT>::plus;
+ CharT const capital_e = lcast_char_constants<CharT>::capital_e;
+ CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
+
+ value = 0.0;
+
+ if (parse_inf_nan(begin, end, value)) return true;
+
+ typedef typename Traits::int_type int_type;
+ typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type<T>::type mantissa_type;
+ int_type const zero = Traits::to_int_type(czero);
+ if (begin == end) return false;
+
+ /* Getting the plus/minus sign */
+ bool has_minus = false;
+ if ( *begin == minus ) {
+ ++ begin;
+ has_minus = true;
+ if (begin == end) return false;
+ } else if ( *begin == plus ) {
+ ++begin;
+ if (begin == end) return false;
+ }
+
+ bool found_decimal = false;
+ bool found_number_before_exp = false;
+ int pow_of_10 = 0;
+ mantissa_type mantissa=0;
+ bool is_mantissa_full = false;
+
+ char length_since_last_delim = 0;
+
+ while ( begin != end )
+ {
+ if (found_decimal) {
+ /* We allow no thousand_separators after decimal point */
+
+ mantissa_type tmp_mantissa = mantissa * 10u;
+ if ( *begin == lowercase_e || *begin == capital_e ) break;
+ if ( *begin < czero || *begin >= czero + 10 ) return false;
+ if ( is_mantissa_full
+ || tmp_mantissa / 10u != mantissa
+ || (std::numeric_limits<mantissa_type>::max)()-(*begin - zero) < tmp_mantissa
+ ) {
+ is_mantissa_full = true;
+ ++ begin;
+ continue;
+ }
+
+ -- pow_of_10;
+ mantissa = tmp_mantissa;
+ mantissa += *begin - zero;
+
+ found_number_before_exp = true;
+ } else {
+
+ if (*begin >= czero && *begin < czero + 10) {
+
+ /* Checking for mantissa overflow. If overflow will
+ * occur, them we only increase multiplyer
+ */
+ mantissa_type tmp_mantissa = mantissa * 10u;
+ if( !is_mantissa_full
+ && tmp_mantissa / 10u == mantissa
+ && (std::numeric_limits<mantissa_type>::max)()-(*begin - zero) >= tmp_mantissa
+ )
+ {
+ mantissa = tmp_mantissa;
+ mantissa += *begin - zero;
+ } else
+ {
+ is_mantissa_full = true;
+ ++ pow_of_10;
+ }
+
+ found_number_before_exp = true;
+ ++ length_since_last_delim;
+ } else if ( *begin == decimal_point || *begin == lowercase_e || *begin == capital_e) {
+#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
+ /* If ( we need to check grouping
+ * and ( grouping missmatches
+ * or grouping position is incorrect
+ * or we are using the grouping position 0 twice
+ * )
+ * ) then return error
+ */
+ if( grouping_size && found_grouping
+ && (
+ length_since_last_delim != grouping[0]
+ || last_grouping_pos>1
+ || (last_grouping_pos==0 && grouping_size>1)
+ )
+ ) return false;
+#endif
+
+ if(*begin == decimal_point){
+ ++ begin;
+ found_decimal = true;
+ continue;
+ }else {
+ if (!found_number_before_exp) return false;
+ break;
+ }
+ }
+#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
+ else if (grouping_size && *begin == thousands_sep){
+ if(found_grouping)
+ {
+ /* It is not he first time, when we find thousands separator,
+ * so we need to chek, is the distance between two groupings
+ * equal to grouping[last_grouping_pos] */
+
+ if (length_since_last_delim != grouping[last_grouping_pos] )
+ {
+ if (!last_grouping_pos) return false;
+ else
+ {
+ -- last_grouping_pos;
+ if (length_since_last_delim != grouping[last_grouping_pos]) return false;
+ }
+ } else
+ /* We are calling the grouping[0] twice, when grouping size is more than 1 */
+ if (grouping_size>1u && last_grouping_pos+1<grouping_size) return false;
+
+ } else {
+ /* Delimiter at the begining ',000' */
+ if (!length_since_last_delim) return false;
+
+ found_grouping = true;
+ if (length_since_last_delim > grouping[last_grouping_pos] ) return false;
+ }
+
+ length_since_last_delim = 0;
+ ++ begin;
+
+ /* Delimiter at the end '100,' */
+ if (begin == end) return false;
+ continue;
+ }
+#endif
+ else return false;
+ }
+
+ ++begin;
}
- // Undefined:
- lexical_stream_limited_src(lexical_stream_limited_src const&);
- void operator=(lexical_stream_limited_src const&);
+ // Exponent found
+ if ( begin != end && ( *begin == lowercase_e || *begin == capital_e ) ) {
+ ++ begin;
+ if ( begin == end ) return false;
+
+ bool exp_has_minus = false;
+ if( *begin == minus ) {
+ exp_has_minus = true;
+ ++ begin;
+ if ( begin == end ) return false;
+ } else if (*begin == plus ) {
+ ++ begin;
+ if ( begin == end ) return false;
+ }
+
+ int exp_pow_of_10 = 0;
+ while ( begin != end )
+ {
+ if ( *begin < czero
+ || *begin >= czero + 10
+ || exp_pow_of_10 * 10 < exp_pow_of_10) /* Overflows are checked lower more precisely*/
+ return false;
+ exp_pow_of_10 *= 10;
+ exp_pow_of_10 += *begin - zero;
+ ++ begin;
+ };
+
+ if ( exp_pow_of_10 ) {
+ /* Overflows are checked lower */
+ if ( exp_has_minus ) {
+ pow_of_10 -= exp_pow_of_10;
+ } else {
+ pow_of_10 += exp_pow_of_10;
+ }
+ }
+ }
+
+ /* We need a more accurate algorithm... We can not use current algorithm
+ * with long doubles (and with doubles if sizeof(double)==sizeof(long double)).
+ */
+ long double result = std::pow(10.0L, pow_of_10) * mantissa;
+ value = static_cast<T>( has_minus ? (boost::math::changesign)(result) : result);
+
+ if ( (boost::math::isinf)(value) || (boost::math::isnan)(value) ) return false;
+
+ return true;
+ }
+ }
+
+ namespace detail // stl_buf_unlocker
+ {
+ template< class BufferType, class CharT >
+ class stl_buf_unlocker: public BufferType{
public:
+ typedef BufferType base_class;
+#ifndef BOOST_NO_USING_TEMPLATE
+ using base_class::pptr;
+ using base_class::pbase;
+ using base_class::setg;
+ using base_class::setp;
+#else
+ CharT* pptr() const { return base_class::pptr(); }
+ CharT* pbase() const { return base_class::pbase(); }
+ void setg(CharT* gbeg, CharT* gnext, CharT* gend){ return base_class::setg(gbeg, gnext, gend); }
+ void setp(CharT* pbeg, CharT* pend) { return setp(pbeg, pend); }
+#endif
+ };
+ }
+ namespace detail
+ {
+ struct do_not_construct_stringbuffer_t{};
+ }
+
+ namespace detail // optimized stream wrapper
+ {
+ // String representation of Source has an upper limit.
+ template< class CharT // a result of widest_char transformation
+ , class Traits // usually char_traits<CharT>
+ , bool RequiresStringbuffer
+ >
+ class lexical_stream_limited_src
+ {
+ typedef stl_buf_unlocker<std::basic_streambuf<CharT, Traits>, CharT > local_streambuffer_t;
+
+#if defined(BOOST_NO_STRINGSTREAM)
+ typedef stl_buf_unlocker<std::strstream, CharT > local_stringbuffer_t;
+#elif defined(BOOST_NO_STD_LOCALE)
+ typedef stl_buf_unlocker<std::stringstream, CharT > local_stringbuffer_t;
+#else
+ typedef stl_buf_unlocker<std::basic_stringbuf<CharT, Traits>, CharT > local_stringbuffer_t;
+#endif
+ typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c<
+ RequiresStringbuffer,
+ local_stringbuffer_t,
+ do_not_construct_stringbuffer_t
+ >::type deduced_stringbuffer_t;
+
+ // A string representation of Source is written to [start, finish).
+ CharT* start;
+ CharT* finish;
+ deduced_stringbuffer_t stringbuffer;
+
+ public:
lexical_stream_limited_src(CharT* sta, CharT* fin)
: start(sta)
, finish(fin)
{}
- public: // output
+ private:
+ // Undefined:
+ lexical_stream_limited_src(lexical_stream_limited_src const&);
+ void operator=(lexical_stream_limited_src const&);
+
+/************************************ HELPER FUNCTIONS FOR OPERATORS << ( ... ) ********************************/
+ bool shl_char(CharT ch)
+ {
+ Traits::assign(*start, ch);
+ finish = start + 1;
+ return true;
+ }
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ template <class T>
+ bool shl_char(T ch)
+ {
+ BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)) ,
+ "boost::lexical_cast does not support conversions from whar_t to char types."
+ "Use boost::locale instead" );
+#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
+ std::locale loc;
+ wchar_t w = BOOST_USE_FACET(std::ctype<wchar_t>, loc).widen(ch);
+#else
+ wchar_t w = ch;
+#endif
+ Traits::assign(*start, w);
+ finish = start + 1;
+ return true;
+ }
+#endif
+
+ bool shl_char_array(CharT const* str)
+ {
+ start = const_cast<CharT*>(str);
+ finish = start + Traits::length(str);
+ return true;
+ }
+
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ template <class T>
+ bool shl_char_array(T const* str)
+ {
+ BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)),
+ "boost::lexical_cast does not support conversions from wchar_t to char types."
+ "Use boost::locale instead" );
+ return shl_input_streamable(str);
+ }
+#endif
+
+ template<typename InputStreamable>
+ bool shl_input_streamable(InputStreamable& input)
+ {
+ std::basic_ostream<CharT> stream(&stringbuffer);
+ bool const result = !(stream << input).fail();
+ start = stringbuffer.pbase();
+ finish = stringbuffer.pptr();
+ return result;
+ }
+
+ template <class T>
+ inline bool shl_signed(T n)
+ {
+ start = lcast_put_unsigned<Traits>(lcast_to_unsigned(n), finish);
+ if(n < 0)
+ {
+ --start;
+ CharT const minus = lcast_char_constants<CharT>::minus;
+ Traits::assign(*start, minus);
+ }
+ return true;
+ }
+
+#if (defined _MSC_VER)
+# pragma warning( push )
+// C4996: This function or variable may be unsafe. Consider using sprintf_s instead
+# pragma warning( disable : 4996 )
+#endif
+
+ template <class T>
+ bool shl_float(float val,T* out)
+ { using namespace std;
+ if (put_inf_nan(start,finish,val)) return true;
+ finish = start + sprintf(out,"%.*g", static_cast<int>(boost::detail::lcast_get_precision<float >()), val );
+ return finish > start;
+ }
+
+ template <class T>
+ bool shl_double(double val,T* out)
+ { using namespace std;
+ if (put_inf_nan(start,finish,val)) return true;
+ finish = start + sprintf(out,"%.*lg", static_cast<int>(boost::detail::lcast_get_precision<double >()), val );
+ return finish > start;
+ }
+#ifndef __MINGW32__
+ template <class T>
+ bool shl_long_double(long double val,T* out)
+ { using namespace std;
+ if (put_inf_nan(start,finish,val)) return true;
+ finish = start + sprintf(out,"%.*Lg", static_cast<int>(boost::detail::lcast_get_precision<long double >()), val );
+ return finish > start;
+ }
+#endif
+
+#if (defined _MSC_VER)
+# pragma warning( pop )
+#endif
+
+
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ bool shl_float(float val,wchar_t* out)
+ { using namespace std;
+ if (put_inf_nan(start,finish,val)) return true;
+ finish = start + swprintf(out,
+#if !defined(__MINGW32__) && !defined(UNDER_CE)
+ finish-start,
+#endif
+ L"%.*g", static_cast<int>(boost::detail::lcast_get_precision<float >()), val );
+
+ return finish > start;
+ }
+
+
+ bool shl_double(double val,wchar_t* out)
+ { using namespace std;
+ if (put_inf_nan(start,finish,val)) return true;
+ /* __MINGW32__ is defined for both mingw.org and for mingw-w64.
+ * For mingw-w64, __MINGW64__ is defined, too, when targetting
+ * 64 bits.
+ *
+ * swprintf realization in MinGW and under WinCE does not conform
+ * to the ISO C
+ * Standard.
+ */
+ finish = start + swprintf(out,
+#if !defined(__MINGW32__) && !defined(UNDER_CE)
+ finish-start,
+#endif
+ L"%.*lg", static_cast<int>(boost::detail::lcast_get_precision<double >()), val );
+ return finish > start;
+ }
+
+#ifndef __MINGW32__
+ bool shl_long_double(long double val,wchar_t* out)
+ { using namespace std;
+ if (put_inf_nan(start,finish,val)) return true;
+ finish = start + swprintf(out,
+#if !defined(UNDER_CE)
+ finish-start,
+#endif
+ L"%.*Lg", static_cast<int>(boost::detail::lcast_get_precision<long double >()), val );
+ return finish > start;
+ }
+#endif
+
+#endif
+
+/************************************ OPERATORS << ( ... ) ********************************/
+ public:
template<class Alloc>
bool operator<<(std::basic_string<CharT,Traits,Alloc> const& str)
{
@@ -879,39 +1209,61 @@
return true;
}
- bool operator<<(bool);
- bool operator<<(char);
- bool operator<<(unsigned char);
- bool operator<<(signed char);
-#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
- bool operator<<(wchar_t);
-#endif
- bool operator<<(unsigned char const*);
- bool operator<<(signed char const*);
- bool operator<<(CharT const*);
- bool operator<<(short);
- bool operator<<(int);
- bool operator<<(long);
- bool operator<<(unsigned short);
- bool operator<<(unsigned int);
- bool operator<<(unsigned long);
+ bool operator<<(bool value)
+ {
+ CharT const czero = lcast_char_constants<CharT>::zero;
+ Traits::assign(*start, Traits::to_char_type(czero + value));
+ finish = start + 1;
+ return true;
+ }
+
+ bool operator<<(char ch) { return shl_char(ch); }
+ bool operator<<(unsigned char ch) { return ((*this) << static_cast<char>(ch)); }
+ bool operator<<(signed char ch) { return ((*this) << static_cast<char>(ch)); }
+#if !defined(BOOST_LCAST_NO_WCHAR_T)
+ bool operator<<(wchar_t const* str) { return shl_char_array(str); }
+ bool operator<<(wchar_t * str) { return shl_char_array(str); }
+#ifndef BOOST_NO_INTRINSIC_WCHAR_T
+ bool operator<<(wchar_t ch) { return shl_char(ch); }
+#endif
+#endif
+ bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast<char const*>(ch)); }
+ bool operator<<(unsigned char * ch) { return ((*this) << reinterpret_cast<char *>(ch)); }
+ bool operator<<(signed char const* ch) { return ((*this) << reinterpret_cast<char const*>(ch)); }
+ bool operator<<(signed char * ch) { return ((*this) << reinterpret_cast<char *>(ch)); }
+ bool operator<<(char const* str) { return shl_char_array(str); }
+ bool operator<<(char* str) { return shl_char_array(str); }
+ bool operator<<(short n) { return shl_signed(n); }
+ bool operator<<(int n) { return shl_signed(n); }
+ bool operator<<(long n) { return shl_signed(n); }
+ bool operator<<(unsigned short n) { start = lcast_put_unsigned<Traits>(n, finish); return true; }
+ bool operator<<(unsigned int n) { start = lcast_put_unsigned<Traits>(n, finish); return true; }
+ bool operator<<(unsigned long n) { start = lcast_put_unsigned<Traits>(n, finish); return true; }
+
#if defined(BOOST_HAS_LONG_LONG)
- bool operator<<(boost::ulong_long_type);
- bool operator<<(boost::long_long_type );
+ bool operator<<(boost::ulong_long_type n) { start = lcast_put_unsigned<Traits>(n, finish); return true; }
+ bool operator<<(boost::long_long_type n) { return shl_signed(n); }
#elif defined(BOOST_HAS_MS_INT64)
- bool operator<<(unsigned __int64);
- bool operator<<( __int64);
+ bool operator<<(unsigned __int64 n) { start = lcast_put_unsigned<Traits>(n, finish); return true; }
+ bool operator<<( __int64 n) { return shl_signed(n); }
#endif
- // These three operators use ostream and streambuf.
- // lcast_streambuf_for_source<T>::value is true.
- bool operator<<(float);
- bool operator<<(double);
- bool operator<<(long double);
+ bool operator<<(float val) { return shl_float(val,start); }
+ bool operator<<(double val) { return shl_double(val,start); }
+ bool operator<<(long double val) {
+#ifndef __MINGW32__
+ return shl_long_double(val,start);
+#else
+ return shl_double(val,start);
+#endif
+ }
- private:
+ template<class InStreamable>
+ bool operator<<(const InStreamable& input) { return shl_input_streamable(input); }
+/************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/
+ private:
template <typename Type>
- bool input_operator_helper_unsigned(Type& output)
+ bool shr_unsigned(Type& output)
{
CharT const minus = lcast_char_constants<CharT>::minus;
CharT const plus = lcast_char_constants<CharT>::plus;
@@ -945,7 +1297,7 @@
}
template <typename Type>
- bool input_operator_helper_signed(Type& output)
+ bool shr_signed(Type& output)
{
CharT const minus = lcast_char_constants<CharT>::minus;
CharT const plus = lcast_char_constants<CharT>::plus;
@@ -988,102 +1340,8 @@
return succeed;
}
- public: // input
-
- bool operator>>(unsigned short& output)
- {
- return input_operator_helper_unsigned(output);
- }
-
- bool operator>>(unsigned int& output)
- {
- return input_operator_helper_unsigned(output);
- }
-
- bool operator>>(unsigned long int& output)
- {
- return input_operator_helper_unsigned(output);
- }
-
- bool operator>>(short& output)
- {
- return input_operator_helper_signed(output);
- }
-
- bool operator>>(int& output)
- {
- return input_operator_helper_signed(output);
- }
-
- bool operator>>(long int& output)
- {
- return input_operator_helper_signed(output);
- }
-
-
-#if defined(BOOST_HAS_LONG_LONG)
- bool operator>>( boost::ulong_long_type& output)
- {
- return input_operator_helper_unsigned(output);
- }
-
- bool operator>>(boost::long_long_type& output)
- {
- return input_operator_helper_signed(output);
- }
-
-#elif defined(BOOST_HAS_MS_INT64)
- bool operator>>(unsigned __int64& output)
- {
- return input_operator_helper_unsigned(output);
- }
-
- bool operator>>(__int64& output)
- {
- return input_operator_helper_signed(output);
- }
-
-#endif
-
- /*
- * case "-0" || "0" || "+0" : output = false; return true;
- * case "1" || "+1": output = true; return true;
- * default: return false;
- */
- bool operator>>(bool& output)
- {
- CharT const zero = lcast_char_constants<CharT>::zero;
- CharT const plus = lcast_char_constants<CharT>::plus;
- CharT const minus = lcast_char_constants<CharT>::minus;
-
- switch(finish-start)
- {
- case 1:
- output = Traits::eq(start[0], zero+1);
- return output || Traits::eq(start[0], zero );
- case 2:
- if ( Traits::eq( plus, *start) )
- {
- ++start;
- output = Traits::eq(start[0], zero +1);
- return output || Traits::eq(start[0], zero );
- } else
- {
- output = false;
- return Traits::eq( minus, *start)
- && Traits::eq( zero, start[1]);
- }
- default:
- output = false; // Suppress warning about uninitalized variable
- return false;
- }
- }
-
-
- // Generic istream-based algorithm.
- // lcast_streambuf_for_target<InputStreamable>::value is true.
template<typename InputStreamable>
- bool operator>>(InputStreamable& output)
+ bool shr_using_base_class(InputStreamable& output)
{
#if (defined _MSC_VER)
# pragma warning( push )
@@ -1093,8 +1351,9 @@
if(is_pointer<InputStreamable>::value)
return false;
- this->setg(start, start, finish);
- std::basic_istream<CharT> stream(static_cast<Base*>(this));
+ local_streambuffer_t bb;
+ bb.setg(start, start, finish);
+ std::basic_istream<CharT> stream(&bb);
stream.unsetf(std::ios::skipws);
lcast_set_precision(stream, static_cast<InputStreamable*>(0));
#if (defined _MSC_VER)
@@ -1107,373 +1366,161 @@
// We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3
// configurations, which do provide std::char_traits<>::eof().
- EOF;
-#else
- Traits::eof();
-#endif
- }
-
- bool operator>>(CharT&);
- bool operator>>(unsigned char&);
- bool operator>>(signed char&);
-
-#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
-// This #if is in sync with lcast_streambuf_for_target
-
- bool operator>>(std::string&);
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- bool operator>>(std::wstring&);
-#endif
-
-#else
- template<class Alloc>
- bool operator>>(std::basic_string<CharT,Traits,Alloc>& str)
- {
- str.assign(start, finish);
- return true;
- }
-#endif
- };
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- bool value)
- {
- typedef typename Traits::int_type int_type;
- CharT const czero = lcast_char_constants<CharT>::zero;
- int_type const zero = Traits::to_int_type(czero);
- Traits::assign(*start, Traits::to_char_type(zero + value));
- finish = start + 1;
- return true;
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- char ch)
- {
- widen_and_assign(start, ch);
- finish = start + 1;
- return true;
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- unsigned char ch)
- {
- return ((*this) << static_cast<char>(ch));
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- signed char ch)
- {
- return ((*this) << static_cast<char>(ch));
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- unsigned char const* ch)
- {
- return ((*this) << reinterpret_cast<char const*>(ch));
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- signed char const* ch)
- {
- return ((*this) << reinterpret_cast<char const*>(ch));
- }
-
-#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- wchar_t ch)
- {
- widen_and_assign(start, ch);
- finish = start + 1;
- return true;
- }
-#endif
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- short n)
- {
- start = lcast_put_unsigned<Traits>(lcast_to_unsigned(n), finish);
- if(n < 0)
- {
- --start;
- CharT const minus = lcast_char_constants<CharT>::minus;
- Traits::assign(*start, minus);
- }
- return true;
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- int n)
- {
- start = lcast_put_unsigned<Traits>(lcast_to_unsigned(n), finish);
- if(n < 0)
- {
- --start;
- CharT const minus = lcast_char_constants<CharT>::minus;
- Traits::assign(*start, minus);
+ EOF;
+#else
+ Traits::eof();
+#endif
}
- return true;
- }
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- long n)
- {
- start = lcast_put_unsigned<Traits>(lcast_to_unsigned(n), finish);
- if(n < 0)
+ template<class T>
+ inline bool shr_xchar(T& output)
{
- --start;
- CharT const minus = lcast_char_constants<CharT>::minus;
- Traits::assign(*start, minus);
+ BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ),
+ "boost::lexical_cast does not support conversions from whar_t to char types."
+ "Use boost::locale instead" );
+ bool const ok = (finish - start == 1);
+ if(ok) {
+ CharT out;
+ Traits::assign(out, *start);
+ output = static_cast<T>(out);
+ }
+ return ok;
}
- return true;
- }
+/************************************ OPERATORS >> ( ... ) ********************************/
+ public:
+ bool operator>>(unsigned short& output) { return shr_unsigned(output); }
+ bool operator>>(unsigned int& output) { return shr_unsigned(output); }
+ bool operator>>(unsigned long int& output) { return shr_unsigned(output); }
+ bool operator>>(short& output) { return shr_signed(output); }
+ bool operator>>(int& output) { return shr_signed(output); }
+ bool operator>>(long int& output) { return shr_signed(output); }
#if defined(BOOST_HAS_LONG_LONG)
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- boost::long_long_type n)
- {
- start = lcast_put_unsigned<Traits>(lcast_to_unsigned(n), finish);
- if(n < 0)
- {
- --start;
- CharT const minus = lcast_char_constants<CharT>::minus;
- Traits::assign(*start, minus);
- }
- return true;
- }
+ bool operator>>(boost::ulong_long_type& output) { return shr_unsigned(output); }
+ bool operator>>(boost::long_long_type& output) { return shr_signed(output); }
#elif defined(BOOST_HAS_MS_INT64)
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- __int64 n)
- {
- start = lcast_put_unsigned<Traits>(lcast_to_unsigned(n), finish);
- if(n < 0)
+ bool operator>>(unsigned __int64& output) { return shr_unsigned(output); }
+ bool operator>>(__int64& output) { return shr_signed(output); }
+
+#endif
+ bool operator>>(CharT& output) { return shr_xchar(output); }
+ bool operator>>(unsigned char& output) { return shr_xchar(output); }
+ bool operator>>(signed char& output) { return shr_xchar(output); }
+#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
+ bool operator>>(std::string& str) { str.assign(start, finish); return true; }
+# ifndef BOOST_LCAST_NO_WCHAR_T
+ bool operator>>(std::wstring& str) { str.assign(start, finish); return true; }
+# endif
+#else
+ template<class Alloc>
+ bool operator>>(std::basic_string<CharT,Traits,Alloc>& str) { str.assign(start, finish); return true; }
+#endif
+ /*
+ * case "-0" || "0" || "+0" : output = false; return true;
+ * case "1" || "+1": output = true; return true;
+ * default: return false;
+ */
+ bool operator>>(bool& output)
{
- --start;
+ CharT const zero = lcast_char_constants<CharT>::zero;
+ CharT const plus = lcast_char_constants<CharT>::plus;
CharT const minus = lcast_char_constants<CharT>::minus;
- Traits::assign(*start, minus);
- }
- return true;
- }
-#endif
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- unsigned short n)
- {
- start = lcast_put_unsigned<Traits>(n, finish);
- return true;
- }
+ switch(finish-start)
+ {
+ case 1:
+ output = Traits::eq(start[0], zero+1);
+ return output || Traits::eq(start[0], zero );
+ case 2:
+ if ( Traits::eq( plus, *start) )
+ {
+ ++start;
+ output = Traits::eq(start[0], zero +1);
+ return output || Traits::eq(start[0], zero );
+ } else
+ {
+ output = false;
+ return Traits::eq( minus, *start)
+ && Traits::eq( zero, start[1]);
+ }
+ default:
+ output = false; // Suppress warning about uninitalized variable
+ return false;
+ }
+ }
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- unsigned int n)
- {
- start = lcast_put_unsigned<Traits>(n, finish);
- return true;
- }
+ bool operator>>(float& output) { return lcast_ret_float<Traits>(output,start,finish); }
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- unsigned long n)
- {
- start = lcast_put_unsigned<Traits>(n, finish);
- return true;
- }
+ private:
+ // Not optimised converter
+ template <class T>
+ bool float_types_converter_internal(T& output, int /*tag*/) {
+ if (parse_inf_nan(start, finish, output)) return true;
+ bool return_value = shr_using_base_class(output);
+
+ /* Some compilers and libraries successfully
+ * parse 'inf', 'INFINITY', '1.0E', '1.0E-'...
+ * We are trying to provide a unified behaviour,
+ * so we just forbid such conversions (as some
+ * of the most popular compilers/libraries do)
+ * */
+ CharT const minus = lcast_char_constants<CharT>::minus;
+ CharT const plus = lcast_char_constants<CharT>::plus;
+ CharT const capital_e = lcast_char_constants<CharT>::capital_e;
+ CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
+ if ( return_value &&
+ (
+ *(finish-1) == lowercase_e // 1.0e
+ || *(finish-1) == capital_e // 1.0E
+ || *(finish-1) == minus // 1.0e- or 1.0E-
+ || *(finish-1) == plus // 1.0e+ or 1.0E+
+ )
+ ) return false;
+
+ return return_value;
+ }
+
+ // Optimised converter
+ bool float_types_converter_internal(double& output,char /*tag*/) {
+ return lcast_ret_float<Traits>(output,start,finish);
+ }
+ public:
-#if defined(BOOST_HAS_LONG_LONG)
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- boost::ulong_long_type n)
- {
- start = lcast_put_unsigned<Traits>(n, finish);
- return true;
- }
-#elif defined(BOOST_HAS_MS_INT64)
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- unsigned __int64 n)
- {
- start = lcast_put_unsigned<Traits>(n, finish);
- return true;
- }
+ bool operator>>(double& output)
+ {
+ /*
+ * Some compilers implement long double as double. In that case these types have
+ * same size, same precision, same max and min values... And it means,
+ * that current implementation of lcast_ret_float cannot be used for type
+ * double, because it will give a big precision loss.
+ * */
+ boost::mpl::if_c<
+#if defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)
+ ::boost::type_traits::ice_eq< sizeof(double), sizeof(long double) >::value,
+#else
+ 0
#endif
+ int,
+ char
+ >::type tag = 0;
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- float val)
- {
- return this->lcast_put(val);
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- double val)
- {
- return this->lcast_put(val);
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- long double val)
- {
- return this->lcast_put(val);
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator<<(
- CharT const* str)
- {
- start = const_cast<CharT*>(str);
- finish = start + Traits::length(str);
- return true;
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator>>(
- CharT& output)
- {
- bool const ok = (finish - start == 1);
- if(ok)
- Traits::assign(output, *start);
- return ok;
- }
-
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator>>(
- unsigned char& output)
- {
- BOOST_STATIC_ASSERT( sizeof(CharT) == sizeof(unsigned char) );
- bool const ok = (finish - start == 1);
- if(ok) {
- CharT out;
- Traits::assign(out, *start);
- output = static_cast<signed char>(out);
+ return float_types_converter_internal(output, tag);
}
- return ok;
- }
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator>>(
- signed char& output)
- {
- BOOST_STATIC_ASSERT( sizeof(CharT) == sizeof(signed char) );
- bool const ok = (finish - start == 1);
- if(ok) {
- CharT out;
- Traits::assign(out, *start);
- output = static_cast<signed char>(out);
+ bool operator>>(long double& output)
+ {
+ int tag = 0;
+ return float_types_converter_internal(output, tag);
}
- return ok;
- }
-
-#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator>>(
- std::string& str)
- {
- str.assign(start, finish);
- return true;
- }
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- template<typename CharT, class Base, class Traits>
- inline bool lexical_stream_limited_src<CharT,Base,Traits>::operator>>(
- std::wstring& str)
- {
- str.assign(start, finish);
- return true;
- }
-#endif
-#endif
- }
-
- namespace detail // lcast_streambuf_for_source
- {
- // Returns true if optimized stream wrapper needs ostream for writing.
- template<class Source>
- struct lcast_streambuf_for_source
- {
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
- template<>
- struct lcast_streambuf_for_source<float>
- {
- BOOST_STATIC_CONSTANT(bool, value = true);
- };
-
- template<>
- struct lcast_streambuf_for_source<double>
- {
- BOOST_STATIC_CONSTANT(bool, value = true);
- };
-
- template<>
- struct lcast_streambuf_for_source<long double>
- {
- BOOST_STATIC_CONSTANT(bool, value = true);
+ // Generic istream-based algorithm.
+ // lcast_streambuf_for_target<InputStreamable>::value is true.
+ template<typename InputStreamable>
+ bool operator>>(InputStreamable& output) { return shr_using_base_class(output); }
};
}
- namespace detail // lcast_streambuf_for_target
- {
- // Returns true if optimized stream wrapper needs istream for reading.
- template<class Target>
- struct lcast_streambuf_for_target
- {
- BOOST_STATIC_CONSTANT(bool, value =
- (
- ::boost::type_traits::ice_not< is_integral<Target>::value >::value
- )
- );
- };
-
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
- template<class Traits, class Alloc>
- struct lcast_streambuf_for_target<
- std::basic_string<char,Traits,Alloc> >
- {
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- template<class Traits, class Alloc>
- struct lcast_streambuf_for_target<
- std::basic_string<wchar_t,Traits,Alloc> >
- {
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
-#endif
-#else
- template<>
- struct lcast_streambuf_for_target<std::string>
- {
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
-
-#ifndef BOOST_LCAST_NO_WCHAR_T
- template<>
- struct lcast_streambuf_for_target<std::wstring>
- {
- BOOST_STATIC_CONSTANT(bool, value = false);
- };
-#endif
-#endif
- }
-
- #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// call-by-const reference version
@@ -1491,47 +1538,6 @@
typedef const T * type;
};
-#if (defined _MSC_VER)
-# pragma warning( push )
-# pragma warning( disable : 4701 ) // possible use of ... before initialization
-# pragma warning( disable : 4702 ) // unreachable code
-# pragma warning( disable : 4267 ) // conversion from 'size_t' to 'unsigned int'
-#endif
-
- template< typename Target
- , typename Source
- , bool Unlimited // string representation of Source is unlimited
- , typename CharT
- >
- Target lexical_cast(
- BOOST_DEDUCED_TYPENAME boost::call_traits<Source>::param_type arg,
- CharT* buf, std::size_t src_len)
- {
- typedef BOOST_DEDUCED_TYPENAME
- deduce_char_traits<CharT,Target,Source>::type traits;
-
- typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
- lcast_streambuf_for_target<Target>::value ||
- lcast_streambuf_for_source<Source>::value
- , std::basic_streambuf<CharT>
- , lexical_streambuf_fake
- >::type base;
-
- BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
- Unlimited
- , detail::lexical_stream<Target,Source,traits>
- , detail::lexical_stream_limited_src<CharT,base,traits>
- >::type interpreter(buf, buf + src_len);
-
- Target result;
- if(!(interpreter << arg && interpreter >> result))
- BOOST_LCAST_THROW_BAD_CAST(Source, Target);
- return result;
- }
-#if (defined _MSC_VER)
-# pragma warning( pop )
-#endif
-
template<typename T>
struct is_stdstring
{
@@ -1634,25 +1640,62 @@
BOOST_STATIC_CONSTANT(bool, value = true );
};
+#if (defined _MSC_VER)
+# pragma warning( push )
+# pragma warning( disable : 4701 ) // possible use of ... before initialization
+# pragma warning( disable : 4702 ) // unreachable code
+# pragma warning( disable : 4267 ) // conversion from 'size_t' to 'unsigned int'
+#endif
template<typename Target, typename Source>
struct lexical_cast_do_cast
{
- static inline Target lexical_cast_impl(const Source &arg)
+ static inline Target lexical_cast_impl(const Source& arg)
{
- typedef typename detail::array_to_pointer_decay<Source>::type src;
+ typedef BOOST_DEDUCED_TYPENAME detail::array_to_pointer_decay<Source>::type src;
- typedef typename detail::widest_char<
- typename detail::stream_char<Target>::type
- , typename detail::stream_char<src>::type
+ typedef BOOST_DEDUCED_TYPENAME detail::widest_char<
+ BOOST_DEDUCED_TYPENAME detail::stream_char<Target>::type
+ , BOOST_DEDUCED_TYPENAME detail::stream_char<src>::type
>::type char_type;
typedef detail::lcast_src_length<char_type, src> lcast_src_length;
std::size_t const src_len = lcast_src_length::value;
char_type buf[src_len + 1];
lcast_src_length::check_coverage();
- return detail::lexical_cast<Target, src, !src_len>(arg, buf, src_len);
+
+ typedef BOOST_DEDUCED_TYPENAME
+ deduce_char_traits<char_type,Target,Source>::type traits;
+
+ typedef BOOST_DEDUCED_TYPENAME remove_pointer<src >::type removed_ptr_t;
+ const bool requires_stringbuf =
+ !(
+ ::boost::type_traits::ice_or<
+ is_stdstring<src >::value,
+ is_arithmetic<src >::value,
+ ::boost::type_traits::ice_and<
+ is_pointer<src >::value,
+ is_char_or_wchar<removed_ptr_t >::value,
+ ::boost::type_traits::ice_eq<
+ sizeof(char_type),
+ sizeof(removed_ptr_t)
+ >::value
+ >::value
+ >::value
+ );
+
+ detail::lexical_stream_limited_src<char_type,traits, requires_stringbuf >
+ interpreter(buf, buf + src_len);
+
+ Target result;
+ // Disabling ADL, by directly specifying operators.
+ if(!(interpreter.operator <<(arg) && interpreter.operator >>(result)))
+ BOOST_LCAST_THROW_BAD_CAST(Source, Target);
+ return result;
}
};
+#if (defined _MSC_VER)
+# pragma warning( pop )
+#endif
template<typename Source>
struct lexical_cast_copy
@@ -1708,6 +1751,7 @@
} catch( ::boost::numeric::bad_numeric_cast const& ) {
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
}
+ BOOST_UNREACHABLE_RETURN(static_cast<Target>(0));
}
};
@@ -1734,6 +1778,7 @@
} catch( ::boost::numeric::bad_numeric_cast const& ) {
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
}
+ BOOST_UNREACHABLE_RETURN(static_cast<Target>(0));
}
};
@@ -1815,6 +1860,78 @@
#else
+ namespace detail // stream wrapper for handling lexical conversions
+ {
+ template<typename Target, typename Source, typename Traits>
+ class lexical_stream
+ {
+ private:
+ typedef typename widest_char<
+ typename stream_char<Target>::type,
+ typename stream_char<Source>::type>::type char_type;
+
+ typedef Traits traits_type;
+
+ public:
+ lexical_stream(char_type* = 0, char_type* = 0)
+ {
+ stream.unsetf(std::ios::skipws);
+ lcast_set_precision(stream, static_cast<Source*>(0), static_cast<Target*>(0) );
+ }
+ ~lexical_stream()
+ {
+ #if defined(BOOST_NO_STRINGSTREAM)
+ stream.freeze(false);
+ #endif
+ }
+ bool operator<<(const Source &input)
+ {
+ return !(stream << input).fail();
+ }
+ template<typename InputStreamable>
+ bool operator>>(InputStreamable &output)
+ {
+ return !is_pointer<InputStreamable>::value &&
+ stream >> output &&
+ stream.get() ==
+#if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING)
+// GCC 2.9x lacks std::char_traits<>::eof().
+// We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3
+// configurations, which do provide std::char_traits<>::eof().
+
+ EOF;
+#else
+ traits_type::eof();
+#endif
+ }
+
+ bool operator>>(std::string &output)
+ {
+ #if defined(BOOST_NO_STRINGSTREAM)
+ stream << '\0';
+ #endif
+ stream.str().swap(output);
+ return true;
+ }
+ #ifndef BOOST_LCAST_NO_WCHAR_T
+ bool operator>>(std::wstring &output)
+ {
+ stream.str().swap(output);
+ return true;
+ }
+ #endif
+
+ private:
+ #if defined(BOOST_NO_STRINGSTREAM)
+ std::strstream stream;
+ #elif defined(BOOST_NO_STD_LOCALE)
+ std::stringstream stream;
+ #else
+ std::basic_stringstream<char_type,traits_type> stream;
+ #endif
+ };
+ }
+
// call-by-value fallback version (deprecated)
template<typename Target, typename Source>
Added: branches/release/doc/html/boost_lexical_cast.html
==============================================================================
--- (empty file)
+++ branches/release/doc/html/boost_lexical_cast.html 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <!-- Copyright (C) 2002 Douglas Gregor <doug.gregor -at- gmail.com>
+
+ 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) -->
+ <title>Redirect to generated documentation</title>
+ <meta http-equiv="refresh" content="0; URL=http://boost-sandbox.sourceforge.net/doc/html/boost_lexical_cast.html">
+ </head>
+ <body>
+ Automatic redirection failed, please go to
+ http://boost-sandbox.sourceforge.net/doc/html/boost_lexical_cast.html
+ </body>
+</html>
Modified: branches/release/libs/conversion/index.html
==============================================================================
--- branches/release/libs/conversion/index.html (original)
+++ branches/release/libs/conversion/index.html 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -24,7 +24,7 @@
and <b>polymorphic_downcast<></b> to perform safe casting between
polymorphic types.<br>
</li>
- <li>The boost/lexical_cast header provides <b>lexical_cast<></b>
+ <li>The boost/lexical_cast header provides <b>lexical_cast<></b>
general literal text conversions, such as an <code>int</code> represented as
a <code>string</code>, or vice-versa.</li>
</ul>
Modified: branches/release/libs/conversion/lexical_cast.htm
==============================================================================
--- branches/release/libs/conversion/lexical_cast.htm (original)
+++ branches/release/libs/conversion/lexical_cast.htm 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -1,351 +1,16 @@
-<!-- saved from url=(0022)http://internet.e-mail -->
-<!doctype html public "-//W3C//DTD HTML Transitional 4.0//EN">
-<html>
- <head>
- <title>lexical_cast</title>
- <meta name="author" content="Kevlin Henney, mailto:kevlin_at_[hidden]">
- <meta name="generator" content="Microsoft FrontPage 5.0">
- </head>
- <body bgcolor="#FFFFFF" text="#000000">
- <h1><img src="../../boost.png" alt="boost.png (6897 bytes)" align="center" width="277" height="86">Header
- boost/lexical_cast.hpp</h1>
- <ul type="square">
- <li>
- Motivation</li>
- <li>
- Examples</li>
- <li>
- Synopsis</li>
- <li>
- lexical_cast
</li>
- <li>
- bad_lexical_cast
</li>
- <li>
- Frequently Asked Questions</li>
- <li>
- References</li>
- <li>
- Changes</li>
- <li>
- Performance</li>
- </ul>
- <hr>
- <h2><a name="motivation">Motivation</a></h2>
- Sometimes a value must be converted to a literal text form, such as an <code>int</code>
- represented as a <code>string</code>, or vice-versa, when a <code>string</code>
- is interpreted as an <code>int</code>. 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.
- <p>
- 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.
- <p>
- For instance, there are a number of limitations with the family of standard C
- functions typified by <code>atoi</code>:
- <ul type="square">
- <li>
- 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 <code>sprintf</code> function, or the loss of
- portability associated with non-standard functions such as <code>itoa</code>.
- </li>
- <li>
- The range of types supported is only a subset of the built-in numeric types,
- namely <code>int</code>, <code>long</code>, and <code>double</code>.
- </li>
- <li>
- The range of types cannot be extended in a uniform manner. For instance,
- conversion from string representation to <code>complex</code> or <code>rational</code>.
- </li>
- </ul>
- The standard C functions typified by <code>strtol</code> 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 <code>scanf</code>
- family of functions offer even greater control, but also lack safety and ease
- of use.
- <p>
- The standard C++ library offers <code>stringstream</code> for the kind of
- in-core formatting being discussed. It offers a great deal of control over the
- formatting and conversion of I/O to and from arbitrary types through text.
- However, for simple conversions direct use of <code>stringstream</code> can be
- either clumsy (with the introduction of extra local variables and the loss of
- infix-expression convenience) or obscure (where <code>stringstream</code>
- 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.
- <p>
- The <code>lexical_cast</code> 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 <code>lexical_cast</code>, the conventional <code>
- stringstream</code> approach is recommended. Where the conversions are
- numeric to numeric, <code>numeric_cast</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>. Also, take a look at the Performance section.
- <p>
- <hr>
- <h2><a name="examples">Examples</a></h2>
- The following example treats command line arguments as a sequence of numeric
- data: <blockquote>
- <pre>int main(int argc, char * argv[])
-{
- using boost::lexical_cast;
- using boost::bad_lexical_cast;
-
- std::vector<short> args;
-
- while(*++argv)
- {
- try
- {
- args.push_back(lexical_cast<short>(*argv));
- }
- catch(bad_lexical_cast &)
- {
- args.push_back(0);
- }
- }
- ...
-}
-</pre>
- </blockquote>The following example uses numeric data in a string expression: <blockquote>
- <pre>void log_message(const std::string &);
-void log_errno(int yoko)
-{
- log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
-}
-</pre>
- </blockquote>
- <hr>
- <h2><a name="synopsis">Synopsis</a></h2>
- Library features defined in "boost/lexical_cast.hpp"
:
- <blockquote>
- <pre>namespace boost
-{
- class bad_lexical_cast;
- template<typename Target, typename Source>
- Target lexical_cast(const Source& arg);
-}
-</pre>
- </blockquote>Unit test defined in "lexical_cast_test.cpp"
.
- <p>
- <hr>
- <h2><a name="lexical_cast"><code>lexical_cast</code></a></h2>
- <blockquote>
- <pre>template<typename Target, typename Source>
- Target lexical_cast(const Source& arg);
-</pre>
- </blockquote>Returns the result of streaming <code>arg</code> into a
- standard library string-based stream and then out as a <code>Target</code> object.
- Where <code>Target</code> is either <code>std::string</code>
- or <code>std::wstring</code>, stream extraction takes the whole content
- of the string, including spaces, rather than relying on the default
- <code>operator>></code> behavior.
- If the conversion is unsuccessful, a <a href="#bad_lexical_cast">
- <code>bad_lexical_cast</code></a> exception is thrown.
- <p>
- The requirements on the argument and result types are:
- <ul type="square">
- <li>
- <code>Source</code> is <i>OutputStreamable</i>, meaning that an <code>operator<<</code>
- is defined that takes a <code>std::ostream</code> or <code>std::wostream</code> object on the
- left hand side and an instance of the argument type on the right.
- </li>
- <li>
- <code>Target</code> is <i>InputStreamable</i>, meaning that an <code>operator>></code>
- is defined that takes a <code>std::istream</code> or <code>std::wistream</code> object on the left hand side
- and an instance of the result type on the right.
- </li>
- <li>
- <code>Target</code> is <i>CopyConstructible</i> [20.1.3].
- </li>
- <li>
- <code>Target</code> is <i>DefaultConstructible</i>, meaning that it is possible
- to <i>default-initialize</i> an object of that type [8.5, 20.1.4].
- </li>
- </ul>
- The character type of the underlying stream is assumed to be <code>char</code> unless
- either the <code>Source</code> or the <code>Target</code> requires wide-character
- streaming, in which case the underlying stream uses <code>wchar_t</code>.
- <code>Source</code> types that require wide-character streaming are <code>wchar_t</code>,
- <code>wchar_t *</code>, and <code>std::wstring</code>. <code>Target</code> types that
- require wide-character streaming are <code>wchar_t</code> and <code>std::wstring</code>.
- <p>
- Where a higher degree of control is required over conversions, <code>std::stringstream</code>
- and <code>std::wstringstream</code> offer a more appropriate path. Where non-stream-based conversions are
- required, <code>lexical_cast</code>
- is the wrong tool for the job and is not special-cased for such scenarios.
- <p>
- <hr>
- <h2><a name="bad_lexical_cast"><code>bad_lexical_cast</code></a></h2>
- <blockquote>
- <pre>class bad_lexical_cast : public std::bad_cast
-{
-public:
- ... // <i>same member function interface as</i> std::exception
-};
-</pre>
- </blockquote>Exception used to indicate runtime lexical_cast
- failure.
-
-<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>
+Copyright 2005-2007 Daniel James.
+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)
-->
-
-<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 numeric_cast:
-<pre>numeric_cast<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 [N1973] to reset the flag but remember that [N1973] 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 ios_state_saver.
- </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,
- N1973.
- <a name="tuning"></a><li> [Tuning] Alexander Nasonov, Fine Tuning for lexical_cast,
- Overload #74 (PDF),
- 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 [Tuning] for more details.
- </li>
-</ul>
-<h3>June 2005:</h3>
-<ul type="square">
- <li>Call-by-const reference for the parameters. This requires partial specialization
- of class templates, so it doesn't work for MSVC 6, and it uses the original
- pass by value there.<br>
- </li>
- <li>The MSVC 6 support is deprecated, and will be removed in a future Boost
- version. </li>
-</ul>
-<h3>Earlier:</h3>
-
-<ul type="square">
- <li>The previous version of <code>lexical_cast</code> used the default stream
- precision for reading and writing floating-point numbers. For numerics that
- have a corresponding specialization of <code>std::numeric_limits</code>, the
- current version now chooses a precision to match. <br>
- <li>The previous version of <code>lexical_cast</code> did not support conversion
- to or from any wide-character-based types. For compilers with full language
- and library support for wide characters, <code>lexical_cast</code> now supports
- conversions from <code>wchar_t</code>, <code>wchar_t *</code>, and <code>std::wstring</code>
- and to <code>wchar_t</code> and <code>std::wstring</code>. <br>
- <li>The previous version of <code>lexical_cast</code> assumed that the conventional
- stream extractor operators were sufficient for reading values. However, string
- I/O is asymmetric, with the result that spaces play the role of I/O separators
- rather than string content. The current version fixes this error for <code>std::string</code>
- and, where supported, <code>std::wstring</code>: <code>lexical_cast<std::string>("Hello,
- World")</code> succeeds instead of failing with a <code>bad_lexical_cast</code>
- exception. <br>
- <li>The previous version of <code>lexical_cast</code> allowed unsafe and meaningless
- conversions to pointers. The current version now throws a <code>bad_lexical_cast</code>
- for conversions to pointers: <code>lexical_cast<char *>("Goodbye, World")</code>
- now throws an exception instead of causing undefined behavior.
-</ul>
- <p>
- <hr>
-
-<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 http://www.boost.org/LICENSE_1_0.txt)</i></small>
-</div>
- </body>
+<html>
+<head>
+ <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_lexical_cast.html">
+</head>
+<body>
+Automatic redirection failed, please go to
+../../doc/html/boost_lexical_cast.html
+</body>
</html>
Modified: branches/release/libs/conversion/lexical_cast_test.cpp
==============================================================================
--- branches/release/libs/conversion/lexical_cast_test.cpp (original)
+++ branches/release/libs/conversion/lexical_cast_test.cpp 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -35,6 +35,7 @@
#include <boost/type_traits/integral_promotion.hpp>
#include <string>
+#include <vector>
#include <memory>
#if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \
@@ -42,6 +43,10 @@
#define LCAST_TEST_LONGLONG
#endif
+#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
+#define BOOST_LCAST_NO_WCHAR_T
+#endif
+
template<class CharT>
struct my_traits : std::char_traits<CharT>
{
@@ -65,6 +70,7 @@
void test_conversion_to_int();
void test_conversion_to_double();
void test_conversion_to_bool();
+void test_conversion_with_nonconst_char();
void test_conversion_to_string();
void test_conversion_from_to_wchar_t_alias();
void test_conversion_to_pointer();
@@ -86,9 +92,6 @@
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();
@@ -96,6 +99,7 @@
void test_wallocator();
#endif
void test_char_types_conversions();
+void operators_overload_test();
unit_test::test_suite *init_unit_test_suite(int, char *[])
{
@@ -108,6 +112,7 @@
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));
+ suite->add(BOOST_TEST_CASE(test_conversion_with_nonconst_char));
#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));
@@ -128,9 +133,6 @@
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));
@@ -139,6 +141,7 @@
#endif
suite->add(BOOST_TEST_CASE(&test_char_types_conversions));
+ suite->add(BOOST_TEST_CASE(&operators_overload_test));
return suite;
}
@@ -201,19 +204,45 @@
lexical_cast<int>(std::string("Test")), bad_lexical_cast);
}
+void test_conversion_with_nonconst_char()
+{
+ std::vector<char> buffer;
+ buffer.push_back('1');
+ buffer.push_back('\0');
+ BOOST_CHECK_EQUAL(boost::lexical_cast<int>(&buffer[0]), 1);
+
+ std::vector<unsigned char> buffer2;
+ buffer2.push_back('1');
+ buffer2.push_back('\0');
+ BOOST_CHECK_EQUAL(boost::lexical_cast<int>(&buffer2[0]), 1);
+
+ std::vector<unsigned char> buffer3;
+ buffer3.push_back('1');
+ buffer3.push_back('\0');
+ BOOST_CHECK_EQUAL(boost::lexical_cast<int>(&buffer3[0]), 1);
+
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ std::vector<wchar_t> buffer4;
+ buffer4.push_back(L'1');
+ buffer4.push_back(L'\0');
+ BOOST_CHECK_EQUAL(boost::lexical_cast<int>(&buffer4[0]), 1);
+#endif
+}
+
void test_conversion_to_double()
{
- BOOST_CHECK_CLOSE(1.0, lexical_cast<double>('1'), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast<double>('1'), (std::numeric_limits<double>::epsilon()));
BOOST_CHECK_THROW(lexical_cast<double>('A'), bad_lexical_cast);
- BOOST_CHECK_CLOSE(1.0, lexical_cast<double>(1), (std::numeric_limits<double>::epsilon()));
- BOOST_CHECK_CLOSE(1.23, lexical_cast<double>(1.23), (std::numeric_limits<double>::epsilon()));
- BOOST_CHECK_CLOSE(1.234567890, 1.234567890, std::numeric_limits<double>::epsilon());
- BOOST_CHECK_CLOSE(1.0, lexical_cast<double>(true), (std::numeric_limits<double>::epsilon()));
- BOOST_CHECK_CLOSE(0.0, lexical_cast<double>(false), (std::numeric_limits<double>::epsilon()));
- BOOST_CHECK_CLOSE(1.23, lexical_cast<double>("1.23"), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast<double>(1), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast<double>(1.23), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast<double>(1.234567890), std::numeric_limits<double>::epsilon());
+ BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast<double>("1.234567890"), std::numeric_limits<double>::epsilon());
+ BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast<double>(true), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(0.0, lexical_cast<double>(false), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast<double>("1.23"), (std::numeric_limits<double>::epsilon()));
BOOST_CHECK_THROW(lexical_cast<double>(""), bad_lexical_cast);
BOOST_CHECK_THROW(lexical_cast<double>("Test"), bad_lexical_cast);
- BOOST_CHECK_CLOSE(1.23, lexical_cast<double>(std::string("1.23")), (std::numeric_limits<double>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast<double>(std::string("1.23")), (std::numeric_limits<double>::epsilon()));
BOOST_CHECK_THROW(
lexical_cast<double>(std::string("")), bad_lexical_cast);
BOOST_CHECK_THROW(
@@ -679,7 +708,7 @@
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) );
+ BOOST_CHECK( lexical_cast<T>("30000") == static_cast<T>(30000) );
}
test_conversion_from_integral_to_integral<T>();
@@ -775,35 +804,6 @@
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>();
@@ -844,19 +844,6 @@
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()
@@ -966,16 +953,40 @@
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<wchar_t>(wc_arr[0]) == wc_arr[0]);
- 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) );
+#endif
+}
- 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
+struct foo_operators_test
+{
+ foo_operators_test() : f(2) {}
+ int f;
+};
+
+template <typename OStream>
+OStream& operator<<(OStream& ostr, const foo_operators_test& foo)
+{
+ ostr << foo.f;
+ return ostr;
+}
+
+template <typename IStream>
+IStream& operator>>(IStream& istr, foo_operators_test& foo)
+{
+ istr >> foo.f;
+ return istr;
}
+
+void operators_overload_test()
+{
+ foo_operators_test foo;
+ BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(foo), "2");
+ BOOST_CHECK_EQUAL((boost::lexical_cast<foo_operators_test>("2")).f, 2);
+
+ // Must compile
+ (void)boost::lexical_cast<foo_operators_test>(foo);
+}
+
Modified: branches/release/libs/conversion/test/Jamfile.v2
==============================================================================
--- branches/release/libs/conversion/test/Jamfile.v2 (original)
+++ branches/release/libs/conversion/test/Jamfile.v2 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -25,6 +25,9 @@
[ 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 ]
+ [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
+ [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
+ [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
;
Added: branches/release/libs/conversion/test/lexical_cast_float_types_test.cpp
==============================================================================
--- (empty file)
+++ branches/release/libs/conversion/test/lexical_cast_float_types_test.cpp 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -0,0 +1,513 @@
+// Unit test for boost::lexical_cast.
+//
+// See http://www.boost.org for most recent version, including documentation.
+//
+// Copyright Antony Polukhin, 2011.
+//
+// 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).
+
+#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/cstdint.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+void test_conversion_from_to_float();
+void test_conversion_from_to_double();
+void test_conversion_from_to_long_double();
+
+using namespace boost;
+
+
+unit_test::test_suite *init_unit_test_suite(int, char *[])
+{
+ unit_test_framework::test_suite *suite =
+ BOOST_TEST_SUITE("lexical_cast float types unit test");
+ 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));
+
+ return suite;
+}
+
+
+// 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>
+void test_conversion_from_to_float_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);
+ BOOST_CHECK_THROW(lexical_cast<T>( std::string("1") + np.thousands_sep() + np.decimal_point() + "e10" ), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<T>( std::string("1e10") + np.thousands_sep() ), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<T>( std::string("1") + np.thousands_sep() + "e10" ), bad_lexical_cast);
+
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( to_str< char >(100000) ), 100000, (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( to_str< char >(100) ), 100, (std::numeric_limits<T>::epsilon()) );
+#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( to_str< wchar_t >(100) ), 100, (std::numeric_limits<T>::epsilon()) );
+#endif
+ // Exception must not be thrown, when we are using no separators at all
+ BOOST_CHECK_CLOSE_FRACTION( lexical_cast<T>("30000"), static_cast<T>(30000), (std::numeric_limits<T>::epsilon()) );
+ }
+}
+
+
+
+
+/*
+ * Converts char* [and wchar_t] to float number type and checks, that generated
+ * number is in interval [base_value-epsilon, base_value+epsilon].
+ */
+#ifndef BOOST_LCAST_NO_WCHAR_T
+#define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \
+ converted_val = lexical_cast<test_t>(#VAL); \
+ BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits<test_t>::epsilon()), \
+ (converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()), \
+ std::numeric_limits<test_t>::epsilon() \
+ ); \
+ BOOST_CHECK_EQUAL(converted_val, lexical_cast<test_t>(L## #VAL) );
+
+#else
+#define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \
+ converted_val = lexical_cast<test_t>(#VAL); \
+ BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits<test_t>::epsilon()), \
+ (converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()), \
+ std::numeric_limits<test_t>::epsilon() \
+ );
+#endif
+
+template <class TestType>
+void test_converion_to_float_types()
+{
+ typedef TestType test_t;
+ test_t converted_val;
+
+ BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast<test_t>('1'), (std::numeric_limits<test_t>::epsilon()));
+ BOOST_CHECK_EQUAL(0.0, lexical_cast<test_t>('0'));
+
+ unsigned char const uc_one = '1';
+ unsigned char const uc_zero ='0';
+ BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast<test_t>(uc_one), (std::numeric_limits<test_t>::epsilon()));
+ BOOST_CHECK_EQUAL(0.0, lexical_cast<test_t>(uc_zero));
+
+ signed char const sc_one = '1';
+ signed char const sc_zero ='0';
+ BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast<test_t>(sc_one), (std::numeric_limits<test_t>::epsilon()));
+ BOOST_CHECK_EQUAL(0.0, lexical_cast<test_t>(sc_zero));
+
+ BOOST_CHECK_CLOSE_FRACTION(1e34L, lexical_cast<test_t>( "10000000000000000000000000000000000"), (std::numeric_limits<test_t>::epsilon()) );
+
+// VC failes the next test
+// BOOST_CHECK_CLOSE_FRACTION(1e-35L, lexical_cast<test_t>("0.00000000000000000000000000000000001"), (std::numeric_limits<test_t>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(
+ 0.1111111111111111111111111111111111111111111111111111111111111111111111111L
+ , lexical_cast<test_t>("0.1111111111111111111111111111111111111111111111111111111111111111111111111")
+ , (std::numeric_limits<test_t>::epsilon()) );
+
+ CHECK_CLOSE_ABS_DIFF(1,test_t);
+ BOOST_CHECK_EQUAL(0,lexical_cast<test_t>("0"));
+ CHECK_CLOSE_ABS_DIFF(-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1.0, test_t);
+ CHECK_CLOSE_ABS_DIFF(0.0, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1.0,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1e1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1.0e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0.0e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1.0e1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1e-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1.0e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0.0e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1.0e-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1E1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1.0E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0.0E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1.0E1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1E-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(1.0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(0.0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-1.0E-1, test_t);
+
+ CHECK_CLOSE_ABS_DIFF(.0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(.0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-.0E-1, test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10.0, test_t);
+ CHECK_CLOSE_ABS_DIFF(00.0, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10.0,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10e1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10.0e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00.0e1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10.0e1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10e-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10.0e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00.0e-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10.0e-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10E1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10.0E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00.0E1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10.0E1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10E-1,test_t);
+
+ CHECK_CLOSE_ABS_DIFF(10.0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(00.0E-1, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10.0E-1, test_t);
+
+ CHECK_CLOSE_ABS_DIFF(-10101.0E-011, test_t);
+ CHECK_CLOSE_ABS_DIFF(-10101093, test_t);
+ CHECK_CLOSE_ABS_DIFF(10101093, test_t);
+
+ CHECK_CLOSE_ABS_DIFF(-.34, test_t);
+ CHECK_CLOSE_ABS_DIFF(.34, test_t);
+ CHECK_CLOSE_ABS_DIFF(.34e10, test_t);
+
+ BOOST_CHECK_THROW(lexical_cast<test_t>("-1.e"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("-1.E"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.e"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.E"), bad_lexical_cast);
+
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0e"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0E"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("10E"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("10e"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0e-"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0E-"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("10E-"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("10e-"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("e1"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("e-1"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("e-"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>(".e"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>(".11111111111111111111111111111111111111111111111111111111111111111111ee"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>(".11111111111111111111111111111111111111111111111111111111111111111111e-"), bad_lexical_cast);
+
+ BOOST_CHECK_THROW(lexical_cast<test_t>("-B"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("0xB"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("0x0"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("--1.0"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0e--1"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0.0"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1e1e1"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0e-1e-1"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>(" 1.0"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1.0 "), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>(""), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("-"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>('\0'), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>('-'), bad_lexical_cast);
+}
+
+template <class T>
+void test_float_typess_for_overflows()
+{
+ typedef T test_t;
+ test_t minvalue = (std::numeric_limits<test_t>::min)();
+ std::string s_min_value = lexical_cast<std::string>(minvalue);
+ BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast<test_t>(minvalue), (std::numeric_limits<test_t>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast<test_t>(s_min_value), (std::numeric_limits<test_t>::epsilon()));
+
+ test_t maxvalue = (std::numeric_limits<test_t>::max)();
+ std::string s_max_value = lexical_cast<std::string>(maxvalue);
+ BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast<test_t>(maxvalue), (std::numeric_limits<test_t>::epsilon()));
+ BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast<test_t>(s_max_value), (std::numeric_limits<test_t>::epsilon()));
+
+ BOOST_CHECK_THROW(lexical_cast<test_t>(s_max_value+"1"), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>(s_max_value+"9"), bad_lexical_cast);
+
+ // VC9 can fail the fllowing tests on floats and doubles when using stingstream...
+ BOOST_CHECK_THROW(lexical_cast<test_t>("1"+s_max_value), bad_lexical_cast);
+ BOOST_CHECK_THROW(lexical_cast<test_t>("9"+s_max_value), bad_lexical_cast);
+
+ if ( is_same<test_t,float>::value )
+ {
+ BOOST_CHECK_THROW(lexical_cast<test_t>( (std::numeric_limits<double>::max)() ), bad_lexical_cast);
+ BOOST_CHECK(
+ (std::numeric_limits<double>::min)() - std::numeric_limits<test_t>::epsilon()
+ <= lexical_cast<test_t>( (std::numeric_limits<double>::min)() )
+ && lexical_cast<test_t>( (std::numeric_limits<double>::min)() )
+ <= (std::numeric_limits<double>::min)() + std::numeric_limits<test_t>::epsilon()
+ );
+ }
+
+ if ( sizeof(test_t) < sizeof(long double) )
+ {
+ BOOST_CHECK_THROW(lexical_cast<test_t>( (std::numeric_limits<long double>::max)() ), bad_lexical_cast);
+ BOOST_CHECK(
+ (std::numeric_limits<long double>::min)() - std::numeric_limits<test_t>::epsilon()
+ <= lexical_cast<test_t>( (std::numeric_limits<long double>::min)() )
+ && lexical_cast<test_t>( (std::numeric_limits<long double>::min)() )
+ <= (std::numeric_limits<long double>::min)() + std::numeric_limits<test_t>::epsilon()
+ );
+ }
+}
+
+#undef CHECK_CLOSE_ABS_DIFF
+
+#define TEST_TO_FROM_CAST_AROUND_TYPED(VAL,STRING_TYPE) \
+ test_value = VAL + std::numeric_limits<test_t>::epsilon() * i ; \
+ converted_val = lexical_cast<test_t>( lexical_cast<STRING_TYPE>(test_value) ); \
+ BOOST_CHECK_CLOSE_FRACTION( \
+ test_value, \
+ converted_val, \
+ std::numeric_limits<test_t>::epsilon() \
+ );
+
+/*
+ * For interval [ from_mult*epsilon+VAL, to_mult*epsilon+VAL ], converts float type
+ * numbers to string[wstring] and then back to float type, then compares initial
+ * values and generated.
+ * Step is epsilon
+ */
+#ifndef BOOST_LCAST_NO_WCHAR_T
+# define TEST_TO_FROM_CAST_AROUND(VAL) \
+ for(i=from_mult; i<=to_mult; ++i) { \
+ TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \
+ TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::wstring) \
+ }
+#else
+# define TEST_TO_FROM_CAST_AROUND(VAL) \
+ for(i=from_mult; i<=to_mult; ++i) { \
+ TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \
+ }
+#endif
+
+template <class TestType>
+void test_converion_from_to_float_types()
+{
+ typedef TestType test_t;
+ test_t test_value;
+ test_t converted_val;
+
+ int i;
+ int from_mult = -50;
+ int to_mult = 50;
+
+ TEST_TO_FROM_CAST_AROUND( 0.0 );
+
+ long double val1;
+ for(val1 = 1.0e-10L; val1 < 1e11; val1*=10 )
+ TEST_TO_FROM_CAST_AROUND( val1 );
+
+ long double val2;
+ for(val2 = -1.0e-10L; val2 > -1e11; val2*=10 )
+ TEST_TO_FROM_CAST_AROUND( val2 );
+
+ from_mult = -100;
+ to_mult = 0;
+ TEST_TO_FROM_CAST_AROUND( (std::numeric_limits<test_t>::max)() );
+
+ from_mult = 0;
+ to_mult = 100;
+ TEST_TO_FROM_CAST_AROUND( (std::numeric_limits<test_t>::min)() );
+}
+
+#undef TEST_TO_FROM_CAST_AROUND
+#undef TEST_TO_FROM_CAST_AROUND_TYPED
+
+
+template<class T, class CharT>
+void test_conversion_from_float_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_float(CharT zero)
+{
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 0)), static_cast<T>(0), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 1)), static_cast<T>(1), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 2)), static_cast<T>(2), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 3)), static_cast<T>(3), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 4)), static_cast<T>(4), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 5)), static_cast<T>(5), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 6)), static_cast<T>(6), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 7)), static_cast<T>(7), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 8)), static_cast<T>(8), (std::numeric_limits<T>::epsilon()) );
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 9)), static_cast<T>(9), (std::numeric_limits<T>::epsilon()) );
+
+ 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);
+}
+
+struct restore_oldloc
+{
+ std::locale oldloc;
+ ~restore_oldloc() { std::locale::global(oldloc); }
+};
+
+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_float_to_char<T>(zero);
+ test_conversion_from_char_to_float<T>(zero);
+ test_conversion_from_float_to_char<T>(szero);
+ test_conversion_from_char_to_float<T>(szero);
+ test_conversion_from_float_to_char<T>(uzero);
+ test_conversion_from_char_to_float<T>(uzero);
+ #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+ wchar_t const wzero = L'0';
+ test_conversion_from_float_to_char<T>(wzero);
+ test_conversion_from_char_to_float<T>(wzero);
+ #endif
+
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>("+1"), 1, std::numeric_limits<T>::epsilon());
+ BOOST_CHECK_CLOSE_FRACTION(lexical_cast<T>("+9"), 9, std::numeric_limits<T>::epsilon());
+
+ 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_converion_to_float_types<T>();
+ test_float_typess_for_overflows<T>();
+ test_converion_from_to_float_types<T>();
+
+
+ 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_float_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_float_for_locale<T>();
+
+ if(grouping1.empty() && grouping2.empty())
+ BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested");
+}
+
+
+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>();
+}
+
+
+
+
+
+
+
Added: branches/release/libs/conversion/test/lexical_cast_inf_nan_test.cpp
==============================================================================
--- (empty file)
+++ branches/release/libs/conversion/test/lexical_cast_inf_nan_test.cpp 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -0,0 +1,180 @@
+// Unit test for boost::lexical_cast.
+//
+// See http://www.boost.org for most recent version, including documentation.
+//
+// Copyright Antony Polukhin, 2011.
+//
+// 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).
+
+#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/math/special_functions/sign.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
+#define BOOST_LCAST_NO_WCHAR_T
+#endif
+
+using namespace boost;
+
+template <class T>
+bool is_pos_inf(T value)
+{
+ return (boost::math::isinf)(value) && !(boost::math::signbit)(value);
+}
+
+template <class T>
+bool is_neg_inf(T value)
+{
+ return (boost::math::isinf)(value) && (boost::math::signbit)(value);
+}
+
+template <class T>
+bool is_pos_nan(T value)
+{
+ return (boost::math::isnan)(value) && !(boost::math::signbit)(value);
+}
+
+template <class T>
+bool is_neg_nan(T value)
+{
+ /* There is some strange behaviour on Itanium platform with -nan nuber for long double.
+ * It is a IA64 feature, or it is a boost::math feature, not a lexical_cast bug */
+#if defined(__ia64__) || defined(_M_IA64)
+ return (boost::math::isnan)(value)
+ && ( boost::is_same<T, long double >::value || (boost::math::signbit)(value) );
+#else
+ return (boost::math::isnan)(value) && (boost::math::signbit)(value);
+#endif
+}
+
+template <class T>
+void test_inf_nan_templated()
+{
+ typedef T test_t;
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("inf") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("INF") ) );
+
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>("-inf") ) );
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>("-INF") ) );
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("+inf") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("+INF") ) );
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("infinity") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("INFINITY") ) );
+
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>("-infinity") ) );
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>("-INFINITY") ) );
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("+infinity") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>("+INFINITY") ) );
+
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>("nan") ) );
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>("NAN") ) );
+
+ BOOST_CHECK( is_neg_nan( lexical_cast<test_t>("-nan") ) );
+ BOOST_CHECK( is_neg_nan( lexical_cast<test_t>("-NAN") ) );
+
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>("+nan") ) );
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>("+NAN") ) );
+
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>("nan()") ) );
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>("NAN(some string)") ) );
+ BOOST_CHECK_THROW( lexical_cast<test_t>("NAN(some string"), bad_lexical_cast );
+
+ BOOST_CHECK(lexical_cast<std::string>( (boost::math::changesign)(std::numeric_limits<test_t >::infinity()))
+ == "-inf" );
+ BOOST_CHECK(lexical_cast<std::string>( std::numeric_limits<test_t >::infinity()) == "inf" );
+ BOOST_CHECK(lexical_cast<std::string>( std::numeric_limits<test_t >::quiet_NaN()) == "nan" );
+#if !defined(__ia64__) && !defined(_M_IA64)
+ BOOST_CHECK(lexical_cast<std::string>(
+ (boost::math::changesign)(std::numeric_limits<test_t >::quiet_NaN()))
+ == "-nan" );
+#endif
+
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"inf") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"INF") ) );
+
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>(L"-inf") ) );
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>(L"-INF") ) );
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"+inf") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"+INF") ) );
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"infinity") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"INFINITY") ) );
+
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>(L"-infinity") ) );
+ BOOST_CHECK( is_neg_inf( lexical_cast<test_t>(L"-INFINITY") ) );
+
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"+infinity") ) );
+ BOOST_CHECK( is_pos_inf( lexical_cast<test_t>(L"+INFINITY") ) );
+
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>(L"nan") ) );
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>(L"NAN") ) );
+
+ BOOST_CHECK( is_neg_nan( lexical_cast<test_t>(L"-nan") ) );
+ BOOST_CHECK( is_neg_nan( lexical_cast<test_t>(L"-NAN") ) );
+
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>(L"+nan") ) );
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>(L"+NAN") ) );
+
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>(L"nan()") ) );
+ BOOST_CHECK( is_pos_nan( lexical_cast<test_t>(L"NAN(some string)") ) );
+ BOOST_CHECK_THROW( lexical_cast<test_t>(L"NAN(some string"), bad_lexical_cast );
+
+ BOOST_CHECK(lexical_cast<std::wstring>( (boost::math::changesign)(std::numeric_limits<test_t >::infinity()))
+ == L"-inf" );
+ BOOST_CHECK(lexical_cast<std::wstring>( std::numeric_limits<test_t >::infinity()) == L"inf" );
+ BOOST_CHECK(lexical_cast<std::wstring>( std::numeric_limits<test_t >::quiet_NaN()) == L"nan" );
+#if !defined(__ia64__) && !defined(_M_IA64)
+ BOOST_CHECK(lexical_cast<std::wstring>(
+ (boost::math::changesign)(std::numeric_limits<test_t >::quiet_NaN()))
+ == L"-nan" );
+#endif
+
+#endif
+}
+
+void test_inf_nan_float()
+{
+ test_inf_nan_templated<float >();
+}
+
+void test_inf_nan_double()
+{
+ test_inf_nan_templated<double >();
+}
+
+void test_inf_nan_long_double()
+{
+ test_inf_nan_templated<long double >();
+}
+
+unit_test::test_suite *init_unit_test_suite(int, char *[])
+{
+ unit_test_framework::test_suite *suite =
+ BOOST_TEST_SUITE("lexical_cast inf anf nan parsing unit test");
+ suite->add(BOOST_TEST_CASE(&test_inf_nan_float));
+ suite->add(BOOST_TEST_CASE(&test_inf_nan_double));
+ suite->add(BOOST_TEST_CASE(&test_inf_nan_long_double));
+
+ return suite;
+}
Modified: branches/release/libs/conversion/test/lexical_cast_loopback_test.cpp
==============================================================================
--- branches/release/libs/conversion/test/lexical_cast_loopback_test.cpp (original)
+++ branches/release/libs/conversion/test/lexical_cast_loopback_test.cpp 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -64,7 +64,6 @@
}
-#if defined(BOOST_MSVC)
// See bug http://tinyurl.com/vhpvo
template<class T>
void test_msvc_magic_values()
@@ -73,7 +72,6 @@
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()
{
@@ -83,16 +81,12 @@
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
}
Added: branches/release/libs/conversion/test/lexical_cast_wchars_test.cpp
==============================================================================
--- (empty file)
+++ branches/release/libs/conversion/test/lexical_cast_wchars_test.cpp 2011-08-17 14:43:10 EDT (Wed, 17 Aug 2011)
@@ -0,0 +1,56 @@
+// Unit test for boost::lexical_cast.
+//
+// See http://www.boost.org for most recent version, including documentation.
+//
+// Copyright Antony Polukhin, 2011.
+//
+// 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).
+
+#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/cstdint.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+using namespace boost;
+
+void test_char_types_conversions()
+{
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ 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";
+ const wchar_t wc_arr[] =L"Test array of chars";
+
+ // Following tests depend on realization of std::locale
+ // and pass for popular compilers and STL realizations
+ BOOST_CHECK(boost::lexical_cast<wchar_t>(c_arr[0]) == wc_arr[0]);
+ 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_EQUAL(boost::lexical_cast<wchar_t>(uc_arr[0]), wc_arr[0]);
+ BOOST_CHECK_EQUAL(boost::lexical_cast<wchar_t>(sc_arr[0]), wc_arr[0]);
+#endif
+ BOOST_CHECK(1);
+}
+
+unit_test::test_suite *init_unit_test_suite(int, char *[])
+{
+ unit_test_framework::test_suite *suite =
+ BOOST_TEST_SUITE("lexical_cast char<->wchar_t unit test");
+ suite->add(BOOST_TEST_CASE(&test_char_types_conversions));
+
+ return suite;
+}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk