Index: boost/lexical_cast.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/lexical_cast.hpp,v retrieving revision 1.20 diff -u -r1.20 lexical_cast.hpp --- boost/lexical_cast.hpp 13 Apr 2006 20:52:28 -0000 1.20 +++ boost/lexical_cast.hpp 6 Jul 2006 18:04:17 -0000 @@ -11,14 +11,19 @@ // enhanced with contributions from Terje SlettebЬ, // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, -// and other Boosters -// when: November 2000, March 2003, June 2005 +// Alexander Nasonov and other Boosters +// when: November 2000, March 2003, June 2005, June 2006 +#include #include +#include +#include #include #include #include #include +#include +#include #include #include #include @@ -120,8 +125,210 @@ typedef wchar_t type; }; } - - namespace detail // stream wrapper for handling lexical conversions + + namespace detail + { + // Max. length of string representation of Source; 0 if unlimited. + // Values with limited string representation are placed to + // the buffer defined locally in lexical_cast function. + // Some types don't have an upper limit yet they have been ... TODO + // Each specialization should have a correspondent operator<< + // defined in lexical_stream_limited. + template< class CharT // A result of widest_char transformation. + , class Source // Source type of lexical_cast. + > + struct lexical_cast_src_length : mpl::size_t<0> + { + // TODO: check_coverage(char*); + // TODO: check_coverage(wchar_t*); + }; + + template + struct lexical_cast_src_length< CharT + , std::basic_string + > + : mpl::size_t<1> // Dummy value. + { + }; + + template + struct lexical_cast_src_length + : mpl::size_t<1> // Dummy value. + { + }; + + template + struct lexical_cast_src_length + : mpl::size_t<1> // Dummy value. + { + }; + + // Helper for integral types. + // Notes on length calculation: + // Max length for 32bit int with grouping "\1" and thousands_sep ',': + // "-2,1,4,7,4,8,3,6,4,7" + // ^ - is_signed + // ^ - 1 digit not counted by digits10 + // ^^^^^^^^^^^^^^^^^^ - digits10 * 2 + // + // Constant is_specialized is used instead of constant 1 + // to prevent buffer overflow in a rare case when + // doesn't add missing specialization for + // numeric_limits for some integral type T. + // When is_specialized is false, the whole expression is 0. + template + struct lexical_cast_src_length_integral + : mpl::size_t< std::numeric_limits::is_signed + + std::numeric_limits::is_specialized + // == 1 + std::numeric_limits::digits10 * 2 + > + { + }; + +# define BOOST_AUX_LEXICAL_CAST_DEF(T) \ + template \ + struct lexical_cast_src_length \ + : lexical_cast_src_length_integral {}; + + BOOST_AUX_LEXICAL_CAST_DEF(short) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned short) + BOOST_AUX_LEXICAL_CAST_DEF(int) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned int) + BOOST_AUX_LEXICAL_CAST_DEF(long) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned long) + // TODO: add specializations for non-standard types + // and correspondent lexical_stream_limited::operator<< + +# undef BOOST_AUX_LEXICAL_CAST_DEF + + template + struct lexical_cast_src_length : mpl::size_t<1> + { + }; + + template + struct lexical_cast_src_length : mpl::size_t<1> + { + }; + + template + struct lexical_cast_src_length : mpl::size_t<1> + { + }; + + template + struct lexical_cast_src_length : mpl::size_t<1> + { + }; + +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + // No specialization for unsupported lexical_cast(L' ') + template<> + struct lexical_cast_src_length : mpl::size_t<1> + { + }; +#endif + } + + namespace detail // '0' and '-' constants + { + template struct lcast_char_constants; + + template<> + struct lcast_char_constants + { + BOOST_STATIC_CONSTANT(char, zero = '0'); + BOOST_STATIC_CONSTANT(char, minus = '-'); + }; + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + template<> + struct lcast_char_constants + { + BOOST_STATIC_CONSTANT(wchar_t, zero = L'0'); + BOOST_STATIC_CONSTANT(wchar_t, minus = L'-'); + }; +#endif + } + + namespace detail // public access to basic_streambuf::setg + { + template + class lexical_streambuf : public std::basic_streambuf + { + public: + using std::basic_streambuf::setg; + }; + } + + namespace detail // lcast_to_unsigned + { + inline unsigned int lcast_to_unsigned(int value) + { + unsigned int result = value; + return value < 0 ? -result : result; + } + + inline unsigned long lcast_to_unsigned(long value) + { + unsigned long result = value; + return value < 0 ? -result : result; + } + + // TODO: non-standard types + } + + namespace detail // lcast_put_unsigned + { + template + CharT* lcast_put_unsigned(T n, CharT* finish) + { + typedef std::numpunct numpunct; + + std::locale loc; + numpunct const& np = std::use_facet(loc); + std::string const& grouping = np.grouping(); + std::string::size_type const grouping_size = grouping.size(); + std::string::size_type group = 0; // current group number + + CharT thousands_sep; + if(grouping_size) + thousands_sep = np.thousands_sep(); + + char last_group_size = grouping[0] <= 0 ? CHAR_MAX : grouping[0]; + // Since grouping is const, grouping[grouping.size()] returns '\0'. + // It's safe to assume here and below that CHAR_MAX is equivalent + // to unlimited grouping. + + char left = last_group_size; + + do + { + if(left == 0) + { + ++group; + if(group < grouping_size) + { + char const size = grouping[group]; + last_group_size = size <= 0 ? CHAR_MAX : size; + } + + left = last_group_size; + --finish; + *finish = thousands_sep; + } + + --left; + --finish; + *finish = n % 10 + lcast_char_constants::zero; + n /= 10; + } while(n); + + return finish; + } + } + + namespace detail // stream wrappers for handling lexical conversions { template class lexical_stream @@ -132,7 +339,7 @@ typename stream_char::type>::type char_type; public: - lexical_stream() + lexical_stream(char_type* = 0, char_type* = 0) { stream.unsetf(std::ios::skipws); @@ -172,13 +379,13 @@ #if defined(BOOST_NO_STRINGSTREAM) stream << '\0'; #endif - output = stream.str(); + stream.str().swap(output); return true; } #ifndef DISABLE_WIDE_CHAR_SUPPORT bool operator>>(std::wstring &output) { - output = stream.str(); + stream.str().swap(output); return true; } #endif @@ -191,6 +398,199 @@ std::basic_stringstream stream; #endif }; + + // String representation of Source has an upper limit. + template + class lexical_stream_limited + { + // 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. + // This might change with an introduction of + // lexical_cast< boost::array >(arg). + CharT* start; + CharT* finish; + + private: + + // Undefined: + lexical_stream_limited(lexical_stream_limited const&); + void operator=(lexical_stream_limited const&); + + public: + + lexical_stream_limited(CharT* start, CharT* finish) + : start(start) + , finish(finish) + {} + + public: // output + + template + bool operator<<(std::basic_string const&); + + bool operator<<(bool); + bool operator<<(CharT); + // TODO: bool operator<<(char); and signed/unsigned variants. + 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); + // TODO: other types + + public: // input + + template + bool operator>>(InputStreamable&); + + bool operator>>(CharT&); + bool operator>>(std::string&); + + #ifndef DISABLE_WIDE_CHAR_SUPPORT + bool operator>>(std::wstring&); + #endif + }; + + template + template + inline bool lexical_stream_limited::operator<<( + std::basic_string const& str) + { + start = const_cast(str.data()); + finish = start + str.length(); + return true; + } + + template + inline bool lexical_stream_limited::operator<<(bool value) + { + *start = value + lcast_char_constants::zero; + finish = start + 1; + return true; + } + + template + inline bool lexical_stream_limited::operator<<(CharT ch) + { + *start = ch; + finish = start + 1; + return true; + } + + template + inline bool lexical_stream_limited::operator<<(short n) + { + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + if(n < 0) + *--start = lcast_char_constants::minus; + return true; + } + + template + inline bool lexical_stream_limited::operator<<(int n) + { + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + if(n < 0) + *--start = lcast_char_constants::minus; + return true; + } + + template + inline bool lexical_stream_limited::operator<<(long n) + { + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + if(n < 0) + *--start = lcast_char_constants::minus; + return true; + } + + template + inline bool lexical_stream_limited::operator<<(unsigned short n) + { + start = lcast_put_unsigned(+n, finish); + return true; + } + + template + inline bool lexical_stream_limited::operator<<(unsigned int n) + { + start = lcast_put_unsigned(n, finish); + return true; + } + + template + inline bool lexical_stream_limited::operator<<(unsigned long n) + { + start = lcast_put_unsigned(n, finish); + return true; + } + + template + inline bool lexical_stream_limited::operator<<(CharT const* str) + { + start = const_cast(str); + finish = start + std::char_traits::length(str); + return true; + } + + template + template + bool lexical_stream_limited::operator>>(InputStreamable &output) + { + if(is_pointer::value) + return false; + + lexical_streambuf sb; + sb.setg(start, start, finish); + + std::basic_istream stream(&sb); + stream.unsetf(std::ios::skipws); + + typedef std::numeric_limits limits; + + if(limits::is_specialized) + stream.precision(limits::digits10 + 1); + + 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 + std::char_traits::eof(); +#endif + } + + template + inline bool lexical_stream_limited::operator>>(CharT& output) + { + bool const ok = (finish - start == 1); + if(ok) + output = *start; + return ok; + } + + template + inline bool lexical_stream_limited::operator>>(std::string& str) + { + str.assign(start, finish); + return true; + } + + #ifndef DISABLE_WIDE_CHAR_SUPPORT + template + inline bool lexical_stream_limited::operator>>(std::wstring& str) + { + str.assign(start, finish); + return true; + } + #endif } #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION @@ -211,11 +611,21 @@ typedef const T * type; }; - template + template< typename Target + , typename Source + , bool Unlimited // string representation of Source is unlimited + , typename CharT + > Target lexical_cast( - BOOST_DEDUCED_TYPENAME boost::call_traits::value_type arg) + BOOST_DEDUCED_TYPENAME boost::call_traits::value_type arg, + CharT* buf, std::size_t src_len) { - detail::lexical_stream interpreter; + BOOST_DEDUCED_TYPENAME mpl::if_c< + Unlimited + , detail::lexical_stream + , detail::lexical_stream_limited + >::type interpreter(buf, buf + src_len); + Target result; if(!(interpreter << arg && interpreter >> result)) @@ -227,8 +637,17 @@ template inline Target lexical_cast(const Source &arg) { - typedef typename detail::array_to_pointer_decay::type NewSource; - return detail::lexical_cast(arg); + typedef typename detail::array_to_pointer_decay::type src; + + typedef typename detail::widest_char< + typename detail::stream_char::type + , typename detail::stream_char::type + >::type char_type; + + std::size_t const src_len = + detail::lexical_cast_src_length::value; + char_type buf[src_len + 1]; + return detail::lexical_cast(arg, buf, src_len); } #else