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;