Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r85486 - trunk/boost
From: antoshkka_at_[hidden]
Date: 2013-08-27 10:23:19


Author: apolukhin
Date: 2013-08-27 10:23:19 EDT (Tue, 27 Aug 2013)
New Revision: 85486
URL: http://svn.boost.org/trac/boost/changeset/85486

Log:
Fix bug introduced by previous commits during conversion of wide character to wide character. Remove duplicate code and add more comments for lcast_ret_unsigned method. Optimize and simplify overflow detection (refs #9046)

Text files modified:
   trunk/boost/lexical_cast.hpp | 276 ++++++++++++++++++++-------------------
   1 files changed, 144 insertions(+), 132 deletions(-)

Modified: trunk/boost/lexical_cast.hpp
==============================================================================
--- trunk/boost/lexical_cast.hpp Tue Aug 27 07:32:24 2013 (r85485)
+++ trunk/boost/lexical_cast.hpp 2013-08-27 10:23:19 EDT (Tue, 27 Aug 2013) (r85486)
@@ -725,35 +725,50 @@
 
     namespace detail // lcast_ret_unsigned
     {
- template<class Traits, class T, class CharT>
- inline bool lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end)
- {
+ template <class Traits, class T, class CharT>
+ class lcast_ret_unsigned {
+ 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<T>::is_signed);
+ BOOST_STATIC_ASSERT(!std::numeric_limits<T>::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<T>::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<T>::is_specialized,
+ "std::numeric_limits are not specialized for integral type passed to boost::lexical_cast"
+ );
 #endif
- CharT const czero = lcast_char_constants<CharT>::zero;
- --end;
- value = 0;
+ }
 
- if (begin > end || *end < czero || *end >= czero + 10)
- return false;
- value = static_cast<T>(*end - czero);
- --end;
- T multiplier = 1;
- bool multiplier_overflowed = false;
+ inline bool convert() {
+ CharT const czero = lcast_char_constants<CharT>::zero;
+ --m_end;
+ m_value = static_cast<T>(0);
+
+ if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10)
+ return false;
+ m_value = static_cast<T>(*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<CharT> numpunct;
                 numpunct const& np = BOOST_USE_FACET(numpunct, loc);
                 std::string const& grouping = np.grouping();
@@ -762,85 +777,86 @@
                 /* 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<char>(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<char>(grouping[current_grouping] - 1);
- bool shall_we_return = true;
-
- for(;end>=begin; --end)
- {
- if (remained) {
- T const multiplier_10 = static_cast<T>(multiplier * 10);
- if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true;
-
- T const dig_value = static_cast<T>(*end - czero);
- T const new_sub_value = static_cast<T>(multiplier_10 * dig_value);
-
- if (*end < czero || *end >= czero + 10
- /* detecting overflow */
- || (dig_value && new_sub_value / dig_value != multiplier_10)
- || static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
- || (multiplier_overflowed && dig_value)
- )
- return false;
-
- value = static_cast<T>(value + new_sub_value);
- multiplier = static_cast<T>(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<numpunct<charT> >(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<numpunct<charT> >(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<T>(multiplier * 10);
- if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true;
+ }
 
- T const dig_value = static_cast<T>(*end - czero);
- T const new_sub_value = static_cast<T>(multiplier_10 * dig_value);
+ 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<CharT>::zero;
+ T const maxv = (std::numeric_limits<T>::max)();
 
- if (*end < czero || *end >= czero + 10
- /* detecting overflow */
- || (dig_value && new_sub_value / dig_value != multiplier_10)
- || static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
- || (multiplier_overflowed && dig_value)
- )
- return false;
+ m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier);
+ m_multiplier = static_cast<T>(m_multiplier * 10);
+
+ T const dig_value = static_cast<T>(*m_end - czero);
+ T const new_sub_value = static_cast<T>(m_multiplier * dig_value);
 
- value = static_cast<T>(value + new_sub_value);
- multiplier = static_cast<T>(multiplier * 10);
- --end;
+ // 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<T>(maxv / dig_value) < m_multiplier // ... subvalue
+ || static_cast<T>(maxv - new_sub_value) < m_value // ... whole expression
+ ))
+ ) return false;
+
+ m_value = static_cast<T>(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;
             }
- return true;
- }
+ };
     }
 
     namespace detail
@@ -1110,12 +1126,11 @@
                 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<mantissa_type>(*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<mantissa_type>::max)()-(*begin - zero) < tmp_mantissa
+ || ((std::numeric_limits<mantissa_type>::max)() - tmp_sub_value) / 10u < mantissa
                             ) {
                         is_mantissa_full = true;
                         ++ begin;
@@ -1123,8 +1138,7 @@
                     }
 
                     -- pow_of_10;
- mantissa = tmp_mantissa;
- mantissa += *begin - zero;
+ mantissa = static_cast<mantissa_type>(mantissa * 10 + tmp_sub_value);
 
                     found_number_before_exp = true;
                 } else {
@@ -1134,14 +1148,12 @@
                         /* Checking for mantissa overflow. If overflow will
                          * occur, them we only increase multiplyer
                          */
- mantissa_type tmp_mantissa = mantissa * 10u;
- if( !is_mantissa_full
- && tmp_mantissa / 10u == mantissa
- && (std::numeric_limits<mantissa_type>::max)()-(*begin - zero) >= tmp_mantissa
+ const mantissa_type tmp_sub_value = static_cast<mantissa_type>(*begin - zero);
+ if( !(is_mantissa_full
+ || ((std::numeric_limits<mantissa_type>::max)() - tmp_sub_value) / 10u < mantissa)
                             )
                         {
- mantissa = tmp_mantissa;
- mantissa += *begin - zero;
+ mantissa = static_cast<mantissa_type>(mantissa * 10 + tmp_sub_value);
                         } else
                         {
                             is_mantissa_full = true;
@@ -1792,7 +1804,7 @@
                     ++start;
                 }
 
- bool const succeed = lcast_ret_unsigned<Traits>(output, start, finish);
+ bool const succeed = lcast_ret_unsigned<Traits, Type, CharT>(output, start, finish).convert();
 
                 if (has_minus) {
                     output = static_cast<Type>(0u - output);
@@ -1821,7 +1833,7 @@
                     ++start;
                 }
 
- bool succeed = lcast_ret_unsigned<Traits>(out_tmp, start, finish);
+ bool succeed = lcast_ret_unsigned<Traits, utype, CharT>(out_tmp, start, finish).convert();
                 if (has_minus) {
                     utype const comp_val = (static_cast<utype>(1) << std::numeric_limits<Type>::digits);
                     succeed = succeed && out_tmp<=comp_val;
@@ -2114,39 +2126,35 @@
         template<typename Target, typename Source>
         struct is_arithmetic_and_not_xchars
         {
- BOOST_STATIC_CONSTANT(bool, value =
- (
- boost::type_traits::ice_and<
- boost::is_arithmetic<Source>::value,
- boost::is_arithmetic<Target>::value,
- boost::type_traits::ice_not<
- boost::detail::is_character<Target>::value
- >::value,
- boost::type_traits::ice_not<
- boost::detail::is_character<Source>::value
- >::value
- >::value
- )
- );
+ BOOST_STATIC_CONSTANT(bool, value = (
+ boost::type_traits::ice_and<
+ boost::type_traits::ice_not<
+ boost::detail::is_character<Target>::value
+ >::value,
+ boost::type_traits::ice_not<
+ boost::detail::is_character<Source>::value
+ >::value,
+ boost::is_arithmetic<Source>::value,
+ boost::is_arithmetic<Target>::value
+ >::value
+ ));
         };
 
         /*
- * is_xchar_to_xchar<Target, Source>::value is true, when
- * Target and Souce are the same char types, or when
- * Target and Souce are char types of the same size (signed char, unsigned char).
+ * is_xchar_to_xchar<Target, Source>::value is true,
+ * Target and Souce are char types of the same size 1 (char, signed char, unsigned char).
          */
         template<typename Target, typename Source>
- struct is_xchar_to_xchar
+ struct is_xchar_to_xchar
         {
- BOOST_STATIC_CONSTANT(bool, value =
- (
- boost::type_traits::ice_and<
- boost::type_traits::ice_eq<sizeof(Source), sizeof(Target)>::value,
- boost::detail::is_character<Target>::value,
- boost::detail::is_character<Source>::value
- >::value
- )
- );
+ BOOST_STATIC_CONSTANT(bool, value = (
+ boost::type_traits::ice_and<
+ boost::type_traits::ice_eq<sizeof(Source), sizeof(Target)>::value,
+ boost::type_traits::ice_eq<sizeof(Source), sizeof(char)>::value,
+ boost::detail::is_character<Target>::value,
+ boost::detail::is_character<Source>::value
+ >::value
+ ));
         };
 
         template<typename Target, typename Source>
@@ -2346,6 +2354,10 @@
             boost::type_traits::ice_and<
                  boost::is_same<Target, src >::value,
                  boost::detail::is_stdstring<Target >::value
+ >::value,
+ boost::type_traits::ice_and<
+ boost::is_same<Target, src >::value,
+ boost::detail::is_character<Target >::value
>::value
> shall_we_copy_t;
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk