#ifndef BOOST_LEXICAL_CAST_INCLUDED #define BOOST_LEXICAL_CAST_INCLUDED // Boost lexical_cast.hpp header -------------------------------------------// // // See http://www.boost.org for most recent version including documentation. // See end of this header for rights and permissions. // // what: lexical_cast custom keyword cast // who: contributed by Kevlin Henney, // enhanced with contributions from Terje SlettebЬ, // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, // 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 #ifdef BOOST_NO_STRINGSTREAM #include #else #include #endif #if defined(BOOST_NO_STRINGSTREAM) || \ defined(BOOST_NO_STD_WSTRING) || \ defined(BOOST_NO_STD_LOCALE) #define DISABLE_WIDE_CHAR_SUPPORT #endif namespace boost { // exception used to indicate runtime lexical_cast failure class bad_lexical_cast : public std::bad_cast { public: bad_lexical_cast() : source(&typeid(void)), target(&typeid(void)) { } bad_lexical_cast( const std::type_info &source_type, const std::type_info &target_type) : source(&source_type), target(&target_type) { } const std::type_info &source_type() const { return *source; } const std::type_info &target_type() const { return *target; } virtual const char *what() const throw() { return "bad lexical cast: " "source type value could not be interpreted as target"; } virtual ~bad_lexical_cast() throw() { } private: const std::type_info *source; const std::type_info *target; }; namespace detail // selectors for choosing stream character type { template struct stream_char { typedef char type; }; #ifndef DISABLE_WIDE_CHAR_SUPPORT #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) template<> struct stream_char { typedef wchar_t type; }; #endif template<> struct stream_char { typedef wchar_t type; }; template<> struct stream_char { typedef wchar_t type; }; template<> struct stream_char { typedef wchar_t type; }; #endif template struct widest_char { typedef TargetChar type; }; template<> struct widest_char { typedef wchar_t type; }; } namespace detail { // 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 { private: typedef typename widest_char< typename stream_char::type, typename stream_char::type>::type char_type; public: lexical_stream(char_type* = 0, char_type* = 0) { stream.unsetf(std::ios::skipws); if(std::numeric_limits::is_specialized) stream.precision(std::numeric_limits::digits10 + 1); else if(std::numeric_limits::is_specialized) stream.precision(std::numeric_limits::digits10 + 1); } ~lexical_stream() { #if defined(BOOST_NO_STRINGSTREAM) stream.freeze(false); #endif } bool operator<<(const Source &input) { return !(stream << input).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 std::char_traits::eof(); #endif } bool operator>>(std::string &output) { #if defined(BOOST_NO_STRINGSTREAM) stream << '\0'; #endif stream.str().swap(output); return true; } #ifndef DISABLE_WIDE_CHAR_SUPPORT 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 }; // 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 // call-by-const reference version namespace detail { template struct array_to_pointer_decay { typedef T type; }; template struct array_to_pointer_decay { typedef const T * type; }; 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, CharT* buf, std::size_t src_len) { 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)) throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); return result; } } template inline Target lexical_cast(const Source &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 // call-by-value fallback version (deprecated) template Target lexical_cast(Source arg) { detail::lexical_stream interpreter; Target result; if(!(interpreter << arg && interpreter >> result)) throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); return result; } #endif } // Copyright Kevlin Henney, 2000-2005. All rights reserved. // // 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) #undef DISABLE_WIDE_CHAR_SUPPORT #endif