Index: src/conversions.cc |
=================================================================== |
--- src/conversions.cc (revision 4332) |
+++ src/conversions.cc (working copy) |
@@ -48,51 +48,6 @@ |
return -1; |
} |
- |
-// Provide a common interface to getting a character at a certain |
-// index from a char* or a String object. |
-static inline int GetChar(const char* str, int index) { |
- ASSERT(index >= 0 && index < StrLength(str)); |
- return str[index]; |
-} |
- |
- |
-static inline int GetChar(String* str, int index) { |
- return str->Get(index); |
-} |
- |
- |
-static inline int GetLength(const char* str) { |
- return StrLength(str); |
-} |
- |
- |
-static inline int GetLength(String* str) { |
- return str->length(); |
-} |
- |
- |
-static inline const char* GetCString(const char* str, int index) { |
- return str + index; |
-} |
- |
- |
-static inline const char* GetCString(String* str, int index) { |
- int length = str->length(); |
- char* result = NewArray<char>(length + 1); |
- for (int i = index; i < length; i++) { |
- uc16 c = str->Get(i); |
- if (c <= 127) { |
- result[i - index] = static_cast<char>(c); |
- } else { |
- result[i - index] = 127; // Force number parsing to fail. |
- } |
- } |
- result[length - index] = '\0'; |
- return result; |
-} |
- |
- |
namespace { |
// C++-style iterator adaptor for StringInputBuffer |
@@ -134,15 +89,6 @@ |
} |
-static inline void ReleaseCString(const char* original, const char* str) { |
-} |
- |
- |
-static inline void ReleaseCString(String* original, const char* str) { |
- DeleteArray(const_cast<char *>(str)); |
-} |
- |
- |
template <class Iterator, class EndMark> |
static bool SubStringEquals(Iterator* current, |
EndMark end, |
@@ -168,98 +114,7 @@ |
// we don't need to preserve all the digits. |
const int kMaxSignificantDigits = 772; |
-// Parse an int from a string starting a given index and in a given |
-// radix. The string can be either a char* or a String*. |
-template <class S> |
-static int InternalStringToInt(S* s, int i, int radix, double* value) { |
- int len = GetLength(s); |
- // Setup limits for computing the value. |
- ASSERT(2 <= radix && radix <= 36); |
- int lim_0 = '0' + (radix < 10 ? radix : 10); |
- int lim_a = 'a' + (radix - 10); |
- int lim_A = 'A' + (radix - 10); |
- |
- // NOTE: The code for computing the value may seem a bit complex at |
- // first glance. It is structured to use 32-bit multiply-and-add |
- // loops as long as possible to avoid loosing precision. |
- |
- double v = 0.0; |
- int j; |
- for (j = i; j < len;) { |
- // Parse the longest part of the string starting at index j |
- // possible while keeping the multiplier, and thus the part |
- // itself, within 32 bits. |
- uint32_t part = 0, multiplier = 1; |
- int k; |
- for (k = j; k < len; k++) { |
- int c = GetChar(s, k); |
- if (c >= '0' && c < lim_0) { |
- c = c - '0'; |
- } else if (c >= 'a' && c < lim_a) { |
- c = c - 'a' + 10; |
- } else if (c >= 'A' && c < lim_A) { |
- c = c - 'A' + 10; |
- } else { |
- break; |
- } |
- |
- // Update the value of the part as long as the multiplier fits |
- // in 32 bits. When we can't guarantee that the next iteration |
- // will not overflow the multiplier, we stop parsing the part |
- // by leaving the loop. |
- static const uint32_t kMaximumMultiplier = 0xffffffffU / 36; |
- uint32_t m = multiplier * radix; |
- if (m > kMaximumMultiplier) break; |
- part = part * radix + c; |
- multiplier = m; |
- ASSERT(multiplier > part); |
- } |
- |
- // Compute the number of part digits. If no digits were parsed; |
- // we're done parsing the entire string. |
- int digits = k - j; |
- if (digits == 0) break; |
- |
- // Update the value and skip the part in the string. |
- ASSERT(multiplier == |
- pow(static_cast<double>(radix), static_cast<double>(digits))); |
- v = v * multiplier + part; |
- j = k; |
- } |
- |
- // If the resulting value is larger than 2^53 the value does not fit |
- // in the mantissa of the double and there is a loss of precision. |
- // When the value is larger than 2^53 the rounding depends on the |
- // code generation. If the code generator spills the double value |
- // it uses 64 bits and if it does not it uses 80 bits. |
- // |
- // If there is a potential for overflow we resort to strtod for |
- // radix 10 numbers to get higher precision. For numbers in another |
- // radix we live with the loss of precision. |
- static const double kPreciseConversionLimit = 9007199254740992.0; |
- if (radix == 10 && v > kPreciseConversionLimit) { |
- const char* cstr = GetCString(s, i); |
- const char* end; |
- v = gay_strtod(cstr, &end); |
- ReleaseCString(s, cstr); |
- } |
- |
- *value = v; |
- return j; |
-} |
- |
- |
-int StringToInt(String* str, int index, int radix, double* value) { |
- return InternalStringToInt(str, index, radix, value); |
-} |
- |
- |
-int StringToInt(const char* str, int index, int radix, double* value) { |
- return InternalStringToInt(const_cast<char*>(str), index, radix, value); |
-} |
- |
- |
static const double JUNK_STRING_VALUE = OS::nan_value(); |
@@ -281,18 +136,23 @@ |
} |
+static double SignedZero(bool sign) { |
+ return sign ? -0.0 : 0.0; |
+} |
+ |
+ |
// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. |
template <int radix_log_2, class Iterator, class EndMark> |
- static double InternalStringToIntDouble(Iterator current, |
- EndMark end, |
- bool sign, |
- bool allow_trailing_junk) { |
+static double InternalStringToIntDouble(Iterator current, |
+ EndMark end, |
+ bool sign, |
+ bool allow_trailing_junk) { |
ASSERT(current != end); |
// Skip leading 0s. |
while (*current == '0') { |
++current; |
- if (current == end) return sign ? -0.0 : 0.0; |
+ if (current == end) return SignedZero(sign); |
} |
int64_t number = 0; |
@@ -382,6 +242,183 @@ |
} |
+template <class Iterator, class EndMark> |
+static double InternalStringToInt(Iterator current, EndMark end, int radix) { |
+ const bool allow_trailing_junk = true; |
+ const double empty_string_val = JUNK_STRING_VALUE; |
+ |
+ if (!AdvanceToNonspace(¤t, end)) return empty_string_val; |
+ |
+ bool sign = false; |
+ bool leading_zero = false; |
+ |
+ if (*current == '+') { |
+ // Ignore leading sign; skip following spaces. |
+ ++current; |
+ if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; |
+ } else if (*current == '-') { |
+ ++current; |
+ if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; |
+ sign = true; |
+ } |
+ |
+ if (radix == 0) { |
+ // Radix detection. |
+ if (*current == '0') { |
+ ++current; |
+ if (current == end) return SignedZero(sign); |
+ if (*current == 'x' || *current == 'X') { |
+ radix = 16; |
+ ++current; |
+ if (current == end) return JUNK_STRING_VALUE; |
+ } else { |
+ radix = 8; |
+ leading_zero = true; |
+ } |
+ } else { |
+ radix = 10; |
+ } |
+ } else if (radix == 16) { |
+ if (*current == '0') { |
+ // Allow "0x" prefix. |
+ ++current; |
+ if (current == end) return SignedZero(sign); |
+ if (*current == 'x' || *current == 'X') { |
+ ++current; |
+ if (current == end) return JUNK_STRING_VALUE; |
+ } else { |
+ leading_zero = true; |
+ } |
+ } |
+ } |
+ |
+ if (radix < 2 || radix > 36) return JUNK_STRING_VALUE; |
+ |
+ // Skip leading zeros. |
+ while (*current == '0') { |
+ leading_zero = true; |
+ ++current; |
+ if (current == end) return SignedZero(sign); |
+ } |
+ |
+ if (!leading_zero && !isDigit(*current, radix)) { |
+ return JUNK_STRING_VALUE; |
+ } |
+ |
+ if (IsPowerOf2(radix)) { |
+ switch (radix) { |
+ case 2: |
+ return InternalStringToIntDouble<1>( |
+ current, end, sign, allow_trailing_junk); |
+ case 4: |
+ return InternalStringToIntDouble<2>( |
+ current, end, sign, allow_trailing_junk); |
+ case 8: |
+ return InternalStringToIntDouble<3>( |
+ current, end, sign, allow_trailing_junk); |
+ |
+ case 16: |
+ return InternalStringToIntDouble<4>( |
+ current, end, sign, allow_trailing_junk); |
+ |
+ case 32: |
+ return InternalStringToIntDouble<5>( |
+ current, end, sign, allow_trailing_junk); |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+ |
+ if (radix == 10) { |
+ // Parsing with strtod. |
+ const int kMaxSignificantDigits = 309; // Doubles are less than 1.8e308. |
+ // The buffer may contain up to kMaxSignificantDigits + 1 digits and a zero |
Florian Loitsch
2010/03/31 16:50:00
Maybe add comment:
A number with more than kMaxSig
SeRya
2010/03/31 17:18:08
The comment 7 lines below says the same. I think t
Florian Loitsch
2010/04/03 13:10:59
true. fine with me.
|
+ // end. |
+ const int kBufferSize = kMaxSignificantDigits + 2; |
+ char buffer[kBufferSize]; |
+ int buffer_pos = 0; |
+ while (*current >= '0' && *current <= '9') { |
+ if (buffer_pos <= kMaxSignificantDigits) { |
+ // If the number has more than kMaxSignificantDigits it will be parsed |
+ // as infinity. |
+ ASSERT(buffer_pos < kBufferSize); |
+ buffer[buffer_pos++] = static_cast<char>(*current); |
+ } |
+ ++current; |
+ if (current == end) break; |
+ } |
+ |
+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
+ return JUNK_STRING_VALUE; |
+ } |
+ |
+ ASSERT(buffer_pos < kBufferSize); |
+ buffer[buffer_pos++] = '\0'; |
+ return sign ? -gay_strtod(buffer, NULL) : gay_strtod(buffer, NULL); |
+ } |
+ |
+ // TODO(serya): The following legacy code causes accumulating rounding |
+ // error for number greater than ~2^56. It should be rewritten using long |
+ // arithmetic. |
+ |
+ int lim_0 = '0' + (radix < 10 ? radix : 10); |
+ int lim_a = 'a' + (radix - 10); |
+ int lim_A = 'A' + (radix - 10); |
+ |
+ // NOTE: The code for computing the value may seem a bit complex at |
+ // first glance. It is structured to use 32-bit multiply-and-add |
+ // loops as long as possible to avoid loosing precision. |
+ |
+ double v = 0.0; |
+ bool done = false; |
+ do { |
+ // Parse the longest part of the string starting at index j |
+ // possible while keeping the multiplier, and thus the part |
+ // itself, within 32 bits. |
+ unsigned int part = 0, multiplier = 1; |
+ while (true) { |
+ int d; |
+ if (*current >= '0' && *current < lim_0) { |
+ d = *current - '0'; |
+ } else if (*current >= 'a' && *current < lim_a) { |
+ d = *current - 'a' + 10; |
+ } else if (*current >= 'A' && *current < lim_A) { |
+ d = *current - 'A' + 10; |
+ } else { |
+ done = true; |
+ break; |
+ } |
+ |
+ // Update the value of the part as long as the multiplier fits |
+ // in 32 bits. When we can't guarantee that the next iteration |
+ // will not overflow the multiplier, we stop parsing the part |
+ // by leaving the loop. |
+ const unsigned int kMaximumMultiplier = 0xffffffffU / 36; |
+ uint32_t m = multiplier * radix; |
+ if (m > kMaximumMultiplier) break; |
+ part = part * radix + d; |
+ multiplier = m; |
+ ASSERT(multiplier > part); |
+ |
+ ++current; |
+ if (current == end) { |
+ done = true; |
+ break; |
+ } |
+ } |
+ |
+ // Update the value and skip the part in the string. |
+ v = v * multiplier + part; |
+ } while (!done); |
+ |
+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
+ return JUNK_STRING_VALUE; |
+ } |
+ |
+ return sign ? -v : v; |
+} |
+ |
+ |
// Converts a string to a double value. Assumes the Iterator supports |
// the following operations: |
// 1. current == end (other ops are not allowed), current != end. |
@@ -417,7 +454,7 @@ |
bool nonzero_digit_dropped = false; |
bool fractional_part = false; |
- double signed_zero = 0.0; |
+ bool sign = false; |
if (*current == '+') { |
// Ignore leading sign; skip following spaces. |
@@ -427,7 +464,7 @@ |
buffer[buffer_pos++] = '-'; |
++current; |
if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; |
- signed_zero = -0.0; |
+ sign = true; |
} |
static const char kInfinitySymbol[] = "Infinity"; |
@@ -447,14 +484,16 @@ |
bool leading_zero = false; |
if (*current == '0') { |
++current; |
- if (current == end) return signed_zero; |
+ if (current == end) return SignedZero(sign); |
leading_zero = true; |
-// It could be hexadecimal value. |
+ // It could be hexadecimal value. |
if ((flags & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { |
++current; |
- if (current == end) return JUNK_STRING_VALUE; // "0x". |
+ if (current == end || !isDigit(*current, 16)) { |
+ return JUNK_STRING_VALUE; // "0x". |
+ } |
bool sign = (buffer_pos > 0 && buffer[0] == '-'); |
return InternalStringToIntDouble<4>(current, |
@@ -466,7 +505,7 @@ |
// Ignore leading zeros in the integer part. |
while (*current == '0') { |
++current; |
- if (current == end) return signed_zero; |
+ if (current == end) return SignedZero(sign); |
} |
} |
@@ -508,7 +547,7 @@ |
// leading zeros (if any). |
while (*current == '0') { |
++current; |
- if (current == end) return signed_zero; |
+ if (current == end) return SignedZero(sign); |
exponent--; // Move this 0 into the exponent. |
} |
} |
@@ -635,7 +674,7 @@ |
ASSERT(exponent == 0); |
buffer_pos += exp_digits; |
} else if (!fractional_part && significant_digits <= kMaxDigitsInInt) { |
- if (significant_digits == 0) return signed_zero; |
+ if (significant_digits == 0) return SignedZero(sign); |
ASSERT(buffer_pos > 0); |
int num = 0; |
int start_pos = (buffer[0] == '-' ? 1 : 0); |
@@ -672,6 +711,25 @@ |
} |
+double StringToInt(String* str, int radix) { |
+ StringShape shape(str); |
+ if (shape.IsSequentialAscii()) { |
+ const char* begin = SeqAsciiString::cast(str)->GetChars(); |
+ const char* end = begin + str->length(); |
+ return InternalStringToInt(begin, end, radix); |
+ } else if (shape.IsSequentialTwoByte()) { |
+ const uc16* begin = SeqTwoByteString::cast(str)->GetChars(); |
+ const uc16* end = begin + str->length(); |
+ return InternalStringToInt(begin, end, radix); |
+ } else { |
+ StringInputBuffer buffer(str); |
+ return InternalStringToInt(StringInputBufferIterator(&buffer), |
+ StringInputBufferIterator::EndMarker(), |
+ radix); |
+ } |
+} |
+ |
+ |
double StringToDouble(const char* str, int flags, double empty_string_val) { |
const char* end = str + StrLength(str); |