diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index ddd7398..6479e5d 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -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 #include #include +#include +#include #include #include #include @@ -28,17 +36,26 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include #include #include #include +#include + #ifndef BOOST_NO_STD_LOCALE -#include +# include +#else +# ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE +# warning "Unable to use 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 boost 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 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 - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_NO_INTRINSIC_WCHAR_T - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#endif -#endif - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#endif - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct lcast_src_length< CharT, std::basic_string > - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#else - template<> - struct lcast_src_length< char, std::basic_string > - { - 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 > - { - 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 @@ namespace boost #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_CONSTANT(std::size_t, value = std::numeric_limits::is_signed + - std::numeric_limits::is_specialized + // == 1 + std::numeric_limits::is_specialized + /* == 1 */ std::numeric_limits::digits10 * 2 ); #else @@ -502,6 +380,9 @@ namespace boost 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 @@ namespace boost 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 @@ namespace boost 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 numpunct; numpunct const& np = BOOST_USE_FACET(numpunct, loc); @@ -639,14 +515,13 @@ namespace boost T multiplier = 1; #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - // TODO: use BOOST_NO_STD_LOCALE std::locale loc; typedef std::numpunct 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 boost } } - namespace detail // stream wrapper for handling lexical conversions + namespace detail { - template - class lexical_stream + /* Returns true and sets the correct value if found NaN or Inf. */ + template + 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) { - private: - typedef typename widest_char< - typename stream_char::type, - typename stream_char::type>::type char_type; + using namespace std; + const wchar_t minus = lcast_char_constants::minus; + const wchar_t plus = lcast_char_constants::plus; + const int inifinity_size = 8; - typedef Traits traits_type; + bool has_minus = false; + /* Parsing +/- */ + if( *begin == minus) + { + ++ begin; + has_minus = true; + } + else if( *begin == plus ) ++begin; - public: - lexical_stream(char_type* = 0, char_type* = 0) + if( end-begin < 3 ) return false; + if( !memcmp(begin, lc_nan, 3*sizeof(CharT)) || !memcmp(begin, lc_NAN, 3*sizeof(CharT)) ) { - stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, static_cast(0), static_cast(0) ); + 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::quiet_NaN(); + else value = (boost::math::changesign) (std::numeric_limits::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)) + ) + ) + { + if( !has_minus ) value = std::numeric_limits::infinity(); + else value = (boost::math::changesign) (std::numeric_limits::infinity()); + return true; } - ~lexical_stream() - { - #if defined(BOOST_NO_STRINGSTREAM) - stream.freeze(false); - #endif - } - bool operator<<(const Source &input) - { - return !(stream << input).fail(); - } - template - bool operator>>(InputStreamable &output) - { - return !is_pointer::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(); + + return false; + } + +#ifndef BOOST_LCAST_NO_WCHAR_T + template + 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 - } -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - - bool operator>>(std::string &output) + template + 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 + 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); - return true; - } - #endif - -#else - bool operator>>(std::basic_string& output) - { - 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; } - template - bool operator>>(std::basic_string& out) - { - std::basic_string str(stream.str()); - out.assign(str.begin(), str.end()); - return true; - } + return false; + } #endif - private: - #if defined(BOOST_NO_STRINGSTREAM) - std::strstream stream; - #elif defined(BOOST_NO_STD_LOCALE) - std::stringstream stream; - #else - std::basic_stringstream stream; - #endif + template + bool put_inf_nan(CharT* begin, CharT*& end, const T& value) + { + using namespace std; + if ( (boost::math::isnan)(value) ) + { + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,"-nan", sizeof("-nan")); + end = begin + 4; + } else + { + memcpy(begin,"nan", sizeof("nan")); + end = begin + 3; + } + return true; + } else if ( (boost::math::isinf)(value) ) + { + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,"-inf", sizeof("-inf")); + end = begin + 4; + } else + { + memcpy(begin,"inf", sizeof("inf")); + end = begin + 3; + } + return true; + } + + return false; + } + + } + + + namespace detail // lcast_ret_float + { + template + struct mantissa_holder_type + { + /* Can not be used with this type */ }; + + template <> + struct mantissa_holder_type + { + typedef unsigned int type; + }; + + template <> + struct mantissa_holder_type + { +#if defined(BOOST_HAS_LONG_LONG) + typedef boost::ulong_long_type type; +#elif defined(BOOST_HAS_MS_INT64) + typedef unsigned __int64 type; +#endif + }; + + template + 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 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::c_decimal_separator; +#endif + + CharT const czero = lcast_char_constants::zero; + CharT const minus = lcast_char_constants::minus; + CharT const plus = lcast_char_constants::plus; + CharT const capital_e = lcast_char_constants::capital_e; + CharT const lowercase_e = lcast_char_constants::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::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::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::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[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; + } + + // 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( 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 Base // lexical_streambuf_fake or basic_streambuf , class Traits // usually char_traits + , bool RequiresStringbuffer > - class lexical_stream_limited_src : public Base + class lexical_stream_limited_src { + typedef stl_buf_unlocker, CharT > local_streambuffer_t; + +#if defined(BOOST_NO_STRINGSTREAM) + typedef stl_buf_unlocker local_stringbuffer_t; +#elif defined(BOOST_NO_STD_LOCALE) + typedef stl_buf_unlocker local_stringbuffer_t; +#else + typedef stl_buf_unlocker, 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). - // Currently, it is assumed that [start, finish) is big enough - // to hold a string representation of any Source value. CharT* start; CharT* finish; - - 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, loc).widen(ch); - Traits::assign(*p, w); - } - - static void widen_and_assign(wchar_t* p, wchar_t ch) - { - Traits::assign(*p, ch); - } - - static void widen_and_assign(char*, wchar_t ch); // undefined -#endif - - template - bool lcast_put(const OutputStreamable& input) - { - this->setp(start, finish); - std::basic_ostream stream(static_cast(this)); - lcast_set_precision(stream, static_cast(0)); - bool const result = !(stream << input).fail(); - finish = this->pptr(); - return result; - } - - // Undefined: - lexical_stream_limited_src(lexical_stream_limited_src const&); - void operator=(lexical_stream_limited_src const&); + 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 + 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, 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(str); + finish = start + Traits::length(str); + return true; + } + +#ifndef BOOST_LCAST_NO_WCHAR_T + template + 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 + bool shl_input_streamable(InputStreamable& input) + { + std::basic_ostream stream(&stringbuffer); + bool const result = !(stream << input).fail(); + start = stringbuffer.pbase(); + finish = stringbuffer.pptr(); + return result; + } + + template + inline bool shl_signed(T n) + { + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + if(n < 0) + { + --start; + CharT const minus = lcast_char_constants::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 + 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(boost::detail::lcast_get_precision()), val ); + return finish > start; + } + + template + 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(boost::detail::lcast_get_precision()), val ); + return finish > start; + } +#ifndef __MINGW32__ + template + 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(boost::detail::lcast_get_precision()), 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(boost::detail::lcast_get_precision()), 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(boost::detail::lcast_get_precision()), 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(boost::detail::lcast_get_precision()), val ); + return finish > start; + } +#endif + +#endif + +/************************************ OPERATORS << ( ... ) ********************************/ + public: template bool operator<<(std::basic_string const& str) { @@ -879,39 +1209,61 @@ namespace boost 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); + bool operator<<(bool value) + { + CharT const czero = lcast_char_constants::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(ch)); } + bool operator<<(signed char ch) { return ((*this) << static_cast(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 - 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); +#endif + bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(unsigned char * ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(signed char const* ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(signed char * ch) { return ((*this) << reinterpret_cast(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(n, finish); return true; } + bool operator<<(unsigned int n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<(unsigned long n) { start = lcast_put_unsigned(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(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(n, finish); return true; } + bool operator<<( __int64 n) { return shl_signed(n); } #endif - // These three operators use ostream and streambuf. - // lcast_streambuf_for_source::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 + } + template + bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } + +/************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ private: - template - bool input_operator_helper_unsigned(Type& output) + bool shr_unsigned(Type& output) { CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; @@ -945,7 +1297,7 @@ namespace boost } template - bool input_operator_helper_signed(Type& output) + bool shr_signed(Type& output) { CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; @@ -988,63 +1340,81 @@ namespace boost return succeed; } - public: // input - - bool operator>>(unsigned short& output) + template + bool shr_using_base_class(InputStreamable& output) { - return input_operator_helper_unsigned(output); +#if (defined _MSC_VER) +# pragma warning( push ) + // conditional expression is constant +# pragma warning( disable : 4127 ) +#endif + if(is_pointer::value) + return false; + + local_streambuffer_t bb; + bb.setg(start, start, finish); + std::basic_istream stream(&bb); + stream.unsetf(std::ios::skipws); + lcast_set_precision(stream, static_cast(0)); +#if (defined _MSC_VER) +# pragma warning( pop ) +#endif + return 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::eof(); +#endif } - bool operator>>(unsigned int& output) + template + inline bool shr_xchar(T& output) { - return input_operator_helper_unsigned(output); + 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(out); + } + return ok; } - 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); - } - - +/************************************ 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) - 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); - } - + 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) - bool operator>>(unsigned __int64& output) - { - return input_operator_helper_unsigned(output); - } - - bool operator>>(__int64& output) - { - return input_operator_helper_signed(output); - } + 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 + bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } +#endif /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; @@ -1079,401 +1449,78 @@ namespace boost } } + bool operator>>(float& output) { return lcast_ret_float(output,start,finish); } + + private: + // Not optimised converter + template + 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::minus; + CharT const plus = lcast_char_constants::plus; + CharT const capital_e = lcast_char_constants::capital_e; + CharT const lowercase_e = lcast_char_constants::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(output,start,finish); + } + public: + + 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; + + return float_types_converter_internal(output, tag); + } + + bool operator>>(long double& output) + { + int tag = 0; + return float_types_converter_internal(output, tag); + } // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. template - bool operator>>(InputStreamable& output) - { -#if (defined _MSC_VER) -# pragma warning( push ) - // conditional expression is constant -# pragma warning( disable : 4127 ) -#endif - if(is_pointer::value) - return false; - - this->setg(start, start, finish); - std::basic_istream stream(static_cast(this)); - stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, static_cast(0)); -#if (defined _MSC_VER) -# pragma warning( pop ) -#endif - return 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::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 - bool operator>>(std::basic_string& str) - { - str.assign(start, finish); - return true; - } -#endif - }; - - template - inline bool lexical_stream_limited_src::operator<<( - bool value) - { - typedef typename Traits::int_type int_type; - CharT const czero = lcast_char_constants::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 - inline bool lexical_stream_limited_src::operator<<( - char ch) - { - widen_and_assign(start, ch); - finish = start + 1; - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned char ch) - { - return ((*this) << static_cast(ch)); - } - - template - inline bool lexical_stream_limited_src::operator<<( - signed char ch) - { - return ((*this) << static_cast(ch)); - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned char const* ch) - { - return ((*this) << reinterpret_cast(ch)); - } - - template - inline bool lexical_stream_limited_src::operator<<( - signed char const* ch) - { - return ((*this) << reinterpret_cast(ch)); - } - -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - template - inline bool lexical_stream_limited_src::operator<<( - wchar_t ch) - { - widen_and_assign(start, ch); - finish = start + 1; - return true; - } -#endif - - template - inline bool lexical_stream_limited_src::operator<<( - short n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - int n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - long n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } - -#if defined(BOOST_HAS_LONG_LONG) - template - inline bool lexical_stream_limited_src::operator<<( - boost::long_long_type n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } -#elif defined(BOOST_HAS_MS_INT64) - template - inline bool lexical_stream_limited_src::operator<<( - __int64 n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } -#endif - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned short n) - { - start = lcast_put_unsigned(n, finish); - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned int n) - { - start = lcast_put_unsigned(n, finish); - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned long n) - { - start = lcast_put_unsigned(n, finish); - return true; - } - -#if defined(BOOST_HAS_LONG_LONG) - template - inline bool lexical_stream_limited_src::operator<<( - boost::ulong_long_type n) - { - start = lcast_put_unsigned(n, finish); - return true; - } -#elif defined(BOOST_HAS_MS_INT64) - template - inline bool lexical_stream_limited_src::operator<<( - unsigned __int64 n) - { - start = lcast_put_unsigned(n, finish); - return true; - } -#endif - - template - inline bool lexical_stream_limited_src::operator<<( - float val) - { - return this->lcast_put(val); - } - - template - inline bool lexical_stream_limited_src::operator<<( - double val) - { - return this->lcast_put(val); - } - - template - inline bool lexical_stream_limited_src::operator<<( - long double val) - { - return this->lcast_put(val); - } - - template - inline bool lexical_stream_limited_src::operator<<( - CharT const* str) - { - start = const_cast(str); - finish = start + Traits::length(str); - return true; - } - - template - inline bool lexical_stream_limited_src::operator>>( - CharT& output) - { - bool const ok = (finish - start == 1); - if(ok) - Traits::assign(output, *start); - return ok; - } - - template - inline bool lexical_stream_limited_src::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(out); - } - return ok; - } - - template - inline bool lexical_stream_limited_src::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(out); - } - return ok; - } - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - inline bool lexical_stream_limited_src::operator>>( - std::string& str) - { - str.assign(start, finish); - return true; - } - -#ifndef BOOST_LCAST_NO_WCHAR_T - template - inline bool lexical_stream_limited_src::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 - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - - template<> - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<> - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<> - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = true); + 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 - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_not< is_integral::value >::value - ) - ); - }; - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct lcast_streambuf_for_target< - std::basic_string > - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template - struct lcast_streambuf_for_target< - std::basic_string > - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif -#else - template<> - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif -#endif - } - - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // call-by-const reference version @@ -1491,47 +1538,6 @@ namespace boost 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::param_type arg, - CharT* buf, std::size_t src_len) - { - typedef BOOST_DEDUCED_TYPENAME - deduce_char_traits::type traits; - - typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - lcast_streambuf_for_target::value || - lcast_streambuf_for_source::value - , std::basic_streambuf - , lexical_streambuf_fake - >::type base; - - BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - Unlimited - , detail::lexical_stream - , detail::lexical_stream_limited_src - >::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 struct is_stdstring { @@ -1634,25 +1640,62 @@ namespace boost 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 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::type src; + typedef BOOST_DEDUCED_TYPENAME detail::array_to_pointer_decay::type src; - typedef typename detail::widest_char< - typename detail::stream_char::type - , typename detail::stream_char::type + typedef BOOST_DEDUCED_TYPENAME detail::widest_char< + BOOST_DEDUCED_TYPENAME detail::stream_char::type + , BOOST_DEDUCED_TYPENAME detail::stream_char::type >::type char_type; typedef detail::lcast_src_length 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(arg, buf, src_len); + + typedef BOOST_DEDUCED_TYPENAME + deduce_char_traits::type traits; + + typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t; + const bool requires_stringbuf = + !( + ::boost::type_traits::ice_or< + is_stdstring::value, + is_arithmetic::value, + ::boost::type_traits::ice_and< + is_pointer::value, + is_char_or_wchar::value, + ::boost::type_traits::ice_eq< + sizeof(char_type), + sizeof(removed_ptr_t) + >::value + >::value + >::value + ); + + detail::lexical_stream_limited_src + 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 struct lexical_cast_copy @@ -1708,6 +1751,7 @@ namespace boost } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } + BOOST_UNREACHABLE_RETURN(static_cast(0)); } }; @@ -1734,6 +1778,7 @@ namespace boost } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } + BOOST_UNREACHABLE_RETURN(static_cast(0)); } }; @@ -1815,6 +1860,78 @@ namespace boost #else + namespace detail // stream wrapper for handling lexical conversions + { + template + class lexical_stream + { + private: + typedef typename widest_char< + typename stream_char::type, + typename stream_char::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(0), static_cast(0) ); + } + ~lexical_stream() + { + #if defined(BOOST_NO_STRINGSTREAM) + stream.freeze(false); + #endif + } + bool operator<<(const Source &input) + { + return !(stream << input).fail(); + } + template + bool operator>>(InputStreamable &output) + { + return !is_pointer::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 stream; + #endif + }; + } + // call-by-value fallback version (deprecated) template diff --git a/index.html b/index.html index cf8527f..133680c 100644 --- a/index.html +++ b/index.html @@ -24,7 +24,7 @@ supplied by several headers:

and polymorphic_downcast<> to perform safe casting between polymorphic types.
-
  • The boost/lexical_cast header provides lexical_cast<> +
  • The boost/lexical_cast header provides lexical_cast<> general literal text conversions, such as an int represented as a string, or vice-versa.
  • diff --git a/lexical_cast.htm b/lexical_cast.htm index 7929dd4..73b6ba5 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -1,351 +1,16 @@ - - - - - lexical_cast - - - - -

    boost.png (6897 bytes)Header - boost/lexical_cast.hpp

    - -
    -

    Motivation

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

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

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

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

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

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

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

    -


    -

    Examples

    - The following example treats command line arguments as a sequence of numeric - data:
    -
    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);
    -        }
    -    }
    -    ...
    -}
    -
    -
    The following example uses numeric data in a string expression:
    -
    void log_message(const std::string &);
    -
    -void log_errno(int yoko)
    -{
    -    log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
    -}
    -
    -
    -
    -

    Synopsis

    - Library features defined in "boost/lexical_cast.hpp": -
    -
    namespace boost
    -{
    -    class bad_lexical_cast;
    -    template<typename Target, typename Source>
    -      Target lexical_cast(const Source& arg);
    -}
    -
    -
    Unit test defined in "lexical_cast_test.cpp". -

    -


    -

    lexical_cast

    -
    -
    template<typename Target, typename Source>
    -  Target lexical_cast(const Source& arg);
    -
    -
    Returns the result of streaming arg into a - standard library string-based stream and then out as a Target object. - Where Target is either std::string - or std::wstring, stream extraction takes the whole content - of the string, including spaces, rather than relying on the default - operator>> behavior. - If the conversion is unsuccessful, a - bad_lexical_cast exception is thrown. -

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

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

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

    -


    -

    bad_lexical_cast

    -
    -
    class bad_lexical_cast : public std::bad_cast
    -{
    -public:
    -    ... // same member function interface as std::exception
    -};
    -
    -
    Exception used to indicate runtime lexical_cast - failure. - -
    - - -

    Frequently Asked Questions

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Question:Why does lexical_cast<int8_t>("127") throw bad_lexical_cast?
    Answer:The type int8_t is a typedef to char or signed char. - 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 int or short int. If bounds checking - is important, you can also call numeric_cast: -
    numeric_cast<int8_t>(lexical_cast<int>("127"));
    -
    Question:What does lexical_cast<std::string> of an int8_t or uint8_t not do what I expect?
    Answer:As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first: -
    lexical_cast<std::string>(static_cast<int>(n));
    -
    Question:The implementation always resets the ios_base::skipws flag of an underlying stream object. It breaks my operator>> that works only in presence of this flag. Can you remove code that resets the flag?
    Answer: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 operator>> conform to the standard. Read a good C++ book, study std::sentry and ios_state_saver. -
    Question:Why std::cout << boost::lexical_cast<unsigned int>("-1"); does not throw, but outputs 4294967295?
    Answer:boost::lexical_cast has the behavior of stringstream, which uses num_get functions of std::locale to convert numbers. If we look at the [22.2.2.1.2] of Programming languages — C++, we'll see, that num_get uses the rules of scanf 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. -
    - -

    References

    -
      -
    • [N1973] Kevlin Henney, Beman Dawes, Lexical Conversion Library Proposal for TR2, - N1973. -
    • [Tuning] Alexander Nasonov, Fine Tuning for lexical_cast, - Overload #74 (PDF), - August 2006.
    • -
    -

    Changes

    -

    May 2011:

    -
      -
    • Optimizations for "C" and other locales without number grouping.
    • -
    • Better performance and less memory usage for unsigned char and signed char conversions.
    • -
    • Better performance and less memory usage for conversions to arithmetic types.
    • -
    • Better performance and less memory usage for conversions from arithmetic type to arithmetic type.
    • -
    • Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others).
    • -
    -

    August, October 2006:

    -
      -
    • Better performance for many combinations of Source and Target - types. Refer to [Tuning] for more details. -
    • -
    -

    June 2005:

    -
      -
    • 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.
      -
    • -
    • The MSVC 6 support is deprecated, and will be removed in a future Boost - version.
    • -
    -

    Earlier:

    - -
      -
    • The previous version of lexical_cast used the default stream - precision for reading and writing floating-point numbers. For numerics that - have a corresponding specialization of std::numeric_limits, the - current version now chooses a precision to match.
      -
    • The previous version of lexical_cast did not support conversion - to or from any wide-character-based types. For compilers with full language - and library support for wide characters, lexical_cast now supports - conversions from wchar_t, wchar_t *, and std::wstring - and to wchar_t and std::wstring.
      -
    • The previous version of lexical_cast 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 std::string - and, where supported, std::wstring: lexical_cast<std::string>("Hello, - World") succeeds instead of failing with a bad_lexical_cast - exception.
      -
    • The previous version of lexical_cast allowed unsafe and meaningless - conversions to pointers. The current version now throws a bad_lexical_cast - for conversions to pointers: lexical_cast<char *>("Goodbye, World") - now throws an exception instead of causing undefined behavior. -
    -

    -


    - -

    Performance

    -This table shows the execution time in milliseconds for 100000 calls of the following string formatters: - - - - - - - - - - - - - - - - - -
    From->To lexical_cast std::stringstream
    with construction
    std::stringstream
    without construction
    sscanf/sprintf
    string->char<191710
    string->int71152318
    string->unsigned int71172217
    string->bool<11041910
    string->float851726033
    char->string71051612
    int->string151312117
    unsigned int->string141252117
    bool->string71222412
    float->string12422311548
    char*->string912320---
    int->int<112026---
    float->float<1262142---
    - -Fastest results are highlitened with green. -
    -
    Copyright © Kevlin Henney, 2000-2005
    -
    Copyright © Alexander Nasonov, 2006-2010
    -
    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) -
    - + + + + + +Automatic redirection failed, please go to +../../doc/html/boost_lexical_cast.html + diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index f20994e..f07926b 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #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 struct my_traits : std::char_traits { @@ -65,6 +70,7 @@ void test_conversion_to_char(); 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_uintmax_t(); 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_allocator(); 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 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(test_conversion_from_to_wchar_t_alias)); suite->add(BOOST_TEST_CASE(test_conversion_to_pointer)); suite->add(BOOST_TEST_CASE(test_conversion_to_string)); + 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 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) 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 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) #endif suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + suite->add(BOOST_TEST_CASE(&operators_overload_test)); return suite; } @@ -201,19 +204,45 @@ void test_conversion_to_int() lexical_cast(std::string("Test")), bad_lexical_cast); } +void test_conversion_with_nonconst_char() +{ + std::vector buffer; + buffer.push_back('1'); + buffer.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer[0]), 1); + + std::vector buffer2; + buffer2.push_back('1'); + buffer2.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer2[0]), 1); + + std::vector buffer3; + buffer3.push_back('1'); + buffer3.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer3[0]), 1); + +#ifndef BOOST_LCAST_NO_WCHAR_T + std::vector buffer4; + buffer4.push_back(L'1'); + buffer4.push_back(L'\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer4[0]), 1); +#endif +} + void test_conversion_to_double() { - BOOST_CHECK_CLOSE(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast('A'), bad_lexical_cast); - BOOST_CHECK_CLOSE(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.234567890, 1.234567890, std::numeric_limits::epsilon()); - BOOST_CHECK_CLOSE(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast(1.234567890), std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast("1.234567890"), std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); - BOOST_CHECK_CLOSE(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW( lexical_cast(std::string("")), bad_lexical_cast); BOOST_CHECK_THROW( @@ -679,7 +708,7 @@ void test_conversion_from_to_integral_for_locale() BOOST_CHECK_THROW(lexical_cast( 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("10000") == static_cast(10000) ); + BOOST_CHECK( lexical_cast("30000") == static_cast(30000) ); } test_conversion_from_integral_to_integral(); @@ -775,35 +804,6 @@ void test_conversion_from_to_integral() BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); } -template -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(zero); - test_conversion_from_char_to_integral(zero); - test_conversion_from_integral_to_char(szero); - test_conversion_from_char_to_integral(szero); - test_conversion_from_integral_to_char(uzero); - test_conversion_from_char_to_integral(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(wzero); - test_conversion_from_char_to_integral(wzero); -#endif - - test_conversion_from_integral_to_integral(); - - BOOST_CHECK_CLOSE(lexical_cast("+1"), 1, std::numeric_limits::epsilon() ); - BOOST_CHECK_CLOSE(lexical_cast("+9"), 9, std::numeric_limits::epsilon()*9 ); - - BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); -} - void test_conversion_from_to_short() { test_conversion_from_to_integral(); @@ -844,19 +844,6 @@ void test_conversion_from_to_uintmax_t() test_conversion_from_to_integral(); } -void test_conversion_from_to_float() -{ - test_conversion_from_to_float(); -} -void test_conversion_from_to_double() -{ - test_conversion_from_to_float(); -} -void test_conversion_from_to_long_double() -{ - test_conversion_from_to_float(); -} - #if defined(BOOST_HAS_LONG_LONG) void test_conversion_from_to_longlong() @@ -966,16 +953,40 @@ void test_char_types_conversions() const wchar_t wc_arr[]=L"Test array of chars"; BOOST_CHECK(boost::lexical_cast(wc_arr) == std::wstring(wc_arr)); - BOOST_CHECK(boost::lexical_cast(c_arr) == std::wstring(wc_arr)); - - BOOST_CHECK(boost::lexical_cast(sc_arr) != std::wstring(wc_arr) ); - BOOST_CHECK(boost::lexical_cast(uc_arr) != std::wstring(wc_arr) ); - - BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); BOOST_CHECK(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); - BOOST_CHECK_THROW(boost::lexical_cast(uc_arr[0]), bad_lexical_cast); - BOOST_CHECK_THROW(boost::lexical_cast(sc_arr[0]), bad_lexical_cast); - #endif } + + + +struct foo_operators_test +{ + foo_operators_test() : f(2) {} + int f; +}; + +template +OStream& operator<<(OStream& ostr, const foo_operators_test& foo) +{ + ostr << foo.f; + return ostr; +} + +template +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(foo), "2"); + BOOST_CHECK_EQUAL((boost::lexical_cast("2")).f, 2); + + // Must compile + (void)boost::lexical_cast(foo); +} + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1fea2fb..2dd3500 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,9 @@ test-suite conversion [ run lexical_cast_abstract_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_noncopyable_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_vc8_bug_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp new file mode 100755 index 0000000..72279bb --- /dev/null +++ b/test/lexical_cast_float_types_test.cpp @@ -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 + +#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 + +#include +#include +#include + +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 +std::basic_string to_str_gcc_workaround(std::basic_string str) +{ + std::locale loc; + std::numpunct const& np = BOOST_USE_FACET(std::numpunct, loc); + std::ctype const& ct = BOOST_USE_FACET(std::ctype, 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 +std::basic_string to_str(T t) +{ + std::basic_ostringstream o; + o << t; + return to_str_gcc_workaround(o.str()); +} + + +template +void test_conversion_from_to_float_for_locale() +{ + std::locale current_locale; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); + if ( !np.grouping().empty() ) + { + BOOST_CHECK_THROW( + lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) + , bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + np.decimal_point() + "e10" ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1e10") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + "e10" ), bad_lexical_cast); + + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(100000) ), 100000, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(100) ), 100, (std::numeric_limits::epsilon()) ); +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(100) ), 100, (std::numeric_limits::epsilon()) ); +#endif + // Exception must not be thrown, when we are using no separators at all + BOOST_CHECK_CLOSE_FRACTION( lexical_cast("30000"), static_cast(30000), (std::numeric_limits::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(#VAL); \ + BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() \ + ); \ + BOOST_CHECK_EQUAL(converted_val, lexical_cast(L## #VAL) ); + +#else +#define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \ + converted_val = lexical_cast(#VAL); \ + BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() \ + ); +#endif + +template +void test_converion_to_float_types() +{ + typedef TestType test_t; + test_t converted_val; + + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast('0')); + + unsigned char const uc_one = '1'; + unsigned char const uc_zero ='0'; + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(uc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(uc_zero)); + + signed char const sc_one = '1'; + signed char const sc_zero ='0'; + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(sc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(sc_zero)); + + BOOST_CHECK_CLOSE_FRACTION(1e34L, lexical_cast( "10000000000000000000000000000000000"), (std::numeric_limits::epsilon()) ); + +// VC failes the next test +// BOOST_CHECK_CLOSE_FRACTION(1e-35L, lexical_cast("0.00000000000000000000000000000000001"), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION( + 0.1111111111111111111111111111111111111111111111111111111111111111111111111L + , lexical_cast("0.1111111111111111111111111111111111111111111111111111111111111111111111111") + , (std::numeric_limits::epsilon()) ); + + CHECK_CLOSE_ABS_DIFF(1,test_t); + BOOST_CHECK_EQUAL(0,lexical_cast("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("-1.e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-1.E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.E"), bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast("1.0e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0E-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10E-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e-1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".11111111111111111111111111111111111111111111111111111111111111111111ee"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".11111111111111111111111111111111111111111111111111111111111111111111e-"), bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast("-B"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("0xB"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("0x0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1e1e1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e-1e-1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(" 1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0 "), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast('\0'), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast('-'), bad_lexical_cast); +} + +template +void test_float_typess_for_overflows() +{ + typedef T test_t; + test_t minvalue = (std::numeric_limits::min)(); + std::string s_min_value = lexical_cast(minvalue); + BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast(minvalue), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast(s_min_value), (std::numeric_limits::epsilon())); + + test_t maxvalue = (std::numeric_limits::max)(); + std::string s_max_value = lexical_cast(maxvalue); + BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast(maxvalue), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast(s_max_value), (std::numeric_limits::epsilon())); + + BOOST_CHECK_THROW(lexical_cast(s_max_value+"1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(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("1"+s_max_value), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("9"+s_max_value), bad_lexical_cast); + + if ( is_same::value ) + { + BOOST_CHECK_THROW(lexical_cast( (std::numeric_limits::max)() ), bad_lexical_cast); + BOOST_CHECK( + (std::numeric_limits::min)() - std::numeric_limits::epsilon() + <= lexical_cast( (std::numeric_limits::min)() ) + && lexical_cast( (std::numeric_limits::min)() ) + <= (std::numeric_limits::min)() + std::numeric_limits::epsilon() + ); + } + + if ( sizeof(test_t) < sizeof(long double) ) + { + BOOST_CHECK_THROW(lexical_cast( (std::numeric_limits::max)() ), bad_lexical_cast); + BOOST_CHECK( + (std::numeric_limits::min)() - std::numeric_limits::epsilon() + <= lexical_cast( (std::numeric_limits::min)() ) + && lexical_cast( (std::numeric_limits::min)() ) + <= (std::numeric_limits::min)() + std::numeric_limits::epsilon() + ); + } +} + +#undef CHECK_CLOSE_ABS_DIFF + +#define TEST_TO_FROM_CAST_AROUND_TYPED(VAL,STRING_TYPE) \ + test_value = VAL + std::numeric_limits::epsilon() * i ; \ + converted_val = lexical_cast( lexical_cast(test_value) ); \ + BOOST_CHECK_CLOSE_FRACTION( \ + test_value, \ + converted_val, \ + std::numeric_limits::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 +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::max)() ); + + from_mult = 0; + to_mult = 100; + TEST_TO_FROM_CAST_AROUND( (std::numeric_limits::min)() ); +} + +#undef TEST_TO_FROM_CAST_AROUND +#undef TEST_TO_FROM_CAST_AROUND_TYPED + + +template +void test_conversion_from_float_to_char(CharT zero) +{ + BOOST_CHECK(lexical_cast(static_cast(0)) == zero + 0); + BOOST_CHECK(lexical_cast(static_cast(1)) == zero + 1); + BOOST_CHECK(lexical_cast(static_cast(2)) == zero + 2); + BOOST_CHECK(lexical_cast(static_cast(3)) == zero + 3); + BOOST_CHECK(lexical_cast(static_cast(4)) == zero + 4); + BOOST_CHECK(lexical_cast(static_cast(5)) == zero + 5); + BOOST_CHECK(lexical_cast(static_cast(6)) == zero + 6); + BOOST_CHECK(lexical_cast(static_cast(7)) == zero + 7); + BOOST_CHECK(lexical_cast(static_cast(8)) == zero + 8); + BOOST_CHECK(lexical_cast(static_cast(9)) == zero + 9); + + BOOST_CHECK_THROW(lexical_cast(static_cast(10)), bad_lexical_cast); + + T t = (std::numeric_limits::max)(); + BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); +} + +template +void test_conversion_from_char_to_float(CharT zero) +{ + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 0)), static_cast(0), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 1)), static_cast(1), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 2)), static_cast(2), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 3)), static_cast(3), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 4)), static_cast(4), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 5)), static_cast(5), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 6)), static_cast(6), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 7)), static_cast(7), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 8)), static_cast(8), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 9)), static_cast(9), (std::numeric_limits::epsilon()) ); + + BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); +} + +struct restore_oldloc +{ + std::locale oldloc; + ~restore_oldloc() { std::locale::global(oldloc); } +}; + +template +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(zero); + test_conversion_from_char_to_float(zero); + test_conversion_from_float_to_char(szero); + test_conversion_from_char_to_float(szero); + test_conversion_from_float_to_char(uzero); + test_conversion_from_char_to_float(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(wzero); + test_conversion_from_char_to_float(wzero); + #endif + + BOOST_CHECK_CLOSE_FRACTION(lexical_cast("+1"), 1, std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast("+9"), 9, std::numeric_limits::epsilon()); + + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); + + test_converion_to_float_types(); + test_float_typess_for_overflows(); + test_converion_from_to_float_types(); + + + typedef std::numpunct 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(); + + 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(); + + 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(); +} +void test_conversion_from_to_double() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_long_double() +{ + test_conversion_from_to_float(); +} + + + + + + + diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp new file mode 100755 index 0000000..4617d5e --- /dev/null +++ b/test/lexical_cast_inf_nan_test.cpp @@ -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 + +#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 + + +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +using namespace boost; + +template +bool is_pos_inf(T value) +{ + return (boost::math::isinf)(value) && !(boost::math::signbit)(value); +} + +template +bool is_neg_inf(T value) +{ + return (boost::math::isinf)(value) && (boost::math::signbit)(value); +} + +template +bool is_pos_nan(T value) +{ + return (boost::math::isnan)(value) && !(boost::math::signbit)(value); +} + +template +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::value || (boost::math::signbit)(value) ); +#else + return (boost::math::isnan)(value) && (boost::math::signbit)(value); +#endif +} + +template +void test_inf_nan_templated() +{ + typedef T test_t; + + BOOST_CHECK( is_pos_inf( lexical_cast("inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INF") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INFINITY") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INFINITY") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INFINITY") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast("-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast("-NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("+NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("nan()") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN(some string)") ) ); + BOOST_CHECK_THROW( lexical_cast("NAN(some string"), bad_lexical_cast ); + + BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::infinity())) + == "-inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == "inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == "nan" ); +#if !defined(__ia64__) && !defined(_M_IA64) + BOOST_CHECK(lexical_cast( + (boost::math::changesign)(std::numeric_limits::quiet_NaN())) + == "-nan" ); +#endif + +#ifndef BOOST_LCAST_NO_WCHAR_T + BOOST_CHECK( is_pos_inf( lexical_cast(L"inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INF") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast(L"-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INFINITY") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast(L"-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-INFINITY") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+INFINITY") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"NAN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast(L"-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast(L"-NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"+NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"nan()") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"NAN(some string)") ) ); + BOOST_CHECK_THROW( lexical_cast(L"NAN(some string"), bad_lexical_cast ); + + BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::infinity())) + == L"-inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == L"inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == L"nan" ); +#if !defined(__ia64__) && !defined(_M_IA64) + BOOST_CHECK(lexical_cast( + (boost::math::changesign)(std::numeric_limits::quiet_NaN())) + == L"-nan" ); +#endif + +#endif +} + +void test_inf_nan_float() +{ + test_inf_nan_templated(); +} + +void test_inf_nan_double() +{ + test_inf_nan_templated(); +} + +void test_inf_nan_long_double() +{ + test_inf_nan_templated(); +} + +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; +} diff --git a/test/lexical_cast_loopback_test.cpp b/test/lexical_cast_loopback_test.cpp index cd058fe..5787996 100644 --- a/test/lexical_cast_loopback_test.cpp +++ b/test/lexical_cast_loopback_test.cpp @@ -64,7 +64,6 @@ void test_round_conversion() } -#if defined(BOOST_MSVC) // See bug http://tinyurl.com/vhpvo template void test_msvc_magic_values() @@ -73,7 +72,6 @@ void test_msvc_magic_values() std::string magic_msvc_s = boost::lexical_cast(magic_msvc); BOOST_CHECK(magic_msvc == lexical_cast(magic_msvc_s)); } -#endif void test_round_conversion_float() { @@ -83,16 +81,12 @@ void test_round_conversion_float() void test_round_conversion_double() { test_round_conversion(); -#if defined(BOOST_MSVC) test_msvc_magic_values(); -#endif } void test_round_conversion_long_double() { test_round_conversion(); -#if defined(BOOST_MSVC) test_msvc_magic_values(); -#endif } diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp new file mode 100755 index 0000000..14ac461 --- /dev/null +++ b/test/lexical_cast_wchars_test.cpp @@ -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 + +#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 + +#include +#include +#include + +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(c_arr[0]) == wc_arr[0]); + BOOST_CHECK(boost::lexical_cast(c_arr) == std::wstring(wc_arr)); + + BOOST_CHECK(boost::lexical_cast(sc_arr) == std::wstring(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(uc_arr) == std::wstring(wc_arr) ); + + BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(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; +}