From 23cac04d45f17ff27c9c0224aa4e0610b1a4f540 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 5 Aug 2017 16:39:46 +0200 Subject: [PATCH 01/27] Update Changelog. --- Changelog | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Changelog b/Changelog index 98247e72..37ab0a24 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,24 @@ +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'. From 9972d3c4ae4324a23365a0a301e43e190640affd Mon Sep 17 00:00:00 2001 From: akindyakov Date: Mon, 7 Aug 2017 23:25:43 +0300 Subject: [PATCH 02/27] Implement ALLOW_CASE_INSENSIBILITY mode for StringToDoubleConverter class --- double-conversion/double-conversion.cc | 60 ++++++++++++++++++++------ double-conversion/double-conversion.h | 5 ++- test/cctest/test-conversions.cc | 43 ++++++++++++++++++ 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index 6f21a012..835e4261 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -26,6 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include #include "double-conversion.h" @@ -414,21 +415,55 @@ void DoubleToStringConverter::DoubleToAscii(double v, } +namespace { + +static inline char ToLower(char ch) { + static const std::ctype& cType = + std::use_facet >(std::locale::classic()); + return cType.tolower(ch); +} + +static inline char Pass(char ch) { + return ch; +} + +template +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 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 +static inline bool ConsumeFirstCharacter(char ch, + const char* str, + bool case_insensibility) { + return case_insensibility ? ToLower(ch) == str[0] : ch == str[0]; +} +} // Maximum number of significant digits in decimal representation. // The longest possible double in decimal representation is @@ -629,7 +664,6 @@ static double RadixStringToIeee(Iterator* current, return Double(DiyFp(number, exponent)).value(); } - template double StringToDoubleConverter::StringToIeee( Iterator input, @@ -645,6 +679,8 @@ 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 +730,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 +749,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_; } diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h index 6bdfa8d2..42aaa3ea 100644 --- a/double-conversion/double-conversion.h +++ b/double-conversion/double-conversion.h @@ -389,7 +389,8 @@ 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, }; // Flags should be a bit-or combination of the possible Flags-enum. @@ -421,6 +422,8 @@ 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. // // 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 diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index 42bca876..6b709edf 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -4710,3 +4710,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); +} From a711666ddd063eb1e4b181a6cb981d39a1fc8bac Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Tue, 5 Sep 2017 19:55:14 -0400 Subject: [PATCH 03/27] Update CMake package generation. --- CMakeLists.txt | 102 ++++++++++---------- cmake/double-conversionConfig.cmake | 1 + double-conversion/CMakeLists.txt | 24 ----- double-conversion/bignum-dtoa.cc | 6 +- double-conversion/bignum-dtoa.h | 2 +- double-conversion/bignum.cc | 4 +- double-conversion/bignum.h | 2 +- double-conversion/cached-powers.cc | 4 +- double-conversion/cached-powers.h | 2 +- double-conversion/diy-fp.cc | 4 +- double-conversion/diy-fp.h | 2 +- double-conversion/double-conversion.cc | 16 +-- double-conversion/double-conversion.h | 2 +- double-conversion/fast-dtoa.cc | 8 +- double-conversion/fast-dtoa.h | 2 +- double-conversion/fixed-dtoa.cc | 4 +- double-conversion/fixed-dtoa.h | 2 +- double-conversion/ieee.h | 2 +- double-conversion/strtod.cc | 8 +- double-conversion/strtod.h | 2 +- double-conversionBuildTreeSettings.cmake.in | 2 - double-conversionConfig.cmake.in | 16 --- double-conversionConfigVersion.cmake.in | 11 --- 23 files changed, 90 insertions(+), 138 deletions(-) create mode 100644 cmake/double-conversionConfig.cmake delete mode 100644 double-conversionBuildTreeSettings.cmake.in delete mode 100644 double-conversionConfig.cmake.in delete mode 100644 double-conversionConfigVersion.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 01196ba6..58f49674 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,27 +1,40 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.0) project(double-conversion) -include(GNUInstallDirs) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) + +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) + +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}) # pick a version # set(double-conversion_VERSION 2.0.1) +set_property(TARGET double-conversion PROPERTY VERSION ${double-conversion_VERSION}) 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 src subdirectory -add_subdirectory(double-conversion) +set(double-conversion_SOVERSION ${double-conversion_SOVERSION_MAJOR}.${double-conversion_SOVERSION_MINOR}.${double-conversion_SOVERSION_PATCH}) +set_property(TARGET double-conversion PROPERTY SOVERSION ${double-conversion_SOVERSION}) -# # set up testing if requested option(BUILD_TESTING "Build test programs" OFF) if(BUILD_TESTING) @@ -30,41 +43,32 @@ 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") - -# -# set this build as an importable package -export(PACKAGE double-conversion) +install(TARGETS double-conversion EXPORT double-conversionTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + INCLUDES DESTINATION include) -# -# 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) +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/double-conversion/double-conversionConfigVersion.cmake" + VERSION ${double-conversion_VERSION} + COMPATIBILITY AnyNewerVersion) -# -# 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) +export(EXPORT double-conversionTargets + FILE "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionTargets.cmake" + NAMESPACE double-conversion::) +configure_file(cmake/double-conversionConfig.cmake + "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfig.cmake" + COPYONLY) -# -# generates install cmake files to find libraries in installation. -install(EXPORT double-conversionLibraryDepends DESTINATION - "${INSTALL_CMAKE_DIR}" COMPONENT dev) +set(ConfigPackageLocation lib/cmake/double-conversion) +install(EXPORT double-conversionTargets + FILE double-conversionTargets.cmake + NAMESPACE double-conversion:: + DESTINATION ${ConfigPackageLocation}) +install(FILES cmake/double-conversionConfig.cmake + "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfigVersion.cmake" + DESTINATION ${ConfigPackageLocation} + COMPONENT Devel) diff --git a/cmake/double-conversionConfig.cmake b/cmake/double-conversionConfig.cmake new file mode 100644 index 00000000..15d63634 --- /dev/null +++ b/cmake/double-conversionConfig.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/double-conversionTargets.cmake") diff --git a/double-conversion/CMakeLists.txt b/double-conversion/CMakeLists.txt index 2d13b36a..47bd52a6 100644 --- a/double-conversion/CMakeLists.txt +++ b/double-conversion/CMakeLists.txt @@ -1,27 +1,3 @@ -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 $) # Add fPIC on x86_64 when supported. diff --git a/double-conversion/bignum-dtoa.cc b/double-conversion/bignum-dtoa.cc index f1ad7a5a..bdb06a29 100644 --- a/double-conversion/bignum-dtoa.cc +++ b/double-conversion/bignum-dtoa.cc @@ -27,10 +27,10 @@ #include -#include "bignum-dtoa.h" +#include -#include "bignum.h" -#include "ieee.h" +#include +#include namespace double_conversion { diff --git a/double-conversion/bignum-dtoa.h b/double-conversion/bignum-dtoa.h index 34b96199..9d15ce3d 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 namespace double_conversion { diff --git a/double-conversion/bignum.cc b/double-conversion/bignum.cc index 8892de8f..0d2eeac3 100644 --- a/double-conversion/bignum.cc +++ b/double-conversion/bignum.cc @@ -25,8 +25,8 @@ // (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 +#include namespace double_conversion { diff --git a/double-conversion/bignum.h b/double-conversion/bignum.h index c385f223..4ff34e26 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 namespace double_conversion { diff --git a/double-conversion/cached-powers.cc b/double-conversion/cached-powers.cc index 2b43f064..780f527b 100644 --- a/double-conversion/cached-powers.cc +++ b/double-conversion/cached-powers.cc @@ -29,9 +29,9 @@ #include #include -#include "utils.h" +#include -#include "cached-powers.h" +#include namespace double_conversion { diff --git a/double-conversion/cached-powers.h b/double-conversion/cached-powers.h index 61a50614..eabff4a1 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 namespace double_conversion { diff --git a/double-conversion/diy-fp.cc b/double-conversion/diy-fp.cc index ddd1891b..82b0d08a 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 +#include namespace double_conversion { diff --git a/double-conversion/diy-fp.h b/double-conversion/diy-fp.h index 2edf3467..e2011d43 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 namespace double_conversion { diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index 6f21a012..6609c563 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -28,14 +28,14 @@ #include #include -#include "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 + +#include +#include +#include +#include +#include +#include namespace double_conversion { diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h index 6bdfa8d2..23cdaf98 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 namespace double_conversion { diff --git a/double-conversion/fast-dtoa.cc b/double-conversion/fast-dtoa.cc index 61350383..e5c22229 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 -#include "cached-powers.h" -#include "diy-fp.h" -#include "ieee.h" +#include +#include +#include namespace double_conversion { diff --git a/double-conversion/fast-dtoa.h b/double-conversion/fast-dtoa.h index 5f1e8eee..ac4317c0 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 namespace double_conversion { diff --git a/double-conversion/fixed-dtoa.cc b/double-conversion/fixed-dtoa.cc index 0f55a0b6..5b6ca5a2 100644 --- a/double-conversion/fixed-dtoa.cc +++ b/double-conversion/fixed-dtoa.cc @@ -27,8 +27,8 @@ #include -#include "fixed-dtoa.h" -#include "ieee.h" +#include +#include namespace double_conversion { diff --git a/double-conversion/fixed-dtoa.h b/double-conversion/fixed-dtoa.h index 3bdd08e2..a9436fc9 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 namespace double_conversion { diff --git a/double-conversion/ieee.h b/double-conversion/ieee.h index b14cf4f7..1b705d2e 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 namespace double_conversion { diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc index 17abcbb2..50eacf07 100644 --- a/double-conversion/strtod.cc +++ b/double-conversion/strtod.cc @@ -28,10 +28,10 @@ #include #include -#include "strtod.h" -#include "bignum.h" -#include "cached-powers.h" -#include "ieee.h" +#include +#include +#include +#include namespace double_conversion { diff --git a/double-conversion/strtod.h b/double-conversion/strtod.h index ed0293b8..32265162 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 namespace double_conversion { diff --git a/double-conversionBuildTreeSettings.cmake.in b/double-conversionBuildTreeSettings.cmake.in deleted file mode 100644 index f46705d6..00000000 --- a/double-conversionBuildTreeSettings.cmake.in +++ /dev/null @@ -1,2 +0,0 @@ -set(double-conversion_INCLUDE_DIRS - "@PROJECT_SOURCE_DIR@/src") diff --git a/double-conversionConfig.cmake.in b/double-conversionConfig.cmake.in deleted file mode 100644 index 110df446..00000000 --- a/double-conversionConfig.cmake.in +++ /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/double-conversionConfigVersion.cmake.in b/double-conversionConfigVersion.cmake.in deleted file mode 100644 index 0f2295d2..00000000 --- a/double-conversionConfigVersion.cmake.in +++ /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() From 8e02bf4f2bcb96d842d1b65e4d77adf4ee56f0b1 Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Wed, 6 Sep 2017 08:45:20 -0400 Subject: [PATCH 04/27] Improve CMake changes. --- CMakeLists.txt | 35 +++++++++++++------------- cmake/double-conversionConfig.cmake | 1 - cmake/double-conversionConfig.cmake.in | 4 +++ 3 files changed, 22 insertions(+), 18 deletions(-) delete mode 100644 cmake/double-conversionConfig.cmake create mode 100644 cmake/double-conversionConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 58f49674..0b8851b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,5 @@ cmake_minimum_required(VERSION 3.0) -project(double-conversion) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) +project(double-conversion VERSION 2.0.1) set(headers double-conversion/bignum.h @@ -25,10 +22,12 @@ add_library(double-conversion double-conversion/fixed-dtoa.cc double-conversion/strtod.cc ${headers}) +target_include_directories( + double-conversion PUBLIC + $ + $) # pick a version # -set(double-conversion_VERSION 2.0.1) -set_property(TARGET double-conversion PROPERTY VERSION ${double-conversion_VERSION}) set(double-conversion_SOVERSION_MAJOR 1) set(double-conversion_SOVERSION_MINOR 0) set(double-conversion_SOVERSION_PATCH 0) @@ -43,32 +42,34 @@ if(BUILD_TESTING) add_subdirectory(test) endif() +include(GNUInstallDirs) install(TARGETS double-conversion EXPORT double-conversionTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(FILES ${headers} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/double-conversion) include(CMakePackageConfigHelpers) +configure_package_config_file( + cmake/double-conversionConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfig.cmake" + INSTALL_DESTINATION "${LIB_INSTALL_DIR}/double-conversion/cmake") write_basic_package_version_file( "${PROJECT_BINARY_DIR}/double-conversion/double-conversionConfigVersion.cmake" - VERSION ${double-conversion_VERSION} - COMPATIBILITY AnyNewerVersion) + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) export(EXPORT double-conversionTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionTargets.cmake" NAMESPACE double-conversion::) -configure_file(cmake/double-conversionConfig.cmake - "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfig.cmake" - COPYONLY) - set(ConfigPackageLocation lib/cmake/double-conversion) install(EXPORT double-conversionTargets FILE double-conversionTargets.cmake NAMESPACE double-conversion:: DESTINATION ${ConfigPackageLocation}) -install(FILES cmake/double-conversionConfig.cmake +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfigVersion.cmake" DESTINATION ${ConfigPackageLocation} COMPONENT Devel) diff --git a/cmake/double-conversionConfig.cmake b/cmake/double-conversionConfig.cmake deleted file mode 100644 index 15d63634..00000000 --- a/cmake/double-conversionConfig.cmake +++ /dev/null @@ -1 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/double-conversionTargets.cmake") diff --git a/cmake/double-conversionConfig.cmake.in b/cmake/double-conversionConfig.cmake.in new file mode 100644 index 00000000..9b4c9ee0 --- /dev/null +++ b/cmake/double-conversionConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") +check_required_components("@PROJECT_NAME@") From aa2df6600b6bb851cb6a53803e426f448e0a4237 Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Wed, 6 Sep 2017 08:50:41 -0400 Subject: [PATCH 05/27] Fix mistake for build interface include dir. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b8851b6..6353184c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ add_library(double-conversion ${headers}) target_include_directories( double-conversion PUBLIC - $ + $ $) # pick a version # From e13e72e17692f5dc0036460d734c637b563f3ac7 Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Thu, 7 Sep 2017 08:15:01 -0400 Subject: [PATCH 06/27] Use template for CMake installation. --- CMakeLists.txt | 101 ++++++++++++------ ...versionConfig.cmake.in => Config.cmake.in} | 0 2 files changed, 69 insertions(+), 32 deletions(-) rename cmake/{double-conversionConfig.cmake.in => Config.cmake.in} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6353184c..8b294ece 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.0) -project(double-conversion VERSION 2.0.1) +project(double-conversion VERSION 3.0.0) set(headers double-conversion/bignum.h @@ -28,11 +28,7 @@ target_include_directories( $) # pick a version # -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_property(TARGET double-conversion PROPERTY SOVERSION ${double-conversion_SOVERSION}) +set_property(TARGET double-conversion PROPERTY SOVERSION ${PROJECT_VERSION}) # set up testing if requested option(BUILD_TESTING "Build test programs" OFF) @@ -42,34 +38,75 @@ if(BUILD_TESTING) add_subdirectory(test) endif() -include(GNUInstallDirs) -install(TARGETS double-conversion EXPORT double-conversionTargets - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(FILES ${headers} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/double-conversion) +#### +# Installation (https://github.com/forexample/package-example) +# Layout. This works for all platforms: +# * /lib/cmake/ +# * /lib/ +# * /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_package_config_file( - cmake/double-conversionConfig.cmake.in - "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfig.cmake" - INSTALL_DESTINATION "${LIB_INSTALL_DIR}/double-conversion/cmake") + +# Configure 'ConfigVersion.cmake' +# Note: PROJECT_VERSION is used as a VERSION write_basic_package_version_file( - "${PROJECT_BINARY_DIR}/double-conversion/double-conversionConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion) + "${version_config}" COMPATIBILITY SameMajorVersion +) + +# Configure 'Config.cmake' +# Use variables: +# * targets_export_name +# * PROJECT_NAME +configure_package_config_file( + "cmake/Config.cmake.in" + "${project_config}" + INSTALL_DESTINATION "${config_install_dir}" +) + +# Targets: +# * /lib/libdouble-conversion.a +# * header location after install: /include/double-conversion/*.h +# * headers can be included by C++ code `#include ` +install( + TARGETS double-conversion + EXPORT "${targets_export_name}" + LIBRARY DESTINATION "lib" + ARCHIVE DESTINATION "lib" + RUNTIME DESTINATION "bin" + INCLUDES DESTINATION "${include_install_dir}" +) + +# Headers: +# * double-conversion/*.h -> /include/double-conversion/*.h +install( + FILES ${headers} + DESTINATION "${include_install_dir}/double-conversion" +) -export(EXPORT double-conversionTargets - FILE "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionTargets.cmake" - NAMESPACE double-conversion::) +# Config +# * /lib/cmake/double-conversion/double-conversionConfig.cmake +# * /lib/cmake/double-conversion/double-conversionConfigVersion.cmake +install( + FILES "${project_config}" "${version_config}" + DESTINATION "${config_install_dir}" +) -set(ConfigPackageLocation lib/cmake/double-conversion) -install(EXPORT double-conversionTargets - FILE double-conversionTargets.cmake - NAMESPACE double-conversion:: - DESTINATION ${ConfigPackageLocation}) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/double-conversion/double-conversionConfigVersion.cmake" - DESTINATION ${ConfigPackageLocation} - COMPONENT Devel) +# Config +# * /lib/cmake/double-conversion/double-conversionTargets.cmake +install( + EXPORT "${targets_export_name}" + NAMESPACE "${namespace}" + DESTINATION "${config_install_dir}" +) diff --git a/cmake/double-conversionConfig.cmake.in b/cmake/Config.cmake.in similarity index 100% rename from cmake/double-conversionConfig.cmake.in rename to cmake/Config.cmake.in From 81407130bac1bd93d95f0c689b3aa6dd29594dd8 Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Thu, 7 Sep 2017 11:44:26 -0400 Subject: [PATCH 07/27] Remove unnecessary INSTALL_INTERFACE expression. --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b294ece..143c4584 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,7 @@ add_library(double-conversion ${headers}) target_include_directories( double-conversion PUBLIC - $ - $) + $) # pick a version # set_property(TARGET double-conversion PROPERTY SOVERSION ${PROJECT_VERSION}) From a131c6546eba81b053674b78a36884cf5b8a6fec Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Fri, 8 Sep 2017 07:27:44 -0400 Subject: [PATCH 08/27] Remove unused CMake file. --- double-conversion/CMakeLists.txt | 33 -------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 double-conversion/CMakeLists.txt diff --git a/double-conversion/CMakeLists.txt b/double-conversion/CMakeLists.txt deleted file mode 100644 index 47bd52a6..00000000 --- a/double-conversion/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -target_include_directories(double-conversion PUBLIC $) - -# 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) From 3c04013193563577bc4e67712e86f607ec6099ba Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Tue, 12 Sep 2017 07:52:56 -0400 Subject: [PATCH 09/27] Suppress issue in clang analyzer. --- double-conversion/bignum.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/double-conversion/bignum.cc b/double-conversion/bignum.cc index 0d2eeac3..c0aaadbf 100644 --- a/double-conversion/bignum.cc +++ b/double-conversion/bignum.cc @@ -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(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); } From 14033f67d1173b88f948440a2234edbab495109d Mon Sep 17 00:00:00 2001 From: uburuntu Date: Thu, 14 Sep 2017 21:18:31 +0300 Subject: [PATCH 10/27] REF: init member in constructor --- double-conversion/bignum.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/double-conversion/bignum.cc b/double-conversion/bignum.cc index c0aaadbf..a7bc86d0 100644 --- a/double-conversion/bignum.cc +++ b/double-conversion/bignum.cc @@ -31,7 +31,7 @@ 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; } From 487370372b403e914951bfa1349693926b0179e4 Mon Sep 17 00:00:00 2001 From: uburuntu Date: Thu, 14 Sep 2017 21:18:47 +0300 Subject: [PATCH 11/27] REF: meaningless static definition in anonymous namespace --- double-conversion/double-conversion.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index 0fa4cd20..7bd7df0e 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -417,13 +417,13 @@ void DoubleToStringConverter::DoubleToAscii(double v, namespace { -static inline char ToLower(char ch) { +inline char ToLower(char ch) { static const std::ctype& cType = std::use_facet >(std::locale::classic()); return cType.tolower(ch); } -static inline char Pass(char ch) { +inline char Pass(char ch) { return ch; } @@ -458,12 +458,12 @@ static bool ConsumeSubString(Iterator* current, } // Consumes first character of the str is equal to ch -static inline bool ConsumeFirstCharacter(char 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 From 1d5a688277446296dd67c8495397b4880ce8610c Mon Sep 17 00:00:00 2001 From: uburuntu Date: Thu, 14 Sep 2017 21:19:09 +0300 Subject: [PATCH 12/27] REF: replace deprecated headers --- double-conversion/bignum-dtoa.cc | 2 +- double-conversion/cached-powers.cc | 6 +++--- double-conversion/double-conversion.cc | 4 ++-- double-conversion/fixed-dtoa.cc | 2 +- double-conversion/strtod.cc | 6 +++--- double-conversion/utils.h | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/double-conversion/bignum-dtoa.cc b/double-conversion/bignum-dtoa.cc index bdb06a29..526f96ed 100644 --- a/double-conversion/bignum-dtoa.cc +++ b/double-conversion/bignum-dtoa.cc @@ -25,7 +25,7 @@ // (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 +#include #include diff --git a/double-conversion/cached-powers.cc b/double-conversion/cached-powers.cc index 780f527b..6f771e9c 100644 --- a/double-conversion/cached-powers.cc +++ b/double-conversion/cached-powers.cc @@ -25,9 +25,9 @@ // (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 -#include -#include +#include +#include +#include #include diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index 7bd7df0e..a65fd4dd 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -25,9 +25,9 @@ // (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 +#include #include -#include +#include #include diff --git a/double-conversion/fixed-dtoa.cc b/double-conversion/fixed-dtoa.cc index 5b6ca5a2..8c111aca 100644 --- a/double-conversion/fixed-dtoa.cc +++ b/double-conversion/fixed-dtoa.cc @@ -25,7 +25,7 @@ // (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 +#include #include #include diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc index 50eacf07..3a59b699 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 -#include +#include +#include -#include #include #include #include +#include namespace double_conversion { diff --git a/double-conversion/utils.h b/double-conversion/utils.h index 2c745f36..04af8754 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -28,10 +28,10 @@ #ifndef DOUBLE_CONVERSION_UTILS_H_ #define DOUBLE_CONVERSION_UTILS_H_ -#include -#include +#include +#include -#include +#include #ifndef ASSERT #define ASSERT(condition) \ assert(condition); From c58352dcb3363df404d8adbf7490124af762c021 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Wed, 6 Dec 2017 17:03:55 +0100 Subject: [PATCH 13/27] Rename macros. Renamed DISALLOW_COPY_AND_ASSIGN and DISALLOW_IMPLICIT_CONSTRUCTORS to DC_DISALLOW_COPY_AND_ASSIGN and DC_DISALLOW_IMPLICIT_CONSTRUCTORS. This makes it easier to use this library in projects that have macros with the same name (as is common in Google). --- Changelog | 6 ++++++ double-conversion/bignum.h | 2 +- double-conversion/double-conversion.h | 4 ++-- double-conversion/ieee.h | 4 ++-- double-conversion/utils.h | 12 ++++++------ 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Changelog b/Changelog index 37ab0a24..33add663 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,9 @@ +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. diff --git a/double-conversion/bignum.h b/double-conversion/bignum.h index 4ff34e26..238a3511 100644 --- a/double-conversion/bignum.h +++ b/double-conversion/bignum.h @@ -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 diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h index 6e3a79bc..9978bdee 100644 --- a/double-conversion/double-conversion.h +++ b/double-conversion/double-conversion.h @@ -374,7 +374,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); }; @@ -538,7 +538,7 @@ class StringToDoubleConverter { bool read_as_double, int* processed_characters_count) const; - DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); + DC_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); }; } // namespace double_conversion diff --git a/double-conversion/ieee.h b/double-conversion/ieee.h index 1b705d2e..baaeced3 100644 --- a/double-conversion/ieee.h +++ b/double-conversion/ieee.h @@ -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 diff --git a/double-conversion/utils.h b/double-conversion/utils.h index 04af8754..d2981edb 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -136,8 +136,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 +148,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 +293,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 From e1aa1279fe303a3c172ba8513b434f76055584f8 Mon Sep 17 00:00:00 2001 From: Guy Kogus Date: Wed, 17 Jan 2018 11:19:55 +0100 Subject: [PATCH 14/27] Fix warning for code that will never be executed (#59) --- double-conversion/strtod.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc index 3a59b699..4392ae6d 100644 --- a/double-conversion/strtod.cc +++ b/double-conversion/strtod.cc @@ -205,7 +205,7 @@ static bool DoubleStrtod(Vector 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 trimmed, } } return false; +#endif } From 1b5fa314800a0e68e2b5d00d17e87a5b1fa3ac5d Mon Sep 17 00:00:00 2001 From: Shane Date: Fri, 2 Mar 2018 01:26:53 -0800 Subject: [PATCH 15/27] Clarify output charset in DoubleToAscii documentation (#61) * Clarify output charset in DoubleToAscii documentation * Fixing typo in charset docs. --- double-conversion/double-conversion.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h index 9978bdee..1ccd7fcd 100644 --- a/double-conversion/double-conversion.h +++ b/double-conversion/double-conversion.h @@ -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(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(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 From 3ad9d2021cb6eadeaa310556e23b7b828ccc3eee Mon Sep 17 00:00:00 2001 From: Tom Jackson Date: Tue, 10 Apr 2018 02:46:55 -0700 Subject: [PATCH 16/27] Processed length should include no trailing junk (#63) --- double-conversion/double-conversion.cc | 4 ++++ test/cctest/test-conversions.cc | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index a65fd4dd..feabe1f2 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -887,9 +887,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_; @@ -901,6 +903,7 @@ double StringToDoubleConverter::StringToIeee( ++current; if (current == end) { if (allow_trailing_junk) { + current = junk_begin; goto parsing_done; } else { return junk_string_value_; @@ -910,6 +913,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_; diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index 6b709edf..aa8ae39a 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -1804,6 +1804,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 | @@ -3184,10 +3196,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"); From 6c1e7143fad7ccf7800b549975578c31d69f94b4 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Fri, 13 Apr 2018 17:52:09 +0200 Subject: [PATCH 17/27] Add `exports_files` The LICENSE file wasn't exported. --- BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILD b/BUILD index d0e01083..6cab2258 100644 --- a/BUILD +++ b/BUILD @@ -2,6 +2,8 @@ licenses(["notice"]) +exports_files(["LICENSE"]) + cc_library( name = "double-conversion", srcs = [ From df50df013e118088abe8605d8bb290589562ac38 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Thu, 19 Apr 2018 14:05:01 +0200 Subject: [PATCH 18/27] Avoid undefined cast to make ASAN happy. --- double-conversion/strtod.cc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc index 4392ae6d..bfdf9241 100644 --- a/double-conversion/strtod.cc +++ b/double-conversion/strtod.cc @@ -483,7 +483,27 @@ float Strtof(Vector buffer, int exponent) { double double_guess; bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); - float float_guess = static_cast(double_guess); + // 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; + float float_guess; + if (double_guess >= max_finite) { + if (double_guess >= half_max_finite_infinity) { + float_guess = Single::Infinity(); + } else { + float_guess = max_finite; + } + } else { + float_guess = static_cast(double_guess); + } if (float_guess == double_guess) { // This shortcut triggers for integer values. return float_guess; From 3ef9576ef2bf1693077a025d4053afc7f0ec73e7 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Fri, 20 Apr 2018 14:50:01 +0200 Subject: [PATCH 19/27] Address comments. --- double-conversion/strtod.cc | 46 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/double-conversion/strtod.cc b/double-conversion/strtod.cc index bfdf9241..e8cc13f2 100644 --- a/double-conversion/strtod.cc +++ b/double-conversion/strtod.cc @@ -472,17 +472,8 @@ double Strtod(Vector buffer, int exponent) { } } -float Strtof(Vector buffer, int exponent) { - char copy_buffer[kMaxSignificantDecimalDigits]; - Vector trimmed; - int updated_exponent; - TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, - &trimmed, &updated_exponent); - exponent = updated_exponent; - - double double_guess; - bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); - +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 @@ -494,16 +485,29 @@ float Strtof(Vector buffer, int exponent) { // this value should become infinity. double half_max_finite_infinity = 3.40282356779733661637539395458142568448e+38; - float float_guess; - if (double_guess >= max_finite) { - if (double_guess >= half_max_finite_infinity) { - float_guess = Single::Infinity(); + if (d >= max_finite) { + if (d >= half_max_finite_infinity) { + return Single::Infinity(); } else { - float_guess = max_finite; + return max_finite; } } else { - float_guess = static_cast(double_guess); + return static_cast(d); } +} + +float Strtof(Vector buffer, int exponent) { + char copy_buffer[kMaxSignificantDecimalDigits]; + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + &trimmed, &updated_exponent); + exponent = updated_exponent; + + double double_guess; + bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); + + float float_guess = SanitizedDoubletof(double_guess); if (float_guess == double_guess) { // This shortcut triggers for integer values. return float_guess; @@ -526,15 +530,15 @@ float Strtof(Vector buffer, int exponent) { double double_next = Double(double_guess).NextDouble(); double double_previous = Double(double_guess).PreviousDouble(); - float f1 = static_cast(double_previous); + float f1 = SanitizedDoubletof(double_previous); float f2 = float_guess; - float f3 = static_cast(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(double_next2); + f4 = SanitizedDoubletof(double_next2); } (void) f2; // Mark variable as used. ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); @@ -549,7 +553,7 @@ float Strtof(Vector 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; From da420c349a482ec5ad2528e9f839377ae001ffd8 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Mon, 7 May 2018 13:57:50 +0200 Subject: [PATCH 20/27] Use `static_assert` with newer compilers. Fixes #66. --- double-conversion/utils.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/double-conversion/utils.h b/double-conversion/utils.h index d2981edb..2bd9ec46 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -92,12 +92,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; @@ -324,8 +318,12 @@ template 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)); From e543cca3e28d4255db4adca096ad1d69104b927e Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Mon, 7 May 2018 14:04:50 +0200 Subject: [PATCH 21/27] Add Native Client as support architecture. Fixes #67. --- double-conversion/utils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/double-conversion/utils.h b/double-conversion/utils.h index d2981edb..cf45534c 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -79,7 +79,8 @@ inline void abort_noreturn() { abort(); } defined(__AARCH64EL__) || defined(__aarch64__) || \ defined(__riscv) #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) From 4e8b3b553c58d6afa78cc212a80c830812431132 Mon Sep 17 00:00:00 2001 From: thomaslmiller <41446875+thomaslmiller@users.noreply.github.com> Date: Thu, 2 Aug 2018 01:32:25 -0700 Subject: [PATCH 22/27] Add support for Windows on ARM and ARM64 (#76) --- double-conversion/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/double-conversion/utils.h b/double-conversion/utils.h index 28bb6942..98a2a11a 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -68,7 +68,7 @@ inline void abort_noreturn() { abort(); } // disabled.) // On Linux,x86 89255e-22 != Div_double(89255.0/1e22) #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__) || \ From 768a445f0c28311bf88685bf0bb990505c12fd4c Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 8 Sep 2018 18:18:15 +0200 Subject: [PATCH 23/27] Add support for aarch64_be, or1k and microblazebe. Fixes #73. --- double-conversion/utils.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/double-conversion/utils.h b/double-conversion/utils.h index 98a2a11a..492bc970 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -76,8 +76,9 @@ 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__) || \ defined(__pnacl__) || defined(__native_client__) From b479bea3c7f69749e1374651c4b35d5eaa7d58ad Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 8 Sep 2018 18:25:13 +0200 Subject: [PATCH 24/27] Add comments for achitecture check. This should make it easier to add new architectures. --- double-conversion/utils.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/double-conversion/utils.h b/double-conversion/utils.h index 492bc970..41c5b02d 100644 --- a/double-conversion/utils.h +++ b/double-conversion/utils.h @@ -67,6 +67,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) +// +// 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__) || \ From aa554d928487a623ec55c7c21f00af09e752b82c Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 8 Sep 2018 23:55:43 +0200 Subject: [PATCH 25/27] Fix bug where hex numbers would lose the minus sign. --- double-conversion/double-conversion.cc | 3 ++- test/cctest/test-conversions.cc | 37 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index feabe1f2..7c8e9c67 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -661,7 +661,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 diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index aa8ae39a..d70624d9 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -2526,6 +2526,43 @@ 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); } From 05a3fead089de46fdd34a87bc108dc29aa0125d0 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sat, 8 Sep 2018 23:54:37 +0200 Subject: [PATCH 26/27] Add support for hexadecimal float literals. Fixes #48. --- double-conversion/double-conversion.cc | 103 +++++++++++++++++-- double-conversion/double-conversion.h | 6 ++ test/cctest/test-conversions.cc | 135 ++++++++++++++++++++++++- 3 files changed, 233 insertions(+), 11 deletions(-) diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index 7c8e9c67..ba83beff 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -537,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. @@ -551,17 +551,57 @@ static bool IsCharacterDigitForRadix(int c, int radix, char a_character) { return radix > 10 && c >= a_character && c < a_character + radix - 10; } +// 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 +static bool IsHexFloatString(Iterator start, + Iterator end, + bool allow_trailing_junk) { + ASSERT(start != end); + + Iterator current = start; + + while (current != end && isDigit(*current, 16)) ++current; + if (current == end) return false; + if (*current == '.') { + ++current; + while (current != end && isDigit(*current, 16)) ++current; + if (current - start == 1) return false; // Only the '.', but no digits. + } + if (current == end) return false; + if (*current != 'p' && *current != 'P') return false; + ++current; + if (current == end) return false; + if (*current == '+' || *current == '-') ++current; + if (current == end) return false; + if (!isDigit(*current, 10)) return false; + ++current; + while (current != end && isDigit(*current, 10)) ++current; + 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 static double RadixStringToIeee(Iterator* current, Iterator end, bool sign, + 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, allow_trailing_junk)); const int kDoubleSize = Double::kSignificandSize; const int kSingleSize = Single::kSignificandSize; @@ -581,15 +621,27 @@ static double RadixStringToIeee(Iterator* current, 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; do { int digit; if (IsDecimalDigitForRadix(**current, radix)) { digit = static_cast(**current) - '0'; + if (post_decimal) exponent -= radix_log_2; } else if (IsCharacterDigitForRadix(**current, radix, 'a')) { digit = static_cast(**current) - 'a' + 10; + if (post_decimal) exponent -= radix_log_2; } else if (IsCharacterDigitForRadix(**current, radix, 'A')) { digit = static_cast(**current) - 'A' + 10; + if (post_decimal) exponent -= radix_log_2; + } else if (parse_as_hex_float && **current == '.') { + post_decimal = true; + ++(*current); + continue; + } else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) { + break; } else { if (allow_trailing_junk || !AdvanceToNonspace(current, end)) { break; @@ -612,17 +664,25 @@ static double RadixStringToIeee(Iterator* current, int dropped_bits_mask = ((1 << overflow_bits_count) - 1); int dropped_bits = static_cast(number) & dropped_bits_mask; number >>= overflow_bits_count; - exponent = overflow_bits_count; + exponent += overflow_bits_count; bool zero_tail = true; for (;;) { ++(*current); + if (parse_as_hex_float && **current == '.') { + // Just run over the '.'. We are just trying to see whether there is + // a non-zero digit somewhere. + ++(*current); + post_decimal = true; + } if (*current == end || !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; } @@ -652,7 +712,26 @@ static double RadixStringToIeee(Iterator* current, *result_is_junk = false; - if (exponent == 0) { + if (parse_as_hex_float) { + ASSERT(**current == 'p' || **current == 'P'); + ++(*current); + bool is_negative = false; + if (**current == '+') { + ++(*current); + } else if (**current == '-') { + is_negative = true; + ++(*current); + } + int written_exponent = 0; + while (*current != end && IsDecimalDigitForRadix(**current, 10)) { + written_exponent = 10 * written_exponent + **current - '0'; + ++(*current); + } + 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; @@ -779,16 +858,23 @@ 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, 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, + parse_as_hex_float, allow_trailing_junk, junk_string_value_, read_as_double, @@ -959,6 +1045,7 @@ double StringToDoubleConverter::StringToIeee( result = RadixStringToIeee<3>(&start, buffer + buffer_pos, sign, + 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 1ccd7fcd..86cf25ea 100644 --- a/double-conversion/double-conversion.h +++ b/double-conversion/double-conversion.h @@ -396,6 +396,7 @@ class StringToDoubleConverter { ALLOW_TRAILING_SPACES = 16, ALLOW_SPACES_AFTER_SIGN = 32, ALLOW_CASE_INSENSIBILITY = 64, + ALLOW_HEX_FLOATS = 128, }; // Flags should be a bit-or combination of the possible Flags-enum. @@ -429,6 +430,11 @@ class StringToDoubleConverter { // 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 diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index d70624d9..cf556e6c 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -2563,6 +2563,91 @@ TEST(StringToDoubleHexString) { 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); } @@ -3789,13 +3874,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; @@ -3892,6 +3994,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; @@ -4014,6 +4130,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 | From 20ecba5eb722b067738ec7e80b7df7a496aaa9f9 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Sun, 9 Sep 2018 02:48:27 +0200 Subject: [PATCH 27/27] Support separator characters. Fixes #49 --- double-conversion/double-conversion.cc | 124 +++++---- double-conversion/double-conversion.h | 23 +- test/cctest/test-conversions.cc | 352 ++++++++++++++++++++++++- 3 files changed, 444 insertions(+), 55 deletions(-) diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc index ba83beff..ecd1a5ef 100644 --- a/double-conversion/double-conversion.cc +++ b/double-conversion/double-conversion.cc @@ -551,6 +551,26 @@ 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 +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. // @@ -561,27 +581,35 @@ static bool IsCharacterDigitForRadix(int c, int radix, char a_character) { template static bool IsHexFloatString(Iterator start, Iterator end, + char separator, bool allow_trailing_junk) { ASSERT(start != end); Iterator current = start; - while (current != end && isDigit(*current, 16)) ++current; - if (current == end) return false; + bool saw_digit = false; + while (isDigit(*current, 16)) { + saw_digit = true; + if (Advance(¤t, separator, 16, end)) return false; + } if (*current == '.') { - ++current; - while (current != end && isDigit(*current, 16)) ++current; - if (current - start == 1) return false; // Only the '.', but no digits. + 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 == end) return false; if (*current != 'p' && *current != 'P') return false; - ++current; - if (current == end) return false; - if (*current == '+' || *current == '-') ++current; - if (current == end) 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; - ++current; - while (current != end && isDigit(*current, 10)) ++current; + 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); } @@ -594,6 +622,7 @@ template static double RadixStringToIeee(Iterator* current, Iterator end, bool sign, + char separator, bool parse_as_hex_float, bool allow_trailing_junk, double junk_string_value, @@ -601,7 +630,7 @@ static double RadixStringToIeee(Iterator* current, bool* result_is_junk) { ASSERT(*current != end); ASSERT(!parse_as_hex_float || - IsHexFloatString(*current, end, allow_trailing_junk)); + IsHexFloatString(*current, end, separator, allow_trailing_junk)); const int kDoubleSize = Double::kSignificandSize; const int kSingleSize = Single::kSignificandSize; @@ -609,15 +638,6 @@ static double RadixStringToIeee(Iterator* current, *result_is_junk = true; - // Skip leading 0s. - while (**current == '0') { - ++(*current); - if (*current == end) { - *result_is_junk = false; - return SignedZero(sign); - } - } - int64_t number = 0; int exponent = 0; const int radix = (1 << radix_log_2); @@ -625,7 +645,15 @@ static double RadixStringToIeee(Iterator* current, // Only relevant if parse_as_hex_float is true. bool post_decimal = false; - do { + // Skip leading 0s. + while (**current == '0') { + if (Advance(current, separator, radix, end)) { + *result_is_junk = false; + return SignedZero(sign); + } + } + + while (true) { int digit; if (IsDecimalDigitForRadix(**current, radix)) { digit = static_cast(**current) - '0'; @@ -638,7 +666,8 @@ static double RadixStringToIeee(Iterator* current, if (post_decimal) exponent -= radix_log_2; } else if (parse_as_hex_float && **current == '.') { post_decimal = true; - ++(*current); + Advance(current, separator, radix, end); + ASSERT(*current != end); continue; } else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) { break; @@ -668,14 +697,15 @@ static double RadixStringToIeee(Iterator* current, bool zero_tail = true; for (;;) { - ++(*current); + 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. - ++(*current); + Advance(current, separator, radix, end); + ASSERT(*current != end); post_decimal = true; } - if (*current == end || !isDigit(**current, radix)) break; + if (!isDigit(**current, radix)) break; zero_tail = zero_tail && **current == '0'; if (!post_decimal) exponent += radix_log_2; } @@ -704,8 +734,8 @@ 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(static_cast(number)) == number); @@ -714,18 +744,21 @@ static double RadixStringToIeee(Iterator* current, if (parse_as_hex_float) { ASSERT(**current == 'p' || **current == 'P'); - ++(*current); + Advance(current, separator, radix, end); + ASSERT(*current != end); bool is_negative = false; if (**current == '+') { - ++(*current); + Advance(current, separator, radix, end); + ASSERT(*current != end); } else if (**current == '-') { is_negative = true; - ++(*current); + Advance(current, separator, radix, end); + ASSERT(*current != end); } int written_exponent = 0; - while (*current != end && IsDecimalDigitForRadix(**current, 10)) { + while (IsDecimalDigitForRadix(**current, 10)) { written_exponent = 10 * written_exponent + **current - '0'; - ++(*current); + if (Advance(current, separator, radix, end)) break; } if (is_negative) written_exponent = -written_exponent; exponent += written_exponent; @@ -761,7 +794,6 @@ double StringToDoubleConverter::StringToIeee( 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: // 1. Each '++current' statement is followed by check for equality to 'end'. @@ -849,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(current - input); return SignedZero(sign); } @@ -863,7 +894,7 @@ double StringToDoubleConverter::StringToIeee( ++current; bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) && - IsHexFloatString(current, end, allow_trailing_junk); + IsHexFloatString(current, end, separator_, allow_trailing_junk); if (current == end) return junk_string_value_; // "0x" if (!parse_as_hex_float && !isDigit(*current, 16)) { @@ -874,6 +905,7 @@ double StringToDoubleConverter::StringToIeee( double result = RadixStringToIeee<4>(¤t, end, sign, + separator_, parse_as_hex_float, allow_trailing_junk, junk_string_value_, @@ -888,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(current - input); return SignedZero(sign); } @@ -910,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) { @@ -922,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 { @@ -936,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(current - input); return SignedZero(sign); } @@ -957,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; } } @@ -1045,6 +1072,7 @@ 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_, diff --git a/double-conversion/double-conversion.h b/double-conversion/double-conversion.h index 86cf25ea..7495d17a 100644 --- a/double-conversion/double-conversion.h +++ b/double-conversion/double-conversion.h @@ -399,6 +399,8 @@ class StringToDoubleConverter { 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. @@ -459,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, @@ -498,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. @@ -542,6 +560,7 @@ class StringToDoubleConverter { const double junk_string_value_; const char* const infinity_symbol_; const char* const nan_symbol_; + const uc16 separator_; template double StringToIeee(Iterator start_pointer, diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index cf556e6c..1173416f 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -1720,9 +1720,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 +1732,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 +1750,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; @@ -3196,6 +3199,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(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(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(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; @@ -3369,6 +3689,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); }