From bf754394035012e3c4a95b5e1a8809189d9c5a16 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 12 Nov 2013 17:15:12 +0000 Subject: [PATCH] Merged a big bunch of internal code changes from trunk for lexical_cast: dropped support of antique compilers, code changed to produce a smaller binaries and simplify compiler's work, simplified and shortened the code, common with other libraries code moved to 'detail/basic_pointerbuf.hpp' (fixes #9046, fixes #9070, fixes #9271) [SVN r86654] --- include/boost/detail/basic_pointerbuf.hpp | 139 ++ include/boost/lexical_cast.hpp | 1636 +++++++++------------ test/lexical_cast_stream_traits_test.cpp | 2 +- test/lexical_cast_wchars_test.cpp | 51 + 4 files changed, 867 insertions(+), 961 deletions(-) create mode 100644 include/boost/detail/basic_pointerbuf.hpp mode change 100755 => 100644 test/lexical_cast_wchars_test.cpp diff --git a/include/boost/detail/basic_pointerbuf.hpp b/include/boost/detail/basic_pointerbuf.hpp new file mode 100644 index 0000000..1d8cf37 --- /dev/null +++ b/include/boost/detail/basic_pointerbuf.hpp @@ -0,0 +1,139 @@ +//----------------------------------------------------------------------------- +// boost detail/templated_streams.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2013 John Maddock, Antony Polukhin +// +// +// 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) + +#ifndef BOOST_DETAIL_BASIC_POINTERBUF_HPP +#define BOOST_DETAIL_BASIC_POINTERBUF_HPP + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) +# pragma once +#endif + +#include "boost/config.hpp" +#include + +namespace boost { namespace detail { + +// +// class basic_pointerbuf: +// acts as a stream buffer which wraps around a pair of pointers: +// +template +class basic_pointerbuf : public BufferT { +protected: + typedef BufferT base_type; + typedef basic_pointerbuf this_type; + typedef typename base_type::int_type int_type; + typedef typename base_type::char_type char_type; + typedef typename base_type::pos_type pos_type; + typedef ::std::streamsize streamsize; + typedef typename base_type::off_type off_type; + +public: + basic_pointerbuf() : base_type() { setbuf(0, 0); } + const charT* getnext() { return this->gptr(); } + +#ifndef BOOST_NO_USING_TEMPLATE + using base_type::pptr; + using base_type::pbase; +#else + charT* pptr() const { return base_type::pptr(); } + charT* pbase() const { return base_type::pbase(); } +#endif + +protected: + // VC mistakenly assumes that `setbuf` and other functions are not referenced. + // Marking those functions with `inline` suppresses the warnings. + // There must be no harm from marking virtual functions as inline: inline virtual + // call can be inlined ONLY when the compiler knows the "exact class". + inline base_type* setbuf(char_type* s, streamsize n); + inline typename this_type::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which); + inline typename this_type::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which); + +private: + basic_pointerbuf& operator=(const basic_pointerbuf&); + basic_pointerbuf(const basic_pointerbuf&); +}; + +template +BufferT* +basic_pointerbuf::setbuf(char_type* s, streamsize n) +{ + this->setg(s, s, s + n); + return this; +} + +template +typename basic_pointerbuf::pos_type +basic_pointerbuf::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) +{ + typedef typename boost::int_t::least cast_type; + + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + std::ptrdiff_t size = this->egptr() - this->eback(); + std::ptrdiff_t pos = this->gptr() - this->eback(); + charT* g = this->eback(); + switch(static_cast(way)) + { + case ::std::ios_base::beg: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + off, g + size); + break; + case ::std::ios_base::end: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + size - off, g + size); + break; + case ::std::ios_base::cur: + { + std::ptrdiff_t newpos = static_cast(pos + off); + if((newpos < 0) || (newpos > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + newpos, g + size); + break; + } + default: ; + } +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#endif + return static_cast(this->gptr() - this->eback()); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +typename basic_pointerbuf::pos_type +basic_pointerbuf::seekpos(pos_type sp, ::std::ios_base::openmode which) +{ + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + off_type size = static_cast(this->egptr() - this->eback()); + charT* g = this->eback(); + if(off_type(sp) <= size) + { + this->setg(g, g + off_type(sp), g + size); + } + return pos_type(off_type(-1)); +} + +}} // namespace boost::detail + +#endif // BOOST_DETAIL_BASIC_POINTERBUF_HPP + diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index ed2291d..c954310 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -3,7 +3,7 @@ // MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#if defined(_MSC_VER) # pragma once #endif @@ -87,50 +87,39 @@ namespace boost { public: - bad_lexical_cast() BOOST_NOEXCEPT : + bad_lexical_cast() BOOST_NOEXCEPT #ifndef BOOST_NO_TYPEID - source(&typeid(void)), target(&typeid(void)) -#else - source(0), target(0) // this breaks getters + : source(&typeid(void)), target(&typeid(void)) #endif - { - } + {} - bad_lexical_cast( - const std::type_info &source_type_arg, - const std::type_info &target_type_arg) BOOST_NOEXCEPT : - source(&source_type_arg), target(&target_type_arg) - { - } - - const std::type_info &source_type() const - { - return *source; - } - const std::type_info &target_type() const - { - return *target; - } - -#ifndef BOOST_NO_CXX11_NOEXCEPT - virtual const char *what() const noexcept -#else - virtual const char *what() const throw() -#endif - { + virtual const char *what() const BOOST_NOEXCEPT_OR_NOTHROW { return "bad lexical cast: " "source type value could not be interpreted as target"; } -#ifndef BOOST_NO_CXX11_NOEXCEPT - virtual ~bad_lexical_cast() BOOST_NOEXCEPT -#else - virtual ~bad_lexical_cast() throw() -#endif + virtual ~bad_lexical_cast() BOOST_NOEXCEPT_OR_NOTHROW {} + +#ifndef BOOST_NO_TYPEID + bad_lexical_cast( + const std::type_info &source_type_arg, + const std::type_info &target_type_arg) BOOST_NOEXCEPT + : source(&source_type_arg), target(&target_type_arg) + {} + + const std::type_info &source_type() const BOOST_NOEXCEPT { + return *source; + } + + const std::type_info &target_type() const BOOST_NOEXCEPT { + return *target; + } + private: const std::type_info *source; const std::type_info *target; +#endif }; namespace detail // widest_char @@ -146,7 +135,7 @@ namespace boost } } // namespace boost -#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__SUNPRO_CC) && !defined(__PGIC__) +#if !defined(__SUNPRO_CC) && !defined(__PGIC__) #include #include @@ -169,17 +158,19 @@ namespace boost #include #include #include +#include +#include #ifndef BOOST_NO_CWCHAR # include #endif namespace boost { - namespace detail // is_char_or_wchar<...> + namespace detail // is_character<...> { // returns true, if T is one of the character types template < typename T > - struct is_char_or_wchar + struct is_character { typedef boost::type_traits::ice_or< boost::is_same< T, char >::value, @@ -236,35 +227,35 @@ namespace boost { // Executed on Stage 1 (See deduce_source_char and deduce_target_char) template < typename Type > struct stream_char_common: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Type >::value, + boost::detail::is_character< Type >::value, Type, boost::detail::deduce_character_type_later< Type > > {}; template < typename Char > struct stream_char_common< Char* >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< Char* > > {}; template < typename Char > struct stream_char_common< const Char* >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< const Char* > > {}; template < typename Char > struct stream_char_common< boost::iterator_range< Char* > >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::iterator_range< Char* > > > {}; template < typename Char > struct stream_char_common< boost::iterator_range< const Char* > >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > > > {}; @@ -283,14 +274,14 @@ namespace boost { template < typename Char, std::size_t N > struct stream_char_common< boost::array< Char, N > >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::array< Char, N > > > {}; template < typename Char, std::size_t N > struct stream_char_common< boost::array< const Char, N > >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::array< const Char, N > > > {}; @@ -298,14 +289,14 @@ namespace boost { #ifndef BOOST_NO_CXX11_HDR_ARRAY template < typename Char, std::size_t N > struct stream_char_common< std::array >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< std::array< Char, N > > > {}; template < typename Char, std::size_t N > struct stream_char_common< std::array< const Char, N > >: public boost::mpl::if_c< - boost::detail::is_char_or_wchar< Char >::value, + boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< std::array< const Char, N > > > {}; @@ -427,86 +418,29 @@ namespace boost { }; } - namespace detail // deduce_char_traits template + namespace detail // extract_char_traits template { - // We are attempting to get char_traits<> from Source or Tagret + // We are attempting to get char_traits<> from T // template parameter. Otherwise we'll be using std::char_traits - template < class Char, class Target, class Source > - struct deduce_char_traits + template < class Char, class T > + struct extract_char_traits + : boost::false_type { - typedef std::char_traits< Char > type; + typedef std::char_traits< Char > trait_t; }; - template < class Char, class Traits, class Alloc, class Source > - struct deduce_char_traits< Char - , std::basic_string< Char, Traits, Alloc > - , Source - > + template < class Char, class Traits, class Alloc > + struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > > + : boost::true_type { - typedef Traits type; + typedef Traits trait_t; }; - template < class Char, class Target, class Traits, class Alloc > - struct deduce_char_traits< Char - , Target - , std::basic_string< Char, Traits, Alloc > - > + template < class Char, class Traits, class Alloc> + struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > > + : boost::true_type { - typedef Traits type; - }; - - template < class Char, class Traits, class Alloc, class Source > - struct deduce_char_traits< Char - , boost::container::basic_string< Char, Traits, Alloc > - , Source - > - { - typedef Traits type; - }; - - template < class Char, class Target, class Traits, class Alloc > - struct deduce_char_traits< Char - , Target - , boost::container::basic_string< Char, Traits, Alloc > - > - { - typedef Traits type; - }; - - template < class Char, class Traits, class Alloc1, class Alloc2 > - struct deduce_char_traits< Char - , std::basic_string< Char, Traits, Alloc1 > - , std::basic_string< Char, Traits, Alloc2 > - > - { - typedef Traits type; - }; - - template - struct deduce_char_traits< Char - , boost::container::basic_string< Char, Traits, Alloc1 > - , boost::container::basic_string< Char, Traits, Alloc2 > - > - { - typedef Traits type; - }; - - template < class Char, class Traits, class Alloc1, class Alloc2 > - struct deduce_char_traits< Char - , boost::container::basic_string< Char, Traits, Alloc1 > - , std::basic_string< Char, Traits, Alloc2 > - > - { - typedef Traits type; - }; - - template < class Char, class Traits, class Alloc1, class Alloc2 > - struct deduce_char_traits< Char - , std::basic_string< Char, Traits, Alloc1 > - , boost::container::basic_string< Char, Traits, Alloc2 > - > - { - typedef Traits type; + typedef Traits trait_t; }; } @@ -552,14 +486,12 @@ namespace boost { namespace detail // lcast_src_length { // Return max. length of string representation of Source; - template< class Source // Source type of lexical_cast. + template< class Source, // Source type of lexical_cast. + class Enable = void // helper type > struct lcast_src_length { BOOST_STATIC_CONSTANT(std::size_t, value = 1); - // To check coverage, build the test with - // bjam --v2 profile optimization=off - static void check_coverage() {} }; // Helper for integral types. @@ -575,8 +507,10 @@ namespace boost { // 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 lcast_src_length_integral + template + struct lcast_src_length< + Source, BOOST_DEDUCED_TYPENAME boost::enable_if >::type + > { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_CONSTANT(std::size_t, value = @@ -590,31 +524,6 @@ namespace boost { #endif }; -#define BOOST_LCAST_DEF(T) \ - template<> struct lcast_src_length \ - : lcast_src_length_integral \ - { static void check_coverage() {} }; - - BOOST_LCAST_DEF(short) - BOOST_LCAST_DEF(unsigned short) - BOOST_LCAST_DEF(int) - BOOST_LCAST_DEF(unsigned int) - BOOST_LCAST_DEF(long) - BOOST_LCAST_DEF(unsigned long) -#if defined(BOOST_HAS_LONG_LONG) - BOOST_LCAST_DEF(boost::ulong_long_type) - BOOST_LCAST_DEF(boost::long_long_type ) -#elif defined(BOOST_HAS_MS_INT64) - BOOST_LCAST_DEF(unsigned __int64) - BOOST_LCAST_DEF( __int64) -#endif -#ifdef BOOST_HAS_INT128 - BOOST_LCAST_DEF(boost::int128_type) - BOOST_LCAST_DEF(boost::uint128_type) -#endif - -#undef BOOST_LCAST_DEF - #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION // Helper for floating point types. // -1.23456789e-123456 @@ -627,38 +536,19 @@ namespace boost { // ^^^^^^ exponent (assumed 6 or less digits) // sign + leading digit + decimal point + "e" + exponent sign == 5 template - struct lcast_src_length_floating + struct lcast_src_length< + Source, BOOST_DEDUCED_TYPENAME boost::enable_if >::type + > { BOOST_STATIC_ASSERT( std::numeric_limits::max_exponent10 <= 999999L && std::numeric_limits::min_exponent10 >= -999999L ); + BOOST_STATIC_CONSTANT(std::size_t, value = 5 + lcast_precision::value + 6 ); }; - - template<> - struct lcast_src_length - : lcast_src_length_floating - { - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - : lcast_src_length_floating - { - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - : lcast_src_length_floating - { - static void check_coverage() {} - }; - #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION } @@ -688,22 +578,24 @@ namespace boost { "Your compiler does not have full support for char32_t" ); #endif - typedef BOOST_DEDUCED_TYPENAME boost::detail::deduce_char_traits< - char_type, Target, no_cv_src - >::type traits; + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + boost::detail::extract_char_traits::value, + BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits, + BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits + >::type::trait_t traits; typedef boost::type_traits::ice_and< boost::is_same::value, // source is not a wide character based type boost::type_traits::ice_ne::value, // target type is based on wide character boost::type_traits::ice_not< - boost::detail::is_char_or_wchar::value // single character widening is optimized + boost::detail::is_character::value // single character widening is optimized >::value // and does not requires stringbuffer > is_string_widening_required_t; typedef boost::type_traits::ice_not< boost::type_traits::ice_or< boost::is_integral::value, boost::detail::is_this_float_conversion_optimized::value, - boost::detail::is_char_or_wchar< + boost::detail::is_character< BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::stage1_type // if we did not get character type at stage1 >::value // then we have no optimization for that type >::value > is_source_input_not_optimized_t; @@ -720,66 +612,26 @@ namespace boost { }; } - namespace detail // '0', '+' and '-' constants + namespace detail // '0', '-', '+', 'e', 'E' and '.' constants { - template < typename Char > struct lcast_char_constants; - - template<> - struct lcast_char_constants - { - 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 = '.'); + template < typename Char > + struct lcast_char_constants { + // We check in tests assumption that static casted character is + // equal to correctly written C++ literal: U'0' == static_cast('0') + BOOST_STATIC_CONSTANT(Char, zero = static_cast('0')); + BOOST_STATIC_CONSTANT(Char, minus = static_cast('-')); + BOOST_STATIC_CONSTANT(Char, plus = static_cast('+')); + BOOST_STATIC_CONSTANT(Char, lowercase_e = static_cast('e')); + BOOST_STATIC_CONSTANT(Char, capital_e = static_cast('E')); + BOOST_STATIC_CONSTANT(Char, c_decimal_separator = static_cast('.')); }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_char_constants - { - 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 - -#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) - template<> - struct lcast_char_constants - { - BOOST_STATIC_CONSTANT(char16_t, zero = u'0'); - BOOST_STATIC_CONSTANT(char16_t, minus = u'-'); - BOOST_STATIC_CONSTANT(char16_t, plus = u'+'); - BOOST_STATIC_CONSTANT(char16_t, lowercase_e = u'e'); - BOOST_STATIC_CONSTANT(char16_t, capital_e = u'E'); - BOOST_STATIC_CONSTANT(char16_t, c_decimal_separator = u'.'); - }; -#endif - -#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) - template<> - struct lcast_char_constants - { - BOOST_STATIC_CONSTANT(char32_t, zero = U'0'); - BOOST_STATIC_CONSTANT(char32_t, minus = U'-'); - BOOST_STATIC_CONSTANT(char32_t, plus = U'+'); - BOOST_STATIC_CONSTANT(char32_t, lowercase_e = U'e'); - BOOST_STATIC_CONSTANT(char32_t, capital_e = U'E'); - BOOST_STATIC_CONSTANT(char32_t, c_decimal_separator = U'.'); - }; -#endif } namespace detail // lcast_to_unsigned { template inline - BOOST_DEDUCED_TYPENAME make_unsigned::type lcast_to_unsigned(T value) BOOST_NOEXCEPT + BOOST_DEDUCED_TYPENAME boost::make_unsigned::type lcast_to_unsigned(const T value) BOOST_NOEXCEPT { typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned::type result_type; return static_cast( @@ -790,114 +642,137 @@ namespace boost { namespace detail // lcast_put_unsigned { - template - CharT* lcast_put_unsigned(const T n_param, CharT* finish) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); -#endif - - typedef typename Traits::int_type int_type; - CharT const czero = lcast_char_constants::zero; - int_type const zero = Traits::to_int_type(czero); + template + class lcast_put_unsigned: boost::noncopyable { + typedef BOOST_DEDUCED_TYPENAME Traits::int_type int_type; BOOST_DEDUCED_TYPENAME boost::mpl::if_c< (sizeof(int_type) > sizeof(T)) , int_type , T - >::type n = n_param; + >::type m_value; + CharT* m_finish; + CharT const m_czero; + int_type const m_zero; + public: + lcast_put_unsigned(const T n_param, CharT* finish) BOOST_NOEXCEPT + : m_value(n_param), m_finish(finish) + , m_czero(lcast_char_constants::zero), m_zero(Traits::to_int_type(m_czero)) + { +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); +#endif + } + + CharT* convert() { #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - std::locale loc; - if (loc != std::locale::classic()) { + std::locale loc; + if (loc == std::locale::classic()) { + return main_convert_loop(); + } + 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(); - if ( grouping_size && grouping[0] > 0 ) - { + if (!grouping_size || grouping[0] <= 0) { + return main_convert_loop(); + } #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS // Check that ulimited group is unreachable: BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); #endif - CharT thousands_sep = np.thousands_sep(); - std::string::size_type group = 0; // current group number - char last_grp_size = grouping[0]; - char left = last_grp_size; + CharT const thousands_sep = np.thousands_sep(); + std::string::size_type group = 0; // current group number + char last_grp_size = grouping[0]; + char left = last_grp_size; - do - { - if(left == 0) - { - ++group; - if(group < grouping_size) - { - char const grp_size = grouping[group]; - last_grp_size = grp_size <= 0 ? static_cast(CHAR_MAX) : grp_size; - } - - left = last_grp_size; - --finish; - Traits::assign(*finish, thousands_sep); + do { + if (left == 0) { + ++group; + if (group < grouping_size) { + char const grp_size = grouping[group]; + last_grp_size = (grp_size <= 0 ? static_cast(CHAR_MAX) : grp_size); } - --left; + left = last_grp_size; + --m_finish; + Traits::assign(*m_finish, thousands_sep); + } - --finish; - int_type const digit = static_cast(n % 10U); - Traits::assign(*finish, Traits::to_char_type(zero + digit)); - n /= 10; - } while(n); - return finish; - } - } + --left; + } while (main_convert_itaration()); + + return m_finish; +#else + return main_convert_loop(); #endif - { - do - { - --finish; - int_type const digit = static_cast(n % 10U); - Traits::assign(*finish, Traits::to_char_type(zero + digit)); - n /= 10; - } while(n); } - return finish; - } + private: + inline bool main_convert_itaration() BOOST_NOEXCEPT { + --m_finish; + int_type const digit = static_cast(m_value % 10U); + Traits::assign(*m_finish, Traits::to_char_type(m_zero + digit)); + m_value /= 10; + return !!m_value; // supressing warnings + } + + inline CharT* main_convert_loop() BOOST_NOEXCEPT { + while (main_convert_itaration()); + return m_finish; + } + }; } namespace detail // lcast_ret_unsigned { - template - inline bool lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) - { + template + class lcast_ret_unsigned: boost::noncopyable { + bool m_multiplier_overflowed; + T m_multiplier; + T& m_value; + const CharT* const m_begin; + const CharT* m_end; + + public: + lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) BOOST_NOEXCEPT + : m_multiplier_overflowed(false), m_multiplier(1), m_value(value), m_begin(begin), m_end(end) + { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); + BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); - // GCC when used with flag -std=c++0x may not have std::numeric_limits - // specializations for __int128 and unsigned __int128 types. - // Try compilation with -std=gnu++0x or -std=gnu++11. - // - // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40856 - BOOST_STATIC_ASSERT_MSG(std::numeric_limits::is_specialized, - "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast" - ); + // GCC when used with flag -std=c++0x may not have std::numeric_limits + // specializations for __int128 and unsigned __int128 types. + // Try compilation with -std=gnu++0x or -std=gnu++11. + // + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40856 + BOOST_STATIC_ASSERT_MSG(std::numeric_limits::is_specialized, + "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast" + ); #endif - CharT const czero = lcast_char_constants::zero; - --end; - value = 0; + } - if (begin > end || *end < czero || *end >= czero + 10) - return false; - value = static_cast(*end - czero); - --end; - T multiplier = 1; - bool multiplier_overflowed = false; + inline bool convert() { + CharT const czero = lcast_char_constants::zero; + --m_end; + m_value = static_cast(0); + + if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10) + return false; + m_value = static_cast(*m_end - czero); + --m_end; + +#ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + return main_convert_loop(); +#else + std::locale loc; + if (loc == std::locale::classic()) { + return main_convert_loop(); + } -#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - std::locale loc; - if (loc != std::locale::classic()) { typedef std::numpunct numpunct; numpunct const& np = BOOST_USE_FACET(numpunct, loc); std::string const& grouping = np.grouping(); @@ -906,85 +781,86 @@ namespace boost { /* According to Programming languages - C++ * we MUST check for correct grouping */ - if (grouping_size && grouping[0] > 0) + if (!grouping_size || grouping[0] <= 0) { + return main_convert_loop(); + } + + unsigned char current_grouping = 0; + CharT const thousands_sep = np.thousands_sep(); + char remained = static_cast(grouping[current_grouping] - 1); + + for (;m_end >= m_begin; --m_end) { - unsigned char current_grouping = 0; - CharT const thousands_sep = np.thousands_sep(); - char remained = static_cast(grouping[current_grouping] - 1); - bool shall_we_return = true; - - for(;end>=begin; --end) - { - if (remained) { - T const multiplier_10 = static_cast(multiplier * 10); - if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true; - - T const dig_value = static_cast(*end - czero); - T const new_sub_value = static_cast(multiplier_10 * dig_value); - - if (*end < czero || *end >= czero + 10 - /* detecting overflow */ - || (dig_value && new_sub_value / dig_value != multiplier_10) - || static_cast((std::numeric_limits::max)()-new_sub_value) < value - || (multiplier_overflowed && dig_value) - ) - return false; - - value = static_cast(value + new_sub_value); - multiplier = static_cast(multiplier * 10); - --remained; + if (remained) { + if (!main_convert_itaration()) { + return false; + } + --remained; + } else { + if ( !Traits::eq(*m_end, thousands_sep) ) //|| begin == end ) return false; + { + /* + * According to Programming languages - C++ + * Digit grouping is checked. That is, the positions of discarded + * separators is examined for consistency with + * use_facet >(loc ).grouping() + * + * BUT what if there is no separators at all and grouping() + * is not empty? Well, we have no extraced separators, so we + * won`t check them for consistency. This will allow us to + * work with "C" locale from other locales + */ + return main_convert_loop(); } else { - if ( !Traits::eq(*end, thousands_sep) ) //|| begin == end ) return false; - { - /* - * According to Programming languages - C++ - * Digit grouping is checked. That is, the positions of discarded - * separators is examined for consistency with - * use_facet >(loc ).grouping() - * - * BUT what if there is no separators at all and grouping() - * is not empty? Well, we have no extraced separators, so we - * won`t check them for consistency. This will allow us to - * work with "C" locale from other locales - */ - shall_we_return = false; - break; - } else { - if ( begin == end ) return false; - if (current_grouping < grouping_size-1 ) ++current_grouping; - remained = grouping[current_grouping]; - } + if (m_begin == m_end) return false; + if (current_grouping < grouping_size - 1) ++current_grouping; + remained = grouping[current_grouping]; } } + } /*for*/ - if (shall_we_return) return true; - } - } + return true; #endif - { - while ( begin <= end ) - { - T const multiplier_10 = static_cast(multiplier * 10); - if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true; - - T const dig_value = static_cast(*end - czero); - T const new_sub_value = static_cast(multiplier_10 * dig_value); - - if (*end < czero || *end >= czero + 10 - /* detecting overflow */ - || (dig_value && new_sub_value / dig_value != multiplier_10) - || static_cast((std::numeric_limits::max)()-new_sub_value) < value - || (multiplier_overflowed && dig_value) - ) - return false; - - value = static_cast(value + new_sub_value); - multiplier = static_cast(multiplier * 10); - --end; - } } - return true; - } + + private: + // Iteration that does not care about grouping/separators and assumes that all + // input characters are digits + inline bool main_convert_itaration() BOOST_NOEXCEPT { + CharT const czero = lcast_char_constants::zero; + T const maxv = (std::numeric_limits::max)(); + + m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier); + m_multiplier = static_cast(m_multiplier * 10); + + T const dig_value = static_cast(*m_end - czero); + T const new_sub_value = static_cast(m_multiplier * dig_value); + + // We must correctly handle situations like `000000000000000000000000000001`. + // So we take care of overflow only if `dig_value` is not '0'. + if (*m_end < czero || *m_end >= czero + 10 // checking for correct digit + || (dig_value && ( // checking for overflow of ... + m_multiplier_overflowed // ... multiplier + || static_cast(maxv / dig_value) < m_multiplier // ... subvalue + || static_cast(maxv - new_sub_value) < m_value // ... whole expression + )) + ) return false; + + m_value = static_cast(m_value + new_sub_value); + + return true; + } + + bool main_convert_loop() BOOST_NOEXCEPT { + for ( ; m_end >= m_begin; --m_end) { + if (!main_convert_itaration()) { + return false; + } + } + + return true; + } + }; } namespace detail @@ -1009,42 +885,37 @@ namespace boost { if (begin == end) return false; const CharT minus = lcast_char_constants::minus; const CharT plus = lcast_char_constants::plus; - const int inifinity_size = 8; + const int inifinity_size = 8; // == sizeof("infinity") - 1 - bool has_minus = false; /* Parsing +/- */ - if( *begin == minus) - { + bool const has_minus = (*begin == minus); + if (has_minus || *begin == plus) { ++ begin; - has_minus = true; } - else if( *begin == plus ) ++begin; - if( end-begin < 3 ) return false; - if( lc_iequal(begin, lc_nan, lc_NAN, 3) ) - { + if (end - begin < 3) return false; + if (lc_iequal(begin, lc_nan, lc_NAN, 3)) { begin += 3; - if (end != begin) /* It is 'nan(...)' or some bad input*/ - { - if(end-begin<2) return false; // bad input + 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 (*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 - && - lc_iequal(begin, lc_infinity, lc_INFINITY, 3) + } else if ( + ( /* 'INF' or 'inf' */ + end - begin == 3 // 3 == sizeof('inf') - 1 + && lc_iequal(begin, lc_infinity, lc_INFINITY, 3) ) || ( /* 'INFINITY' or 'infinity' */ - end-begin==inifinity_size - && - lc_iequal(begin, lc_infinity, lc_INFINITY, inifinity_size) + end - begin == inifinity_size + && lc_iequal(begin, lc_infinity, lc_INFINITY, inifinity_size) ) ) { @@ -1063,10 +934,8 @@ namespace boost { { using namespace std; const CharT minus = lcast_char_constants::minus; - if ( (boost::math::isnan)(value) ) - { - if ( (boost::math::signbit)(value) ) - { + if ((boost::math::isnan)(value)) { + if ((boost::math::signbit)(value)) { *begin = minus; ++ begin; } @@ -1074,10 +943,8 @@ namespace boost { memcpy(begin, lc_nan, 3 * sizeof(CharT)); end = begin + 3; return true; - } else if ( (boost::math::isinf)(value) ) - { - if ( (boost::math::signbit)(value) ) - { + } else if ((boost::math::isinf)(value)) { + if ((boost::math::signbit)(value)) { *begin = minus; ++ begin; } @@ -1093,8 +960,7 @@ namespace boost { #ifndef BOOST_LCAST_NO_WCHAR_T template - bool parse_inf_nan(const wchar_t* begin, const wchar_t* end, T& value) BOOST_NOEXCEPT - { + bool parse_inf_nan(const wchar_t* begin, const wchar_t* end, T& value) BOOST_NOEXCEPT { return parse_inf_nan_impl(begin, end, value , L"NAN", L"nan" , L"INFINITY", L"infinity" @@ -1102,16 +968,14 @@ namespace boost { } template - bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value) BOOST_NOEXCEPT - { + bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value) BOOST_NOEXCEPT { return put_inf_nan_impl(begin, end, value, L"nan", L"infinity"); } #endif #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) template - bool parse_inf_nan(const char16_t* begin, const char16_t* end, T& value) BOOST_NOEXCEPT - { + bool parse_inf_nan(const char16_t* begin, const char16_t* end, T& value) BOOST_NOEXCEPT { return parse_inf_nan_impl(begin, end, value , u"NAN", u"nan" , u"INFINITY", u"infinity" @@ -1119,15 +983,13 @@ namespace boost { } template - bool put_inf_nan(char16_t* begin, char16_t*& end, const T& value) BOOST_NOEXCEPT - { + bool put_inf_nan(char16_t* begin, char16_t*& end, const T& value) BOOST_NOEXCEPT { return put_inf_nan_impl(begin, end, value, u"nan", u"infinity"); } #endif #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) template - bool parse_inf_nan(const char32_t* begin, const char32_t* end, T& value) BOOST_NOEXCEPT - { + bool parse_inf_nan(const char32_t* begin, const char32_t* end, T& value) BOOST_NOEXCEPT { return parse_inf_nan_impl(begin, end, value , U"NAN", U"nan" , U"INFINITY", U"infinity" @@ -1135,15 +997,13 @@ namespace boost { } template - bool put_inf_nan(char32_t* begin, char32_t*& end, const T& value) BOOST_NOEXCEPT - { + bool put_inf_nan(char32_t* begin, char32_t*& end, const T& value) BOOST_NOEXCEPT { return put_inf_nan_impl(begin, end, value, U"nan", U"infinity"); } #endif template - bool parse_inf_nan(const CharT* begin, const CharT* end, T& value) BOOST_NOEXCEPT - { + bool parse_inf_nan(const CharT* begin, const CharT* end, T& value) BOOST_NOEXCEPT { return parse_inf_nan_impl(begin, end, value , "NAN", "nan" , "INFINITY", "infinity" @@ -1151,8 +1011,7 @@ namespace boost { } template - bool put_inf_nan(CharT* begin, CharT*& end, const T& value) BOOST_NOEXCEPT - { + bool put_inf_nan(CharT* begin, CharT*& end, const T& value) BOOST_NOEXCEPT { return put_inf_nan_impl(begin, end, value, "nan", "infinity"); } } @@ -1193,8 +1052,27 @@ namespace boost { }; template - inline bool lcast_ret_float(T& value, const CharT* begin, const CharT* end) + inline bool lcast_ret_float(T& value, const CharT* begin, const CharT* const end) { + value = static_cast(0); + if (begin == end) return false; + if (parse_inf_nan(begin, end, value)) return true; + + 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; + + typedef BOOST_DEDUCED_TYPENAME Traits::int_type int_type; + int_type const zero = Traits::to_int_type(czero); + + /* Getting the plus/minus sign */ + bool const has_minus = Traits::eq(*begin, minus); + if (has_minus || Traits::eq(*begin, plus)) { + ++ begin; + if (begin == end) return false; + } #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; @@ -1214,52 +1092,25 @@ namespace boost { 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 = static_cast(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; - typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type::wide_result_t wide_result_t; - int_type const zero = Traits::to_int_type(czero); - if (begin == end) return false; - - /* Getting the plus/minus sign */ - bool has_minus = false; - if (Traits::eq(*begin, minus) ) { - ++ begin; - has_minus = true; - if (begin == end) return false; - } else if (Traits::eq(*begin, plus) ) { - ++begin; - if (begin == end) return false; - } - bool found_decimal = false; bool found_number_before_exp = false; - int pow_of_10 = 0; + typedef int pow_of_10_t; + pow_of_10_t pow_of_10 = 0; + + typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type::type mantissa_type; mantissa_type mantissa=0; bool is_mantissa_full = false; - char length_since_last_delim = 0; - while ( begin != end ) - { + while (begin != end) { if (found_decimal) { /* We allow no thousand_separators after decimal point */ - mantissa_type tmp_mantissa = mantissa * 10u; + const mantissa_type tmp_sub_value = static_cast(*begin - zero); if (Traits::eq(*begin, lowercase_e) || Traits::eq(*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 + || ((std::numeric_limits::max)() - tmp_sub_value) / 10u < mantissa ) { is_mantissa_full = true; ++ begin; @@ -1267,8 +1118,7 @@ namespace boost { } -- pow_of_10; - mantissa = tmp_mantissa; - mantissa += *begin - zero; + mantissa = static_cast(mantissa * 10 + tmp_sub_value); found_number_before_exp = true; } else { @@ -1278,18 +1128,15 @@ namespace boost { /* 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 + const mantissa_type tmp_sub_value = static_cast(*begin - zero); + if( is_mantissa_full + || ((std::numeric_limits::max)() - tmp_sub_value) / 10u < mantissa ) - { - mantissa = tmp_mantissa; - mantissa += *begin - zero; - } else { is_mantissa_full = true; ++ pow_of_10; + } else { + mantissa = static_cast(mantissa * 10 + tmp_sub_value); } found_number_before_exp = true; @@ -1312,12 +1159,12 @@ namespace boost { ) return false; #endif - if(Traits::eq(*begin, decimal_point)) { + if (Traits::eq(*begin, decimal_point)) { ++ begin; found_decimal = true; if (!found_number_before_exp && begin==end) return false; continue; - }else { + } else { if (!found_number_before_exp) return false; break; } @@ -1365,52 +1212,48 @@ namespace boost { } // Exponent found - if ( begin != end && (Traits::eq(*begin, lowercase_e) || Traits::eq(*begin, capital_e)) ) { + if (begin != end && (Traits::eq(*begin, lowercase_e) || Traits::eq(*begin, capital_e))) { ++ begin; - if ( begin == end ) return false; + if (begin == end) return false; - bool exp_has_minus = false; - if(Traits::eq(*begin, minus)) { - exp_has_minus = true; + bool const exp_has_minus = Traits::eq(*begin, minus); + if (exp_has_minus || Traits::eq(*begin, plus)) { ++ begin; - if ( begin == end ) return false; - } else if (Traits::eq(*begin, plus)) { - ++ begin; - if ( begin == end ) return false; + 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*/ + pow_of_10_t exp_pow_of_10 = 0; + while (begin != end) { + pow_of_10_t const sub_value = *begin - zero; + + if ( *begin < czero || *begin >= czero + 10 + || ((std::numeric_limits::max)() - sub_value) / 10 < exp_pow_of_10) return false; exp_pow_of_10 *= 10; - exp_pow_of_10 += *begin - zero; + exp_pow_of_10 += sub_value; ++ 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; - } + if (exp_has_minus) { + if ((std::numeric_limits::min)() + exp_pow_of_10 > pow_of_10) + return false; // failed overflow check + pow_of_10 -= exp_pow_of_10; + } else { + if ((std::numeric_limits::max)() - exp_pow_of_10 < pow_of_10) + return false; // failed overflow check + 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)). */ + typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type::wide_result_t wide_result_t; const wide_result_t result = std::pow(static_cast(10.0), 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; + return !((boost::math::isinf)(value) || (boost::math::isnan)(value)); } // Unsilence buggy MS warnings like C4244: '+=' : conversion from 'int' to 'unsigned short', possible loss of data #if defined(_MSC_VER) && (_MSC_VER == 1400) @@ -1418,158 +1261,107 @@ namespace boost { #endif } - namespace detail // parser_buf + namespace detail // basic_unlockedbuf { - // - // class parser_buf: // acts as a stream buffer which wraps around a pair of pointers - // - // This class is copied (and slightly changed) from - // boost/regex/v4/cpp_regex_traits.hpp - // Thanks John Maddock for it! (previous version had some - // problems with libc++ and some other STL implementations) - template - class parser_buf : public BufferType { - typedef BufferType base_type; - typedef typename base_type::int_type int_type; - typedef typename base_type::char_type char_type; - typedef typename base_type::pos_type pos_type; - typedef ::std::streamsize streamsize; - typedef typename base_type::off_type off_type; - + // and gives acces to internals + template + class basic_unlockedbuf : public basic_pointerbuf { public: - parser_buf() : base_type() { setbuf(0, 0); } - const charT* getnext() { return this->gptr(); } + typedef basic_pointerbuf base_type; + typedef BOOST_DEDUCED_TYPENAME base_type::streamsize streamsize; + #ifndef BOOST_NO_USING_TEMPLATE using base_type::pptr; using base_type::pbase; + using base_type::setbuf; #else charT* pptr() const { return base_type::pptr(); } charT* pbase() const { return base_type::pbase(); } + BufferType* setbuf(char_type* s, streamsize n) { return base_type::setbuf(s, n); } #endif - base_type* setbuf(char_type* s, streamsize n) { - this->setg(s, s, s + n); - return this; - } - - pos_type seekpos(pos_type sp, ::std::ios_base::openmode which) { - if(which & ::std::ios_base::out) - return pos_type(off_type(-1)); - off_type size = static_cast(this->egptr() - this->eback()); - charT* g = this->eback(); - if(off_type(sp) <= size) - { - this->setg(g, g + off_type(sp), g + size); - } - return pos_type(off_type(-1)); - } - - pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) { - typedef typename boost::int_t::least cast_type; - - if(which & ::std::ios_base::out) - return pos_type(off_type(-1)); - std::ptrdiff_t size = this->egptr() - this->eback(); - std::ptrdiff_t pos = this->gptr() - this->eback(); - charT* g = this->eback(); - switch(static_cast(way)) - { - case ::std::ios_base::beg: - if((off < 0) || (off > size)) - return pos_type(off_type(-1)); - else - this->setg(g, g + off, g + size); - break; - case ::std::ios_base::end: - if((off < 0) || (off > size)) - return pos_type(off_type(-1)); - else - this->setg(g, g + size - off, g + size); - break; - case ::std::ios_base::cur: - { - std::ptrdiff_t newpos = static_cast(pos + off); - if((newpos < 0) || (newpos > size)) - return pos_type(off_type(-1)); - else - this->setg(g, g + newpos, g + size); - break; - } - default: ; - } -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4244) -#endif - return static_cast(this->gptr() - this->eback()); -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - } - private: - parser_buf& operator=(const parser_buf&); - parser_buf(const parser_buf&); }; } namespace detail { struct do_not_construct_out_stream_t{}; + + template + struct out_stream_helper_trait { +#if defined(BOOST_NO_STRINGSTREAM) + typedef std::ostrstream out_stream_t; + typedef void buffer_t; +#elif defined(BOOST_NO_STD_LOCALE) + typedef std::ostringstream out_stream_t; + typedef basic_unlockedbuf buffer_t; +#else + typedef std::basic_ostringstream + out_stream_t; + typedef basic_unlockedbuf, CharT> + buffer_t; +#endif + }; } - namespace detail // optimized stream wrapper + namespace detail // optimized stream wrappers { - // String representation of Source has an upper limit. template< class CharT // a result of widest_char transformation - , class Traits // usually char_traits + , class Traits , bool RequiresStringbuffer + , std::size_t CharacterBufferSize > - class lexical_stream_limited_src - { + class lexical_istream_limited_src: boost::noncopyable { + typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait::buffer_t + buffer_t; -#if defined(BOOST_NO_STRINGSTREAM) - typedef std::ostrstream out_stream_t; -#elif defined(BOOST_NO_STD_LOCALE) - typedef std::ostringstream out_stream_t; - typedef parser_buf buffer_t; -#else - typedef std::basic_ostringstream out_stream_t; - typedef parser_buf, CharT> buffer_t; -#endif + typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait::out_stream_t + out_stream_t; + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< RequiresStringbuffer, out_stream_t, do_not_construct_out_stream_t >::type deduced_out_stream_t; - // A string representation of Source is written to [start, finish). - CharT* start; - CharT* finish; + // A string representation of Source is written to `buffer`. deduced_out_stream_t out_stream; + CharT buffer[CharacterBufferSize]; + + // After the `operator <<` finishes, `[start, finish)` is + // the range to output by `operator >>` + const CharT* start; + const CharT* finish; public: - lexical_stream_limited_src(CharT* sta, CharT* fin) BOOST_NOEXCEPT - : start(sta) - , finish(fin) + lexical_istream_limited_src() BOOST_NOEXCEPT + : start(buffer) + , finish(buffer + CharacterBufferSize) {} + + const CharT* cbegin() const BOOST_NOEXCEPT { + return start; + } + + const CharT* cend() const BOOST_NOEXCEPT { + return finish; + } private: // Undefined: - lexical_stream_limited_src(lexical_stream_limited_src const&); - void operator=(lexical_stream_limited_src const&); + lexical_istream_limited_src(lexical_istream_limited_src const&); + void operator=(lexical_istream_limited_src const&); /************************************ HELPER FUNCTIONS FOR OPERATORS << ( ... ) ********************************/ - bool shl_char(CharT ch) BOOST_NOEXCEPT - { - Traits::assign(*start, ch); + bool shl_char(CharT ch) BOOST_NOEXCEPT { + Traits::assign(buffer[0], ch); finish = start + 1; return true; } #ifndef BOOST_LCAST_NO_WCHAR_T template - bool shl_char(T ch) - { + bool shl_char(T ch) { BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)) , "boost::lexical_cast does not support narrowing of char types." "Use boost::locale instead" ); @@ -1579,38 +1371,34 @@ namespace boost { #else CharT const w = static_cast(ch); #endif - Traits::assign(*start, w); + Traits::assign(buffer[0], w); finish = start + 1; return true; } #endif - bool shl_char_array(CharT const* str) BOOST_NOEXCEPT - { - start = const_cast(str); + bool shl_char_array(CharT const* str) BOOST_NOEXCEPT { + start = str; finish = start + Traits::length(str); return true; } template - bool shl_char_array(T const* str) - { + bool shl_char_array(T const* str) { BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)), "boost::lexical_cast does not support narrowing of char types." "Use boost::locale instead" ); return shl_input_streamable(str); } - bool shl_char_array_limited(CharT const* str, std::size_t max_size) BOOST_NOEXCEPT - { - start = const_cast(str); + bool shl_char_array_limited(CharT const* str, std::size_t max_size) BOOST_NOEXCEPT { + start = str; finish = std::find(start, start + max_size, Traits::to_char_type(0)); return true; } template - bool shl_input_streamable(InputStreamable& input) - { + bool shl_input_streamable(InputStreamable& input) { #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) // If you have compilation error at this point, than your STL library // does not support such conversions. Try updating it. @@ -1636,167 +1424,156 @@ namespace boost { } template - inline bool shl_signed(T n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; + inline bool shl_unsigned(const T n) { + CharT* tmp_finish = buffer + CharacterBufferSize; + start = lcast_put_unsigned(n, tmp_finish).convert(); + finish = tmp_finish; + return true; + } + + template + inline bool shl_signed(const T n) { + CharT* tmp_finish = buffer + CharacterBufferSize; + typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned::type utype; + CharT* tmp_start = lcast_put_unsigned(lcast_to_unsigned(n), tmp_finish).convert(); + if (n < 0) { + --tmp_start; CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); + Traits::assign(*tmp_start, minus); } + start = tmp_start; + finish = tmp_finish; return true; } template - bool shl_real_type(const T& val, SomeCharT* begin, SomeCharT*& end) - { - if (put_inf_nan(begin, end, val)) return true; + bool shl_real_type(const T& val, SomeCharT* /*begin*/) { lcast_set_precision(out_stream, &val); return shl_input_streamable(val); } - static bool shl_real_type(float val, char* begin, char*& end) - { using namespace std; - if (put_inf_nan(begin, end, val)) return true; + bool shl_real_type(float val, char* begin) { + using namespace std; const double val_as_double = val; - end = begin + + finish = start + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) - sprintf_s(begin, end-begin, + sprintf_s(begin, CharacterBufferSize, #else sprintf(begin, #endif "%.*g", static_cast(boost::detail::lcast_get_precision()), val_as_double); - return end > begin; + return finish > start; } - static bool shl_real_type(double val, char* begin, char*& end) - { using namespace std; - if (put_inf_nan(begin, end, val)) return true; - end = begin + + bool shl_real_type(double val, char* begin) { + using namespace std; + finish = start + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) - sprintf_s(begin, end-begin, + sprintf_s(begin, CharacterBufferSize, #else sprintf(begin, #endif "%.*g", static_cast(boost::detail::lcast_get_precision()), val); - return end > begin; + return finish > start; } #ifndef __MINGW32__ - static bool shl_real_type(long double val, char* begin, char*& end) - { using namespace std; - if (put_inf_nan(begin, end, val)) return true; - end = begin + + bool shl_real_type(long double val, char* begin) { + using namespace std; + finish = start + #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) - sprintf_s(begin, end-begin, + sprintf_s(begin, CharacterBufferSize, #else sprintf(begin, #endif "%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); - return end > begin; + return finish > start; } #endif #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__) - static bool shl_real_type(float val, wchar_t* begin, wchar_t*& end) - { using namespace std; - if (put_inf_nan(begin, end, val)) return true; + bool shl_real_type(float val, wchar_t* begin) { + using namespace std; const double val_as_double = val; - end = begin + swprintf(begin, end-begin, + finish = start + swprintf(begin, CharacterBufferSize, L"%.*g", static_cast(boost::detail::lcast_get_precision()), val_as_double ); - return end > begin; + return finish > start; } - static bool shl_real_type(double val, wchar_t* begin, wchar_t*& end) - { using namespace std; - if (put_inf_nan(begin, end, val)) return true; - end = begin + swprintf(begin, end-begin, + bool shl_real_type(double val, wchar_t* begin) { + using namespace std; + finish = start + swprintf(begin, CharacterBufferSize, L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); - return end > begin; + return finish > start; } - static bool shl_real_type(long double val, wchar_t* begin, wchar_t*& end) - { using namespace std; - if (put_inf_nan(begin, end, val)) return true; - end = begin + swprintf(begin, end-begin, + bool shl_real_type(long double val, wchar_t* begin) { + using namespace std; + finish = start + swprintf(begin, CharacterBufferSize, L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); - return end > begin; + return finish > start; } #endif + template + bool shl_real(T val) { + CharT* tmp_finish = buffer + CharacterBufferSize; + if (put_inf_nan(buffer, tmp_finish, val)) { + finish = tmp_finish; + return true; + } + + return shl_real_type(val, static_cast(buffer)); + } /************************************ OPERATORS << ( ... ) ********************************/ public: template - bool operator<<(std::basic_string const& str) BOOST_NOEXCEPT - { - start = const_cast(str.data()); + bool operator<<(std::basic_string const& str) BOOST_NOEXCEPT { + start = str.data(); finish = start + str.length(); return true; } template - bool operator<<(boost::container::basic_string const& str) BOOST_NOEXCEPT - { - start = const_cast(str.data()); + bool operator<<(boost::container::basic_string const& str) BOOST_NOEXCEPT { + start = str.data(); finish = start + str.length(); return true; } - bool operator<<(bool value) BOOST_NOEXCEPT - { + bool operator<<(bool value) BOOST_NOEXCEPT { CharT const czero = lcast_char_constants::zero; - Traits::assign(*start, Traits::to_char_type(czero + value)); + Traits::assign(buffer[0], Traits::to_char_type(czero + value)); finish = start + 1; return true; } - bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT - { + template + BOOST_DEDUCED_TYPENAME boost::disable_if, bool>::type + operator<<(const iterator_range& rng) BOOST_NOEXCEPT { + return (*this) << iterator_range(rng.begin(), rng.end()); + } + + bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT { start = rng.begin(); finish = rng.end(); return true; } - - bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT - { - start = const_cast(rng.begin()); - finish = const_cast(rng.end()); - return true; - } - bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT - { - return (*this) << iterator_range( - const_cast(reinterpret_cast(rng.begin())), - const_cast(reinterpret_cast(rng.end())) + bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT { + return (*this) << iterator_range( + reinterpret_cast(rng.begin()), + reinterpret_cast(rng.end()) ); } - bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT - { - return (*this) << iterator_range( - const_cast(reinterpret_cast(rng.begin())), - const_cast(reinterpret_cast(rng.end())) - ); - } - - bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT - { - return (*this) << iterator_range( - reinterpret_cast(rng.begin()), - reinterpret_cast(rng.end()) - ); - } - - bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT - { - return (*this) << iterator_range( - reinterpret_cast(rng.begin()), - reinterpret_cast(rng.end()) + bool operator<<(const iterator_range& rng) BOOST_NOEXCEPT { + return (*this) << iterator_range( + reinterpret_cast(rng.begin()), + reinterpret_cast(rng.end()) ); } @@ -1829,114 +1606,103 @@ namespace boost { 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; } + bool operator<<(unsigned short n) { return shl_unsigned(n); } + bool operator<<(unsigned int n) { return shl_unsigned(n); } + bool operator<<(unsigned long n) { return shl_unsigned(n); } #if defined(BOOST_HAS_LONG_LONG) - bool operator<<(boost::ulong_long_type n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<(boost::ulong_long_type n) { return shl_unsigned(n); } bool operator<<(boost::long_long_type n) { return shl_signed(n); } #elif defined(BOOST_HAS_MS_INT64) - bool operator<<(unsigned __int64 n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<(unsigned __int64 n) { return shl_unsigned(n); } bool operator<<( __int64 n) { return shl_signed(n); } #endif #ifdef BOOST_HAS_INT128 - bool operator<<(const boost::uint128_type& n) { start = lcast_put_unsigned(n, finish); return true; } - bool operator<<(const boost::int128_type& n) { return shl_signed(n); } + bool operator<<(const boost::uint128_type& n) { return shl_unsigned(n); } + bool operator<<(const boost::int128_type& n) { return shl_signed(n); } #endif - - bool operator<<(float val) { return shl_real_type(val, start, finish); } - bool operator<<(double val) { return shl_real_type(val, start, finish); } + bool operator<<(float val) { return shl_real(val); } + bool operator<<(double val) { return shl_real(val); } bool operator<<(long double val) { #ifndef __MINGW32__ - return shl_real_type(val, start, finish); + return shl_real(val); #else - return shl_real_type(static_cast(val), start, finish); + return shl_real(static_cast(val)); #endif } - template - bool operator<<(boost::array const& input) BOOST_NOEXCEPT - { return shl_char_array_limited(input.begin(), N); } + // Adding constness to characters. Constness does not change layout + template + BOOST_DEDUCED_TYPENAME boost::disable_if, bool>::type + operator<<(boost::array const& input) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG( + (sizeof(boost::array) == sizeof(boost::array)), + "boost::array and boost::array must have exactly the same layout." + ); + return ((*this) << reinterpret_cast const& >(input)); + } template - bool operator<<(boost::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } + bool operator<<(boost::array const& input) BOOST_NOEXCEPT { + return shl_char_array_limited(input.begin(), N); + } template - bool operator<<(boost::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } + bool operator<<(boost::array const& input) BOOST_NOEXCEPT { + return ((*this) << reinterpret_cast const& >(input)); + } template - bool operator<<(boost::array const& input) BOOST_NOEXCEPT - { return shl_char_array_limited(input.begin(), N); } - - template - bool operator<<(boost::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } - - template - bool operator<<(boost::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } + bool operator<<(boost::array const& input) BOOST_NOEXCEPT { + return ((*this) << reinterpret_cast const& >(input)); + } #ifndef BOOST_NO_CXX11_HDR_ARRAY - template - bool operator<<(std::array const& input) BOOST_NOEXCEPT - { - if (input.size()) return shl_char_array_limited(&input[0], N); - else return true; + // Making a Boost.Array from std::array + template + bool operator<<(std::array const& input) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG( + (sizeof(std::array) == sizeof(boost::array)), + "std::array and boost::array must have exactly the same layout. " + "Bug in implementation of std::array or boost::array." + ); + return ((*this) << reinterpret_cast const& >(input)); } - - template - bool operator<<(std::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } - - template - bool operator<<(std::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } - - template - bool operator<<(std::array const& input) BOOST_NOEXCEPT - { - if (input.size()) return shl_char_array_limited(&input[0], N); - else return true; - } - - template - bool operator<<(std::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } - - template - bool operator<<(std::array const& input) BOOST_NOEXCEPT - { return ((*this) << reinterpret_cast const& >(input)); } #endif template bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } + }; + + + template + class lexical_ostream_limited_src: boost::noncopyable { + //`[start, finish)` is the range to output by `operator >>` + const CharT* start; + const CharT* const finish; + + public: + lexical_ostream_limited_src(const CharT* begin, const CharT* end) BOOST_NOEXCEPT + : start(begin) + , finish(end) + {} /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ private: - template - bool shr_unsigned(Type& output) - { + bool shr_unsigned(Type& output) { if (start == finish) return false; CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; - bool has_minus = false; + bool const has_minus = Traits::eq(minus, *start); /* We won`t use `start' any more, so no need in decrementing it after */ - if ( Traits::eq(minus,*start) ) - { - ++start; - has_minus = true; - } else if ( Traits::eq( plus, *start ) ) - { + if (has_minus || Traits::eq(plus, *start)) { ++start; } - bool const succeed = lcast_ret_unsigned(output, start, finish); + bool const succeed = lcast_ret_unsigned(output, start, finish).convert(); if (has_minus) { output = static_cast(0u - output); @@ -1946,26 +1712,20 @@ namespace boost { } template - bool shr_signed(Type& output) - { + bool shr_signed(Type& output) { if (start == finish) return false; CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; typedef BOOST_DEDUCED_TYPENAME make_unsigned::type utype; - utype out_tmp =0; - bool has_minus = false; + utype out_tmp = 0; + bool const has_minus = Traits::eq(minus, *start); /* We won`t use `start' any more, so no need in decrementing it after */ - if ( Traits::eq(minus,*start) ) - { - ++start; - has_minus = true; - } else if ( Traits::eq(plus, *start) ) - { + if (has_minus || Traits::eq(plus, *start)) { ++start; } - bool succeed = lcast_ret_unsigned(out_tmp, start, finish); + bool succeed = lcast_ret_unsigned(out_tmp, start, finish).convert(); if (has_minus) { utype const comp_val = (static_cast(1) << std::numeric_limits::digits); succeed = succeed && out_tmp<=comp_val; @@ -1992,13 +1752,17 @@ namespace boost { "support such conversions. Try updating it." ); #endif + typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait::buffer_t + buffer_t; #if defined(BOOST_NO_STRINGSTREAM) std::istrstream stream(start, finish - start); #else buffer_t buf; - buf.setbuf(start, finish - start); + // Usually `istream` and `basic_istream` do not modify + // content of buffer; `buffer_t` assures that this is true + buf.setbuf(const_cast(start), finish - start); #if defined(BOOST_NO_STD_LOCALE) std::istream stream(&buf); #else @@ -2013,17 +1777,8 @@ namespace boost { stream.unsetf(std::ios::skipws); lcast_set_precision(stream, static_cast(0)); - 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 + return (stream >> output) + && (stream.get() == Traits::eof()); #ifndef BOOST_NO_EXCEPTIONS } catch (const ::std::ios_base::failure& /*f*/) { @@ -2033,8 +1788,7 @@ namespace boost { } template - inline bool shr_xchar(T& output) - { + inline bool shr_xchar(T& output) BOOST_NOEXCEPT { BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ), "boost::lexical_cast does not support narrowing of character types." "Use boost::locale instead" ); @@ -2047,6 +1801,19 @@ namespace boost { return ok; } + template + bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT { + using namespace std; + const std::size_t size = finish - start; + if (size > N - 1) { // `-1` because we need to store \0 at the end + return false; + } + + memcpy(&output[0], start, size * sizeof(CharT)); + output[size] = Traits::to_char_type(0); + return true; + } + /************************************ OPERATORS >> ( ... ) ********************************/ public: bool operator>>(unsigned short& output) { return shr_unsigned(output); } @@ -2081,98 +1848,68 @@ namespace boost { bool operator>>(char32_t& output) { return shr_xchar(output); } #endif template - bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } - - template - bool operator>>(boost::container::basic_string& str) { str.assign(start, finish); return true; } - - - private: - template - bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT - { - using namespace std; - const std::size_t size = finish - start; - if (size > N - 1) { // `-1` because we need to store \0 at the end - return false; - } - - memcpy(&output[0], start, size * sizeof(CharT)); - output[size] = Traits::to_char_type(0); - return true; + bool operator>>(std::basic_string& str) { + str.assign(start, finish); return true; } - public: + template + bool operator>>(boost::container::basic_string& str) { + str.assign(start, finish); return true; + } template - bool operator>>(boost::array& output) BOOST_NOEXCEPT - { + bool operator>>(boost::array& output) BOOST_NOEXCEPT { return shr_std_array(output); } template - bool operator>>(boost::array& output) - { + bool operator>>(boost::array& output) BOOST_NOEXCEPT { return ((*this) >> reinterpret_cast& >(output)); } template - bool operator>>(boost::array& output) - { + bool operator>>(boost::array& output) BOOST_NOEXCEPT { return ((*this) >> reinterpret_cast& >(output)); } #ifndef BOOST_NO_CXX11_HDR_ARRAY - template - bool operator>>(std::array& output) BOOST_NOEXCEPT - { - return shr_std_array(output); - } - - template - bool operator>>(std::array& output) - { - return ((*this) >> reinterpret_cast& >(output)); - } - - template - bool operator>>(std::array& output) - { - return ((*this) >> reinterpret_cast& >(output)); + template + bool operator>>(std::array& output) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG( + (sizeof(boost::array) == sizeof(boost::array)), + "std::array and boost::array must have exactly the same layout." + ); + return ((*this) >> reinterpret_cast& >(output)); } #endif - /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; * default: return false; */ - bool operator>>(bool& output) BOOST_NOEXCEPT - { + bool operator>>(bool& output) BOOST_NOEXCEPT { CharT const zero = lcast_char_constants::zero; CharT const plus = lcast_char_constants::plus; CharT const minus = lcast_char_constants::minus; - switch(finish-start) - { + output = false; // Suppress warning about uninitalized variable + switch (finish - start) { case 1: output = Traits::eq(start[0], zero+1); return output || Traits::eq(start[0], zero ); + case 2: - if ( Traits::eq( plus, *start) ) - { + if (Traits::eq(plus, *start)) { ++start; - output = Traits::eq(start[0], zero +1); + output = Traits::eq(start[0], zero + 1); return output || Traits::eq(start[0], zero ); - } else - { - output = false; + } else { return Traits::eq( minus, *start) && Traits::eq( zero, start[1]); } + default: - output = false; // Suppress warning about uninitalized variable return false; } } @@ -2184,7 +1921,7 @@ namespace boost { 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); + bool const return_value = shr_using_base_class(output); /* Some compilers and libraries successfully * parse 'inf', 'INFINITY', '1.0E', '1.0E-'... @@ -2209,13 +1946,12 @@ namespace boost { } // Optimised converter - bool float_types_converter_internal(double& output,char /*tag*/) { - return lcast_ret_float(output,start,finish); + bool float_types_converter_internal(double& output, char /*tag*/) { + return lcast_ret_float(output, start, finish); } public: - bool operator>>(double& output) - { + 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, @@ -2235,16 +1971,17 @@ namespace boost { return float_types_converter_internal(output, tag); } - bool operator>>(long double& output) - { + 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) { return shr_using_base_class(output); } + template + bool operator>>(InputStreamable& output) { + return shr_using_base_class(output); + } }; } @@ -2252,103 +1989,78 @@ namespace boost { { template struct is_stdstring - { - BOOST_STATIC_CONSTANT(bool, value = false ); - }; + : boost::false_type + {}; template struct is_stdstring< std::basic_string > - { - BOOST_STATIC_CONSTANT(bool, value = true ); - }; + : boost::true_type + {}; template struct is_stdstring< boost::container::basic_string > - { - BOOST_STATIC_CONSTANT(bool, value = true ); - }; + : boost::true_type + {}; template struct is_arithmetic_and_not_xchars { - BOOST_STATIC_CONSTANT(bool, value = - ( - boost::type_traits::ice_and< - boost::is_arithmetic::value, - boost::is_arithmetic::value, - boost::type_traits::ice_not< - detail::is_char_or_wchar::value - >::value, - boost::type_traits::ice_not< - detail::is_char_or_wchar::value - >::value - >::value - ) - ); + BOOST_STATIC_CONSTANT(bool, value = ( + boost::type_traits::ice_and< + boost::type_traits::ice_not< + boost::detail::is_character::value + >::value, + boost::type_traits::ice_not< + boost::detail::is_character::value + >::value, + boost::is_arithmetic::value, + boost::is_arithmetic::value + >::value + )); }; /* - * is_xchar_to_xchar::value is true, when - * Target and Souce are the same char types, or when - * Target and Souce are char types of the same size. + * is_xchar_to_xchar::value is true, + * Target and Souce are char types of the same size 1 (char, signed char, unsigned char). */ template - struct is_xchar_to_xchar + struct is_xchar_to_xchar { - BOOST_STATIC_CONSTANT(bool, value = - ( - boost::type_traits::ice_or< - boost::type_traits::ice_and< - is_same::value, - is_char_or_wchar::value - >::value, - boost::type_traits::ice_and< - boost::type_traits::ice_eq< sizeof(char),sizeof(Target)>::value, - boost::type_traits::ice_eq< sizeof(char),sizeof(Source)>::value, - is_char_or_wchar::value, - is_char_or_wchar::value - >::value - >::value - ) - ); + BOOST_STATIC_CONSTANT(bool, value = ( + boost::type_traits::ice_and< + boost::type_traits::ice_eq::value, + boost::type_traits::ice_eq::value, + boost::detail::is_character::value, + boost::detail::is_character::value + >::value + )); }; template struct is_char_array_to_stdstring - { - BOOST_STATIC_CONSTANT(bool, value = false ); - }; + : boost::false_type + {}; template struct is_char_array_to_stdstring< std::basic_string, CharT* > - { - BOOST_STATIC_CONSTANT(bool, value = true ); - }; + : boost::true_type + {}; template struct is_char_array_to_stdstring< std::basic_string, const CharT* > - { - BOOST_STATIC_CONSTANT(bool, value = true ); - }; + : boost::true_type + {}; template struct is_char_array_to_stdstring< boost::container::basic_string, CharT* > - { - BOOST_STATIC_CONSTANT(bool, value = true ); - }; + : boost::true_type + {}; template struct is_char_array_to_stdstring< boost::container::basic_string, const CharT* > - { - BOOST_STATIC_CONSTANT(bool, value = true ); - }; + : boost::true_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 struct lexical_cast_do_cast { @@ -2356,30 +2068,35 @@ namespace boost { { typedef lexical_cast_stream_traits stream_trait; - typedef detail::lexical_stream_limited_src< + typedef detail::lexical_istream_limited_src< BOOST_DEDUCED_TYPENAME stream_trait::char_type, BOOST_DEDUCED_TYPENAME stream_trait::traits, - stream_trait::requires_stringbuf - > interpreter_type; + stream_trait::requires_stringbuf, + stream_trait::len_t::value + 1 + > i_interpreter_type; + + typedef detail::lexical_ostream_limited_src< + BOOST_DEDUCED_TYPENAME stream_trait::char_type, + BOOST_DEDUCED_TYPENAME stream_trait::traits + > o_interpreter_type; // Target type must be default constructible - Target result; + Target result; - BOOST_DEDUCED_TYPENAME stream_trait::char_type buf[stream_trait::len_t::value + 1]; - stream_trait::len_t::check_coverage(); - - interpreter_type interpreter(buf, buf + stream_trait::len_t::value + 1); + i_interpreter_type i_interpreter; // Disabling ADL, by directly specifying operators. - if(!(interpreter.operator <<(arg) && interpreter.operator >>(result))) + const bool input_ok = (i_interpreter.operator <<(arg)); + + o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend()); + + // Disabling ADL, by directly specifying operators. + if(!input_ok || !(out.operator >>(result))) BOOST_LCAST_THROW_BAD_CAST(Source, Target); return result; } }; -#if (defined _MSC_VER) -# pragma warning( pop ) -#endif template struct lexical_cast_copy @@ -2492,6 +2209,7 @@ namespace boost { { typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< boost::type_traits::ice_and< + boost::is_unsigned::value, boost::type_traits::ice_or< boost::is_signed::value, boost::is_float::value @@ -2501,8 +2219,7 @@ namespace boost { >::value, boost::type_traits::ice_not< boost::is_same::value - >::value, - boost::is_unsigned::value + >::value >::value, lexical_cast_dynamic_num_ignoring_minus, lexical_cast_dynamic_num_not_ignoring_minus @@ -2519,33 +2236,41 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay::type src; typedef BOOST_DEDUCED_TYPENAME boost::type_traits::ice_or< - boost::detail::is_xchar_to_xchar::value, - boost::detail::is_char_array_to_stdstring::value, - boost::type_traits::ice_and< - boost::is_same::value, - boost::detail::is_stdstring::value - >::value + boost::detail::is_xchar_to_xchar::value, + boost::detail::is_char_array_to_stdstring::value, + boost::type_traits::ice_and< + boost::is_same::value, + boost::detail::is_stdstring::value + >::value, + boost::type_traits::ice_and< + boost::is_same::value, + boost::detail::is_character::value + >::value > shall_we_copy_t; - typedef BOOST_DEDUCED_TYPENAME - boost::detail::is_arithmetic_and_not_xchars shall_we_copy_with_dynamic_check_t; + typedef boost::detail::is_arithmetic_and_not_xchars + shall_we_copy_with_dynamic_check_t; + // We do evaluate second `if_` lazily to avoid unnecessary instantiations + // of `shall_we_copy_with_dynamic_check_t` and improve compilation times. typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< shall_we_copy_t::value, - boost::detail::lexical_cast_copy, - BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - shall_we_copy_with_dynamic_check_t::value, + boost::mpl::identity >, + boost::mpl::if_< + shall_we_copy_with_dynamic_check_t, boost::detail::lexical_cast_dynamic_num, boost::detail::lexical_cast_do_cast - >::type - >::type caster_type; + > + >::type caster_type_lazy; + + typedef BOOST_DEDUCED_TYPENAME caster_type_lazy::type caster_type; return caster_type::lexical_cast_impl(arg); } template inline Target lexical_cast(const char* chars, std::size_t count) - { + { return ::boost::lexical_cast( ::boost::iterator_range(chars, chars + count) ); @@ -2558,7 +2283,7 @@ namespace boost { return ::boost::lexical_cast( ::boost::iterator_range(chars, chars + count) ); - } + } template inline Target lexical_cast(const signed char* chars, std::size_t count) @@ -2598,7 +2323,7 @@ namespace boost { } // namespace boost -#else // #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#else namespace boost { namespace detail @@ -2671,16 +2396,7 @@ namespace boost { { 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 + stream.get() == traits_type::eof(); } bool operator>>(std::string &output) diff --git a/test/lexical_cast_stream_traits_test.cpp b/test/lexical_cast_stream_traits_test.cpp index ac7acbe..e041fa9 100644 --- a/test/lexical_cast_stream_traits_test.cpp +++ b/test/lexical_cast_stream_traits_test.cpp @@ -40,7 +40,7 @@ static void test_optimized_types_to_string_const() BOOST_CHECK((boost::is_same::value)); BOOST_CHECK((boost::is_same::value)); - BOOST_CHECK((boost::detail::is_char_or_wchar::value != trait_3::is_string_widening_required_t::value)); + BOOST_CHECK((boost::detail::is_character::value != trait_3::is_string_widening_required_t::value)); BOOST_CHECK(!trait_3::is_source_input_not_optimized_t::value); } diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp old mode 100755 new mode 100644 index dede81e..41fc400 --- a/test/lexical_cast_wchars_test.cpp +++ b/test/lexical_cast_wchars_test.cpp @@ -51,6 +51,23 @@ void test_char_types_conversions_wchar_t() { #ifndef BOOST_LCAST_NO_WCHAR_T test_impl(L"Test array of chars"); + wchar_t c = boost::detail::lcast_char_constants::zero; + BOOST_CHECK_EQUAL(L'0', c); + + c = boost::detail::lcast_char_constants::minus; + BOOST_CHECK_EQUAL(L'-', c); + + c = boost::detail::lcast_char_constants::plus; + BOOST_CHECK_EQUAL(L'+', c); + + c = boost::detail::lcast_char_constants::lowercase_e; + BOOST_CHECK_EQUAL(L'e', c); + + c = boost::detail::lcast_char_constants::capital_e; + BOOST_CHECK_EQUAL(L'E', c); + + c = boost::detail::lcast_char_constants::c_decimal_separator; + BOOST_CHECK_EQUAL(L'.', c); #endif BOOST_CHECK(true); @@ -60,6 +77,23 @@ void test_char_types_conversions_char16_t() { #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) test_impl(u"Test array of chars"); + char16_t c = boost::detail::lcast_char_constants::zero; + BOOST_CHECK_EQUAL(u'0', c); + + c = boost::detail::lcast_char_constants::minus; + BOOST_CHECK_EQUAL(u'-', c); + + c = boost::detail::lcast_char_constants::plus; + BOOST_CHECK_EQUAL(u'+', c); + + c = boost::detail::lcast_char_constants::lowercase_e; + BOOST_CHECK_EQUAL(u'e', c); + + c = boost::detail::lcast_char_constants::capital_e; + BOOST_CHECK_EQUAL(u'E', c); + + c = boost::detail::lcast_char_constants::c_decimal_separator; + BOOST_CHECK_EQUAL(u'.', c); #endif BOOST_CHECK(true); @@ -69,6 +103,23 @@ void test_char_types_conversions_char32_t() { #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) test_impl(U"Test array of chars"); + char32_t c = boost::detail::lcast_char_constants::zero; + BOOST_CHECK_EQUAL(U'0', c); + + c = boost::detail::lcast_char_constants::minus; + BOOST_CHECK_EQUAL(U'-', c); + + c = boost::detail::lcast_char_constants::plus; + BOOST_CHECK_EQUAL(U'+', c); + + c = boost::detail::lcast_char_constants::lowercase_e; + BOOST_CHECK_EQUAL(U'e', c); + + c = boost::detail::lcast_char_constants::capital_e; + BOOST_CHECK_EQUAL(U'E', c); + + c = boost::detail::lcast_char_constants::c_decimal_separator; + BOOST_CHECK_EQUAL(U'.', c); #endif BOOST_CHECK(true);