diff options
Diffstat (limited to 'boost/convert/strtol.hpp')
-rw-r--r-- | boost/convert/strtol.hpp | 48 |
1 files changed, 21 insertions, 27 deletions
diff --git a/boost/convert/strtol.hpp b/boost/convert/strtol.hpp index 5d10bde5a7..4dd26eef7f 100644 --- a/boost/convert/strtol.hpp +++ b/boost/convert/strtol.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 Vladimir Batov. +// Copyright (c) 2009-2016 Vladimir Batov. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. @@ -31,18 +31,6 @@ namespace boost { namespace cnv struct boost::cnv::strtol : public boost::cnv::cnvbase<boost::cnv::strtol> { - // C2. Old C-strings have an advantage over [begin, end) ranges. They do not need the 'end' iterator! - // Instead, they provide a sentinel (0 terminator). Consequently, C strings can be traversed - // without the need to compare if the 'end' has been reached (i.e. "for (; it != end; ++it)"). - // Instead, the current character is checked if it's 0 (i.e. "for (; *p; ++p)") which is faster. - // - // So, the implementation takes advantage of the fact. Namely, we simply check if *cnv_end == 0 - // instead of traversing once with strlen() to find the end iterator and then comparing to it as in - // - // char const* str_end = str + strlen(str); // Unnecessary traversal! - // ... - // bool const good = ... && cnv_end == str_end; - typedef boost::cnv::strtol this_type; typedef boost::cnv::cnvbase<this_type> base_type; @@ -88,16 +76,16 @@ boost::cnv::strtol::i_to_str(Type in_value, char_type* buf) const typedef typename boost::make_unsigned<Type>::type unsigned_type; - char_type* beg = buf + bufsize_ / 2; - char_type* end = beg; - bool const is_negative = in_value < 0; - unsigned_type value = static_cast<unsigned_type>(is_negative ? -in_value : in_value); + char_type* beg = buf + bufsize_ / 2; + char_type* end = beg; + bool const is_neg = std::is_signed<Type>::value && in_value < 0; + unsigned_type value = static_cast<unsigned_type>(is_neg ? -in_value : in_value); if (base_ == 10) for (; value; *(--beg) = int(value % 10) + '0', value /= 10); //C1 else for (; value; *(--beg) = get_char(value % base_), value /= base_); - if (beg == end) *(--beg) = '0'; - if (is_negative) *(--beg) = '-'; + if (beg == end) *(--beg) = '0'; + if (is_neg) *(--beg) = '-'; return cnv::range<char_type*>(beg, end); } @@ -209,14 +197,20 @@ template<typename string_type, typename out_type> void boost::cnv::strtol::str_to_d(cnv::range<string_type> range, optional<out_type>& result_out) const { - typedef cnv::range<string_type> range_type; - typedef typename range_type::value_type char_type; - - char_type const* str = &*range.begin(); // Currently only works with 'char' - char* cnv_end = 0; - ldbl_type const result = strtold(str, &cnv_end); - bool const good = result != -HUGE_VALL && result != HUGE_VALL && *cnv_end == 0/*C2*/; - out_type const max = (std::numeric_limits<out_type>::max)(); + // C1. Because of strtold() currently only works with 'char' + // C2. strtold() does not work with ranges. + // Consequently, we have to copy the supplied range into a string for strtold(). + // C3. Check if the end-of-string was reached -- *cnv_end == 0. + + typedef cnv::range<string_type> range_type; + typedef typename range_type::value_type ch_type; + + size_t const sz = 128; + ch_type str[sz] = {0}; std::strncpy(str, &*range.begin(), std::min(sz - 1, range.size())); + char* cnv_end = 0; + ldbl_type result = strtold(str, &cnv_end); + bool good = result != -HUGE_VALL && result != HUGE_VALL && *cnv_end == 0; //C3 + out_type max = (std::numeric_limits<out_type>::max)(); if (good && -max <= result && result <= max) result_out = out_type(result); |