ext/include/iv/conversions.h in iv-phonic-0.0.5 vs ext/include/iv/conversions.h in iv-phonic-0.0.6

- old
+ new

@@ -46,10 +46,11 @@ template<typename Iter> inline double StringToDouble(Iter it, Iter last, bool parse_float) { bool is_decimal = true; bool is_signed = false; bool is_sign_found = false; + bool is_found_zero = false; std::size_t pos = 0; int significant_digits = 0; int insignificant_digits = 0; std::tr1::array<char, Conversions::kMaxSignificantDigits+10> buffer; @@ -82,13 +83,14 @@ return Conversions::kNaN; } if (Chars::IsDecimalDigit(*it)) { if (*it == '0') { + is_found_zero = true; ++it; if (it == last) { - return 0; + return (is_signed) ? -0.0 : 0.0; } if (!parse_float && (*it == 'x' || *it == 'X')) { if (is_sign_found) { return Conversions::kNaN; } @@ -146,18 +148,22 @@ } } else { if (*it == '.') { buffer[pos++] = '.'; ++it; + const Iter start = it; while (it != last && Chars::IsDecimalDigit(*it)) { if (significant_digits < Conversions::kMaxSignificantDigits) { buffer[pos++] = *it; ++significant_digits; } ++it; } + if (start == it) { + return Conversions::kNaN; + } } else { for (std::string::const_iterator inf_it = Conversions::kInfinity.begin(), inf_last = Conversions::kInfinity.end(); inf_it != inf_last; ++inf_it, ++it) { if (it == last || @@ -188,23 +194,35 @@ return Conversions::kNaN; } buffer[pos++] = *it; ++it; if (it == last) { + if (parse_float) { + --it; + --pos; + goto exponent_pasing_done; + } return Conversions::kNaN; } + bool is_signed_exp = false; if (*it == '+' || *it == '-') { buffer[pos++] = *it; ++it; + is_signed_exp = true; } - if (it == last) { + if (it == last || !Chars::IsDecimalDigit(*it)) { + if (parse_float) { + --it; + --pos; + if (is_signed_exp) { + --it; + --pos; + } + goto exponent_pasing_done; + } return Conversions::kNaN; } - // more than 1 decimal digit required - if (!Chars::IsDecimalDigit(*it)) { - return Conversions::kNaN; - } int exponent = 0; do { if (exponent > 9999) { exponent = 9999; } else { @@ -218,19 +236,22 @@ } std::snprintf(buffer.data()+pos, 5, "%d", exponent); // NOLINT pos+=4; } + // exponent_pasing_done label + exponent_pasing_done: + while (it != last && (Chars::IsWhiteSpace(*it) || Chars::IsLineTerminator(*it))) { ++it; } if (it == last || parse_float) { if (pos == 0) { // empty - return (parse_float) ? Conversions::kNaN : 0; + return (parse_float && !is_found_zero) ? Conversions::kNaN : 0; } else { buffer[pos++] = '\0'; return std::strtod(buffer.data(), NULL); } } else { @@ -244,10 +265,112 @@ inline double StringToDouble(const UStringPiece& str, bool parse_float) { return StringToDouble(str.begin(), str.end(), parse_float); } +inline int OctalValue(const int c) { + if ('0' <= c && c <= '8') { + return c - '0'; + } + return -1; +} + +inline int HexValue(const int c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } + if ('a' <= c && c <= 'f') { + return c - 'a' + 10; + } + if ('A' <= c && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +inline int Radix36Value(const int c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } + if ('a' <= c && c <= 'z') { + return c - 'a' + 10; + } + if ('A' <= c && c <= 'Z') { + return c - 'A' + 10; + } + return -1; +} + +template<typename Iter> +inline double StringToIntegerWithRadix(Iter it, Iter last, + int radix, bool strip_prefix) { + // remove leading white space + while (it != last && + (Chars::IsWhiteSpace(*it) || Chars::IsLineTerminator(*it))) { + ++it; + } + + // empty string "" + if (it == last) { + return Conversions::kNaN; + } + + int sign = 1; + if (*it == '-') { + sign = -1; + ++it; + } else if (*it == '+') { + ++it; + } + + if (it == last) { + return Conversions::kNaN; + } + + if (strip_prefix) { + if (*it == '0') { + ++it; + if (it != last && + (*it == 'x' || *it == 'X')) { + // strip_prefix + ++it; + radix = 16; + } else { + --it; + } + } + } + + if (it == last) { + return Conversions::kNaN; + } + + double result = 0; + const Iter start = it; + for (; it != last; ++it) { + const int val = Radix36Value(*it); + if (val != -1 && val < radix) { + result = result * radix + val; + } else { + return (start == it) ? Conversions::kNaN : sign * result; + } + } + return sign * result; +} + +inline double StringToIntegerWithRadix(const StringPiece& range, + int radix, bool strip_prefix) { + return StringToIntegerWithRadix(range.begin(), range.end(), + radix, strip_prefix); +} + +inline double StringToIntegerWithRadix(const UStringPiece& range, + int radix, bool strip_prefix) { + return StringToIntegerWithRadix(range.begin(), range.end(), + radix, strip_prefix); +} + inline std::size_t StringToHash(const UStringPiece& x) { std::size_t len = x.size(); std::size_t step = (len >> 5) + 1; std::size_t h = 0; for (std::size_t l1 = len; l1 >= step; l1 -= step) { @@ -282,12 +405,12 @@ std::floor(d) : std::ceil(d) + Conversions::DoubleToInt32_Two32; return static_cast<int32_t>(d >= Conversions::DoubleToInt32_Two31 ? d - Conversions::DoubleToInt32_Two32 : d); } -inline int32_t DoubleToUInt32(double d) { - return static_cast<uint32_t>(d); +inline uint32_t DoubleToUInt32(double d) { + return static_cast<uint32_t>(DoubleToInt32(d)); } inline double DoubleToInteger(double d) { if (std::isnan(d)) { return 0; @@ -297,10 +420,11 @@ } return std::floor(std::abs(d)) * (std::signbit(d) ? -1 : 1); } inline bool ConvertToUInt32(const UStringPiece& str, uint32_t* value) { + static const uint32_t uint32_t_max = std::numeric_limits<uint32_t>::max(); uint16_t ch; *value = 0; UStringPiece::const_iterator it = str.begin(); const UStringPiece::const_iterator last = str.end(); if (it != last && *it != '0' && Chars::IsDecimalDigit(*it)) { @@ -318,12 +442,12 @@ *value = ch + (prev * 10); } else { return false; } } - return (prev < (std::numeric_limits<uint32_t>::max() / 10) || - ((prev == (std::numeric_limits<uint32_t>::max() / 10)) && - (ch < (std::numeric_limits<uint32_t>::max() % 10)))); + return (prev < (uint32_t_max / 10) || + ((prev == (uint32_t_max / 10)) && + (ch < (uint32_t_max % 10)))); } template<typename T> inline std::size_t DoubleToStringWithRadix(double v, int radix, T* buf) { static const int kMaxBufSize = 1100;