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

- old
+ new

@@ -19,10 +19,12 @@ static const double kNaN; static const int kMaxSignificantDigits = 772; static const std::string kInfinity; static const double DoubleToInt32_Two32; static const double DoubleToInt32_Two31; + static const char* kHex; + static const int kMaxDoubleToStringWithRadixBufferSize = 2200; }; template<typename T> const double Conversions<T>::kNaN = std::numeric_limits<double>::quiet_NaN(); template<typename T> @@ -31,44 +33,51 @@ template<typename T> const double Conversions<T>::DoubleToInt32_Two32 = 4294967296.0; template<typename T> const double Conversions<T>::DoubleToInt32_Two31 = 2147483648.0; + +template<typename T> +const char* Conversions<T>::kHex = "0123456789abcdefghijklmnopqrstuvwxyz"; + } // namespace iv::core::detail typedef detail::Conversions<None> Conversions; template<typename Iter> -inline double StringToDouble(Iter it, Iter last) { +inline double StringToDouble(Iter it, Iter last, bool parse_float) { bool is_decimal = true; bool is_signed = false; + bool is_sign_found = false; std::size_t pos = 0; int significant_digits = 0; int insignificant_digits = 0; std::tr1::array<char, Conversions::kMaxSignificantDigits+10> buffer; // empty string "" if (it == last) { - return 0; + return (parse_float) ? Conversions::kNaN : 0; } while (it != last && (Chars::IsWhiteSpace(*it) || Chars::IsLineTerminator(*it))) { ++it; } // white space only " " if (it == last) { - return 0; + return (parse_float) ? Conversions::kNaN : 0; } if (*it == '-') { buffer[pos++] = '-'; ++it; is_signed = true; + is_sign_found = true; } else if (*it == '+') { ++it; + is_sign_found = true; } if (it == last) { return Conversions::kNaN; } @@ -77,11 +86,14 @@ if (*it == '0') { ++it; if (it == last) { return 0; } - if (*it == 'x' || *it == 'X') { + if (!parse_float && (*it == 'x' || *it == 'X')) { + if (is_sign_found) { + return Conversions::kNaN; + } is_decimal = false; buffer[pos++] = '0'; buffer[pos++] = *it; ++it; ++significant_digits; @@ -156,11 +168,11 @@ // infinity while (it != last && (Chars::IsWhiteSpace(*it) || Chars::IsLineTerminator(*it))) { ++it; } - if (it == last) { + if (it == last || parse_float) { if (is_signed) { return -std::numeric_limits<double>::infinity(); } else { return std::numeric_limits<double>::infinity(); } @@ -211,29 +223,29 @@ while (it != last && (Chars::IsWhiteSpace(*it) || Chars::IsLineTerminator(*it))) { ++it; } - if (it == last) { + if (it == last || parse_float) { if (pos == 0) { // empty - return 0; + return (parse_float) ? Conversions::kNaN : 0; } else { buffer[pos++] = '\0'; return std::strtod(buffer.data(), NULL); } } else { return Conversions::kNaN; } } -inline double StringToDouble(const StringPiece& str) { - return StringToDouble(str.begin(), str.end()); +inline double StringToDouble(const StringPiece& str, bool parse_float) { + return StringToDouble(str.begin(), str.end(), parse_float); } -inline double StringToDouble(const UStringPiece& str) { - return StringToDouble(str.begin(), str.end()); +inline double StringToDouble(const UStringPiece& str, bool parse_float) { + return StringToDouble(str.begin(), str.end(), parse_float); } inline std::size_t StringToHash(const UStringPiece& x) { std::size_t len = x.size(); std::size_t step = (len >> 5) + 1; @@ -274,10 +286,20 @@ inline int32_t DoubleToUInt32(double d) { return static_cast<uint32_t>(d); } +inline double DoubleToInteger(double d) { + if (std::isnan(d)) { + return 0; + } + if (!std::isfinite(d) || d == 0) { + return d; + } + return std::floor(std::abs(d)) * (std::signbit(d) ? -1 : 1); +} + inline bool ConvertToUInt32(const UStringPiece& str, uint32_t* value) { uint16_t ch; *value = 0; UStringPiece::const_iterator it = str.begin(); const UStringPiece::const_iterator last = str.end(); @@ -301,8 +323,54 @@ 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)))); } +template<typename T> +inline std::size_t DoubleToStringWithRadix(double v, int radix, T* buf) { + static const int kMaxBufSize = 1100; + std::tr1::array< + char, + Conversions::kMaxDoubleToStringWithRadixBufferSize> buffer; + const bool is_negative = v < 0.0; + if (is_negative) { + v = -v; + } + double integer = std::floor(v); + double decimal = v - integer; + + // integer part + int integer_pos = kMaxBufSize - 1; + do { + buffer[integer_pos--] = + Conversions::kHex[static_cast<std::size_t>(std::fmod(integer, radix))]; + integer /= radix; + } while (integer >= 1.0); + if (is_negative) { + buffer[integer_pos--] = '-'; + } + assert(integer_pos >= 0); + + // decimal part + int decimal_pos = kMaxBufSize; + if (decimal) { + buffer[decimal_pos++] = '.'; + while ((decimal > 0.0) && (decimal_pos < (kMaxBufSize * 2))) { + decimal *= radix; + const std::size_t res = static_cast<std::size_t>(std::floor(decimal)); + buffer[decimal_pos++] = Conversions::kHex[res]; + decimal -= res; + } + } + buf->assign(buffer.data() + integer_pos + 1, + buffer.data() + decimal_pos); + return decimal_pos - integer_pos - 1; // size +} + +inline std::string DoubleToStringWithRadix(double v, int radix) { + std::string str; + DoubleToStringWithRadix(v, radix, &str); + return str; +} } } // namespace iv::core #endif // IV_CONVERSIONS_H_