Browse Source

Upgrade to double-converson 3.1.4

pull/184/head
Paul J. Davis 6 years ago
parent
commit
8813ee3eec
18 changed files with 393 additions and 131 deletions
  1. +6
    -6
      c_src/double-conversion/README.md
  2. +2
    -1
      c_src/double-conversion/VERSION
  3. +1
    -1
      c_src/double-conversion/bignum-dtoa.cc
  4. +1
    -1
      c_src/double-conversion/bignum-dtoa.h
  5. +7
    -6
      c_src/double-conversion/bignum.cc
  6. +2
    -2
      c_src/double-conversion/bignum.h
  7. +5
    -6
      c_src/double-conversion/cached-powers.cc
  8. +2
    -2
      c_src/double-conversion/diy-fp.cc
  9. +1
    -1
      c_src/double-conversion/diy-fp.h
  10. +219
    -57
      c_src/double-conversion/double-conversion.cc
  11. +43
    -10
      c_src/double-conversion/double-conversion.h
  12. +1
    -1
      c_src/double-conversion/fast-dtoa.h
  13. +4
    -3
      c_src/double-conversion/fixed-dtoa.cc
  14. +1
    -1
      c_src/double-conversion/fixed-dtoa.h
  15. +3
    -3
      c_src/double-conversion/ieee.h
  16. +34
    -9
      c_src/double-conversion/strtod.cc
  17. +1
    -1
      c_src/double-conversion/strtod.h
  18. +60
    -20
      c_src/double-conversion/utils.h

c_src/double-conversion/README → c_src/double-conversion/README.md View File

@ -1,4 +1,4 @@
https://github.com/google/double-conversion/
https://github.com/google/double-conversion
This project (double-conversion) provides binary-decimal and decimal-binary This project (double-conversion) provides binary-decimal and decimal-binary
routines for IEEE doubles. routines for IEEE doubles.
@ -7,14 +7,14 @@ The library consists of efficient conversion routines that have been extracted
from the V8 JavaScript engine. The code has been refactored and improved so that from the V8 JavaScript engine. The code has been refactored and improved so that
it can be used more easily in other projects. it can be used more easily in other projects.
There is extensive documentation in src/double-conversion.h. Other examples can
be found in test/cctest/test-conversions.cc.
There is extensive documentation in `double-conversion/double-conversion.h`. Other
examples can be found in `test/cctest/test-conversions.cc`.
Building Building
======== ========
This library can be built with scons [0] or cmake [1].
This library can be built with [scons][0] or [cmake][1].
The checked-in Makefile simply forwards to scons, and provides a The checked-in Makefile simply forwards to scons, and provides a
shortcut to run all tests: shortcut to run all tests:
@ -50,5 +50,5 @@ Use `-DBUILD_TESTING=ON` to build the test executable.
make make
test/cctest/cctest --list | tr -d '<' | xargs test/cctest/cctest test/cctest/cctest --list | tr -d '<' | xargs test/cctest/cctest
[0]: http://www.scons.org
[1]: http://www.cmake.org
[0]: http://www.scons.org/
[1]: https://cmake.org/

+ 2
- 1
c_src/double-conversion/VERSION View File

@ -1,2 +1,3 @@
Clone from: https://github.com/google/double-conversion Clone from: https://github.com/google/double-conversion
Version: v2.0.1-23-gc3e0c97
Version: v3.1.4
Commit: 8fcee05fae7f2d6962deb9093891c47993c3d6a2

+ 1
- 1
c_src/double-conversion/bignum-dtoa.cc View File

@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <math.h>
#include <cmath>
#include "bignum-dtoa.h" #include "bignum-dtoa.h"

+ 1
- 1
c_src/double-conversion/bignum-dtoa.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_ #ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_
#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_ #define DOUBLE_CONVERSION_BIGNUM_DTOA_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {

+ 7
- 6
c_src/double-conversion/bignum.cc View File

@ -25,13 +25,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "double-conversion/bignum.h"
#include "double-conversion/utils.h"
#include "bignum.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {
Bignum::Bignum() Bignum::Bignum()
: bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
: bigits_buffer_(), bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
for (int i = 0; i < kBigitCapacity; ++i) { for (int i = 0; i < kBigitCapacity; ++i) {
bigits_[i] = 0; bigits_[i] = 0;
} }
@ -445,26 +445,27 @@ void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
mask >>= 2; mask >>= 2;
uint64_t this_value = base; uint64_t this_value = base;
bool delayed_multipliciation = false;
bool delayed_multiplication = false;
const uint64_t max_32bits = 0xFFFFFFFF; const uint64_t max_32bits = 0xFFFFFFFF;
while (mask != 0 && this_value <= max_32bits) { while (mask != 0 && this_value <= max_32bits) {
this_value = this_value * this_value; this_value = this_value * this_value;
// Verify that there is enough space in this_value to perform the // Verify that there is enough space in this_value to perform the
// multiplication. The first bit_size bits must be 0. // multiplication. The first bit_size bits must be 0.
if ((power_exponent & mask) != 0) { if ((power_exponent & mask) != 0) {
ASSERT(bit_size > 0);
uint64_t base_bits_mask = uint64_t base_bits_mask =
~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1); ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
bool high_bits_zero = (this_value & base_bits_mask) == 0; bool high_bits_zero = (this_value & base_bits_mask) == 0;
if (high_bits_zero) { if (high_bits_zero) {
this_value *= base; this_value *= base;
} else { } else {
delayed_multipliciation = true;
delayed_multiplication = true;
} }
} }
mask >>= 1; mask >>= 1;
} }
AssignUInt64(this_value); AssignUInt64(this_value);
if (delayed_multipliciation) {
if (delayed_multiplication) {
MultiplyByUInt32(base); MultiplyByUInt32(base);
} }

+ 2
- 2
c_src/double-conversion/bignum.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_BIGNUM_H_ #ifndef DOUBLE_CONVERSION_BIGNUM_H_
#define DOUBLE_CONVERSION_BIGNUM_H_ #define DOUBLE_CONVERSION_BIGNUM_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {
@ -136,7 +136,7 @@ class Bignum {
// The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize). // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
int exponent_; int exponent_;
DISALLOW_COPY_AND_ASSIGN(Bignum);
DC_DISALLOW_COPY_AND_ASSIGN(Bignum);
}; };
} // namespace double_conversion } // namespace double_conversion

+ 5
- 6
c_src/double-conversion/cached-powers.cc View File

@ -25,11 +25,11 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#include <limits.h>
#include <math.h>
#include <climits>
#include <cmath>
#include <cstdarg>
#include "double-conversion/utils.h"
#include "utils.h"
#include "cached-powers.h" #include "cached-powers.h"
@ -131,7 +131,6 @@ static const CachedPower kCachedPowers[] = {
{UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
}; };
static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);
static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent. static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent.
static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
// Difference between the decimal exponents in the table above. // Difference between the decimal exponents in the table above.
@ -149,7 +148,7 @@ void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
int foo = kCachedPowersOffset; int foo = kCachedPowersOffset;
int index = int index =
(foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1; (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
ASSERT(0 <= index && index < kCachedPowersLength);
ASSERT(0 <= index && index < static_cast<int>(ARRAY_SIZE(kCachedPowers)));
CachedPower cached_power = kCachedPowers[index]; CachedPower cached_power = kCachedPowers[index];
ASSERT(min_exponent <= cached_power.binary_exponent); ASSERT(min_exponent <= cached_power.binary_exponent);
(void) max_exponent; // Mark variable as used. (void) max_exponent; // Mark variable as used.

+ 2
- 2
c_src/double-conversion/diy-fp.cc View File

@ -26,8 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "double-conversion/diy-fp.h"
#include "double-conversion/utils.h"
#include "diy-fp.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {

+ 1
- 1
c_src/double-conversion/diy-fp.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_DIY_FP_H_ #ifndef DOUBLE_CONVERSION_DIY_FP_H_
#define DOUBLE_CONVERSION_DIY_FP_H_ #define DOUBLE_CONVERSION_DIY_FP_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {

+ 219
- 57
c_src/double-conversion/double-conversion.cc View File

@ -25,17 +25,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits.h>
#include <math.h>
#include <climits>
#include <locale>
#include <cmath>
#include "double-conversion/double-conversion.h"
#include "double-conversion.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"
#include "bignum-dtoa.h"
#include "fast-dtoa.h"
#include "fixed-dtoa.h"
#include "ieee.h"
#include "strtod.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {
@ -118,7 +119,7 @@ void DoubleToStringConverter::CreateDecimalRepresentation(
StringBuilder* result_builder) const { StringBuilder* result_builder) const {
// Create a representation that is padded with zeros if needed. // Create a representation that is padded with zeros if needed.
if (decimal_point <= 0) { if (decimal_point <= 0) {
// "0.00000decimal_rep".
// "0.00000decimal_rep" or "0.000decimal_rep00".
result_builder->AddCharacter('0'); result_builder->AddCharacter('0');
if (digits_after_point > 0) { if (digits_after_point > 0) {
result_builder->AddCharacter('.'); result_builder->AddCharacter('.');
@ -129,7 +130,7 @@ void DoubleToStringConverter::CreateDecimalRepresentation(
result_builder->AddPadding('0', remaining_digits); result_builder->AddPadding('0', remaining_digits);
} }
} else if (decimal_point >= length) { } else if (decimal_point >= length) {
// "decimal_rep0000.00000" or "decimal_rep.0000"
// "decimal_rep0000.00000" or "decimal_rep.0000".
result_builder->AddSubstring(decimal_digits, length); result_builder->AddSubstring(decimal_digits, length);
result_builder->AddPadding('0', decimal_point - length); result_builder->AddPadding('0', decimal_point - length);
if (digits_after_point > 0) { if (digits_after_point > 0) {
@ -137,7 +138,7 @@ void DoubleToStringConverter::CreateDecimalRepresentation(
result_builder->AddPadding('0', digits_after_point); result_builder->AddPadding('0', digits_after_point);
} }
} else { } else {
// "decima.l_rep000"
// "decima.l_rep000".
ASSERT(digits_after_point > 0); ASSERT(digits_after_point > 0);
result_builder->AddSubstring(decimal_digits, decimal_point); result_builder->AddSubstring(decimal_digits, decimal_point);
result_builder->AddCharacter('.'); result_builder->AddCharacter('.');
@ -249,6 +250,12 @@ bool DoubleToStringConverter::ToExponential(
const int kDecimalRepCapacity = kMaxExponentialDigits + 2; const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
ASSERT(kDecimalRepCapacity > kBase10MaximalLength); ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
char decimal_rep[kDecimalRepCapacity]; char decimal_rep[kDecimalRepCapacity];
#ifndef NDEBUG
// Problem: there is an assert in StringBuilder::AddSubstring() that
// will pass this buffer to strlen(), and this buffer is not generally
// null-terminated.
memset(decimal_rep, 0, sizeof(decimal_rep));
#endif
int decimal_rep_length; int decimal_rep_length;
if (requested_digits == -1) { if (requested_digits == -1) {
@ -414,21 +421,55 @@ void DoubleToStringConverter::DoubleToAscii(double v,
} }
namespace {
inline char ToLower(char ch) {
static const std::ctype<char>& cType =
std::use_facet<std::ctype<char> >(std::locale::classic());
return cType.tolower(ch);
}
inline char Pass(char ch) {
return ch;
}
template <class Iterator, class Converter>
static inline bool ConsumeSubStringImpl(Iterator* current,
Iterator end,
const char* substring,
Converter converter) {
ASSERT(converter(**current) == *substring);
for (substring++; *substring != '\0'; substring++) {
++*current;
if (*current == end || converter(**current) != *substring) {
return false;
}
}
++*current;
return true;
}
// Consumes the given substring from the iterator. // Consumes the given substring from the iterator.
// Returns false, if the substring does not match. // Returns false, if the substring does not match.
template <class Iterator> template <class Iterator>
static bool ConsumeSubString(Iterator* current, static bool ConsumeSubString(Iterator* current,
Iterator end, Iterator end,
const char* substring) {
ASSERT(**current == *substring);
for (substring++; *substring != '\0'; substring++) {
++*current;
if (*current == end || **current != *substring) return false;
const char* substring,
bool allow_case_insensibility) {
if (allow_case_insensibility) {
return ConsumeSubStringImpl(current, end, substring, ToLower);
} else {
return ConsumeSubStringImpl(current, end, substring, Pass);
} }
++*current;
return true;
} }
// Consumes first character of the str is equal to ch
inline bool ConsumeFirstCharacter(char ch,
const char* str,
bool case_insensibility) {
return case_insensibility ? ToLower(ch) == str[0] : ch == str[0];
}
} // namespace
// Maximum number of significant digits in decimal representation. // Maximum number of significant digits in decimal representation.
// The longest possible double in decimal representation is // The longest possible double in decimal representation is
@ -494,7 +535,7 @@ static double SignedZero(bool sign) {
// because it constant-propagated the radix and concluded that the last // because it constant-propagated the radix and concluded that the last
// condition was always true. By moving it into a separate function the // condition was always true. By moving it into a separate function the
// compiler wouldn't warn anymore. // compiler wouldn't warn anymore.
#if _MSC_VER
#ifdef _MSC_VER
#pragma optimize("",off) #pragma optimize("",off)
static bool IsDecimalDigitForRadix(int c, int radix) { static bool IsDecimalDigitForRadix(int c, int radix) {
return '0' <= c && c <= '9' && (c - '0') < radix; return '0' <= c && c <= '9' && (c - '0') < radix;
@ -502,7 +543,7 @@ static bool IsDecimalDigitForRadix(int c, int radix) {
#pragma optimize("",on) #pragma optimize("",on)
#else #else
static bool inline IsDecimalDigitForRadix(int c, int radix) { static bool inline IsDecimalDigitForRadix(int c, int radix) {
return '0' <= c && c <= '9' && (c - '0') < radix;
return '0' <= c && c <= '9' && (c - '0') < radix;
} }
#endif #endif
// Returns true if 'c' is a character digit that is valid for the given radix. // Returns true if 'c' is a character digit that is valid for the given radix.
@ -516,17 +557,86 @@ static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
return radix > 10 && c >= a_character && c < a_character + radix - 10; return radix > 10 && c >= a_character && c < a_character + radix - 10;
} }
// Returns true, when the iterator is equal to end.
template<class Iterator>
static bool Advance (Iterator* it, uc16 separator, int base, Iterator& end) {
if (separator == StringToDoubleConverter::kNoSeparator) {
++(*it);
return *it == end;
}
if (!isDigit(**it, base)) {
++(*it);
return *it == end;
}
++(*it);
if (*it == end) return true;
if (*it + 1 == end) return false;
if (**it == separator && isDigit(*(*it + 1), base)) {
++(*it);
}
return *it == end;
}
// Checks whether the string in the range start-end is a hex-float string.
// This function assumes that the leading '0x'/'0X' is already consumed.
//
// Hex float strings are of one of the following forms:
// - hex_digits+ 'p' ('+'|'-')? exponent_digits+
// - hex_digits* '.' hex_digits+ 'p' ('+'|'-')? exponent_digits+
// - hex_digits+ '.' 'p' ('+'|'-')? exponent_digits+
template<class Iterator>
static bool IsHexFloatString(Iterator start,
Iterator end,
uc16 separator,
bool allow_trailing_junk) {
ASSERT(start != end);
Iterator current = start;
bool saw_digit = false;
while (isDigit(*current, 16)) {
saw_digit = true;
if (Advance(&current, separator, 16, end)) return false;
}
if (*current == '.') {
if (Advance(&current, separator, 16, end)) return false;
while (isDigit(*current, 16)) {
saw_digit = true;
if (Advance(&current, separator, 16, end)) return false;
}
if (!saw_digit) return false; // Only the '.', but no digits.
}
if (*current != 'p' && *current != 'P') return false;
if (Advance(&current, separator, 16, end)) return false;
if (*current == '+' || *current == '-') {
if (Advance(&current, separator, 16, end)) return false;
}
if (!isDigit(*current, 10)) return false;
if (Advance(&current, separator, 16, end)) return true;
while (isDigit(*current, 10)) {
if (Advance(&current, separator, 16, end)) return true;
}
return allow_trailing_junk || !AdvanceToNonspace(&current, end);
}
// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
//
// If parse_as_hex_float is true, then the string must be a valid
// hex-float.
template <int radix_log_2, class Iterator> template <int radix_log_2, class Iterator>
static double RadixStringToIeee(Iterator* current, static double RadixStringToIeee(Iterator* current,
Iterator end, Iterator end,
bool sign, bool sign,
uc16 separator,
bool parse_as_hex_float,
bool allow_trailing_junk, bool allow_trailing_junk,
double junk_string_value, double junk_string_value,
bool read_as_double, bool read_as_double,
bool* result_is_junk) { bool* result_is_junk) {
ASSERT(*current != end); ASSERT(*current != end);
ASSERT(!parse_as_hex_float ||
IsHexFloatString(*current, end, separator, allow_trailing_junk));
const int kDoubleSize = Double::kSignificandSize; const int kDoubleSize = Double::kSignificandSize;
const int kSingleSize = Single::kSignificandSize; const int kSingleSize = Single::kSignificandSize;
@ -534,27 +644,39 @@ static double RadixStringToIeee(Iterator* current,
*result_is_junk = true; *result_is_junk = true;
int64_t number = 0;
int exponent = 0;
const int radix = (1 << radix_log_2);
// Whether we have encountered a '.' and are parsing the decimal digits.
// Only relevant if parse_as_hex_float is true.
bool post_decimal = false;
// Skip leading 0s. // Skip leading 0s.
while (**current == '0') { while (**current == '0') {
++(*current);
if (*current == end) {
if (Advance(current, separator, radix, end)) {
*result_is_junk = false; *result_is_junk = false;
return SignedZero(sign); return SignedZero(sign);
} }
} }
int64_t number = 0;
int exponent = 0;
const int radix = (1 << radix_log_2);
do {
while (true) {
int digit; int digit;
if (IsDecimalDigitForRadix(**current, radix)) { if (IsDecimalDigitForRadix(**current, radix)) {
digit = static_cast<char>(**current) - '0'; digit = static_cast<char>(**current) - '0';
if (post_decimal) exponent -= radix_log_2;
} else if (IsCharacterDigitForRadix(**current, radix, 'a')) { } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
digit = static_cast<char>(**current) - 'a' + 10; digit = static_cast<char>(**current) - 'a' + 10;
if (post_decimal) exponent -= radix_log_2;
} else if (IsCharacterDigitForRadix(**current, radix, 'A')) { } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
digit = static_cast<char>(**current) - 'A' + 10; digit = static_cast<char>(**current) - 'A' + 10;
if (post_decimal) exponent -= radix_log_2;
} else if (parse_as_hex_float && **current == '.') {
post_decimal = true;
Advance(current, separator, radix, end);
ASSERT(*current != end);
continue;
} else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) {
break;
} else { } else {
if (allow_trailing_junk || !AdvanceToNonspace(current, end)) { if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
break; break;
@ -577,17 +699,26 @@ static double RadixStringToIeee(Iterator* current,
int dropped_bits_mask = ((1 << overflow_bits_count) - 1); int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
int dropped_bits = static_cast<int>(number) & dropped_bits_mask; int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
number >>= overflow_bits_count; number >>= overflow_bits_count;
exponent = overflow_bits_count;
exponent += overflow_bits_count;
bool zero_tail = true; bool zero_tail = true;
for (;;) { for (;;) {
++(*current);
if (*current == end || !isDigit(**current, radix)) break;
if (Advance(current, separator, radix, end)) break;
if (parse_as_hex_float && **current == '.') {
// Just run over the '.'. We are just trying to see whether there is
// a non-zero digit somewhere.
Advance(current, separator, radix, end);
ASSERT(*current != end);
post_decimal = true;
}
if (!isDigit(**current, radix)) break;
zero_tail = zero_tail && **current == '0'; zero_tail = zero_tail && **current == '0';
exponent += radix_log_2;
if (!post_decimal) exponent += radix_log_2;
} }
if (!allow_trailing_junk && AdvanceToNonspace(current, end)) {
if (!parse_as_hex_float &&
!allow_trailing_junk &&
AdvanceToNonspace(current, end)) {
return junk_string_value; return junk_string_value;
} }
@ -609,15 +740,37 @@ static double RadixStringToIeee(Iterator* current,
} }
break; break;
} }
++(*current);
} while (*current != end);
if (Advance(current, separator, radix, end)) break;
}
ASSERT(number < ((int64_t)1 << kSignificandSize)); ASSERT(number < ((int64_t)1 << kSignificandSize));
ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number); ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
*result_is_junk = false; *result_is_junk = false;
if (exponent == 0) {
if (parse_as_hex_float) {
ASSERT(**current == 'p' || **current == 'P');
Advance(current, separator, radix, end);
ASSERT(*current != end);
bool is_negative = false;
if (**current == '+') {
Advance(current, separator, radix, end);
ASSERT(*current != end);
} else if (**current == '-') {
is_negative = true;
Advance(current, separator, radix, end);
ASSERT(*current != end);
}
int written_exponent = 0;
while (IsDecimalDigitForRadix(**current, 10)) {
written_exponent = 10 * written_exponent + **current - '0';
if (Advance(current, separator, radix, end)) break;
}
if (is_negative) written_exponent = -written_exponent;
exponent += written_exponent;
}
if (exponent == 0 || number == 0) {
if (sign) { if (sign) {
if (number == 0) return -0.0; if (number == 0) return -0.0;
number = -number; number = -number;
@ -626,10 +779,10 @@ static double RadixStringToIeee(Iterator* current,
} }
ASSERT(number != 0); ASSERT(number != 0);
return Double(DiyFp(number, exponent)).value();
double result = Double(DiyFp(number, exponent)).value();
return sign ? -result : result;
} }
template <class Iterator> template <class Iterator>
double StringToDoubleConverter::StringToIeee( double StringToDoubleConverter::StringToIeee(
Iterator input, Iterator input,
@ -645,6 +798,7 @@ double StringToDoubleConverter::StringToIeee(
const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
const bool allow_case_insensibility = (flags_ & ALLOW_CASE_INSENSIBILITY) != 0;
// To make sure that iterator dereferencing is valid the following // To make sure that iterator dereferencing is valid the following
// convention is used: // convention is used:
@ -694,8 +848,8 @@ double StringToDoubleConverter::StringToIeee(
} }
if (infinity_symbol_ != NULL) { if (infinity_symbol_ != NULL) {
if (*current == infinity_symbol_[0]) {
if (!ConsumeSubString(&current, end, infinity_symbol_)) {
if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensibility)) {
if (!ConsumeSubString(&current, end, infinity_symbol_, allow_case_insensibility)) {
return junk_string_value_; return junk_string_value_;
} }
@ -713,8 +867,8 @@ double StringToDoubleConverter::StringToIeee(
} }
if (nan_symbol_ != NULL) { if (nan_symbol_ != NULL) {
if (*current == nan_symbol_[0]) {
if (!ConsumeSubString(&current, end, nan_symbol_)) {
if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensibility)) {
if (!ConsumeSubString(&current, end, nan_symbol_, allow_case_insensibility)) {
return junk_string_value_; return junk_string_value_;
} }
@ -733,8 +887,7 @@ double StringToDoubleConverter::StringToIeee(
bool leading_zero = false; bool leading_zero = false;
if (*current == '0') { if (*current == '0') {
++current;
if (current == end) {
if (Advance(&current, separator_, 10, end)) {
*processed_characters_count = static_cast<int>(current - input); *processed_characters_count = static_cast<int>(current - input);
return SignedZero(sign); return SignedZero(sign);
} }
@ -742,16 +895,24 @@ double StringToDoubleConverter::StringToIeee(
leading_zero = true; leading_zero = true;
// It could be hexadecimal value. // It could be hexadecimal value.
if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
if (((flags_ & ALLOW_HEX) || (flags_ & ALLOW_HEX_FLOATS)) &&
(*current == 'x' || *current == 'X')) {
++current; ++current;
if (current == end || !isDigit(*current, 16)) {
return junk_string_value_; // "0x".
bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) &&
IsHexFloatString(current, end, separator_, allow_trailing_junk);
if (current == end) return junk_string_value_; // "0x"
if (!parse_as_hex_float && !isDigit(*current, 16)) {
return junk_string_value_;
} }
bool result_is_junk; bool result_is_junk;
double result = RadixStringToIeee<4>(&current, double result = RadixStringToIeee<4>(&current,
end, end,
sign, sign,
separator_,
parse_as_hex_float,
allow_trailing_junk, allow_trailing_junk,
junk_string_value_, junk_string_value_,
read_as_double, read_as_double,
@ -765,8 +926,7 @@ double StringToDoubleConverter::StringToIeee(
// Ignore leading zeros in the integer part. // Ignore leading zeros in the integer part.
while (*current == '0') { while (*current == '0') {
++current;
if (current == end) {
if (Advance(&current, separator_, 10, end)) {
*processed_characters_count = static_cast<int>(current - input); *processed_characters_count = static_cast<int>(current - input);
return SignedZero(sign); return SignedZero(sign);
} }
@ -787,8 +947,7 @@ double StringToDoubleConverter::StringToIeee(
nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
} }
octal = octal && *current < '8'; octal = octal && *current < '8';
++current;
if (current == end) goto parsing_done;
if (Advance(&current, separator_, 10, end)) goto parsing_done;
} }
if (significant_digits == 0) { if (significant_digits == 0) {
@ -799,8 +958,7 @@ double StringToDoubleConverter::StringToIeee(
if (octal && !allow_trailing_junk) return junk_string_value_; if (octal && !allow_trailing_junk) return junk_string_value_;
if (octal) goto parsing_done; if (octal) goto parsing_done;
++current;
if (current == end) {
if (Advance(&current, separator_, 10, end)) {
if (significant_digits == 0 && !leading_zero) { if (significant_digits == 0 && !leading_zero) {
return junk_string_value_; return junk_string_value_;
} else { } else {
@ -813,8 +971,7 @@ double StringToDoubleConverter::StringToIeee(
// Integer part consists of 0 or is absent. Significant digits start after // Integer part consists of 0 or is absent. Significant digits start after
// leading zeros (if any). // leading zeros (if any).
while (*current == '0') { while (*current == '0') {
++current;
if (current == end) {
if (Advance(&current, separator_, 10, end)) {
*processed_characters_count = static_cast<int>(current - input); *processed_characters_count = static_cast<int>(current - input);
return SignedZero(sign); return SignedZero(sign);
} }
@ -834,8 +991,7 @@ double StringToDoubleConverter::StringToIeee(
// Ignore insignificant digits in the fractional part. // Ignore insignificant digits in the fractional part.
nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
} }
++current;
if (current == end) goto parsing_done;
if (Advance(&current, separator_, 10, end)) goto parsing_done;
} }
} }
@ -851,9 +1007,11 @@ double StringToDoubleConverter::StringToIeee(
if (*current == 'e' || *current == 'E') { if (*current == 'e' || *current == 'E') {
if (octal && !allow_trailing_junk) return junk_string_value_; if (octal && !allow_trailing_junk) return junk_string_value_;
if (octal) goto parsing_done; if (octal) goto parsing_done;
Iterator junk_begin = current;
++current; ++current;
if (current == end) { if (current == end) {
if (allow_trailing_junk) { if (allow_trailing_junk) {
current = junk_begin;
goto parsing_done; goto parsing_done;
} else { } else {
return junk_string_value_; return junk_string_value_;
@ -865,6 +1023,7 @@ double StringToDoubleConverter::StringToIeee(
++current; ++current;
if (current == end) { if (current == end) {
if (allow_trailing_junk) { if (allow_trailing_junk) {
current = junk_begin;
goto parsing_done; goto parsing_done;
} else { } else {
return junk_string_value_; return junk_string_value_;
@ -874,6 +1033,7 @@ double StringToDoubleConverter::StringToIeee(
if (current == end || *current < '0' || *current > '9') { if (current == end || *current < '0' || *current > '9') {
if (allow_trailing_junk) { if (allow_trailing_junk) {
current = junk_begin;
goto parsing_done; goto parsing_done;
} else { } else {
return junk_string_value_; return junk_string_value_;
@ -918,6 +1078,8 @@ double StringToDoubleConverter::StringToIeee(
result = RadixStringToIeee<3>(&start, result = RadixStringToIeee<3>(&start,
buffer + buffer_pos, buffer + buffer_pos,
sign, sign,
separator_,
false, // Don't parse as hex_float.
allow_trailing_junk, allow_trailing_junk,
junk_string_value_, junk_string_value_,
read_as_double, read_as_double,

+ 43
- 10
c_src/double-conversion/double-conversion.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ #ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ #define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {
@ -294,13 +294,18 @@ class DoubleToStringConverter {
// should be at least kBase10MaximalLength + 1 characters long. // should be at least kBase10MaximalLength + 1 characters long.
static const int kBase10MaximalLength = 17; static const int kBase10MaximalLength = 17;
// Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or
// -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v'
// after it has been casted to a single-precision float. That is, in this
// mode static_cast<float>(v) must not be NaN, +Infinity or -Infinity.
// Converts the given double 'v' to digit characters. 'v' must not be NaN,
// +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
// applies to 'v' after it has been casted to a single-precision float. That
// is, in this mode static_cast<float>(v) must not be NaN, +Infinity or
// -Infinity.
// //
// The result should be interpreted as buffer * 10^(point-length). // The result should be interpreted as buffer * 10^(point-length).
// //
// The digits are written to the buffer in the platform's charset, which is
// often UTF-8 (with ASCII-range digits) but may be another charset, such
// as EBCDIC.
//
// The output depends on the given mode: // The output depends on the given mode:
// - SHORTEST: produce the least amount of digits for which the internal // - SHORTEST: produce the least amount of digits for which the internal
// identity requirement is still satisfied. If the digits are printed // identity requirement is still satisfied. If the digits are printed
@ -374,7 +379,7 @@ class DoubleToStringConverter {
const int max_leading_padding_zeroes_in_precision_mode_; const int max_leading_padding_zeroes_in_precision_mode_;
const int max_trailing_padding_zeroes_in_precision_mode_; const int max_trailing_padding_zeroes_in_precision_mode_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
DC_DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
}; };
@ -389,9 +394,13 @@ class StringToDoubleConverter {
ALLOW_TRAILING_JUNK = 4, ALLOW_TRAILING_JUNK = 4,
ALLOW_LEADING_SPACES = 8, ALLOW_LEADING_SPACES = 8,
ALLOW_TRAILING_SPACES = 16, ALLOW_TRAILING_SPACES = 16,
ALLOW_SPACES_AFTER_SIGN = 32
ALLOW_SPACES_AFTER_SIGN = 32,
ALLOW_CASE_INSENSIBILITY = 64,
ALLOW_HEX_FLOATS = 128,
}; };
static const uc16 kNoSeparator = '\0';
// Flags should be a bit-or combination of the possible Flags-enum. // Flags should be a bit-or combination of the possible Flags-enum.
// - NO_FLAGS: no special flags. // - NO_FLAGS: no special flags.
// - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers. // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
@ -421,6 +430,13 @@ class StringToDoubleConverter {
// - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign. // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign.
// Ex: StringToDouble("- 123.2") -> -123.2. // Ex: StringToDouble("- 123.2") -> -123.2.
// StringToDouble("+ 123.2") -> 123.2 // StringToDouble("+ 123.2") -> 123.2
// - ALLOW_CASE_INSENSIBILITY: ignore case of characters for special values:
// infinity and nan.
// - ALLOW_HEX_FLOATS: allows hexadecimal float literals.
// This *must* start with "0x" and separate the exponent with "p".
// Examples: 0x1.2p3 == 9.0
// 0x10.1p0 == 16.0625
// ALLOW_HEX and ALLOW_HEX_FLOATS are indendent.
// //
// empty_string_value is returned when an empty string is given as input. // empty_string_value is returned when an empty string is given as input.
// If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
@ -445,6 +461,12 @@ class StringToDoubleConverter {
// - they must not have the same first character. // - they must not have the same first character.
// - they must not start with digits. // - they must not start with digits.
// //
// If the separator character is not kNoSeparator, then that specific
// character is ignored when in between two valid digits of the significant.
// It is not allowed to appear in the exponent.
// It is not allowed to lead or trail the number.
// It is not allowed to appear twice next to each other.
//
// Examples: // Examples:
// flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
// empty_string_value = 0.0, // empty_string_value = 0.0,
@ -484,16 +506,26 @@ class StringToDoubleConverter {
// StringToDouble("01239E45") -> 1239e45. // StringToDouble("01239E45") -> 1239e45.
// StringToDouble("-infinity") -> NaN // junk_string_value. // StringToDouble("-infinity") -> NaN // junk_string_value.
// StringToDouble("NaN") -> NaN // junk_string_value. // StringToDouble("NaN") -> NaN // junk_string_value.
//
// flags = NO_FLAGS,
// separator = ' ':
// StringToDouble("1 2 3 4") -> 1234.0
// StringToDouble("1 2") -> NaN // junk_string_value
// StringToDouble("1 000 000.0") -> 1000000.0
// StringToDouble("1.000 000") -> 1.0
// StringToDouble("1.0e1 000") -> NaN // junk_string_value
StringToDoubleConverter(int flags, StringToDoubleConverter(int flags,
double empty_string_value, double empty_string_value,
double junk_string_value, double junk_string_value,
const char* infinity_symbol, const char* infinity_symbol,
const char* nan_symbol)
const char* nan_symbol,
uc16 separator = kNoSeparator)
: flags_(flags), : flags_(flags),
empty_string_value_(empty_string_value), empty_string_value_(empty_string_value),
junk_string_value_(junk_string_value), junk_string_value_(junk_string_value),
infinity_symbol_(infinity_symbol), infinity_symbol_(infinity_symbol),
nan_symbol_(nan_symbol) {
nan_symbol_(nan_symbol),
separator_(separator) {
} }
// Performs the conversion. // Performs the conversion.
@ -528,6 +560,7 @@ class StringToDoubleConverter {
const double junk_string_value_; const double junk_string_value_;
const char* const infinity_symbol_; const char* const infinity_symbol_;
const char* const nan_symbol_; const char* const nan_symbol_;
const uc16 separator_;
template <class Iterator> template <class Iterator>
double StringToIeee(Iterator start_pointer, double StringToIeee(Iterator start_pointer,
@ -535,7 +568,7 @@ class StringToDoubleConverter {
bool read_as_double, bool read_as_double,
int* processed_characters_count) const; int* processed_characters_count) const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
}; };
} // namespace double_conversion } // namespace double_conversion

+ 1
- 1
c_src/double-conversion/fast-dtoa.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_FAST_DTOA_H_ #ifndef DOUBLE_CONVERSION_FAST_DTOA_H_
#define DOUBLE_CONVERSION_FAST_DTOA_H_ #define DOUBLE_CONVERSION_FAST_DTOA_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {

+ 4
- 3
c_src/double-conversion/fixed-dtoa.cc View File

@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <math.h>
#include <cmath>
#include "fixed-dtoa.h" #include "fixed-dtoa.h"
#include "ieee.h" #include "ieee.h"
@ -98,7 +98,7 @@ class UInt128 {
return high_bits_ == 0 && low_bits_ == 0; return high_bits_ == 0 && low_bits_ == 0;
} }
int BitAt(int position) {
int BitAt(int position) const {
if (position >= 64) { if (position >= 64) {
return static_cast<int>(high_bits_ >> (position - 64)) & 1; return static_cast<int>(high_bits_ >> (position - 64)) & 1;
} else { } else {
@ -259,7 +259,8 @@ static void FillFractionals(uint64_t fractionals, int exponent,
fractionals -= static_cast<uint64_t>(digit) << point; fractionals -= static_cast<uint64_t>(digit) << point;
} }
// If the first bit after the point is set we have to round up. // If the first bit after the point is set we have to round up.
if (((fractionals >> (point - 1)) & 1) == 1) {
ASSERT(fractionals == 0 || point - 1 >= 0);
if ((fractionals != 0) && ((fractionals >> (point - 1)) & 1) == 1) {
RoundUp(buffer, length, decimal_point); RoundUp(buffer, length, decimal_point);
} }
} else { // We need 128 bits. } else { // We need 128 bits.

+ 1
- 1
c_src/double-conversion/fixed-dtoa.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_ #ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_
#define DOUBLE_CONVERSION_FIXED_DTOA_H_ #define DOUBLE_CONVERSION_FIXED_DTOA_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {

+ 3
- 3
c_src/double-conversion/ieee.h View File

@ -99,7 +99,7 @@ class Double {
} }
double PreviousDouble() const { double PreviousDouble() const {
if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity();
if (d64_ == (kInfinity | kSignMask)) return -Infinity();
if (Sign() < 0) { if (Sign() < 0) {
return Double(d64_ + 1).value(); return Double(d64_ + 1).value();
} else { } else {
@ -257,7 +257,7 @@ class Double {
(biased_exponent << kPhysicalSignificandSize); (biased_exponent << kPhysicalSignificandSize);
} }
DISALLOW_COPY_AND_ASSIGN(Double);
DC_DISALLOW_COPY_AND_ASSIGN(Double);
}; };
class Single { class Single {
@ -394,7 +394,7 @@ class Single {
const uint32_t d32_; const uint32_t d32_;
DISALLOW_COPY_AND_ASSIGN(Single);
DC_DISALLOW_COPY_AND_ASSIGN(Single);
}; };
} // namespace double_conversion } // namespace double_conversion

+ 34
- 9
c_src/double-conversion/strtod.cc View File

@ -25,13 +25,13 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#include <limits.h>
#include <climits>
#include <cstdarg>
#include "strtod.h"
#include "bignum.h" #include "bignum.h"
#include "cached-powers.h" #include "cached-powers.h"
#include "ieee.h" #include "ieee.h"
#include "strtod.h"
namespace double_conversion { namespace double_conversion {
@ -205,7 +205,7 @@ static bool DoubleStrtod(Vector trimmed,
// Note that the ARM simulator is compiled for 32bits. It therefore exhibits // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
// the same problem. // the same problem.
return false; return false;
#endif
#else
if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
int read_digits; int read_digits;
// The trimmed input fits into a double. // The trimmed input fits into a double.
@ -243,6 +243,7 @@ static bool DoubleStrtod(Vector trimmed,
} }
} }
return false; return false;
#endif
} }
@ -471,6 +472,30 @@ double Strtod(Vector buffer, int exponent) {
} }
} }
static float SanitizedDoubletof(double d) {
ASSERT(d >= 0.0);
// ASAN has a sanitize check that disallows casting doubles to floats if
// they are too big.
// https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks
// The behavior should be covered by IEEE 754, but some projects use this
// flag, so work around it.
float max_finite = 3.4028234663852885981170418348451692544e+38;
// The half-way point between the max-finite and infinity value.
// Since infinity has an even significand everything equal or greater than
// this value should become infinity.
double half_max_finite_infinity =
3.40282356779733661637539395458142568448e+38;
if (d >= max_finite) {
if (d >= half_max_finite_infinity) {
return Single::Infinity();
} else {
return max_finite;
}
} else {
return static_cast<float>(d);
}
}
float Strtof(Vector<const char> buffer, int exponent) { float Strtof(Vector<const char> buffer, int exponent) {
char copy_buffer[kMaxSignificantDecimalDigits]; char copy_buffer[kMaxSignificantDecimalDigits];
Vector<const char> trimmed; Vector<const char> trimmed;
@ -482,7 +507,7 @@ float Strtof(Vector buffer, int exponent) {
double double_guess; double double_guess;
bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
float float_guess = static_cast<float>(double_guess);
float float_guess = SanitizedDoubletof(double_guess);
if (float_guess == double_guess) { if (float_guess == double_guess) {
// This shortcut triggers for integer values. // This shortcut triggers for integer values.
return float_guess; return float_guess;
@ -505,15 +530,15 @@ float Strtof(Vector buffer, int exponent) {
double double_next = Double(double_guess).NextDouble(); double double_next = Double(double_guess).NextDouble();
double double_previous = Double(double_guess).PreviousDouble(); double double_previous = Double(double_guess).PreviousDouble();
float f1 = static_cast<float>(double_previous);
float f1 = SanitizedDoubletof(double_previous);
float f2 = float_guess; float f2 = float_guess;
float f3 = static_cast<float>(double_next);
float f3 = SanitizedDoubletof(double_next);
float f4; float f4;
if (is_correct) { if (is_correct) {
f4 = f3; f4 = f3;
} else { } else {
double double_next2 = Double(double_next).NextDouble(); double double_next2 = Double(double_next).NextDouble();
f4 = static_cast<float>(double_next2);
f4 = SanitizedDoubletof(double_next2);
} }
(void) f2; // Mark variable as used. (void) f2; // Mark variable as used.
ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
@ -528,7 +553,7 @@ float Strtof(Vector buffer, int exponent) {
(f1 == f2 && f2 != f3 && f3 == f4) || (f1 == f2 && f2 != f3 && f3 == f4) ||
(f1 == f2 && f2 == f3 && f3 != f4)); (f1 == f2 && f2 == f3 && f3 != f4));
// guess and next are the two possible canditates (in the same way that
// guess and next are the two possible candidates (in the same way that
// double_guess was the lower candidate for a double-precision guess). // double_guess was the lower candidate for a double-precision guess).
float guess = f1; float guess = f1;
float next = f4; float next = f4;

+ 1
- 1
c_src/double-conversion/strtod.h View File

@ -28,7 +28,7 @@
#ifndef DOUBLE_CONVERSION_STRTOD_H_ #ifndef DOUBLE_CONVERSION_STRTOD_H_
#define DOUBLE_CONVERSION_STRTOD_H_ #define DOUBLE_CONVERSION_STRTOD_H_
#include "double-conversion/utils.h"
#include "utils.h"
namespace double_conversion { namespace double_conversion {

+ 60
- 20
c_src/double-conversion/utils.h View File

@ -28,10 +28,10 @@
#ifndef DOUBLE_CONVERSION_UTILS_H_ #ifndef DOUBLE_CONVERSION_UTILS_H_
#define DOUBLE_CONVERSION_UTILS_H_ #define DOUBLE_CONVERSION_UTILS_H_
#include <stdlib.h>
#include <string.h>
#include <cstdlib>
#include <cstring>
#include <assert.h>
#include <cassert>
#ifndef ASSERT #ifndef ASSERT
#define ASSERT(condition) \ #define ASSERT(condition) \
assert(condition); assert(condition);
@ -39,9 +39,30 @@
#ifndef UNIMPLEMENTED #ifndef UNIMPLEMENTED
#define UNIMPLEMENTED() (abort()) #define UNIMPLEMENTED() (abort())
#endif #endif
#ifndef DOUBLE_CONVERSION_NO_RETURN
#ifdef _MSC_VER
#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn)
#else
#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn))
#endif
#endif
#ifndef UNREACHABLE #ifndef UNREACHABLE
#ifdef _MSC_VER
void DOUBLE_CONVERSION_NO_RETURN abort_noreturn();
inline void abort_noreturn() { abort(); }
#define UNREACHABLE() (abort_noreturn())
#else
#define UNREACHABLE() (abort()) #define UNREACHABLE() (abort())
#endif #endif
#endif
#ifndef DOUBLE_CONVERSION_UNUSED
#ifdef __GNUC__
#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
#else
#define DOUBLE_CONVERSION_UNUSED
#endif
#endif
// Double operations detection based on target architecture. // Double operations detection based on target architecture.
// Linux uses a 80bit wide floating point stack on x86. This induces double // Linux uses a 80bit wide floating point stack on x86. This induces double
@ -53,18 +74,38 @@
// the output of the division with the expected result. (Inlining must be // the output of the division with the expected result. (Inlining must be
// disabled.) // disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22) // On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
//
// For example:
/*
// -- in div.c
double Div_double(double x, double y) { return x / y; }
// -- in main.c
double Div_double(double x, double y); // Forward declaration.
int main(int argc, char** argv) {
return Div_double(89255.0, 1e22) == 89255e-22;
}
*/
// Run as follows ./main || echo "correct"
//
// If it prints "correct" then the architecture should be here, in the "correct" section.
#if defined(_M_X64) || defined(__x86_64__) || \ #if defined(_M_X64) || defined(__x86_64__) || \
defined(__ARMEL__) || defined(__avr32__) || \
defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
defined(__hppa__) || defined(__ia64__) || \ defined(__hppa__) || defined(__ia64__) || \
defined(__mips__) || \ defined(__mips__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
defined(__SH4__) || defined(__alpha__) || \ defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || \
defined(__AARCH64EL__) || defined(__aarch64__)
defined(_MIPS_ARCH_MIPS32R2) || defined(__ARMEB__) ||\
defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \
defined(__riscv) || \
defined(__or1k__) || defined(__arc__) || \
defined(__EMSCRIPTEN__)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(__mc68000__)
#elif defined(__mc68000__) || \
defined(__pnacl__) || defined(__native_client__)
#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
#if defined(_WIN32) #if defined(_WIN32)
@ -77,12 +118,6 @@
#error Target architecture was not detected as supported by Double-Conversion. #error Target architecture was not detected as supported by Double-Conversion.
#endif #endif
#if defined(__GNUC__)
#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
#else
#define DOUBLE_CONVERSION_UNUSED
#endif
#if defined(_WIN32) && !defined(__MINGW32__) #if defined(_WIN32) && !defined(__MINGW32__)
typedef signed char int8_t; typedef signed char int8_t;
@ -121,8 +156,8 @@ typedef uint16_t uc16;
// A macro to disallow the evil copy constructor and operator= functions // A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class // This should be used in the private: declarations for a class
#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
#ifndef DC_DISALLOW_COPY_AND_ASSIGN
#define DC_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \ TypeName(const TypeName&); \
void operator=(const TypeName&) void operator=(const TypeName&)
#endif #endif
@ -133,10 +168,10 @@ typedef uint16_t uc16;
// This should be used in the private: declarations for a class // This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is // that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods. // especially useful for classes containing only static methods.
#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
#ifndef DC_DISALLOW_IMPLICIT_CONSTRUCTORS
#define DC_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \ TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
DC_DISALLOW_COPY_AND_ASSIGN(TypeName)
#endif #endif
namespace double_conversion { namespace double_conversion {
@ -278,7 +313,7 @@ class StringBuilder {
bool is_finalized() const { return position_ < 0; } bool is_finalized() const { return position_ < 0; }
DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
}; };
// The type-based aliasing rule allows the compiler to assume that pointers of // The type-based aliasing rule allows the compiler to assume that pointers of
@ -309,8 +344,13 @@ template
inline Dest BitCast(const Source& source) { inline Dest BitCast(const Source& source) {
// Compile time assertion: sizeof(Dest) == sizeof(Source) // Compile time assertion: sizeof(Dest) == sizeof(Source)
// A compile error here means your Dest and Source have different sizes. // A compile error here means your Dest and Source have different sizes.
#if __cplusplus >= 201103L
static_assert(sizeof(Dest) == sizeof(Source),
"source and destination size mismatch");
#else
DOUBLE_CONVERSION_UNUSED DOUBLE_CONVERSION_UNUSED
typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
#endif
Dest dest; Dest dest;
memmove(&dest, &source, sizeof(dest)); memmove(&dest, &source, sizeof(dest));

Loading…
Cancel
Save