Index: runtime/third_party/double-conversion/src/double-conversion.cc |
diff --git a/runtime/third_party/double-conversion/src/double-conversion.cc b/runtime/third_party/double-conversion/src/double-conversion.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..944ddf798eaef829742ff94e6d6f09731913453f |
--- /dev/null |
+++ b/runtime/third_party/double-conversion/src/double-conversion.cc |
@@ -0,0 +1,869 @@ |
+// Copyright 2010 the V8 project authors. All rights reserved. |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following |
+// disclaimer in the documentation and/or other materials provided |
+// with the distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived |
+// from this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+#include <limits.h> |
+#include <math.h> |
+ |
+#include "double-conversion.h" |
+ |
+#include "bignum-dtoa.h" |
+#include "double.h" |
+#include "fast-dtoa.h" |
+#include "fixed-dtoa.h" |
+#include "strtod.h" |
+#include "utils.h" |
+ |
+namespace double_conversion { |
+ |
+const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() { |
+ int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN; |
+ static DoubleToStringConverter converter(flags, |
+ "Infinity", |
+ "NaN", |
+ 'e', |
+ -6, 21, |
+ 6, 0); |
+ return converter; |
+} |
+ |
+ |
+bool DoubleToStringConverter::HandleSpecialValues( |
+ double value, |
+ StringBuilder* result_builder) const { |
+ Double double_inspect(value); |
+ if (double_inspect.IsInfinite()) { |
+ if (infinity_symbol_ == NULL) return false; |
+ if (value < 0) { |
+ result_builder->AddCharacter('-'); |
+ } |
+ result_builder->AddString(infinity_symbol_); |
+ return true; |
+ } |
+ if (double_inspect.IsNan()) { |
+ if (nan_symbol_ == NULL) return false; |
+ result_builder->AddString(nan_symbol_); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+ |
+void DoubleToStringConverter::CreateExponentialRepresentation( |
+ const char* decimal_digits, |
+ int length, |
+ int exponent, |
+ StringBuilder* result_builder) const { |
+ ASSERT(length != 0); |
+ result_builder->AddCharacter(decimal_digits[0]); |
+ if (length != 1) { |
+ result_builder->AddCharacter('.'); |
+ result_builder->AddSubstring(&decimal_digits[1], length-1); |
+ } |
+ result_builder->AddCharacter(exponent_character_); |
+ if (exponent < 0) { |
+ result_builder->AddCharacter('-'); |
+ exponent = -exponent; |
+ } else { |
+ if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { |
+ result_builder->AddCharacter('+'); |
+ } |
+ } |
+ if (exponent == 0) { |
+ result_builder->AddCharacter('0'); |
+ return; |
+ } |
+ ASSERT(exponent < 1e4); |
+ const int kMaxExponentLength = 5; |
+ char buffer[kMaxExponentLength]; |
+ int first_char_pos = kMaxExponentLength; |
+ while (exponent > 0) { |
+ buffer[--first_char_pos] = '0' + (exponent % 10); |
+ exponent /= 10; |
+ } |
+ result_builder->AddSubstring(&buffer[first_char_pos], |
+ kMaxExponentLength - first_char_pos); |
+} |
+ |
+ |
+void DoubleToStringConverter::CreateDecimalRepresentation( |
+ const char* decimal_digits, |
+ int length, |
+ int decimal_point, |
+ int digits_after_point, |
+ StringBuilder* result_builder) const { |
+ // Create a representation that is padded with zeros if needed. |
+ if (decimal_point <= 0) { |
+ // "0.00000decimal_rep". |
+ result_builder->AddCharacter('0'); |
+ if (digits_after_point > 0) { |
+ result_builder->AddCharacter('.'); |
+ result_builder->AddPadding('0', -decimal_point); |
+ ASSERT(length <= digits_after_point - (-decimal_point)); |
+ result_builder->AddSubstring(decimal_digits, length); |
+ int remaining_digits = digits_after_point - (-decimal_point) - length; |
+ result_builder->AddPadding('0', remaining_digits); |
+ } |
+ } else if (decimal_point >= length) { |
+ // "decimal_rep0000.00000" or "decimal_rep.0000" |
+ result_builder->AddSubstring(decimal_digits, length); |
+ result_builder->AddPadding('0', decimal_point - length); |
+ if (digits_after_point > 0) { |
+ result_builder->AddCharacter('.'); |
+ result_builder->AddPadding('0', digits_after_point); |
+ } |
+ } else { |
+ // "decima.l_rep000" |
+ ASSERT(digits_after_point > 0); |
+ result_builder->AddSubstring(decimal_digits, decimal_point); |
+ result_builder->AddCharacter('.'); |
+ ASSERT(length - decimal_point <= digits_after_point); |
+ result_builder->AddSubstring(&decimal_digits[decimal_point], |
+ length - decimal_point); |
+ int remaining_digits = digits_after_point - (length - decimal_point); |
+ result_builder->AddPadding('0', remaining_digits); |
+ } |
+ if (digits_after_point == 0) { |
+ if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { |
+ result_builder->AddCharacter('.'); |
+ } |
+ if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { |
+ result_builder->AddCharacter('0'); |
+ } |
+ } |
+} |
+ |
+ |
+bool DoubleToStringConverter::ToShortest(double value, |
+ StringBuilder* result_builder) const { |
+ if (Double(value).IsSpecial()) { |
+ return HandleSpecialValues(value, result_builder); |
+ } |
+ |
+ int decimal_point; |
+ bool sign; |
+ const int kDecimalRepCapacity = kBase10MaximalLength + 1; |
+ char decimal_rep[kDecimalRepCapacity]; |
+ int decimal_rep_length; |
+ |
+ DoubleToAscii(value, SHORTEST, 0, decimal_rep, kDecimalRepCapacity, |
+ &sign, &decimal_rep_length, &decimal_point); |
+ |
+ bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; |
+ if (sign && (value != 0.0 || !unique_zero)) { |
+ result_builder->AddCharacter('-'); |
+ } |
+ |
+ int exponent = decimal_point - 1; |
+ if ((decimal_in_shortest_low_ <= exponent) && |
+ (exponent < decimal_in_shortest_high_)) { |
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, |
+ decimal_point, |
+ Max(0, decimal_rep_length - decimal_point), |
+ result_builder); |
+ } else { |
+ CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, |
+ result_builder); |
+ } |
+ return true; |
+} |
+ |
+ |
+bool DoubleToStringConverter::ToFixed(double value, |
+ int requested_digits, |
+ StringBuilder* result_builder) const { |
+ ASSERT(kMaxFixedDigitsBeforePoint == 60); |
+ const double kFirstNonFixed = 1e60; |
+ |
+ if (Double(value).IsSpecial()) { |
+ return HandleSpecialValues(value, result_builder); |
+ } |
+ |
+ if (requested_digits > kMaxFixedDigitsAfterPoint) return false; |
+ if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; |
+ |
+ // Find a sufficiently precise decimal representation of n. |
+ int decimal_point; |
+ bool sign; |
+ // Add space for the '\0' byte. |
+ const int kDecimalRepCapacity = |
+ kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; |
+ char decimal_rep[kDecimalRepCapacity]; |
+ int decimal_rep_length; |
+ DoubleToAscii(value, FIXED, requested_digits, |
+ decimal_rep, kDecimalRepCapacity, |
+ &sign, &decimal_rep_length, &decimal_point); |
+ |
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); |
+ if (sign && (value != 0.0 || !unique_zero)) { |
+ result_builder->AddCharacter('-'); |
+ } |
+ |
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, |
+ requested_digits, result_builder); |
+ return true; |
+} |
+ |
+ |
+bool DoubleToStringConverter::ToExponential( |
+ double value, |
+ int requested_digits, |
+ StringBuilder* result_builder) const { |
+ if (Double(value).IsSpecial()) { |
+ return HandleSpecialValues(value, result_builder); |
+ } |
+ |
+ if (requested_digits < -1) return false; |
+ if (requested_digits > kMaxExponentialDigits) return false; |
+ |
+ int decimal_point; |
+ bool sign; |
+ // Add space for digit before the decimal point and the '\0' character. |
+ const int kDecimalRepCapacity = kMaxExponentialDigits + 2; |
+ ASSERT(kDecimalRepCapacity > kBase10MaximalLength); |
+ char decimal_rep[kDecimalRepCapacity]; |
+ int decimal_rep_length; |
+ |
+ if (requested_digits == -1) { |
+ DoubleToAscii(value, SHORTEST, 0, |
+ decimal_rep, kDecimalRepCapacity, |
+ &sign, &decimal_rep_length, &decimal_point); |
+ } else { |
+ DoubleToAscii(value, PRECISION, requested_digits + 1, |
+ decimal_rep, kDecimalRepCapacity, |
+ &sign, &decimal_rep_length, &decimal_point); |
+ ASSERT(decimal_rep_length <= requested_digits + 1); |
+ |
+ for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { |
+ decimal_rep[i] = '0'; |
+ } |
+ decimal_rep_length = requested_digits + 1; |
+ } |
+ |
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); |
+ if (sign && (value != 0.0 || !unique_zero)) { |
+ result_builder->AddCharacter('-'); |
+ } |
+ |
+ int exponent = decimal_point - 1; |
+ CreateExponentialRepresentation(decimal_rep, |
+ decimal_rep_length, |
+ exponent, |
+ result_builder); |
+ return true; |
+} |
+ |
+ |
+bool DoubleToStringConverter::ToPrecision(double value, |
+ int precision, |
+ StringBuilder* result_builder) const { |
+ if (Double(value).IsSpecial()) { |
+ return HandleSpecialValues(value, result_builder); |
+ } |
+ |
+ if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { |
+ return false; |
+ } |
+ |
+ // Find a sufficiently precise decimal representation of n. |
+ int decimal_point; |
+ bool sign; |
+ // Add one for the terminating null character. |
+ const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; |
+ char decimal_rep[kDecimalRepCapacity]; |
+ int decimal_rep_length; |
+ |
+ DoubleToAscii(value, PRECISION, precision, |
+ decimal_rep, kDecimalRepCapacity, |
+ &sign, &decimal_rep_length, &decimal_point); |
+ ASSERT(decimal_rep_length <= precision); |
+ |
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); |
+ if (sign && (value != 0.0 || !unique_zero)) { |
+ result_builder->AddCharacter('-'); |
+ } |
+ |
+ // The exponent if we print the number as x.xxeyyy. That is with the |
+ // decimal point after the first digit. |
+ int exponent = decimal_point - 1; |
+ |
+ int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; |
+ if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || |
+ (decimal_point - precision + extra_zero > |
+ max_trailing_padding_zeroes_in_precision_mode_)) { |
+ // Fill buffer to contain 'precision' digits. |
+ // Usually the buffer is already at the correct length, but 'DoubleToAscii' |
+ // is allowed to return less characters. |
+ for (int i = decimal_rep_length; i < precision; ++i) { |
+ decimal_rep[i] = '0'; |
+ } |
+ |
+ CreateExponentialRepresentation(decimal_rep, |
+ precision, |
+ exponent, |
+ result_builder); |
+ } else { |
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, |
+ Max(0, precision - decimal_point), |
+ result_builder); |
+ } |
+ return true; |
+} |
+ |
+ |
+static BignumDtoaMode DtoaToBignumDtoaMode( |
+ DoubleToStringConverter::DtoaMode dtoa_mode) { |
+ switch (dtoa_mode) { |
+ case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; |
+ case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; |
+ case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; |
+ default: |
+ UNREACHABLE(); |
+ return BIGNUM_DTOA_SHORTEST; // To silence compiler. |
+ } |
+} |
+ |
+ |
+void DoubleToStringConverter::DoubleToAscii(double v, |
+ DtoaMode mode, |
+ int requested_digits, |
+ char* buffer, |
+ int buffer_length, |
+ bool* sign, |
+ int* length, |
+ int* point) { |
+ Vector<char> vector(buffer, buffer_length); |
+ ASSERT(!Double(v).IsSpecial()); |
+ ASSERT(mode == SHORTEST || requested_digits >= 0); |
+ |
+ if (Double(v).Sign() < 0) { |
+ *sign = true; |
+ v = -v; |
+ } else { |
+ *sign = false; |
+ } |
+ |
+ if (mode == PRECISION && requested_digits == 0) { |
+ vector[0] = '\0'; |
+ *length = 0; |
+ return; |
+ } |
+ |
+ if (v == 0) { |
+ vector[0] = '0'; |
+ vector[1] = '\0'; |
+ *length = 1; |
+ *point = 1; |
+ return; |
+ } |
+ |
+ bool fast_worked; |
+ switch (mode) { |
+ case SHORTEST: |
+ fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); |
+ break; |
+ case FIXED: |
+ fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); |
+ break; |
+ case PRECISION: |
+ fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, |
+ vector, length, point); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ fast_worked = false; |
+ } |
+ if (fast_worked) return; |
+ |
+ // If the fast dtoa didn't succeed use the slower bignum version. |
+ BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); |
+ BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); |
+ vector[*length] = '\0'; |
+} |
+ |
+ |
+// Consumes the given substring from the iterator. |
+// Returns false, if the substring does not match. |
+static bool ConsumeSubString(const char** current, |
+ const char* end, |
+ const char* substring) { |
+ ASSERT(**current == *substring); |
+ for (substring++; *substring != '\0'; substring++) { |
+ ++*current; |
+ if (*current == end || **current != *substring) return false; |
+ } |
+ ++*current; |
+ return true; |
+} |
+ |
+ |
+// Maximum number of significant digits in decimal representation. |
+// The longest possible double in decimal representation is |
+// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074 |
+// (768 digits). If we parse a number whose first digits are equal to a |
+// mean of 2 adjacent doubles (that could have up to 769 digits) the result |
+// must be rounded to the bigger one unless the tail consists of zeros, so |
+// we don't need to preserve all the digits. |
+const int kMaxSignificantDigits = 772; |
+ |
+ |
+// Returns true if a nonspace found and false if the end has reached. |
+static inline bool AdvanceToNonspace(const char** current, const char* end) { |
+ while (*current != end) { |
+ if (**current != ' ') return true; |
+ ++*current; |
+ } |
+ return false; |
+} |
+ |
+ |
+static bool isDigit(int x, int radix) { |
+ return (x >= '0' && x <= '9' && x < '0' + radix) |
+ || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) |
+ || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); |
+} |
+ |
+ |
+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> |
+static double RadixStringToDouble(const char* current, |
+ const char* end, |
+ bool sign, |
+ bool allow_trailing_junk, |
+ double junk_string_value, |
+ const char** trailing_pointer) { |
+ ASSERT(current != end); |
+ |
+ // Skip leading 0s. |
+ while (*current == '0') { |
+ ++current; |
+ if (current == end) { |
+ *trailing_pointer = end; |
+ return SignedZero(sign); |
+ } |
+ } |
+ |
+ int64_t number = 0; |
+ int exponent = 0; |
+ const int radix = (1 << radix_log_2); |
+ |
+ do { |
+ int digit; |
+ if (*current >= '0' && *current <= '9' && *current < '0' + radix) { |
+ digit = static_cast<char>(*current) - '0'; |
+ } else if (radix > 10 && *current >= 'a' && *current < 'a' + radix - 10) { |
+ digit = static_cast<char>(*current) - 'a' + 10; |
+ } else if (radix > 10 && *current >= 'A' && *current < 'A' + radix - 10) { |
+ digit = static_cast<char>(*current) - 'A' + 10; |
+ } else { |
+ if (allow_trailing_junk || !AdvanceToNonspace(¤t, end)) { |
+ break; |
+ } else { |
+ return junk_string_value; |
+ } |
+ } |
+ |
+ number = number * radix + digit; |
+ int overflow = static_cast<int>(number >> 53); |
+ if (overflow != 0) { |
+ // Overflow occurred. Need to determine which direction to round the |
+ // result. |
+ int overflow_bits_count = 1; |
+ while (overflow > 1) { |
+ overflow_bits_count++; |
+ overflow >>= 1; |
+ } |
+ |
+ int dropped_bits_mask = ((1 << overflow_bits_count) - 1); |
+ int dropped_bits = static_cast<int>(number) & dropped_bits_mask; |
+ number >>= overflow_bits_count; |
+ exponent = overflow_bits_count; |
+ |
+ bool zero_tail = true; |
+ while (true) { |
+ ++current; |
+ if (current == end || !isDigit(*current, radix)) break; |
+ zero_tail = zero_tail && *current == '0'; |
+ exponent += radix_log_2; |
+ } |
+ |
+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
+ return junk_string_value; |
+ } |
+ |
+ int middle_value = (1 << (overflow_bits_count - 1)); |
+ if (dropped_bits > middle_value) { |
+ number++; // Rounding up. |
+ } else if (dropped_bits == middle_value) { |
+ // Rounding to even to consistency with decimals: half-way case rounds |
+ // up if significant part is odd and down otherwise. |
+ if ((number & 1) != 0 || !zero_tail) { |
+ number++; // Rounding up. |
+ } |
+ } |
+ |
+ // Rounding up may cause overflow. |
+ if ((number & ((int64_t)1 << 53)) != 0) { |
+ exponent++; |
+ number >>= 1; |
+ } |
+ break; |
+ } |
+ ++current; |
+ } while (current != end); |
+ |
+ ASSERT(number < ((int64_t)1 << 53)); |
+ ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number); |
+ |
+ *trailing_pointer = current; |
+ |
+ if (exponent == 0) { |
+ if (sign) { |
+ if (number == 0) return -0.0; |
+ number = -number; |
+ } |
+ return static_cast<double>(number); |
+ } |
+ |
+ ASSERT(number != 0); |
+ return Double(DiyFp(number, exponent)).value(); |
+} |
+ |
+ |
+double StringToDoubleConverter::StringToDouble( |
+ const char* input, |
+ int length, |
+ int* processed_characters_count) { |
+ const char* current = input; |
+ const char* end = input + length; |
+ |
+ *processed_characters_count = 0; |
+ |
+ const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0; |
+ const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; |
+ const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; |
+ const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; |
+ |
+ // To make sure that iterator dereferencing is valid the following |
+ // convention is used: |
+ // 1. Each '++current' statement is followed by check for equality to 'end'. |
+ // 2. If AdvanceToNonspace returned false then current == end. |
+ // 3. If 'current' becomes equal to 'end' the function returns or goes to |
+ // 'parsing_done'. |
+ // 4. 'current' is not dereferenced after the 'parsing_done' label. |
+ // 5. Code before 'parsing_done' may rely on 'current != end'. |
+ if (current == end) return empty_string_value_; |
+ |
+ if (allow_leading_spaces || allow_trailing_spaces) { |
+ if (!AdvanceToNonspace(¤t, end)) { |
+ *processed_characters_count = current - input; |
+ return empty_string_value_; |
+ } |
+ if (!allow_leading_spaces && (input != current)) { |
+ // No leading spaces allowed, but AdvanceToNonspace moved forward. |
+ return junk_string_value_; |
+ } |
+ } |
+ |
+ // The longest form of simplified number is: "-<significant digits>.1eXXX\0". |
+ const int kBufferSize = kMaxSignificantDigits + 10; |
+ char buffer[kBufferSize]; // NOLINT: size is known at compile time. |
+ int buffer_pos = 0; |
+ |
+ // Exponent will be adjusted if insignificant digits of the integer part |
+ // or insignificant leading zeros of the fractional part are dropped. |
+ int exponent = 0; |
+ int significant_digits = 0; |
+ int insignificant_digits = 0; |
+ bool nonzero_digit_dropped = false; |
+ bool fractional_part = false; |
+ |
+ bool sign = false; |
+ |
+ if (*current == '+' || *current == '-') { |
+ sign = (*current == '-'); |
+ ++current; |
+ const char* next_non_space = current; |
+ // Skip following spaces (if allowed). |
+ if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_; |
+ if (!allow_spaces_after_sign && (current != next_non_space)) { |
+ return junk_string_value_; |
+ } |
+ current = next_non_space; |
+ } |
+ |
+ if (infinity_symbol_ != NULL) { |
+ if (*current == infinity_symbol_[0]) { |
+ if (!ConsumeSubString(¤t, end, infinity_symbol_)) { |
+ return junk_string_value_; |
+ } |
+ |
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
+ return junk_string_value_; |
+ } |
+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
+ return junk_string_value_; |
+ } |
+ |
+ ASSERT(buffer_pos == 0); |
+ *processed_characters_count = current - input; |
+ return sign ? -Double::Infinity() : Double::Infinity(); |
+ } |
+ } |
+ |
+ if (nan_symbol_ != NULL) { |
+ if (*current == nan_symbol_[0]) { |
+ if (!ConsumeSubString(¤t, end, nan_symbol_)) { |
+ return junk_string_value_; |
+ } |
+ |
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
+ return junk_string_value_; |
+ } |
+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
+ return junk_string_value_; |
+ } |
+ |
+ ASSERT(buffer_pos == 0); |
+ *processed_characters_count = current - input; |
+ return sign ? -Double::NaN() : Double::NaN(); |
+ } |
+ } |
+ |
+ bool leading_zero = false; |
+ if (*current == '0') { |
+ ++current; |
+ if (current == end) { |
+ *processed_characters_count = current - input; |
+ return SignedZero(sign); |
+ } |
+ |
+ leading_zero = true; |
+ |
+ // It could be hexadecimal value. |
+ if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { |
+ ++current; |
+ if (current == end || !isDigit(*current, 16)) { |
+ return junk_string_value_; // "0x". |
+ } |
+ |
+ const char* tail_pointer = NULL; |
+ double result = RadixStringToDouble<4>(current, |
+ end, |
+ sign, |
+ allow_trailing_junk, |
+ junk_string_value_, |
+ &tail_pointer); |
+ if (tail_pointer != NULL) { |
+ if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end); |
+ *processed_characters_count = tail_pointer - input; |
+ } |
+ return result; |
+ } |
+ |
+ // Ignore leading zeros in the integer part. |
+ while (*current == '0') { |
+ ++current; |
+ if (current == end) { |
+ *processed_characters_count = current - input; |
+ return SignedZero(sign); |
+ } |
+ } |
+ } |
+ |
+ bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0; |
+ |
+ // Copy significant digits of the integer part (if any) to the buffer. |
+ while (*current >= '0' && *current <= '9') { |
+ if (significant_digits < kMaxSignificantDigits) { |
+ ASSERT(buffer_pos < kBufferSize); |
+ buffer[buffer_pos++] = static_cast<char>(*current); |
+ significant_digits++; |
+ // Will later check if it's an octal in the buffer. |
+ } else { |
+ insignificant_digits++; // Move the digit into the exponential part. |
+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; |
+ } |
+ octal = octal && *current < '8'; |
+ ++current; |
+ if (current == end) goto parsing_done; |
+ } |
+ |
+ if (significant_digits == 0) { |
+ octal = false; |
+ } |
+ |
+ if (*current == '.') { |
+ if (octal && !allow_trailing_junk) return junk_string_value_; |
+ if (octal) goto parsing_done; |
+ |
+ ++current; |
+ if (current == end) { |
+ if (significant_digits == 0 && !leading_zero) { |
+ return junk_string_value_; |
+ } else { |
+ goto parsing_done; |
+ } |
+ } |
+ |
+ if (significant_digits == 0) { |
+ // octal = false; |
+ // Integer part consists of 0 or is absent. Significant digits start after |
+ // leading zeros (if any). |
+ while (*current == '0') { |
+ ++current; |
+ if (current == end) { |
+ *processed_characters_count = current - input; |
+ return SignedZero(sign); |
+ } |
+ exponent--; // Move this 0 into the exponent. |
+ } |
+ } |
+ |
+ // We don't emit a '.', but adjust the exponent instead. |
+ fractional_part = true; |
+ |
+ // There is a fractional part. |
+ while (*current >= '0' && *current <= '9') { |
+ if (significant_digits < kMaxSignificantDigits) { |
+ ASSERT(buffer_pos < kBufferSize); |
+ buffer[buffer_pos++] = static_cast<char>(*current); |
+ significant_digits++; |
+ exponent--; |
+ } else { |
+ // Ignore insignificant digits in the fractional part. |
+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; |
+ } |
+ ++current; |
+ if (current == end) goto parsing_done; |
+ } |
+ } |
+ |
+ if (!leading_zero && exponent == 0 && significant_digits == 0) { |
+ // If leading_zeros is true then the string contains zeros. |
+ // If exponent < 0 then string was [+-]\.0*... |
+ // If significant_digits != 0 the string is not equal to 0. |
+ // Otherwise there are no digits in the string. |
+ return junk_string_value_; |
+ } |
+ |
+ // Parse exponential part. |
+ if (*current == 'e' || *current == 'E') { |
+ if (octal && !allow_trailing_junk) return junk_string_value_; |
+ if (octal) goto parsing_done; |
+ ++current; |
+ if (current == end) { |
+ if (allow_trailing_junk) { |
+ goto parsing_done; |
+ } else { |
+ return junk_string_value_; |
+ } |
+ } |
+ char sign = '+'; |
+ if (*current == '+' || *current == '-') { |
+ sign = static_cast<char>(*current); |
+ ++current; |
+ if (current == end) { |
+ if (allow_trailing_junk) { |
+ goto parsing_done; |
+ } else { |
+ return junk_string_value_; |
+ } |
+ } |
+ } |
+ |
+ if (current == end || *current < '0' || *current > '9') { |
+ if (allow_trailing_junk) { |
+ goto parsing_done; |
+ } else { |
+ return junk_string_value_; |
+ } |
+ } |
+ |
+ const int max_exponent = INT_MAX / 2; |
+ ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); |
+ int num = 0; |
+ do { |
+ // Check overflow. |
+ int digit = *current - '0'; |
+ if (num >= max_exponent / 10 |
+ && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { |
+ num = max_exponent; |
+ } else { |
+ num = num * 10 + digit; |
+ } |
+ ++current; |
+ } while (current != end && *current >= '0' && *current <= '9'); |
+ |
+ exponent += (sign == '-' ? -num : num); |
+ } |
+ |
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
+ return junk_string_value_; |
+ } |
+ if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { |
+ return junk_string_value_; |
+ } |
+ if (allow_trailing_spaces) { |
+ AdvanceToNonspace(¤t, end); |
+ } |
+ |
+ parsing_done: |
+ exponent += insignificant_digits; |
+ |
+ if (octal) { |
+ double result; |
+ const char* tail_pointer = NULL; |
+ result = RadixStringToDouble<3>(buffer, |
+ buffer + buffer_pos, |
+ sign, |
+ allow_trailing_junk, |
+ junk_string_value_, |
+ &tail_pointer); |
+ ASSERT(tail_pointer != NULL); |
+ *processed_characters_count = current - input; |
+ return result; |
+ } |
+ |
+ if (nonzero_digit_dropped) { |
+ buffer[buffer_pos++] = '1'; |
+ exponent--; |
+ } |
+ |
+ ASSERT(buffer_pos < kBufferSize); |
+ buffer[buffer_pos] = '\0'; |
+ |
+ double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent); |
+ *processed_characters_count = current - input; |
+ return sign? -converted: converted; |
+} |
+ |
+} // namespace double_conversion |