]> granicus.if.org Git - icu/commitdiff
ICU-20438 Updating double-conversion from upstream master.
authorShane Carr <shane@unicode.org>
Tue, 26 Feb 2019 05:10:37 +0000 (21:10 -0800)
committerShane F. Carr <shane@unicode.org>
Wed, 27 Feb 2019 02:53:26 +0000 (20:53 -0600)
37 files changed:
icu4c/source/i18n/double-conversion-bignum-dtoa.cpp
icu4c/source/i18n/double-conversion-bignum.cpp
icu4c/source/i18n/double-conversion-bignum.h
icu4c/source/i18n/double-conversion-cached-powers.cpp
icu4c/source/i18n/double-conversion-ieee.h
icu4c/source/i18n/double-conversion-utils.h
icu4c/source/i18n/double-conversion.cpp
icu4c/source/i18n/double-conversion.h
vendor/double-conversion/upstream/BUILD
vendor/double-conversion/upstream/CMakeLists.txt
vendor/double-conversion/upstream/Changelog
vendor/double-conversion/upstream/SConstruct
vendor/double-conversion/upstream/cmake/Config.cmake.in [new file with mode: 0644]
vendor/double-conversion/upstream/double-conversion/CMakeLists.txt [deleted file]
vendor/double-conversion/upstream/double-conversion/bignum-dtoa.cc
vendor/double-conversion/upstream/double-conversion/bignum-dtoa.h
vendor/double-conversion/upstream/double-conversion/bignum.cc
vendor/double-conversion/upstream/double-conversion/bignum.h
vendor/double-conversion/upstream/double-conversion/cached-powers.cc
vendor/double-conversion/upstream/double-conversion/cached-powers.h
vendor/double-conversion/upstream/double-conversion/diy-fp.cc
vendor/double-conversion/upstream/double-conversion/diy-fp.h
vendor/double-conversion/upstream/double-conversion/double-conversion.cc
vendor/double-conversion/upstream/double-conversion/double-conversion.h
vendor/double-conversion/upstream/double-conversion/fast-dtoa.cc
vendor/double-conversion/upstream/double-conversion/fast-dtoa.h
vendor/double-conversion/upstream/double-conversion/fixed-dtoa.cc
vendor/double-conversion/upstream/double-conversion/fixed-dtoa.h
vendor/double-conversion/upstream/double-conversion/ieee.h
vendor/double-conversion/upstream/double-conversion/strtod.cc
vendor/double-conversion/upstream/double-conversion/strtod.h
vendor/double-conversion/upstream/double-conversion/utils.h
vendor/double-conversion/upstream/double-conversionBuildTreeSettings.cmake.in [deleted file]
vendor/double-conversion/upstream/double-conversionConfig.cmake.in [deleted file]
vendor/double-conversion/upstream/double-conversionConfigVersion.cmake.in [deleted file]
vendor/double-conversion/upstream/test/cctest/test-bignum-dtoa.cc
vendor/double-conversion/upstream/test/cctest/test-conversions.cc

index 07d0b0eb0f8717ef6a38fdeda464e5b166e8fa02..2add399f87c91f52ff57e3763a7095d7187d8bab 100644 (file)
@@ -34,7 +34,7 @@
 #include "unicode/utypes.h"
 #if !UCONFIG_NO_FORMATTING
 
-#include <math.h>
+#include <cmath>
 
 // ICU PATCH: Customize header file paths for ICU.
 
index d5682af35f866dd7c1586038451b8a602e6195ca..5356923921c3c1e9b13506e7edb0503beef72513 100644 (file)
@@ -45,7 +45,7 @@ U_NAMESPACE_BEGIN
 namespace double_conversion {
 
 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) {
     bigits_[i] = 0;
   }
@@ -459,26 +459,27 @@ void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
   mask >>= 2;
   uint64_t this_value = base;
 
-  bool delayed_multipliciation = false;
+  bool delayed_multiplication = false;
   const uint64_t max_32bits = 0xFFFFFFFF;
   while (mask != 0 && this_value <= max_32bits) {
     this_value = this_value * this_value;
     // Verify that there is enough space in this_value to perform the
     // multiplication.  The first bit_size bits must be 0.
     if ((power_exponent & mask) != 0) {
+      ASSERT(bit_size > 0);
       uint64_t base_bits_mask =
           ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
       bool high_bits_zero = (this_value & base_bits_mask) == 0;
       if (high_bits_zero) {
         this_value *= base;
       } else {
-        delayed_multipliciation = true;
+        delayed_multiplication = true;
       }
     }
     mask >>= 1;
   }
   AssignUInt64(this_value);
-  if (delayed_multipliciation) {
+  if (delayed_multiplication) {
     MultiplyByUInt32(base);
   }
 
index d1af3bf5e77b15a84633da46ea48188d35609b7e..d39a3dee010d8b315e6a19ad19be2659e91aca5f 100644 (file)
@@ -150,7 +150,7 @@ class Bignum {
   // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
   int exponent_;
 
-  DISALLOW_COPY_AND_ASSIGN(Bignum);
+  DC_DISALLOW_COPY_AND_ASSIGN(Bignum);
 };
 
 }  // namespace double_conversion
index e49700444c6b489c4ac45c8f6d79e2ef1ac10b08..e1b66d2c65c82ead92a4f4209f2b7b9bbe2d9829 100644 (file)
@@ -34,9 +34,9 @@
 #include "unicode/utypes.h"
 #if !UCONFIG_NO_FORMATTING
 
-#include <stdarg.h>
-#include <limits.h>
-#include <math.h>
+#include <climits>
+#include <cmath>
+#include <cstdarg>
 
 // ICU PATCH: Customize header file paths for ICU.
 
index 952bcea27f6615cba56f2b5d558e0d263c64c5ec..c83c8d9abbb46e866ad2309060c789e054aa323f 100644 (file)
@@ -271,7 +271,7 @@ class Double {
         (biased_exponent << kPhysicalSignificandSize);
   }
 
-  DISALLOW_COPY_AND_ASSIGN(Double);
+  DC_DISALLOW_COPY_AND_ASSIGN(Double);
 };
 
 class Single {
@@ -408,7 +408,7 @@ class Single {
 
   const uint32_t d32_;
 
-  DISALLOW_COPY_AND_ASSIGN(Single);
+  DC_DISALLOW_COPY_AND_ASSIGN(Single);
 };
 
 }  // namespace double_conversion
index 57fc49b231a3a066f6800d97f66ceac08c5ead6e..1e44fcaa0e398dcdf31609ac0dfb130f0f70871a 100644 (file)
@@ -37,8 +37,8 @@
 #ifndef DOUBLE_CONVERSION_UTILS_H_
 #define DOUBLE_CONVERSION_UTILS_H_
 
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
 
 // ICU PATCH: Use U_ASSERT instead of <assert.h>
 #include "uassert.h"
@@ -75,7 +75,22 @@ inline void abort_noreturn() { abort(); }
 // the output of the division with the expected result. (Inlining must be
 // disabled.)
 // On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
-// ICU PATCH: Enable ARM32 & ARM64 builds for Windows with 'defined(_M_ARM) || defined(_M_ARM64)'.
+//
+// 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__) || \
     defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
     defined(__hppa__) || defined(__ia64__) || \
@@ -85,10 +100,13 @@ inline void abort_noreturn() { abort(); }
     defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
     defined(__SH4__) || defined(__alpha__) || \
     defined(_MIPS_ARCH_MIPS32R2) || \
-    defined(__AARCH64EL__) || defined(__aarch64__) || \
-    defined(__riscv)
+    defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \
+    defined(__riscv) || \
+    defined(__or1k__) || defined(__arc__) || \
+    defined(__EMSCRIPTEN__)
 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(__mc68000__)
+#elif defined(__mc68000__) || \
+    defined(__pnacl__) || defined(__native_client__)
 #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
 #if defined(_WIN32)
@@ -101,12 +119,6 @@ inline void abort_noreturn() { abort(); }
 #error Target architecture was not detected as supported by Double-Conversion.
 #endif
 
-#if defined(__GNUC__)
-#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
-#else
-#define DOUBLE_CONVERSION_UNUSED
-#endif
-
 #if defined(_WIN32) && !defined(__MINGW32__)
 
 typedef signed char int8_t;
@@ -145,8 +157,8 @@ typedef uint16_t uc16;
 
 // A macro to disallow the evil copy constructor and operator= functions
 // 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&);                    \
   void operator=(const TypeName&)
 #endif
@@ -157,10 +169,10 @@ typedef uint16_t uc16;
 // This should be used in the private: declarations for a class
 // that wants to prevent anyone from instantiating it. This is
 // 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();                                    \
-  DISALLOW_COPY_AND_ASSIGN(TypeName)
+  DC_DISALLOW_COPY_AND_ASSIGN(TypeName)
 #endif
 
 // ICU PATCH: Wrap in ICU namespace
@@ -305,7 +317,7 @@ class StringBuilder {
 
   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
@@ -336,8 +348,12 @@ template <class Dest, class Source>
 inline Dest BitCast(const Source& source) {
   // Compile time assertion: sizeof(Dest) == sizeof(Source)
   // A compile error here means your Dest and Source have different sizes.
-  DOUBLE_CONVERSION_UNUSED
-      typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#if __cplusplus >= 201103L
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "source and destination size mismatch");
+#else
+  typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#endif
 
   Dest dest;
   memmove(&dest, &source, sizeof(dest));
index 570a05bc42946c690f7f64da6b655c5a698565c3..66252341f109d51563cfd4970fed469ae3c100cb 100644 (file)
@@ -34,8 +34,9 @@
 #include "unicode/utypes.h"
 #if !UCONFIG_NO_FORMATTING
 
-#include <limits.h>
-#include <math.h>
+#include <climits>
+#include <locale>
+#include <cmath>
 
 // ICU PATCH: Customize header file paths for ICU.
 // The file fixed-dtoa.h is not needed.
@@ -432,21 +433,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.
 // Returns false, if the substring does not match.
 template <class Iterator>
 static bool ConsumeSubString(Iterator* current,
                              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.
 // The longest possible double in decimal representation is
@@ -513,7 +548,7 @@ static double SignedZero(bool sign) {
 // 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
+#ifdef _MSC_VER
 #pragma optimize("",off)
 static bool IsDecimalDigitForRadix(int c, int radix) {
   return '0' <= c && c <= '9' && (c - '0') < radix;
@@ -521,7 +556,7 @@ static bool IsDecimalDigitForRadix(int c, int radix) {
 #pragma optimize("",on)
 #else
 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
 // Returns true if 'c' is a character digit that is valid for the given radix.
@@ -535,17 +570,86 @@ static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
   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, char 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,
+                             char 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.
+//
+// If parse_as_hex_float is true, then the string must be a valid
+// hex-float.
 template <int radix_log_2, class Iterator>
 static double RadixStringToIeee(Iterator* current,
                                 Iterator end,
                                 bool sign,
+                                char separator,
+                                bool parse_as_hex_float,
                                 bool allow_trailing_junk,
                                 double junk_string_value,
                                 bool read_as_double,
                                 bool* result_is_junk) {
   ASSERT(*current != end);
+  ASSERT(!parse_as_hex_float ||
+      IsHexFloatString(*current, end, separator, allow_trailing_junk));
 
   const int kDoubleSize = Double::kSignificandSize;
   const int kSingleSize = Single::kSignificandSize;
@@ -553,27 +657,39 @@ static double RadixStringToIeee(Iterator* current,
 
   *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.
   while (**current == '0') {
-    ++(*current);
-    if (*current == end) {
+    if (Advance(current, separator, radix, end)) {
       *result_is_junk = false;
       return SignedZero(sign);
     }
   }
 
-  int64_t number = 0;
-  int exponent = 0;
-  const int radix = (1 << radix_log_2);
-
-  do {
+  while (true) {
     int digit;
     if (IsDecimalDigitForRadix(**current, radix)) {
       digit = static_cast<char>(**current) - '0';
+      if (post_decimal) exponent -= radix_log_2;
     } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
       digit = static_cast<char>(**current) - 'a' + 10;
+      if (post_decimal) exponent -= radix_log_2;
     } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
       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 {
       if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
         break;
@@ -596,17 +712,26 @@ static double RadixStringToIeee(Iterator* current,
       int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
       int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
       number >>= overflow_bits_count;
-      exponent = overflow_bits_count;
+      exponent += overflow_bits_count;
 
       bool zero_tail = true;
       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';
-        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;
       }
 
@@ -628,15 +753,37 @@ static double RadixStringToIeee(Iterator* current,
       }
       break;
     }
-    ++(*current);
-  } while (*current != end);
+    if (Advance(current, separator, radix, end)) break;
+  }
 
   ASSERT(number < ((int64_t)1 << kSignificandSize));
   ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
 
   *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 (number == 0) return -0.0;
       number = -number;
@@ -645,7 +792,8 @@ static double RadixStringToIeee(Iterator* current,
   }
 
   ASSERT(number != 0);
-  return Double(DiyFp(number, exponent)).value();
+  double result = Double(DiyFp(number, exponent)).value();
+  return sign ? -result : result;
 }
 
 template <class Iterator>
@@ -663,6 +811,7 @@ double StringToDoubleConverter::StringToIeee(
   const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
   const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
   const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
+  const bool allow_case_insensibility = (flags_ & ALLOW_CASE_INSENSIBILITY) != 0;
 
   // To make sure that iterator dereferencing is valid the following
   // convention is used:
@@ -712,8 +861,8 @@ double StringToDoubleConverter::StringToIeee(
   }
 
   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_;
       }
 
@@ -731,8 +880,8 @@ double StringToDoubleConverter::StringToIeee(
   }
 
   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_;
       }
 
@@ -751,8 +900,7 @@ double StringToDoubleConverter::StringToIeee(
 
   bool leading_zero = false;
   if (*current == '0') {
-    ++current;
-    if (current == end) {
+    if (Advance(&current, separator_, 10, end)) {
       *processed_characters_count = static_cast<int>(current - input);
       return SignedZero(sign);
     }
@@ -760,16 +908,24 @@ double StringToDoubleConverter::StringToIeee(
     leading_zero = true;
 
     // 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;
-      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;
       double result = RadixStringToIeee<4>(&current,
                                            end,
                                            sign,
+                                           separator_,
+                                           parse_as_hex_float,
                                            allow_trailing_junk,
                                            junk_string_value_,
                                            read_as_double,
@@ -783,8 +939,7 @@ double StringToDoubleConverter::StringToIeee(
 
     // Ignore leading zeros in the integer part.
     while (*current == '0') {
-      ++current;
-      if (current == end) {
+      if (Advance(&current, separator_, 10, end)) {
         *processed_characters_count = static_cast<int>(current - input);
         return SignedZero(sign);
       }
@@ -805,8 +960,7 @@ double StringToDoubleConverter::StringToIeee(
       nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
     }
     octal = octal && *current < '8';
-    ++current;
-    if (current == end) goto parsing_done;
+    if (Advance(&current, separator_, 10, end)) goto parsing_done;
   }
 
   if (significant_digits == 0) {
@@ -817,8 +971,7 @@ double StringToDoubleConverter::StringToIeee(
     if (octal && !allow_trailing_junk) return junk_string_value_;
     if (octal) goto parsing_done;
 
-    ++current;
-    if (current == end) {
+    if (Advance(&current, separator_, 10, end)) {
       if (significant_digits == 0 && !leading_zero) {
         return junk_string_value_;
       } else {
@@ -831,8 +984,7 @@ double StringToDoubleConverter::StringToIeee(
       // Integer part consists of 0 or is absent. Significant digits start after
       // leading zeros (if any).
       while (*current == '0') {
-        ++current;
-        if (current == end) {
+        if (Advance(&current, separator_, 10, end)) {
           *processed_characters_count = static_cast<int>(current - input);
           return SignedZero(sign);
         }
@@ -852,8 +1004,7 @@ double StringToDoubleConverter::StringToIeee(
         // Ignore insignificant digits in the fractional part.
         nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
       }
-      ++current;
-      if (current == end) goto parsing_done;
+      if (Advance(&current, separator_, 10, end)) goto parsing_done;
     }
   }
 
@@ -869,9 +1020,11 @@ double StringToDoubleConverter::StringToIeee(
   if (*current == 'e' || *current == 'E') {
     if (octal && !allow_trailing_junk) return junk_string_value_;
     if (octal) goto parsing_done;
+    Iterator junk_begin = current;
     ++current;
     if (current == end) {
       if (allow_trailing_junk) {
+        current = junk_begin;
         goto parsing_done;
       } else {
         return junk_string_value_;
@@ -883,6 +1036,7 @@ double StringToDoubleConverter::StringToIeee(
       ++current;
       if (current == end) {
         if (allow_trailing_junk) {
+          current = junk_begin;
           goto parsing_done;
         } else {
           return junk_string_value_;
@@ -892,6 +1046,7 @@ double StringToDoubleConverter::StringToIeee(
 
     if (current == end || *current < '0' || *current > '9') {
       if (allow_trailing_junk) {
+        current = junk_begin;
         goto parsing_done;
       } else {
         return junk_string_value_;
@@ -936,6 +1091,8 @@ double StringToDoubleConverter::StringToIeee(
     result = RadixStringToIeee<3>(&start,
                                   buffer + buffer_pos,
                                   sign,
+                                  separator_,
+                                  false, // Don't parse as hex_float.
                                   allow_trailing_junk,
                                   junk_string_value_,
                                   read_as_double,
index 200537a360a7cc2423d86ec930d6ba1d3131f425..377c710bf791e7aff730f0abcd11cfaa2dd8a0c9 100644 (file)
@@ -310,13 +310,18 @@ class DoubleToStringConverter {
   // should be at least kBase10MaximalLength + 1 characters long.
   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 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:
   //  - SHORTEST: produce the least amount of digits for which the internal
   //   identity requirement is still satisfied. If the digits are printed
@@ -393,7 +398,7 @@ class DoubleToStringConverter {
   const int max_trailing_padding_zeroes_in_precision_mode_;
 #endif // not needed for ICU
 
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
+  DC_DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
 };
 
 
@@ -408,9 +413,13 @@ class StringToDoubleConverter {
     ALLOW_TRAILING_JUNK = 4,
     ALLOW_LEADING_SPACES = 8,
     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.
   //  - NO_FLAGS: no special flags.
   //  - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
@@ -440,6 +449,13 @@ class StringToDoubleConverter {
   //  - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign.
   //       Ex: 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.
   // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
@@ -464,6 +480,12 @@ class StringToDoubleConverter {
   //  - they must not have the same first character.
   //  - 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:
   //  flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
   //  empty_string_value = 0.0,
@@ -503,16 +525,26 @@ class StringToDoubleConverter {
   //    StringToDouble("01239E45") -> 1239e45.
   //    StringToDouble("-infinity") -> 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,
                           double empty_string_value,
                           double junk_string_value,
                           const char* infinity_symbol,
-                          const char* nan_symbol)
+                          const char* nan_symbol,
+                          uc16 separator = kNoSeparator)
       : flags_(flags),
         empty_string_value_(empty_string_value),
         junk_string_value_(junk_string_value),
         infinity_symbol_(infinity_symbol),
-        nan_symbol_(nan_symbol) {
+        nan_symbol_(nan_symbol),
+        separator_(separator) {
   }
 
   // Performs the conversion.
@@ -547,6 +579,7 @@ class StringToDoubleConverter {
   const double junk_string_value_;
   const char* const infinity_symbol_;
   const char* const nan_symbol_;
+  const uc16 separator_;
 
   template <class Iterator>
   double StringToIeee(Iterator start_pointer,
@@ -554,7 +587,7 @@ class StringToDoubleConverter {
                       bool read_as_double,
                       int* processed_characters_count) const;
 
-  DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
+  DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
 };
 
 }  // namespace double_conversion
index d0e01083601edb3127bee585431fcfc098eb76d6..6cab2258d047c659185453667aafdbceb749f2f4 100644 (file)
@@ -2,6 +2,8 @@
 
 licenses(["notice"])
 
+exports_files(["LICENSE"])
+
 cc_library(
     name = "double-conversion",
     srcs = [
index 01196ba6417f22846b19930f349491285c4e795d..3cd74241090b2c9d3a14a668df9922ff74e09865 100644 (file)
@@ -1,27 +1,34 @@
-cmake_minimum_required(VERSION 2.8.12)
-project(double-conversion)
+cmake_minimum_required(VERSION 3.0)
+project(double-conversion VERSION 3.1.1)
 
-include(GNUInstallDirs)
+set(headers
+    double-conversion/bignum.h
+    double-conversion/cached-powers.h
+    double-conversion/diy-fp.h
+    double-conversion/double-conversion.h
+    double-conversion/fast-dtoa.h
+    double-conversion/fixed-dtoa.h
+    double-conversion/ieee.h
+    double-conversion/strtod.h
+    double-conversion/utils.h)
 
-# pick a version #
-set(double-conversion_VERSION 2.0.1)
-set(double-conversion_SOVERSION_MAJOR 1)
-set(double-conversion_SOVERSION_MINOR 0)
-set(double-conversion_SOVERSION_PATCH 0)
-set(double-conversion_SOVERSION
-  ${double-conversion_SOVERSION_MAJOR}.${double-conversion_SOVERSION_MINOR}.${double-conversion_SOVERSION_PATCH})
-
-# set suffix for CMake files used for packaging
-if(WIN32 AND NOT CYGWIN)
-  set(INSTALL_CMAKE_DIR CMake)
-else()
-  set(INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/double-conversion)
-endif()
+add_library(double-conversion
+            double-conversion/bignum.cc
+            double-conversion/bignum-dtoa.cc
+            double-conversion/cached-powers.cc
+            double-conversion/diy-fp.cc
+            double-conversion/double-conversion.cc
+            double-conversion/fast-dtoa.cc
+            double-conversion/fixed-dtoa.cc
+            double-conversion/strtod.cc
+            ${headers})
+target_include_directories(
+    double-conversion PUBLIC
+    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
 
-# Add src subdirectory
-add_subdirectory(double-conversion)
+# pick a version #
+set_target_properties(double-conversion PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 3)
 
-#
 # set up testing if requested
 option(BUILD_TESTING "Build test programs" OFF)
 if(BUILD_TESTING)
@@ -30,41 +37,75 @@ if(BUILD_TESTING)
   add_subdirectory(test)
 endif()
 
-#
-# mention the library target as export library
-export(TARGETS double-conversion
-  FILE "${PROJECT_BINARY_DIR}/double-conversionLibraryDepends.cmake")
+####
+# Installation (https://github.com/forexample/package-example)
+
+# Layout. This works for all platforms:
+#   * <prefix>/lib/cmake/<PROJECT-NAME>
+#   * <prefix>/lib/
+#   * <prefix>/include/
+set(config_install_dir "lib/cmake/${PROJECT_NAME}")
+set(include_install_dir "include")
+
+set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
+
+# Configuration
+set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
+set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
+set(targets_export_name "${PROJECT_NAME}Targets")
+set(namespace "${PROJECT_NAME}::")
+
+# Include module with function 'write_basic_package_version_file'
+include(CMakePackageConfigHelpers)
+
+# Configure '<PROJECT-NAME>ConfigVersion.cmake'
+# Note: PROJECT_VERSION is used as a VERSION
+write_basic_package_version_file(
+    "${version_config}" COMPATIBILITY SameMajorVersion
+)
 
-#
-# set this build as an importable package
-export(PACKAGE double-conversion)
+# Configure '<PROJECT-NAME>Config.cmake'
+# Use variables:
+#   * targets_export_name
+#   * PROJECT_NAME
+configure_package_config_file(
+    "cmake/Config.cmake.in"
+    "${project_config}"
+    INSTALL_DESTINATION "${config_install_dir}"
+)
 
-#
-# make a cmake file -- in this case, all that needs defining
-# is double-conversion_INCLUDE_DIRS
-configure_file(double-conversionBuildTreeSettings.cmake.in
-  "${PROJECT_BINARY_DIR}/double-conversionBuildTreeSettings.cmake"
-  @ONLY)
+# Targets:
+#   * <prefix>/lib/libdouble-conversion.a
+#   * header location after install: <prefix>/include/double-conversion/*.h
+#   * headers can be included by C++ code `#include <double-conversion/*.h>`
+install(
+    TARGETS double-conversion
+    EXPORT "${targets_export_name}"
+    LIBRARY DESTINATION "lib"
+    ARCHIVE DESTINATION "lib"
+    RUNTIME DESTINATION "bin"
+    INCLUDES DESTINATION "${include_install_dir}"
+)
 
-#
-# sets up config to be used by CMake find_package
-configure_file(double-conversionConfig.cmake.in
-  "${PROJECT_BINARY_DIR}/double-conversionConfig.cmake"
-  @ONLY)
-#
-# Export version # checked by find_package
-configure_file(double-conversionConfigVersion.cmake.in
-  "${PROJECT_BINARY_DIR}/double-conversionConfigVersion.cmake"
-  @ONLY)
-#
-# install config files for find_package
-install(FILES
-  "${PROJECT_BINARY_DIR}/double-conversionConfig.cmake"
-  "${PROJECT_BINARY_DIR}/double-conversionConfigVersion.cmake"
-  DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev)
+# Headers:
+#   * double-conversion/*.h -> <prefix>/include/double-conversion/*.h
+install(
+    FILES ${headers}
+    DESTINATION "${include_install_dir}/double-conversion"
+)
 
+# Config
+#   * <prefix>/lib/cmake/double-conversion/double-conversionConfig.cmake
+#   * <prefix>/lib/cmake/double-conversion/double-conversionConfigVersion.cmake
+install(
+    FILES "${project_config}" "${version_config}"
+    DESTINATION "${config_install_dir}"
+)
 
-#
-# generates install cmake files to find libraries in installation.
-install(EXPORT double-conversionLibraryDepends DESTINATION
-  "${INSTALL_CMAKE_DIR}" COMPONENT dev)
+# Config
+#   * <prefix>/lib/cmake/double-conversion/double-conversionTargets.cmake
+install(
+    EXPORT "${targets_export_name}"
+    NAMESPACE "${namespace}"
+    DESTINATION "${config_install_dir}"
+)
index 13e86e396a4d3566f4e84111f6e83bc1ea716d1c..16e92d5fd563fa495d4867a6965694027b16f823 100644 (file)
@@ -1,6 +1,23 @@
+2018-09-15:
+  Update version numbers. This also updates the shared-library version number.
+
+2018-09-09:
+  Fix bug where large hex literals would lose their minus sign.
+  Added support for separator characters (which adds a new optional
+  argument). Thus increasing the version number to 3.1.0
+  Added support for hexadecimal float literals.
+  Support for more architectures.
+
+2017-12-06:
+  Renamed `DISALLOW_COPY_AND_ASSIGN` and `DISALLOW_IMPLICIT_CONSTRUCTORS`
+  macros to `DC_DISALLOW_COPY_AND_ASSIGN` and
+  `DC_DISALLOW_IMPLICIT_CONSTRUCTORS` to make it easier to integrate the
+  library with other libraries that have similar macros.
+
 2017-08-05:
   Tagged v3.0.0.
   Due to the directory rename switching to a new version number.
+  The API for the library itself hasn't changed.
 
 2017-03-04:
   Avoid negative shift. Fixes #41.
index cff18b4c33f486657dff03c3d06c3193075e32bc..c4de4b48ff14eeb8d7e6cfa1de61b268670a1b81 100644 (file)
@@ -16,7 +16,7 @@ optimize = ARGUMENTS.get('optimize', 0)
 env.Replace(CXX = ARGUMENTS.get('CXX', 'g++'))
 
 # for shared lib, requires scons 2.3.0
-env['SHLIBVERSION'] = '1.0.0'
+env['SHLIBVERSION'] = '3.0.0'
 
 CCFLAGS = []
 if int(debug):
diff --git a/vendor/double-conversion/upstream/cmake/Config.cmake.in b/vendor/double-conversion/upstream/cmake/Config.cmake.in
new file mode 100644 (file)
index 0000000..9b4c9ee
--- /dev/null
@@ -0,0 +1,4 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
+check_required_components("@PROJECT_NAME@")
diff --git a/vendor/double-conversion/upstream/double-conversion/CMakeLists.txt b/vendor/double-conversion/upstream/double-conversion/CMakeLists.txt
deleted file mode 100644 (file)
index 2d13b36..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-set(headers
-  bignum.h
-  cached-powers.h
-  diy-fp.h
-  double-conversion.h
-  fast-dtoa.h
-  fixed-dtoa.h
-  ieee.h
-  strtod.h
-  utils.h
-  )
-
-add_library(double-conversion
-bignum.cc
-bignum-dtoa.cc
-cached-powers.cc
-diy-fp.cc
-double-conversion.cc
-fast-dtoa.cc
-fixed-dtoa.cc
-strtod.cc
-${headers}
-)
-
-target_include_directories(double-conversion PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
-
-# Add fPIC on x86_64 when supported.
-include(CheckCXXCompilerFlag)
-check_cxx_compiler_flag(-fPIC CXX_HAS_FPIC)
-
-if(CXX_HAS_FPIC AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
-  set_target_properties(double-conversion PROPERTIES COMPILE_FLAGS "-fPIC")
-endif()
-
-#
-# associates the list of headers with the library
-# for the purposes of installation/import into other projects
-set_target_properties(double-conversion
-    PROPERTIES PUBLIC_HEADER "${headers}")
-
-if (BUILD_SHARED_LIBS)
-  set_target_properties(double-conversion
-    PROPERTIES VERSION ${double-conversion_SOVERSION}
-               SOVERSION ${double-conversion_SOVERSION_MAJOR})
-endif()
-
-#
-# install command to set up library install
-# given the above PUBLIC_HEADER property set, this
-# pulls along all the header files with the library.
-install(TARGETS double-conversion
-  EXPORT double-conversionLibraryDepends
-  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin
-  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib
-  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib
-  PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/double-conversion"
-  COMPONENT dev)
index f1ad7a5ae8dd027d53e2786d3f6c459aed04e397..526f96edf5459199de3f898bfce4ccb92d86209c 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <math.h>
+#include <cmath>
 
-#include "bignum-dtoa.h"
+#include <double-conversion/bignum-dtoa.h>
 
-#include "bignum.h"
-#include "ieee.h"
+#include <double-conversion/bignum.h>
+#include <double-conversion/ieee.h>
 
 namespace double_conversion {
 
index 34b961992d672c1713bc19dde430939d28dffb53..9d15ce3dce97969964056426af6d5da776c83abb 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_
 #define DOUBLE_CONVERSION_BIGNUM_DTOA_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
index 8892de8f2a3a70102aa8f5b724db8f664992ee28..a7bc86d0c0e155c22741dc42c925a39673ada96b 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "bignum.h"
-#include "utils.h"
+#include <double-conversion/bignum.h>
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
 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) {
     bigits_[i] = 0;
   }
@@ -445,26 +445,27 @@ void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
   mask >>= 2;
   uint64_t this_value = base;
 
-  bool delayed_multipliciation = false;
+  bool delayed_multiplication = false;
   const uint64_t max_32bits = 0xFFFFFFFF;
   while (mask != 0 && this_value <= max_32bits) {
     this_value = this_value * this_value;
     // Verify that there is enough space in this_value to perform the
     // multiplication.  The first bit_size bits must be 0.
     if ((power_exponent & mask) != 0) {
+      ASSERT(bit_size > 0);
       uint64_t base_bits_mask =
           ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
       bool high_bits_zero = (this_value & base_bits_mask) == 0;
       if (high_bits_zero) {
         this_value *= base;
       } else {
-        delayed_multipliciation = true;
+        delayed_multiplication = true;
       }
     }
     mask >>= 1;
   }
   AssignUInt64(this_value);
-  if (delayed_multipliciation) {
+  if (delayed_multiplication) {
     MultiplyByUInt32(base);
   }
 
index c385f2237bae1a6e2f7313f9a065b0dbd9b225e8..238a351196e4733dd0ae035deab1a83bbb71a672 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_BIGNUM_H_
 #define DOUBLE_CONVERSION_BIGNUM_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
@@ -136,7 +136,7 @@ class Bignum {
   // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
   int exponent_;
 
-  DISALLOW_COPY_AND_ASSIGN(Bignum);
+  DC_DISALLOW_COPY_AND_ASSIGN(Bignum);
 };
 
 }  // namespace double_conversion
index 2b43f06412777509a8100ae591d84065af626e47..6f771e9c73d95f0db32c906331e379c4f46cd0e7 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <stdarg.h>
-#include <limits.h>
-#include <math.h>
+#include <climits>
+#include <cmath>
+#include <cstdarg>
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
-#include "cached-powers.h"
+#include <double-conversion/cached-powers.h>
 
 namespace double_conversion {
 
index 61a50614cf10c730829467007be06c6e66a6d44e..eabff4a15afd982eaa30088fc69d2ae04925b093 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_CACHED_POWERS_H_
 #define DOUBLE_CONVERSION_CACHED_POWERS_H_
 
-#include "diy-fp.h"
+#include <double-conversion/diy-fp.h>
 
 namespace double_conversion {
 
index ddd1891b168ada0b67b3d124ff3c63b352d7fda6..82b0d08af4efaf7d4f07d7030582624d5e608c40 100644 (file)
@@ -26,8 +26,8 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-#include "diy-fp.h"
-#include "utils.h"
+#include <double-conversion/diy-fp.h>
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
index 2edf34674ee25c34969406d6f4bdcfb215924730..e2011d43e5aa55bf2e774a314191c3ef3194d934 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_DIY_FP_H_
 #define DOUBLE_CONVERSION_DIY_FP_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
index 6f21a0124c43decdfef2679794b7678590e69326..854f4b60ef275863a7b3d808fef17c30b15b6e17 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <limits.h>
-#include <math.h>
+#include <climits>
+#include <locale>
+#include <cmath>
 
-#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 {
 
@@ -414,21 +415,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.
 // Returns false, if the substring does not match.
 template <class Iterator>
 static bool ConsumeSubString(Iterator* current,
                              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.
 // The longest possible double in decimal representation is
@@ -494,7 +529,7 @@ static double SignedZero(bool sign) {
 // 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
+#ifdef _MSC_VER
 #pragma optimize("",off)
 static bool IsDecimalDigitForRadix(int c, int radix) {
   return '0' <= c && c <= '9' && (c - '0') < radix;
@@ -502,7 +537,7 @@ static bool IsDecimalDigitForRadix(int c, int radix) {
 #pragma optimize("",on)
 #else
 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
 // Returns true if 'c' is a character digit that is valid for the given radix.
@@ -516,17 +551,86 @@ static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
   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, char 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,
+                             char 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.
+//
+// If parse_as_hex_float is true, then the string must be a valid
+// hex-float.
 template <int radix_log_2, class Iterator>
 static double RadixStringToIeee(Iterator* current,
                                 Iterator end,
                                 bool sign,
+                                char separator,
+                                bool parse_as_hex_float,
                                 bool allow_trailing_junk,
                                 double junk_string_value,
                                 bool read_as_double,
                                 bool* result_is_junk) {
   ASSERT(*current != end);
+  ASSERT(!parse_as_hex_float ||
+      IsHexFloatString(*current, end, separator, allow_trailing_junk));
 
   const int kDoubleSize = Double::kSignificandSize;
   const int kSingleSize = Single::kSignificandSize;
@@ -534,27 +638,39 @@ static double RadixStringToIeee(Iterator* current,
 
   *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.
   while (**current == '0') {
-    ++(*current);
-    if (*current == end) {
+    if (Advance(current, separator, radix, end)) {
       *result_is_junk = false;
       return SignedZero(sign);
     }
   }
 
-  int64_t number = 0;
-  int exponent = 0;
-  const int radix = (1 << radix_log_2);
-
-  do {
+  while (true) {
     int digit;
     if (IsDecimalDigitForRadix(**current, radix)) {
       digit = static_cast<char>(**current) - '0';
+      if (post_decimal) exponent -= radix_log_2;
     } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
       digit = static_cast<char>(**current) - 'a' + 10;
+      if (post_decimal) exponent -= radix_log_2;
     } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
       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 {
       if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
         break;
@@ -577,17 +693,26 @@ static double RadixStringToIeee(Iterator* current,
       int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
       int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
       number >>= overflow_bits_count;
-      exponent = overflow_bits_count;
+      exponent += overflow_bits_count;
 
       bool zero_tail = true;
       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';
-        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;
       }
 
@@ -609,15 +734,37 @@ static double RadixStringToIeee(Iterator* current,
       }
       break;
     }
-    ++(*current);
-  } while (*current != end);
+    if (Advance(current, separator, radix, end)) break;
+  }
 
   ASSERT(number < ((int64_t)1 << kSignificandSize));
   ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
 
   *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 (number == 0) return -0.0;
       number = -number;
@@ -626,10 +773,10 @@ static double RadixStringToIeee(Iterator* current,
   }
 
   ASSERT(number != 0);
-  return Double(DiyFp(number, exponent)).value();
+  double result = Double(DiyFp(number, exponent)).value();
+  return sign ? -result : result;
 }
 
-
 template <class Iterator>
 double StringToDoubleConverter::StringToIeee(
     Iterator input,
@@ -645,6 +792,7 @@ double StringToDoubleConverter::StringToIeee(
   const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
   const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
   const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
+  const bool allow_case_insensibility = (flags_ & ALLOW_CASE_INSENSIBILITY) != 0;
 
   // To make sure that iterator dereferencing is valid the following
   // convention is used:
@@ -694,8 +842,8 @@ double StringToDoubleConverter::StringToIeee(
   }
 
   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_;
       }
 
@@ -713,8 +861,8 @@ double StringToDoubleConverter::StringToIeee(
   }
 
   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_;
       }
 
@@ -733,8 +881,7 @@ double StringToDoubleConverter::StringToIeee(
 
   bool leading_zero = false;
   if (*current == '0') {
-    ++current;
-    if (current == end) {
+    if (Advance(&current, separator_, 10, end)) {
       *processed_characters_count = static_cast<int>(current - input);
       return SignedZero(sign);
     }
@@ -742,16 +889,24 @@ double StringToDoubleConverter::StringToIeee(
     leading_zero = true;
 
     // 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;
-      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;
       double result = RadixStringToIeee<4>(&current,
                                            end,
                                            sign,
+                                           separator_,
+                                           parse_as_hex_float,
                                            allow_trailing_junk,
                                            junk_string_value_,
                                            read_as_double,
@@ -765,8 +920,7 @@ double StringToDoubleConverter::StringToIeee(
 
     // Ignore leading zeros in the integer part.
     while (*current == '0') {
-      ++current;
-      if (current == end) {
+      if (Advance(&current, separator_, 10, end)) {
         *processed_characters_count = static_cast<int>(current - input);
         return SignedZero(sign);
       }
@@ -787,8 +941,7 @@ double StringToDoubleConverter::StringToIeee(
       nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
     }
     octal = octal && *current < '8';
-    ++current;
-    if (current == end) goto parsing_done;
+    if (Advance(&current, separator_, 10, end)) goto parsing_done;
   }
 
   if (significant_digits == 0) {
@@ -799,8 +952,7 @@ double StringToDoubleConverter::StringToIeee(
     if (octal && !allow_trailing_junk) return junk_string_value_;
     if (octal) goto parsing_done;
 
-    ++current;
-    if (current == end) {
+    if (Advance(&current, separator_, 10, end)) {
       if (significant_digits == 0 && !leading_zero) {
         return junk_string_value_;
       } else {
@@ -813,8 +965,7 @@ double StringToDoubleConverter::StringToIeee(
       // Integer part consists of 0 or is absent. Significant digits start after
       // leading zeros (if any).
       while (*current == '0') {
-        ++current;
-        if (current == end) {
+        if (Advance(&current, separator_, 10, end)) {
           *processed_characters_count = static_cast<int>(current - input);
           return SignedZero(sign);
         }
@@ -834,8 +985,7 @@ double StringToDoubleConverter::StringToIeee(
         // Ignore insignificant digits in the fractional part.
         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 +1001,11 @@ double StringToDoubleConverter::StringToIeee(
   if (*current == 'e' || *current == 'E') {
     if (octal && !allow_trailing_junk) return junk_string_value_;
     if (octal) goto parsing_done;
+    Iterator junk_begin = current;
     ++current;
     if (current == end) {
       if (allow_trailing_junk) {
+        current = junk_begin;
         goto parsing_done;
       } else {
         return junk_string_value_;
@@ -865,6 +1017,7 @@ double StringToDoubleConverter::StringToIeee(
       ++current;
       if (current == end) {
         if (allow_trailing_junk) {
+          current = junk_begin;
           goto parsing_done;
         } else {
           return junk_string_value_;
@@ -874,6 +1027,7 @@ double StringToDoubleConverter::StringToIeee(
 
     if (current == end || *current < '0' || *current > '9') {
       if (allow_trailing_junk) {
+        current = junk_begin;
         goto parsing_done;
       } else {
         return junk_string_value_;
@@ -918,6 +1072,8 @@ double StringToDoubleConverter::StringToIeee(
     result = RadixStringToIeee<3>(&start,
                                   buffer + buffer_pos,
                                   sign,
+                                  separator_,
+                                  false, // Don't parse as hex_float.
                                   allow_trailing_junk,
                                   junk_string_value_,
                                   read_as_double,
index 6bdfa8d25d768a640ac460ec1283f2ceae1098aa..7495d17a1d5970acf4a9b01649963810e5f206a4 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
 #define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
@@ -294,13 +294,18 @@ class DoubleToStringConverter {
   // should be at least kBase10MaximalLength + 1 characters long.
   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 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:
   //  - SHORTEST: produce the least amount of digits for which the internal
   //   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_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_LEADING_SPACES = 8,
     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.
   //  - NO_FLAGS: no special flags.
   //  - 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.
   //       Ex: 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.
   // 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 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:
   //  flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
   //  empty_string_value = 0.0,
@@ -484,16 +506,26 @@ class StringToDoubleConverter {
   //    StringToDouble("01239E45") -> 1239e45.
   //    StringToDouble("-infinity") -> 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,
                           double empty_string_value,
                           double junk_string_value,
                           const char* infinity_symbol,
-                          const char* nan_symbol)
+                          const char* nan_symbol,
+                          uc16 separator = kNoSeparator)
       : flags_(flags),
         empty_string_value_(empty_string_value),
         junk_string_value_(junk_string_value),
         infinity_symbol_(infinity_symbol),
-        nan_symbol_(nan_symbol) {
+        nan_symbol_(nan_symbol),
+        separator_(separator) {
   }
 
   // Performs the conversion.
@@ -528,6 +560,7 @@ class StringToDoubleConverter {
   const double junk_string_value_;
   const char* const infinity_symbol_;
   const char* const nan_symbol_;
+  const uc16 separator_;
 
   template <class Iterator>
   double StringToIeee(Iterator start_pointer,
@@ -535,7 +568,7 @@ class StringToDoubleConverter {
                       bool read_as_double,
                       int* processed_characters_count) const;
 
-  DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
+  DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
 };
 
 }  // namespace double_conversion
index 61350383a95ea69e73604bd692ae2037ff4b7b14..e5c222291f5e92d5b44c6e8d2936c56bfae5d83e 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "fast-dtoa.h"
+#include <double-conversion/fast-dtoa.h>
 
-#include "cached-powers.h"
-#include "diy-fp.h"
-#include "ieee.h"
+#include <double-conversion/cached-powers.h>
+#include <double-conversion/diy-fp.h>
+#include <double-conversion/ieee.h>
 
 namespace double_conversion {
 
index 5f1e8eee5e56e7c496c84dc0a5bf9dad0b97fc9f..ac4317c04dd4e925e9b62944bf717def606c9942 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_FAST_DTOA_H_
 #define DOUBLE_CONVERSION_FAST_DTOA_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
index 0f55a0b6eb3bf73cc178d4357681e2ccc9db95cd..8c111aca6425783728c96fa726b03d1a76f7ccc3 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <math.h>
+#include <cmath>
 
-#include "fixed-dtoa.h"
-#include "ieee.h"
+#include <double-conversion/fixed-dtoa.h>
+#include <double-conversion/ieee.h>
 
 namespace double_conversion {
 
index 3bdd08e21f59d5fece37eb14a6f510f464c3f2ba..a9436fc9f617157786f539955475e7498215a655 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_FIXED_DTOA_H_
 #define DOUBLE_CONVERSION_FIXED_DTOA_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
index b14cf4f7172ac774ed9758642d08cbf54f08e24c..baaeced31ce7b04a4e83b0cfefed8c7da49c5ddb 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_DOUBLE_H_
 #define DOUBLE_CONVERSION_DOUBLE_H_
 
-#include "diy-fp.h"
+#include <double-conversion/diy-fp.h>
 
 namespace double_conversion {
 
@@ -257,7 +257,7 @@ class Double {
         (biased_exponent << kPhysicalSignificandSize);
   }
 
-  DISALLOW_COPY_AND_ASSIGN(Double);
+  DC_DISALLOW_COPY_AND_ASSIGN(Double);
 };
 
 class Single {
@@ -394,7 +394,7 @@ class Single {
 
   const uint32_t d32_;
 
-  DISALLOW_COPY_AND_ASSIGN(Single);
+  DC_DISALLOW_COPY_AND_ASSIGN(Single);
 };
 
 }  // namespace double_conversion
index 17abcbb2a557b5e1973b655a9471008349b8acbf..e8cc13f2de97c5692f43001b6c33881cfc800058 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <stdarg.h>
-#include <limits.h>
+#include <climits>
+#include <cstdarg>
 
-#include "strtod.h"
-#include "bignum.h"
-#include "cached-powers.h"
-#include "ieee.h"
+#include <double-conversion/bignum.h>
+#include <double-conversion/cached-powers.h>
+#include <double-conversion/ieee.h>
+#include <double-conversion/strtod.h>
 
 namespace double_conversion {
 
@@ -205,7 +205,7 @@ static bool DoubleStrtod(Vector<const char> trimmed,
   // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
   // the same problem.
   return false;
-#endif
+#else
   if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
     int read_digits;
     // The trimmed input fits into a double.
@@ -243,6 +243,7 @@ static bool DoubleStrtod(Vector<const char> trimmed,
     }
   }
   return false;
+#endif
 }
 
 
@@ -471,6 +472,30 @@ double Strtod(Vector<const char> 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) {
   char copy_buffer[kMaxSignificantDecimalDigits];
   Vector<const char> trimmed;
@@ -482,7 +507,7 @@ float Strtof(Vector<const char> buffer, int exponent) {
   double 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) {
     // This shortcut triggers for integer values.
     return float_guess;
@@ -505,15 +530,15 @@ float Strtof(Vector<const char> buffer, int exponent) {
   double double_next = Double(double_guess).NextDouble();
   double double_previous = Double(double_guess).PreviousDouble();
 
-  float f1 = static_cast<float>(double_previous);
+  float f1 = SanitizedDoubletof(double_previous);
   float f2 = float_guess;
-  float f3 = static_cast<float>(double_next);
+  float f3 = SanitizedDoubletof(double_next);
   float f4;
   if (is_correct) {
     f4 = f3;
   } else {
     double double_next2 = Double(double_next).NextDouble();
-    f4 = static_cast<float>(double_next2);
+    f4 = SanitizedDoubletof(double_next2);
   }
   (void) f2;  // Mark variable as used.
   ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
@@ -528,7 +553,7 @@ float Strtof(Vector<const char> buffer, int exponent) {
          (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).
   float guess = f1;
   float next = f4;
index ed0293b8f54a373762f17fe4dd70f2896eb1d193..322651621fb29c7ac4e30981f1cc037eb3af412c 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef DOUBLE_CONVERSION_STRTOD_H_
 #define DOUBLE_CONVERSION_STRTOD_H_
 
-#include "utils.h"
+#include <double-conversion/utils.h>
 
 namespace double_conversion {
 
index 2c745f363f69480cfd4c54f00f8ecdddfcca2d39..47489f66e163d4909cf2def6566196b40d8d20dc 100644 (file)
 #ifndef 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
 #define ASSERT(condition)         \
     assert(condition);
@@ -67,8 +67,24 @@ inline void abort_noreturn() { abort(); }
 // the output of the division with the expected result. (Inlining must be
 // disabled.)
 // 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__) || \
-    defined(__ARMEL__) || defined(__avr32__) || \
+    defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
     defined(__hppa__) || defined(__ia64__) || \
     defined(__mips__) || \
     defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
@@ -76,10 +92,13 @@ inline void abort_noreturn() { abort(); }
     defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
     defined(__SH4__) || defined(__alpha__) || \
     defined(_MIPS_ARCH_MIPS32R2) || \
-    defined(__AARCH64EL__) || defined(__aarch64__) || \
-    defined(__riscv)
+    defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \
+    defined(__riscv) || \
+    defined(__or1k__) || defined(__arc__) || \
+    defined(__EMSCRIPTEN__)
 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(__mc68000__)
+#elif defined(__mc68000__) || \
+    defined(__pnacl__) || defined(__native_client__)
 #undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
 #if defined(_WIN32)
@@ -92,12 +111,6 @@ inline void abort_noreturn() { abort(); }
 #error Target architecture was not detected as supported by Double-Conversion.
 #endif
 
-#if defined(__GNUC__)
-#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
-#else
-#define DOUBLE_CONVERSION_UNUSED
-#endif
-
 #if defined(_WIN32) && !defined(__MINGW32__)
 
 typedef signed char int8_t;
@@ -136,8 +149,8 @@ typedef uint16_t uc16;
 
 // A macro to disallow the evil copy constructor and operator= functions
 // 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&);                    \
   void operator=(const TypeName&)
 #endif
@@ -148,10 +161,10 @@ typedef uint16_t uc16;
 // This should be used in the private: declarations for a class
 // that wants to prevent anyone from instantiating it. This is
 // 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();                                    \
-  DISALLOW_COPY_AND_ASSIGN(TypeName)
+  DC_DISALLOW_COPY_AND_ASSIGN(TypeName)
 #endif
 
 namespace double_conversion {
@@ -293,7 +306,7 @@ class StringBuilder {
 
   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
@@ -324,8 +337,12 @@ template <class Dest, class Source>
 inline Dest BitCast(const Source& source) {
   // Compile time assertion: sizeof(Dest) == sizeof(Source)
   // A compile error here means your Dest and Source have different sizes.
-  DOUBLE_CONVERSION_UNUSED
-      typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#if __cplusplus >= 201103L
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "source and destination size mismatch");
+#else
+  typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#endif
 
   Dest dest;
   memmove(&dest, &source, sizeof(dest));
diff --git a/vendor/double-conversion/upstream/double-conversionBuildTreeSettings.cmake.in b/vendor/double-conversion/upstream/double-conversionBuildTreeSettings.cmake.in
deleted file mode 100644 (file)
index f46705d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-set(double-conversion_INCLUDE_DIRS
-  "@PROJECT_SOURCE_DIR@/src")
diff --git a/vendor/double-conversion/upstream/double-conversionConfig.cmake.in b/vendor/double-conversion/upstream/double-conversionConfig.cmake.in
deleted file mode 100644 (file)
index 110df44..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# - Config file for the double-conversion package
-# It defines the following variables
-# double-conversion_INCLUDE_DIRS
-# double-conversion_LIBRARIES
-
-get_filename_component(double-conversion_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-
-if(EXISTS "${double-conversion_CMAKE_DIR}/CMakeCache.txt")
-  include("${double-conversion_CMAKE_DIR}/double-conversionBuildTreeSettings.cmake")
-else()
-  set(double-conversion_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@/double-conversion")
-endif()
-
-include("@CMAKE_INSTALL_FULL_LIBDIR@/cmake/double-conversion/double-conversionLibraryDepends.cmake")
-
-set(double-conversion_LIBRARIES double-conversion)
diff --git a/vendor/double-conversion/upstream/double-conversionConfigVersion.cmake.in b/vendor/double-conversion/upstream/double-conversionConfigVersion.cmake.in
deleted file mode 100644 (file)
index 0f2295d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-set(PACKAGE_VERSION "@double-conversion_VERSION@")
-# Check whether the requested PACKAGE_FIND_VERSION is compatible
-if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
-  set(PACKAGE_VERSION_COMPATIBLE FALSE)
-else()
-  set(PACKAGE_VERSION_COMPATIBLE TRUE)
-  if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
-    set(PACKAGE_VERSION_EXACT TRUE)
-  endif()
-endif()
index 86494647244077ab82e9f538e729533a9c296243..28063a58b434343d429c6b3933b350f73a8eba74 100644 (file)
@@ -191,6 +191,11 @@ TEST(BignumDtoaVariousDoubles) {
   CHECK_EQ("35844466", buffer.start());
   CHECK_EQ(299, point);
 
+  BignumDtoa(1e-23, BIGNUM_DTOA_SHORTEST, 0,
+             buffer, &length, &point);
+  CHECK_EQ("1", buffer.start());
+  CHECK_EQ(-22, point);
+
   uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000);
   double v = Double(smallest_normal64).value();
   BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point);
index 42bca876ca3891a16949b60cdf1fe6c4c6d63ebd..9ebc823f26a7ee04313d20f127a4a0342e802c69 100644 (file)
@@ -35,6 +35,10 @@ TEST(DoubleToShortest) {
   CHECK(dc.ToShortest(1e21, &builder));
   CHECK_EQ("1e+21", builder.Finalize());
 
+  builder.Reset();
+  CHECK(dc.ToShortest(1e-23, &builder));
+  CHECK_EQ("1e-23", builder.Finalize());
+
   builder.Reset();
   CHECK(dc.ToShortest(1e20, &builder));
   CHECK_EQ("100000000000000000000", builder.Finalize());
@@ -1720,9 +1724,10 @@ TEST(DoubleToStringJavaScript) {
 
 static double StrToD16(const uc16* str16, int length, int flags,
                        double empty_string_value,
-                       int* processed_characters_count, bool* processed_all) {
+                       int* processed_characters_count, bool* processed_all,
+                       uc16 separator = StringToDoubleConverter::kNoSeparator) {
   StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(),
-                                    NULL, NULL);
+                                    NULL, NULL, separator);
   double result =
       converter.StringToDouble(str16, length, processed_characters_count);
   *processed_all = (length == *processed_characters_count);
@@ -1731,9 +1736,10 @@ static double StrToD16(const uc16* str16, int length, int flags,
 
 
 static double StrToD(const char* str, int flags, double empty_string_value,
-                     int* processed_characters_count, bool* processed_all) {
+                     int* processed_characters_count, bool* processed_all,
+                     uc16 separator = StringToDoubleConverter::kNoSeparator) {
   StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(),
-                                    NULL, NULL);
+                                    NULL, NULL, separator);
   double result = converter.StringToDouble(str, strlen(str),
                                            processed_characters_count);
   *processed_all =
@@ -1748,7 +1754,8 @@ static double StrToD(const char* str, int flags, double empty_string_value,
   int processed_characters_count16;
   bool processed_all16;
   double result16 = StrToD16(buffer16, len, flags, empty_string_value,
-                             &processed_characters_count16, &processed_all16);
+                             &processed_characters_count16, &processed_all16,
+                             separator);
   CHECK_EQ(result, result16);
   CHECK_EQ(*processed_characters_count, processed_characters_count16);
   return result;
@@ -1804,6 +1811,18 @@ TEST(StringToDoubleVarious) {
   CHECK_EQ(0, processed);
 
 
+  flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK;
+
+  CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(processed, 3);
+
+  CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(processed, 3);
+
+  CHECK_EQ(123.0, StrToD("123e-a", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(processed, 3);
+
+
   flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
       StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN |
       StringToDoubleConverter::ALLOW_TRAILING_SPACES |
@@ -2514,6 +2533,128 @@ TEST(StringToDoubleHexString) {
   CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0,
                                  &processed, &all_used));
   CHECK_EQ(0, processed);
+
+  CHECK_EQ(-5.634002666912405e+27, StrToD("-0x123456789012345678901234",
+                                          flags, 0.0,
+                                          &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(72057594037927940.0, StrToD("0x100000000000001", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(72057594037927940.0, StrToD("0x100000000000000", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000001", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000000", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352900000.0, StrToD("0x100000000000008001", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000008000", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018001", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018000", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  flags = StringToDoubleConverter::ALLOW_HEX_FLOATS;
+
+  CHECK_EQ(3.0, StrToD("0x3p0", flags, 0.0, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0, StrToD("0x.0p0", flags, 0.0, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(3.0, StrToD("0x3.0p0", flags, 0.0, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(3.0, StrToD("0x3.p0", flags, 0.0, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-5.634002666912405e+27, StrToD("-0x123456789012345678901234p0",
+                                          flags, 0.0,
+                                          &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(72057594037927940.0, StrToD("0x100000000000001p0", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(72057594037927940.0, StrToD("0x100000000000000p0", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000001p0", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000000p0", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352900000.0, StrToD("0x100000000000008001p0", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000008000p0", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018001p0", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018000p0", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(4.722366482869645e+21, StrToD("0x100000000000000001p4", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(4.722366482869645e+21, StrToD("0x100000000000000000p+4", flags, 0.0,
+                                       &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(4.722366482869646e+21, StrToD("0x100000000000008001p04", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(18446744073709552000.0, StrToD("0x100000000000008000p-4", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(18446744073709560000.0, StrToD("0x100000000000018001p-04", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(4.722366482869647e+21, StrToD("0x100000000000018000p4", flags, 0.0,
+                                           &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::Infinity(), StrToD("0x1p2000", flags, 0.0,
+                                      &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0, StrToD("0x1p-2000", flags, 0.0, &processed, &all_used));
+  CHECK(all_used);
+
+  CHECK_EQ(-0.0, StrToD("-0x1p-2000", flags, 0.0, &processed, &all_used));
+  CHECK(all_used);
 }
 
 
@@ -3062,6 +3203,323 @@ TEST(StringToDoubleOctalString) {
 }
 
 
+TEST(StringToDoubleSeparator) {
+  int flags;
+  int processed;
+  bool all_used;
+  char separator;
+
+  separator = '\'';
+  flags = StringToDoubleConverter::NO_FLAGS;
+
+  CHECK_EQ(1.0, StrToD("000'001.0'0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0, StrToD("0'0'0'0'0'1.0'0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(), StrToD("'1.0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1'.0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.'0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("0''1.0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e1'0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e1'", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e'1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0'e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("+'1.0e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("-'1.0e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e+'1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e-'1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e'+1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e'-1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  separator = ' ';
+  flags = StringToDoubleConverter::NO_FLAGS;
+
+  CHECK_EQ(1.0, StrToD("000 001.0 0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0, StrToD("0 0 0 0 0 1.0 0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(), StrToD(" 1.0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1 .0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1. 0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("0  1.0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e1 0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e1 ", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e 1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0 e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("+ 1.0e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("- 1.0e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e+ 1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e- 1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e +1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e -1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  separator = ' ';
+  flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
+      StringToDoubleConverter::ALLOW_TRAILING_SPACES;
+
+  CHECK_EQ(1.0, StrToD("000 001.0 0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0, StrToD("0 0 0 0 0 1.0 0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0, StrToD("  000 001.0 0   ", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0, StrToD("   0 0 0 0 0 1.0 0   ", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0, StrToD(" 1.0", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(), StrToD("1 .0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1. 0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("0  1.0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e1 0", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(10.0, StrToD("1.0e1 ", flags, 0.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e 1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0 e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("+ 1.0e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("- 1.0e1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e+ 1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e- 1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e +1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("1.0e -1", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  separator = ' ';
+  flags = StringToDoubleConverter::ALLOW_HEX |
+      StringToDoubleConverter::ALLOW_HEX_FLOATS |
+      StringToDoubleConverter::ALLOW_LEADING_SPACES |
+      StringToDoubleConverter::ALLOW_TRAILING_SPACES;
+
+  CHECK_EQ(18.0, StrToD("0x1 2", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0, StrToD("0x0 0", flags, 1.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(static_cast<double>(0x123456789),
+           StrToD("0x1 2 3 4 5 6 7 8 9", flags, Double::NaN(),
+                  &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(18.0, StrToD(" 0x1 2 ", flags, 0.0,
+                        &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0, StrToD(" 0x0 ", flags, 1.0,
+                       &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(static_cast<double>(0x123456789),
+           StrToD(" 0x1 2 3 4 5 6 7 8 9 ", flags, Double::NaN(),
+                  &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(static_cast<double>(0xabcdef),
+           StrToD("0xa b c d e f", flags, 0.0,
+                  &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(), StrToD("0x 1 2", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD("0 x0", flags, 1.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x1 2  3 4 5 6 7 8 9", flags, Double::NaN(),
+                  &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(), StrToD(" 0 x1 2 ", flags, 0.0,
+                                 &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(3.0,
+           StrToD("0x0 3p0", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(0.0,
+           StrToD("0x.0 0p0", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(3.0,
+           StrToD("0x3.0 0p0", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(3.0,
+           StrToD("0x0 3.p0", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x 3p0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x.0 p0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x3.0p0 0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x0 3.p 0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x3p+ 0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x.0p- 0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x3.0p +0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("0x0 3.p -0", flags, 0.0, &processed, &all_used));
+  CHECK_EQ(0, processed);
+}
+
 TEST(StringToDoubleSpecialValues) {
   int processed;
   int flags = StringToDoubleConverter::NO_FLAGS;
@@ -3184,10 +3642,10 @@ TEST(StringToDoubleCommentExamples) {
   CHECK(all_used);
 
   CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used));
-  CHECK(all_used);
+  CHECK_EQ(processed, 3);
 
   CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used));
-  CHECK(all_used);
+  CHECK_EQ(processed, 3);
 
   {
     StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "NaN");
@@ -3235,6 +3693,28 @@ TEST(StringToDoubleCommentExamples) {
 
   CHECK_EQ(Double::NaN(), StrToD("NaN", flags, 0.0, &processed, &all_used));
   CHECK_EQ(0, processed);
+
+  flags = StringToDoubleConverter::NO_FLAGS;
+  char separator = ' ';
+  CHECK_EQ(1234.0,
+           StrToD("1 2 3 4", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("1  2", flags, 0.0, &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(1000000.0,
+           StrToD("1 000 000.0", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(1.0,
+           StrToD("1.000 000", flags, 0.0, &processed, &all_used, separator));
+  CHECK(all_used);
+
+  CHECK_EQ(Double::NaN(),
+           StrToD("1.0e1 000", flags, 0.0, &processed, &all_used, separator));
+  CHECK_EQ(0, processed);
 }
 
 
@@ -3740,13 +4220,30 @@ TEST(StringToFloatHexString) {
   CHECK_EQ(5.0f, StrToF(" + 0x5 ", flags, 0.0f, &processed, &all_used));
   CHECK(all_used);
 
-  CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0f,  &processed, &all_used));
+  CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0f, 
+                                 &processed, &all_used));
   CHECK_EQ(0, processed);
 
-  CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0f,  &processed, &all_used));
+  CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0f,
+                                 &processed, &all_used));
   CHECK_EQ(0, processed);
 
-  CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f,  &processed, &all_used));
+  CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f,
+                                 &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x3p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x.0p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x3.0p0", flags, 0.0f,
+                                 &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x3.p0", flags, 0.0f,
+                                 &processed, &all_used));
   CHECK_EQ(0, processed);
 
   flags = StringToDoubleConverter::ALLOW_HEX;
@@ -3843,6 +4340,20 @@ TEST(StringToFloatHexString) {
   CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f,  &processed, &all_used));
   CHECK_EQ(0, processed);
 
+  CHECK_EQ(Single::NaN(), StrToF("0x3p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x.0p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x3.0p0", flags, 0.0f,
+                                 &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x3.p0", flags, 0.0f,
+                                 &processed, &all_used));
+  CHECK_EQ(0, processed);
+
   flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK |
       StringToDoubleConverter::ALLOW_HEX;
 
@@ -3965,6 +4476,19 @@ TEST(StringToFloatHexString) {
   CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f,  &processed, &all_used));
   CHECK_EQ(0, processed);
 
+  CHECK_EQ(3.0f, StrToF("0x3p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(Single::NaN(), StrToF("0x.0p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(3.0f, StrToF("0x3.0p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(3.0f, StrToF("0x3.p0", flags, 0.0f, &processed, &all_used));
+  CHECK_EQ(3, processed);
+
+
   flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK |
       StringToDoubleConverter::ALLOW_LEADING_SPACES |
       StringToDoubleConverter::ALLOW_TRAILING_SPACES |
@@ -4710,3 +5234,46 @@ TEST(StringToDoubleFloatWhitespace) {
                            &processed, &all_used));
   CHECK(all_used);
 }
+
+
+TEST(StringToDoubleCaseInsensitiveSpecialValues) {
+  int processed = 0;
+
+  int flags = StringToDoubleConverter::ALLOW_CASE_INSENSIBILITY |
+    StringToDoubleConverter::ALLOW_LEADING_SPACES |
+    StringToDoubleConverter::ALLOW_TRAILING_JUNK |
+    StringToDoubleConverter::ALLOW_TRAILING_SPACES;
+
+  // Use 1.0 as junk_string_value.
+  StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "nan");
+
+  CHECK_EQ(Double::NaN(), converter.StringToDouble("+nan", 4, &processed));
+  CHECK_EQ(4, processed);
+
+  CHECK_EQ(Double::NaN(), converter.StringToDouble("-nAN", 4, &processed));
+  CHECK_EQ(4, processed);
+
+  CHECK_EQ(Double::NaN(), converter.StringToDouble("nAN", 3, &processed));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(Double::NaN(), converter.StringToDouble("nANabc", 6, &processed));
+  CHECK_EQ(3, processed);
+
+  CHECK_EQ(+Double::Infinity(),
+           converter.StringToDouble("+Infinity", 9, &processed));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(-Double::Infinity(),
+           converter.StringToDouble("-INFinity", 9, &processed));
+  CHECK_EQ(9, processed);
+
+  CHECK_EQ(Double::Infinity(),
+           converter.StringToDouble("infINITY", 8, &processed));
+  CHECK_EQ(8, processed);
+
+  CHECK_EQ(1.0, converter.StringToDouble("INF", 3, &processed));
+  CHECK_EQ(0, processed);
+
+  CHECK_EQ(1.0, converter.StringToDouble("+inf", 4, &processed));
+  CHECK_EQ(0, processed);
+}