|
|
@ -28,14 +28,14 @@ |
|
|
|
#include <limits.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "double-conversion.h"
|
|
|
|
#include "double-conversion/double-conversion.h"
|
|
|
|
|
|
|
|
#include "bignum-dtoa.h"
|
|
|
|
#include "fast-dtoa.h"
|
|
|
|
#include "fixed-dtoa.h"
|
|
|
|
#include "ieee.h"
|
|
|
|
#include "strtod.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "double-conversion/bignum-dtoa.h"
|
|
|
|
#include "double-conversion/fast-dtoa.h"
|
|
|
|
#include "double-conversion/fixed-dtoa.h"
|
|
|
|
#include "double-conversion/ieee.h"
|
|
|
|
#include "double-conversion/strtod.h"
|
|
|
|
#include "double-conversion/utils.h"
|
|
|
|
|
|
|
|
namespace double_conversion { |
|
|
|
|
|
|
@ -348,7 +348,6 @@ static BignumDtoaMode DtoaToBignumDtoaMode( |
|
|
|
case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
return BIGNUM_DTOA_SHORTEST; // To silence compiler.
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -403,8 +402,8 @@ void DoubleToStringConverter::DoubleToAscii(double v, |
|
|
|
vector, length, point); |
|
|
|
break; |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
fast_worked = false; |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
if (fast_worked) return; |
|
|
|
|
|
|
@ -417,8 +416,9 @@ void DoubleToStringConverter::DoubleToAscii(double v, |
|
|
|
|
|
|
|
// Consumes the given substring from the iterator.
|
|
|
|
// Returns false, if the substring does not match.
|
|
|
|
static bool ConsumeSubString(const char** current, |
|
|
|
const char* end, |
|
|
|
template <class Iterator> |
|
|
|
static bool ConsumeSubString(Iterator* current, |
|
|
|
Iterator end, |
|
|
|
const char* substring) { |
|
|
|
ASSERT(**current == *substring); |
|
|
|
for (substring++; *substring != '\0'; substring++) { |
|
|
@ -440,10 +440,36 @@ static bool ConsumeSubString(const char** current, |
|
|
|
const int kMaxSignificantDigits = 772; |
|
|
|
|
|
|
|
|
|
|
|
static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 }; |
|
|
|
static const int kWhitespaceTable7Length = ARRAY_SIZE(kWhitespaceTable7); |
|
|
|
|
|
|
|
|
|
|
|
static const uc16 kWhitespaceTable16[] = { |
|
|
|
160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195, |
|
|
|
8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279 |
|
|
|
}; |
|
|
|
static const int kWhitespaceTable16Length = ARRAY_SIZE(kWhitespaceTable16); |
|
|
|
|
|
|
|
|
|
|
|
static bool isWhitespace(int x) { |
|
|
|
if (x < 128) { |
|
|
|
for (int i = 0; i < kWhitespaceTable7Length; i++) { |
|
|
|
if (kWhitespaceTable7[i] == x) return true; |
|
|
|
} |
|
|
|
} else { |
|
|
|
for (int i = 0; i < kWhitespaceTable16Length; i++) { |
|
|
|
if (kWhitespaceTable16[i] == x) return true; |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Returns true if a nonspace found and false if the end has reached.
|
|
|
|
static inline bool AdvanceToNonspace(const char** current, const char* end) { |
|
|
|
template <class Iterator> |
|
|
|
static inline bool AdvanceToNonspace(Iterator* current, Iterator end) { |
|
|
|
while (*current != end) { |
|
|
|
if (**current != ' ') return true; |
|
|
|
if (!isWhitespace(**current)) return true; |
|
|
|
++*current; |
|
|
|
} |
|
|
|
return false; |
|
|
@ -462,26 +488,57 @@ static double SignedZero(bool sign) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Returns true if 'c' is a decimal digit that is valid for the given radix.
|
|
|
|
//
|
|
|
|
// The function is small and could be inlined, but VS2012 emitted a warning
|
|
|
|
// because it constant-propagated the radix and concluded that the last
|
|
|
|
// condition was always true. By moving it into a separate function the
|
|
|
|
// compiler wouldn't warn anymore.
|
|
|
|
#if _MSC_VER
|
|
|
|
#pragma optimize("",off)
|
|
|
|
static bool IsDecimalDigitForRadix(int c, int radix) { |
|
|
|
return '0' <= c && c <= '9' && (c - '0') < radix; |
|
|
|
} |
|
|
|
#pragma optimize("",on)
|
|
|
|
#else
|
|
|
|
static bool inline IsDecimalDigitForRadix(int c, int radix) { |
|
|
|
return '0' <= c && c <= '9' && (c - '0') < radix; |
|
|
|
} |
|
|
|
#endif
|
|
|
|
// Returns true if 'c' is a character digit that is valid for the given radix.
|
|
|
|
// The 'a_character' should be 'a' or 'A'.
|
|
|
|
//
|
|
|
|
// The function is small and could be inlined, but VS2012 emitted a warning
|
|
|
|
// because it constant-propagated the radix and concluded that the first
|
|
|
|
// condition was always false. By moving it into a separate function the
|
|
|
|
// compiler wouldn't warn anymore.
|
|
|
|
static bool IsCharacterDigitForRadix(int c, int radix, char a_character) { |
|
|
|
return radix > 10 && c >= a_character && c < a_character + radix - 10; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
|
|
|
|
template <int radix_log_2> |
|
|
|
static double RadixStringToIeee(const char* current, |
|
|
|
const char* end, |
|
|
|
template <int radix_log_2, class Iterator> |
|
|
|
static double RadixStringToIeee(Iterator* current, |
|
|
|
Iterator end, |
|
|
|
bool sign, |
|
|
|
bool allow_trailing_junk, |
|
|
|
double junk_string_value, |
|
|
|
bool read_as_double, |
|
|
|
const char** trailing_pointer) { |
|
|
|
ASSERT(current != end); |
|
|
|
bool* result_is_junk) { |
|
|
|
ASSERT(*current != end); |
|
|
|
|
|
|
|
const int kDoubleSize = Double::kSignificandSize; |
|
|
|
const int kSingleSize = Single::kSignificandSize; |
|
|
|
const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize; |
|
|
|
|
|
|
|
*result_is_junk = true; |
|
|
|
|
|
|
|
// Skip leading 0s.
|
|
|
|
while (*current == '0') { |
|
|
|
++current; |
|
|
|
if (current == end) { |
|
|
|
*trailing_pointer = end; |
|
|
|
while (**current == '0') { |
|
|
|
++(*current); |
|
|
|
if (*current == end) { |
|
|
|
*result_is_junk = false; |
|
|
|
return SignedZero(sign); |
|
|
|
} |
|
|
|
} |
|
|
@ -492,14 +549,14 @@ static double RadixStringToIeee(const char* current, |
|
|
|
|
|
|
|
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; |
|
|
|
if (IsDecimalDigitForRadix(**current, radix)) { |
|
|
|
digit = static_cast<char>(**current) - '0'; |
|
|
|
} else if (IsCharacterDigitForRadix(**current, radix, 'a')) { |
|
|
|
digit = static_cast<char>(**current) - 'a' + 10; |
|
|
|
} else if (IsCharacterDigitForRadix(**current, radix, 'A')) { |
|
|
|
digit = static_cast<char>(**current) - 'A' + 10; |
|
|
|
} else { |
|
|
|
if (allow_trailing_junk || !AdvanceToNonspace(¤t, end)) { |
|
|
|
if (allow_trailing_junk || !AdvanceToNonspace(current, end)) { |
|
|
|
break; |
|
|
|
} else { |
|
|
|
return junk_string_value; |
|
|
@ -523,14 +580,14 @@ static double RadixStringToIeee(const char* current, |
|
|
|
exponent = overflow_bits_count; |
|
|
|
|
|
|
|
bool zero_tail = true; |
|
|
|
while (true) { |
|
|
|
++current; |
|
|
|
if (current == end || !isDigit(*current, radix)) break; |
|
|
|
zero_tail = zero_tail && *current == '0'; |
|
|
|
for (;;) { |
|
|
|
++(*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)) { |
|
|
|
if (!allow_trailing_junk && AdvanceToNonspace(current, end)) { |
|
|
|
return junk_string_value; |
|
|
|
} |
|
|
|
|
|
|
@ -552,13 +609,13 @@ static double RadixStringToIeee(const char* current, |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
++current; |
|
|
|
} while (current != end); |
|
|
|
++(*current); |
|
|
|
} while (*current != end); |
|
|
|
|
|
|
|
ASSERT(number < ((int64_t)1 << kSignificandSize)); |
|
|
|
ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number); |
|
|
|
|
|
|
|
*trailing_pointer = current; |
|
|
|
*result_is_junk = false; |
|
|
|
|
|
|
|
if (exponent == 0) { |
|
|
|
if (sign) { |
|
|
@ -573,13 +630,14 @@ static double RadixStringToIeee(const char* current, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <class Iterator> |
|
|
|
double StringToDoubleConverter::StringToIeee( |
|
|
|
const char* input, |
|
|
|
Iterator input, |
|
|
|
int length, |
|
|
|
int* processed_characters_count, |
|
|
|
bool read_as_double) { |
|
|
|
const char* current = input; |
|
|
|
const char* end = input + length; |
|
|
|
bool read_as_double, |
|
|
|
int* processed_characters_count) const { |
|
|
|
Iterator current = input; |
|
|
|
Iterator end = input + length; |
|
|
|
|
|
|
|
*processed_characters_count = 0; |
|
|
|
|
|
|
@ -600,7 +658,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
|
|
|
|
if (allow_leading_spaces || allow_trailing_spaces) { |
|
|
|
if (!AdvanceToNonspace(¤t, end)) { |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return empty_string_value_; |
|
|
|
} |
|
|
|
if (!allow_leading_spaces && (input != current)) { |
|
|
@ -626,7 +684,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
if (*current == '+' || *current == '-') { |
|
|
|
sign = (*current == '-'); |
|
|
|
++current; |
|
|
|
const char* next_non_space = current; |
|
|
|
Iterator 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)) { |
|
|
@ -649,7 +707,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
} |
|
|
|
|
|
|
|
ASSERT(buffer_pos == 0); |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return sign ? -Double::Infinity() : Double::Infinity(); |
|
|
|
} |
|
|
|
} |
|
|
@ -668,7 +726,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
} |
|
|
|
|
|
|
|
ASSERT(buffer_pos == 0); |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return sign ? -Double::NaN() : Double::NaN(); |
|
|
|
} |
|
|
|
} |
|
|
@ -677,7 +735,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
if (*current == '0') { |
|
|
|
++current; |
|
|
|
if (current == end) { |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return SignedZero(sign); |
|
|
|
} |
|
|
|
|
|
|
@ -690,17 +748,17 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
return junk_string_value_; // "0x".
|
|
|
|
} |
|
|
|
|
|
|
|
const char* tail_pointer = NULL; |
|
|
|
double result = RadixStringToIeee<4>(current, |
|
|
|
bool result_is_junk; |
|
|
|
double result = RadixStringToIeee<4>(¤t, |
|
|
|
end, |
|
|
|
sign, |
|
|
|
allow_trailing_junk, |
|
|
|
junk_string_value_, |
|
|
|
read_as_double, |
|
|
|
&tail_pointer); |
|
|
|
if (tail_pointer != NULL) { |
|
|
|
if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end); |
|
|
|
*processed_characters_count = tail_pointer - input; |
|
|
|
&result_is_junk); |
|
|
|
if (!result_is_junk) { |
|
|
|
if (allow_trailing_spaces) AdvanceToNonspace(¤t, end); |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
@ -709,7 +767,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
while (*current == '0') { |
|
|
|
++current; |
|
|
|
if (current == end) { |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return SignedZero(sign); |
|
|
|
} |
|
|
|
} |
|
|
@ -757,7 +815,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
while (*current == '0') { |
|
|
|
++current; |
|
|
|
if (current == end) { |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return SignedZero(sign); |
|
|
|
} |
|
|
|
exponent--; // Move this 0 into the exponent.
|
|
|
@ -801,9 +859,9 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
return junk_string_value_; |
|
|
|
} |
|
|
|
} |
|
|
|
char sign = '+'; |
|
|
|
char exponen_sign = '+'; |
|
|
|
if (*current == '+' || *current == '-') { |
|
|
|
sign = static_cast<char>(*current); |
|
|
|
exponen_sign = static_cast<char>(*current); |
|
|
|
++current; |
|
|
|
if (current == end) { |
|
|
|
if (allow_trailing_junk) { |
|
|
@ -837,7 +895,7 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
++current; |
|
|
|
} while (current != end && *current >= '0' && *current <= '9'); |
|
|
|
|
|
|
|
exponent += (sign == '-' ? -num : num); |
|
|
|
exponent += (exponen_sign == '-' ? -num : num); |
|
|
|
} |
|
|
|
|
|
|
|
if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { |
|
|
@ -855,16 +913,17 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
|
|
|
|
if (octal) { |
|
|
|
double result; |
|
|
|
const char* tail_pointer = NULL; |
|
|
|
result = RadixStringToIeee<3>(buffer, |
|
|
|
bool result_is_junk; |
|
|
|
char* start = buffer; |
|
|
|
result = RadixStringToIeee<3>(&start, |
|
|
|
buffer + buffer_pos, |
|
|
|
sign, |
|
|
|
allow_trailing_junk, |
|
|
|
junk_string_value_, |
|
|
|
read_as_double, |
|
|
|
&tail_pointer); |
|
|
|
ASSERT(tail_pointer != NULL); |
|
|
|
*processed_characters_count = current - input; |
|
|
|
&result_is_junk); |
|
|
|
ASSERT(!result_is_junk); |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
@ -882,8 +941,42 @@ double StringToDoubleConverter::StringToIeee( |
|
|
|
} else { |
|
|
|
converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent); |
|
|
|
} |
|
|
|
*processed_characters_count = current - input; |
|
|
|
*processed_characters_count = static_cast<int>(current - input); |
|
|
|
return sign? -converted: converted; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double StringToDoubleConverter::StringToDouble( |
|
|
|
const char* buffer, |
|
|
|
int length, |
|
|
|
int* processed_characters_count) const { |
|
|
|
return StringToIeee(buffer, length, true, processed_characters_count); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double StringToDoubleConverter::StringToDouble( |
|
|
|
const uc16* buffer, |
|
|
|
int length, |
|
|
|
int* processed_characters_count) const { |
|
|
|
return StringToIeee(buffer, length, true, processed_characters_count); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
float StringToDoubleConverter::StringToFloat( |
|
|
|
const char* buffer, |
|
|
|
int length, |
|
|
|
int* processed_characters_count) const { |
|
|
|
return static_cast<float>(StringToIeee(buffer, length, false, |
|
|
|
processed_characters_count)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
float StringToDoubleConverter::StringToFloat( |
|
|
|
const uc16* buffer, |
|
|
|
int length, |
|
|
|
int* processed_characters_count) const { |
|
|
|
return static_cast<float>(StringToIeee(buffer, length, false, |
|
|
|
processed_characters_count)); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace double_conversion
|