From ea701b23e1d96fafee836f823e059f576ca05e3c Mon Sep 17 00:00:00 2001 From: double-conversion Upstream <kwrobot@kitware.com> Date: Thu, 25 Oct 2018 16:46:15 -0400 Subject: [PATCH] doubleconversion 2018-10-25 (58a98568) Code extracted from: https://gitlab.kitware.com/third-party/double-conversion.git at commit 58a985685fd92f482822ba519e3d0c4d17b238fc (for/vtk-20181025-3.1.1). --- CMakeLists.txt | 32 +-- Changelog | 71 +++++++ README.kitware.md | 18 +- double-conversion/CMakeLists.txt | 57 ------ double-conversion/bignum-dtoa.cc | 8 +- double-conversion/bignum-dtoa.h | 2 +- double-conversion/bignum.cc | 13 +- double-conversion/bignum.h | 2 +- double-conversion/cached-powers.cc | 10 +- double-conversion/cached-powers.h | 2 +- double-conversion/diy-fp.cc | 4 +- double-conversion/diy-fp.h | 2 +- double-conversion/double-conversion.cc | 262 ++++++++++++++++++++----- double-conversion/double-conversion.h | 49 ++++- double-conversion/fast-dtoa.cc | 8 +- double-conversion/fast-dtoa.h | 2 +- double-conversion/fixed-dtoa.cc | 6 +- double-conversion/fixed-dtoa.h | 2 +- double-conversion/ieee.h | 2 +- double-conversion/strtod.cc | 49 +++-- double-conversion/strtod.h | 2 +- double-conversion/utils.h | 51 +++-- 22 files changed, 441 insertions(+), 213 deletions(-) create mode 100644 Changelog delete mode 100644 double-conversion/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index f011d832113..1fe06e7c22d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,3 @@ -cmake_minimum_required(VERSION 3.3) -project(doubleconversion) - set(headers double-conversion/bignum.h double-conversion/cached-powers.h @@ -10,7 +7,8 @@ set(headers double-conversion/fixed-dtoa.h double-conversion/ieee.h double-conversion/strtod.h - double-conversion/utils.h) + double-conversion/utils.h + "${CMAKE_CURRENT_BINARY_DIR}/vtkdoubleconversion_export.h") set(sources double-conversion/bignum.cc @@ -22,28 +20,12 @@ set(sources double-conversion/fixed-dtoa.cc double-conversion/strtod.cc) -vtk_add_library(vtkdoubleconversion - ${sources} - ${headers}) - -target_include_directories( - vtkdoubleconversion - PUBLIC - $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> - $<INSTALL_INTERFACE:${VTK_INSTALL_INCLUDE_DIR}> -) +vtk_module_add_module(VTK::doubleconversion + SOURCES ${sources} + HEADERS ${headers} + HEADERS_SUBDIR "vtkdoubleconversion") include(GenerateExportHeader) -generate_export_header(vtkdoubleconversion +generate_export_header(doubleconversion EXPORT_MACRO_NAME VTKDOUBLECONVERSION_EXPORT EXPORT_FILE_NAME vtkdoubleconversion_export.h) - -if (NOT VTK_INSTALL_NO_DEVELOPMENT) - install( - DIRECTORY double-conversion/ - DESTINATION "${VTK_INSTALL_INCLUDE_DIR}/vtkdoubleconversion/double-conversion" - FILES_MATCHING PATTERN "*.h") - install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/vtkdoubleconversion_export.h - DESTINATION "${VTK_INSTALL_INCLUDE_DIR}/vtkdoubleconversion/double-conversion") -endif() diff --git a/Changelog b/Changelog new file mode 100644 index 00000000000..dfaaa91a120 --- /dev/null +++ b/Changelog @@ -0,0 +1,71 @@ +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. + +2016-11-17: + Support RISC-V. + + +2016-09-10: + Add fPIC flag on x86_64 if the compiler supports it. Fixes #34. + +2015 and 2016: + Lots of improvements to the build system. + +2015: + Warning fixes. + +2015-05-19: + Rename 'src' directory to 'double-conversion'. + +2014-03-08: + Update version number for cmake. + Support shared libraries with cmake. + Add build instructions to the README. + +2014-01-12: + Tagged v2.0.1. + Fix compilation for ARMv8 64bit (used wrong define). + Improved SConstruct file. Thanks to Milan Bouchet-Valat and Elan Ruusamäe. + Fixed lots of warnings (especially on Windows). Thanks to Greg Smith. + +2013-11-09: + Tagged v2.0.0. + String-to-Double|Float: ALLOW_LEADING_SPACES and similar flags now include + new-lines, tabs and all Unicode whitespace characters. + +2013-11-09: + Tagged v1.1.2. + Add support for ARM 64 and OsX ppc. + Rewrite tests so they pass under Visual Studio. + Add CMake build system support. + Fix warnings. + +2012-06-10: + Tagged v1.1.1. + Null terminate exponent buffer (only an issue when asserts are enabled). + Support more architectures. + +2012-02-05: + Merged in Single-branch with single-precision support. + Tagged v1.1 (based on b28450f33e1db493948a535d8f84e88fa211bd10). + +2012-02-05: + Tagged v1.0 (based on eda0196e9ac8fcdf59e92cb62885ee0af5391969). diff --git a/README.kitware.md b/README.kitware.md index 1307d1b621f..8bb0971bc91 100644 --- a/README.kitware.md +++ b/README.kitware.md @@ -1,10 +1,12 @@ -double-conversion fork for VTK ---------------------- +# double-conversion fork for VTK -This branch contains required changes to embed double-conversion into VTK. -This includes the following: +This branch contains changes required to embed double-conversion into VTK. +This includes changes made primarily to the build system to allow it to be +embedded into another source tree as well as a header to facilitate mangling +of the symbols to avoid conflicts with other copies of the library within a +single process. -* add `.gitattributes` -* integrate VTK's module system (added CMakeLists.vtk.txt) -* update `double-conversion/utils.h` to include exports header and mangle namespace. -* add exports to `double-conversion/utils.h and `double-conversion/double-conversion.h`. + * add `.gitattributes` + * integrate VTK's module system + * mangle symbols for VTK + * export symbols diff --git a/double-conversion/CMakeLists.txt b/double-conversion/CMakeLists.txt deleted file mode 100644 index 2d13b36af1f..00000000000 --- a/double-conversion/CMakeLists.txt +++ /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) diff --git a/double-conversion/bignum-dtoa.cc b/double-conversion/bignum-dtoa.cc index f1ad7a5ae8d..526f96edf54 100644 --- a/double-conversion/bignum-dtoa.cc +++ b/double-conversion/bignum-dtoa.cc @@ -25,12 +25,12 @@ // (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 { diff --git a/double-conversion/bignum-dtoa.h b/double-conversion/bignum-dtoa.h index 34b961992d6..9d15ce3dce9 100644 --- a/double-conversion/bignum-dtoa.h +++ b/double-conversion/bignum-dtoa.h @@ -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 { diff --git a/double-conversion/bignum.cc b/double-conversion/bignum.cc index 8892de8f2a3..a7bc86d0c0e 100644 --- a/double-conversion/bignum.cc +++ b/double-conversion/bignum.cc @@ -25,13 +25,13 @@ // (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); } diff --git a/double-conversion/bignum.h b/double-conversion/bignum.h index 7c289fa2f6b..238a351196e 100644 --- a/double-conversion/bignum.h +++ b/double-conversion/bignum.h @@ -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 { diff --git a/double-conversion/cached-powers.cc b/double-conversion/cached-powers.cc index 2b43f064127..6f771e9c73d 100644 --- a/double-conversion/cached-powers.cc +++ b/double-conversion/cached-powers.cc @@ -25,13 +25,13 @@ // (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 { diff --git a/double-conversion/cached-powers.h b/double-conversion/cached-powers.h index 61a50614cf1..eabff4a15af 100644 --- a/double-conversion/cached-powers.h +++ b/double-conversion/cached-powers.h @@ -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 { diff --git a/double-conversion/diy-fp.cc b/double-conversion/diy-fp.cc index ddd1891b168..82b0d08af4e 100644 --- a/double-conversion/diy-fp.cc +++ b/double-conversion/diy-fp.cc @@ -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 { diff --git a/double-conversion/diy-fp.h b/double-conversion/diy-fp.h index 2edf34674ee..e2011d43e5a 100644 --- a/double-conversion/diy-fp.h +++ b/double-conversion/diy-fp.h @@ -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 { diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index 6f21a0124c4..ecd1a5ef3f1 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -25,17 +25,18 @@ // (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 @@ -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(¤t, separator, 16, end)) return false; + } + if (*current == '.') { + if (Advance(¤t, separator, 16, end)) return false; + while (isDigit(*current, 16)) { + saw_digit = true; + if (Advance(¤t, separator, 16, end)) return false; + } + if (!saw_digit) return false; // Only the '.', but no digits. + } + if (*current != 'p' && *current != 'P') return false; + if (Advance(¤t, separator, 16, end)) return false; + if (*current == '+' || *current == '-') { + if (Advance(¤t, separator, 16, end)) return false; + } + if (!isDigit(*current, 10)) return false; + if (Advance(¤t, separator, 16, end)) return true; + while (isDigit(*current, 10)) { + if (Advance(¤t, separator, 16, end)) return true; + } + return allow_trailing_junk || !AdvanceToNonspace(¤t, 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(¤t, end, infinity_symbol_)) { + if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensibility)) { + if (!ConsumeSubString(¤t, 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(¤t, end, nan_symbol_)) { + if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensibility)) { + if (!ConsumeSubString(¤t, 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(¤t, 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>(¤t, 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(¤t, 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(¤t, 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(¤t, 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(¤t, 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(¤t, 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, diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h index 49db8180fe9..c995eb783b7 100644 --- a/double-conversion/double-conversion.h +++ b/double-conversion/double-conversion.h @@ -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 VTKDOUBLECONVERSION_EXPORT 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 @@ -389,9 +394,13 @@ class VTKDOUBLECONVERSION_EXPORT 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 VTKDOUBLECONVERSION_EXPORT 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 VTKDOUBLECONVERSION_EXPORT 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 VTKDOUBLECONVERSION_EXPORT 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 VTKDOUBLECONVERSION_EXPORT 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, diff --git a/double-conversion/fast-dtoa.cc b/double-conversion/fast-dtoa.cc index 61350383a95..e5c222291f5 100644 --- a/double-conversion/fast-dtoa.cc +++ b/double-conversion/fast-dtoa.cc @@ -25,11 +25,11 @@ // (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 { diff --git a/double-conversion/fast-dtoa.h b/double-conversion/fast-dtoa.h index 5f1e8eee5e5..ac4317c04dd 100644 --- a/double-conversion/fast-dtoa.h +++ b/double-conversion/fast-dtoa.h @@ -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 { diff --git a/double-conversion/fixed-dtoa.cc b/double-conversion/fixed-dtoa.cc index 0f55a0b6eb3..8c111aca642 100644 --- a/double-conversion/fixed-dtoa.cc +++ b/double-conversion/fixed-dtoa.cc @@ -25,10 +25,10 @@ // (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 { diff --git a/double-conversion/fixed-dtoa.h b/double-conversion/fixed-dtoa.h index 3bdd08e21f5..a9436fc9f61 100644 --- a/double-conversion/fixed-dtoa.h +++ b/double-conversion/fixed-dtoa.h @@ -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 { diff --git a/double-conversion/ieee.h b/double-conversion/ieee.h index 4a5fe8f9c0a..baaeced31ce 100644 --- a/double-conversion/ieee.h +++ b/double-conversion/ieee.h @@ -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 { diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc index 17abcbb2a55..e8cc13f2de9 100644 --- a/double-conversion/strtod.cc +++ b/double-conversion/strtod.cc @@ -25,13 +25,13 @@ // (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; diff --git a/double-conversion/strtod.h b/double-conversion/strtod.h index ed0293b8f54..322651621fb 100644 --- a/double-conversion/strtod.h +++ b/double-conversion/strtod.h @@ -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 { diff --git a/double-conversion/utils.h b/double-conversion/utils.h index bfd29c4e38d..9354b5ff64e 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -28,16 +28,15 @@ #ifndef DOUBLE_CONVERSION_UTILS_H_ #define DOUBLE_CONVERSION_UTILS_H_ -// xxx(kitware) -// include exports header +// XXX(kitware): // include exports header #include "vtkdoubleconversion_export.h" // mangle the double_conversion namespace -#define double_conversion vtkdoubleconversion +#define double_conversion vtkdouble_conversion -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> -#include <assert.h> +#include <cassert> #ifndef ASSERT #define ASSERT(condition) \ assert(condition); @@ -73,8 +72,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__) || \ @@ -82,10 +97,12 @@ 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__) #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) @@ -98,12 +115,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; @@ -330,8 +341,12 @@ template <class Dest, class Source> inline Dest VTKDOUBLECONVERSION_EXPORT 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)); -- GitLab