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_