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