diff --git a/deps/double-conversion/.gitignore b/deps/double-conversion/.gitignore index e8352aeb..e402d079 100644 --- a/deps/double-conversion/.gitignore +++ b/deps/double-conversion/.gitignore @@ -1,4 +1,5 @@ .sconsign.dblite +*~ *.o *.obj msvc/Release/ @@ -7,3 +8,24 @@ msvc/Debug/ *.opensdf *.sdf *.user +*.a +*.so +*.so.* +*.dylib +/run_tests +Makefile +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +*.cmake +*.kdev4 +DartConfiguration.tcl +bazel-* +.cache diff --git a/deps/double-conversion/AUTHORS b/deps/double-conversion/AUTHORS index 88b38ae0..4edeeedc 100644 --- a/deps/double-conversion/AUTHORS +++ b/deps/double-conversion/AUTHORS @@ -12,3 +12,5 @@ Mike Hommey Martin Olsson Kent Williams Elan Ruusamäe +Colin Hirsch +Zhenyi Peng diff --git a/deps/double-conversion/BUILD b/deps/double-conversion/BUILD index ab0e3318..8c2eee56 100644 --- a/deps/double-conversion/BUILD +++ b/deps/double-conversion/BUILD @@ -1,19 +1,22 @@ -# Bazel (https://bazel.build/) BUILD file +# Bazel(http://bazel.io) BUILD file + +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") licenses(["notice"]) +exports_files(["LICENSE"]) + cc_library( name = "double-conversion", srcs = [ "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/double-to-string.cc", "double-conversion/fast-dtoa.cc", "double-conversion/fixed-dtoa.cc", + "double-conversion/string-to-double.cc", "double-conversion/strtod.cc", - "double-conversion/utils.h", ], hdrs = [ "double-conversion/bignum.h", @@ -21,10 +24,13 @@ cc_library( "double-conversion/cached-powers.h", "double-conversion/diy-fp.h", "double-conversion/double-conversion.h", + "double-conversion/double-to-string.h", "double-conversion/fast-dtoa.h", "double-conversion/fixed-dtoa.h", "double-conversion/ieee.h", + "double-conversion/string-to-double.h", "double-conversion/strtod.h", + "double-conversion/utils.h", ], linkopts = [ "-lm", diff --git a/deps/double-conversion/CMakeLists.txt b/deps/double-conversion/CMakeLists.txt index 01196ba6..3f0c62cf 100644 --- a/deps/double-conversion/CMakeLists.txt +++ b/deps/double-conversion/CMakeLists.txt @@ -1,27 +1,42 @@ -cmake_minimum_required(VERSION 2.8.12) -project(double-conversion) +cmake_minimum_required(VERSION 3.0) +project(double-conversion VERSION 3.2.0) -include(GNUInstallDirs) +option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" OFF) -# pick a version # -set(double-conversion_VERSION 2.0.1) -set(double-conversion_SOVERSION_MAJOR 1) -set(double-conversion_SOVERSION_MINOR 0) -set(double-conversion_SOVERSION_PATCH 0) -set(double-conversion_SOVERSION - ${double-conversion_SOVERSION_MAJOR}.${double-conversion_SOVERSION_MINOR}.${double-conversion_SOVERSION_PATCH}) - -# set suffix for CMake files used for packaging -if(WIN32 AND NOT CYGWIN) - set(INSTALL_CMAKE_DIR CMake) -else() - set(INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/double-conversion) +if(BUILD_SHARED_LIBS AND MSVC) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() -# Add src subdirectory -add_subdirectory(double-conversion) +set(headers + double-conversion/bignum.h + double-conversion/cached-powers.h + double-conversion/diy-fp.h + double-conversion/double-conversion.h + double-conversion/double-to-string.h + double-conversion/fast-dtoa.h + double-conversion/fixed-dtoa.h + double-conversion/ieee.h + double-conversion/string-to-double.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/double-to-string.cc + double-conversion/fast-dtoa.cc + double-conversion/fixed-dtoa.cc + double-conversion/string-to-double.cc + double-conversion/strtod.cc + ${headers}) +target_include_directories( + double-conversion PUBLIC + $) + +# pick a version # +set_target_properties(double-conversion PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 3) -# # set up testing if requested option(BUILD_TESTING "Build test programs" OFF) if(BUILD_TESTING) @@ -30,41 +45,85 @@ 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) - -# -# 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) - -# -# 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) - - -# -# generates install cmake files to find libraries in installation. -install(EXPORT double-conversionLibraryDepends DESTINATION - "${INSTALL_CMAKE_DIR}" COMPONENT dev) +#### +# Installation (https://github.com/forexample/package-example) + +include(GNUInstallDirs) + +# Layout. This works for all platforms: +# * /lib/cmake/ +# * /lib/ +# * /include/ +set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + +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 'ConfigVersion.cmake' +# Note: PROJECT_VERSION is used as a VERSION +write_basic_package_version_file( + "${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 "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +# Headers: +# * double-conversion/*.h -> /include/double-conversion/*.h +install( + FILES ${headers} + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/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}" +) + +# Config +# * /lib/cmake/double-conversion/double-conversionTargets.cmake +install( + EXPORT "${targets_export_name}" + NAMESPACE "${namespace}" + DESTINATION "${config_install_dir}" +) + +if (MSVC AND BUILD_SHARED_LIBS) + # Install companion PDB for Visual Studio + install( + FILES $ + TYPE BIN + OPTIONAL + ) +endif() diff --git a/deps/double-conversion/Changelog b/deps/double-conversion/Changelog index 98247e72..553fa845 100644 --- a/deps/double-conversion/Changelog +++ b/deps/double-conversion/Changelog @@ -1,3 +1,127 @@ +2022-01-16: + Install Visual Studio debugger (pdb) files. + +2022-01-10: + Fix quiet NANs on MIPS* and PA-RISC architectures. + Update version number. + +2021-12-22: + Add support of Synopsys ARC64 architecture. + Reintroduce macros, if DOUBLE_CONVERSION_NON_PREFIXED_MACROS is set. + +2021-12-04: + Update version number. + +2021-10-04: + Consistently use semicolons after DOUBLE_CONVERSION_ASSERT. + +2021-07-16: + Fix spelling. + +2021-05-19: + Loongarch is a RISC-style command system architecture. + Add support for loongarch architecture. + +2020-02-16: + Add support for quiet and signaling NaNs to ieee header. + +2019-10-31: + Add support for xtensa architecture. + Add support for nios2 architecture. + +2019-10-12: + Really add support for microblaze. A previous commit was lacking + the necessary line. + +2019-09-02: + Add support for e2k architecture. Thanks to Michael Shigorin. + +2019-08-01: + Add min exponent width option in double-to-string conversion. + +2019-06-22: + Remove redundant parenthesis. + +2019-06-11: + Changed all macros to use DOUBLE_CONVERSION_ as prefix. + Renamed ALLOW_CASE_INSENSIBILITY to ALLOW_CASE_INSENSITIVITY, + the old name is still available but officially deprecated. + Created and exposed new intermediate function StrtodTrimmed(). + +2019-05-25: + Fix `0x` for string->double conversion when Hex Floats are allowed. + Avoid integer overflow when exponents for hex floats were too big. + Update version number. + +2019-04-22: + Fixed warning in gcc4.9. Thanks to Scott McCaskill + (https://github.com/usefulcat) for the patch. + +2019-04-16: + Merged changes to install libraries in the correct place when + using 64-bit libraries. + Contributed by Jason Zaman and (independently) + Dan Church (https://github.com/h3xx) + +2019-03-11: + Use relative includes in the library. This shouldn't have any visible effect + for consumers of the library. + + Update version number. + +2019-03-06: + Fix typo in test. + Update version number. + +2019-03-03: + Fix separator characters when they they don't fit into 8 bits. + Update version number. + +2019-02-16: + Check correctly for _MSC_VER. + Patch by Ben Boeckel + +2019-01-17: + Allow the library to be compiled for Emscripten. + Patch by Tim Paine. + +2018-09-15: + Update version numbers. This also updates the shared-library version number. + +2018-09-09: + Fix bug where large hex literals would lose their minus sign. + Added support for separator characters (which adds a new optional + argument). Thus increasing the version number to 3.1.0 + Added support for hexadecimal float literals. + Support for more architectures. + +2017-12-06: + Renamed `DISALLOW_COPY_AND_ASSIGN` and `DISALLOW_IMPLICIT_CONSTRUCTORS` + macros to `DC_DISALLOW_COPY_AND_ASSIGN` and + `DC_DISALLOW_IMPLICIT_CONSTRUCTORS` to make it easier to integrate the + library with other libraries that have similar macros. + +2017-08-05: + Tagged v3.0.0. + Due to the directory rename switching to a new version number. + The API for the library itself hasn't changed. + +2017-03-04: + Avoid negative shift. Fixes #41. + +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'. diff --git a/deps/double-conversion/Makefile b/deps/double-conversion/Makefile index 4e7e104a..873f4b95 100644 --- a/deps/double-conversion/Makefile +++ b/deps/double-conversion/Makefile @@ -2,6 +2,6 @@ all: scons debug=1 test: - ./run_tests --list | tr -d '<' | xargs ./run_tests + ./run_tests .PHONY: test all diff --git a/deps/double-conversion/README.md b/deps/double-conversion/README.md index 1660179b..e5d9a4e6 100644 --- a/deps/double-conversion/README.md +++ b/deps/double-conversion/README.md @@ -7,8 +7,9 @@ The library consists of efficient conversion routines that have been extracted from the V8 JavaScript engine. The code has been refactored and improved so that it can be used more easily in other projects. -There is extensive documentation in `double-conversion/double-conversion.h`. Other -examples can be found in `test/cctest/test-conversions.cc`. +There is extensive documentation in `double-conversion/string-to-double.h` and +`double-conversion/double-to-string.h`. Other examples can be found in +`test/cctest/test-conversions.cc`. Building @@ -48,7 +49,7 @@ Use `-DBUILD_TESTING=ON` to build the test executable. cmake . -DBUILD_TESTING=ON make - test/cctest/cctest --list | tr -d '<' | xargs test/cctest/cctest + test/cctest/cctest [0]: http://www.scons.org/ [1]: https://cmake.org/ diff --git a/deps/double-conversion/SConstruct b/deps/double-conversion/SConstruct index cff18b4c..cebd7e0a 100644 --- a/deps/double-conversion/SConstruct +++ b/deps/double-conversion/SConstruct @@ -16,13 +16,13 @@ optimize = ARGUMENTS.get('optimize', 0) env.Replace(CXX = ARGUMENTS.get('CXX', 'g++')) # for shared lib, requires scons 2.3.0 -env['SHLIBVERSION'] = '1.0.0' +env['SHLIBVERSION'] = '3.0.0' CCFLAGS = [] if int(debug): - CCFLAGS.append(ARGUMENTS.get('CXXFLAGS', '-g -Wall -Wshadow -Werror')) + CCFLAGS.append(ARGUMENTS.get('CXXFLAGS', '-g -Wall -Wshadow -Werror -UNDEBUG')) if int(optimize): - CCFLAGS.append(ARGUMENTS.get('CXXFLAGS', '-O3')) + CCFLAGS.append(ARGUMENTS.get('CXXFLAGS', '-O3 -DNDEBUG=1')) env.Append(CCFLAGS = " ".join(CCFLAGS)) diff --git a/deps/double-conversion/WORKSPACE b/deps/double-conversion/WORKSPACE index 95d8c770..52106e75 100644 --- a/deps/double-conversion/WORKSPACE +++ b/deps/double-conversion/WORKSPACE @@ -1 +1 @@ -# Bazel (https://bazel.build/) WORKSPACE file for double-conversion. +# Bazel (http://bazel.io/) WORKSPACE file for double-conversion. diff --git a/deps/double-conversion/cmake/Config.cmake.in b/deps/double-conversion/cmake/Config.cmake.in new file mode 100644 index 00000000..9b4c9ee0 --- /dev/null +++ b/deps/double-conversion/cmake/Config.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/deps/double-conversion/double-conversion/.gitignore b/deps/double-conversion/double-conversion/.gitignore new file mode 100644 index 00000000..1edeb79f --- /dev/null +++ b/deps/double-conversion/double-conversion/.gitignore @@ -0,0 +1 @@ +*.os diff --git a/deps/double-conversion/double-conversion/CMakeLists.txt b/deps/double-conversion/double-conversion/CMakeLists.txt deleted file mode 100644 index 2d13b36a..00000000 --- a/deps/double-conversion/double-conversion/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -set(headers - bignum.h - cached-powers.h - diy-fp.h - double-conversion.h - fast-dtoa.h - fixed-dtoa.h - ieee.h - strtod.h - utils.h - ) - -add_library(double-conversion -bignum.cc -bignum-dtoa.cc -cached-powers.cc -diy-fp.cc -double-conversion.cc -fast-dtoa.cc -fixed-dtoa.cc -strtod.cc -${headers} -) - -target_include_directories(double-conversion PUBLIC $) - -# Add fPIC on x86_64 when supported. -include(CheckCXXCompilerFlag) -check_cxx_compiler_flag(-fPIC CXX_HAS_FPIC) - -if(CXX_HAS_FPIC AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set_target_properties(double-conversion PROPERTIES COMPILE_FLAGS "-fPIC") -endif() - -# -# associates the list of headers with the library -# for the purposes of installation/import into other projects -set_target_properties(double-conversion - PROPERTIES PUBLIC_HEADER "${headers}") - -if (BUILD_SHARED_LIBS) - set_target_properties(double-conversion - PROPERTIES VERSION ${double-conversion_SOVERSION} - SOVERSION ${double-conversion_SOVERSION_MAJOR}) -endif() - -# -# install command to set up library install -# given the above PUBLIC_HEADER property set, this -# pulls along all the header files with the library. -install(TARGETS double-conversion - EXPORT double-conversionLibraryDepends - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT bin - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT shlib - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib - PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/double-conversion" - COMPONENT dev) diff --git a/deps/double-conversion/double-conversion/SConscript b/deps/double-conversion/double-conversion/SConscript index a117c32b..d7ae3d78 100644 --- a/deps/double-conversion/double-conversion/SConscript +++ b/deps/double-conversion/double-conversion/SConscript @@ -3,10 +3,10 @@ double_conversion_sources = [ 'bignum.cc', 'bignum-dtoa.cc', 'cached-powers.cc', - 'diy-fp.cc', - 'double-conversion.cc', + 'double-to-string.cc', 'fast-dtoa.cc', 'fixed-dtoa.cc', + 'string-to-double.cc', 'strtod.cc' ] Return('double_conversion_sources') diff --git a/deps/double-conversion/double-conversion/bignum-dtoa.cc b/deps/double-conversion/double-conversion/bignum-dtoa.cc index f1ad7a5a..15123e6a 100644 --- a/deps/double-conversion/double-conversion/bignum-dtoa.cc +++ b/deps/double-conversion/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 "bignum-dtoa.h" @@ -35,7 +35,7 @@ namespace double_conversion { static int NormalizedExponent(uint64_t significand, int exponent) { - ASSERT(significand != 0); + DOUBLE_CONVERSION_ASSERT(significand != 0); while ((significand & Double::kHiddenBit) == 0) { significand = significand << 1; exponent = exponent - 1; @@ -76,26 +76,26 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, // Generates 'requested_digits' after the decimal point. static void BignumToFixed(int requested_digits, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length); + Vector buffer, int* length); // Generates 'count' digits of numerator/denominator. // Once 'count' digits have been produced rounds the result depending on the // remainder (remainders of exactly .5 round upwards). Might update the // decimal_point when rounding up (for example for 0.9999). static void GenerateCountedDigits(int count, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length); + Vector buffer, int* length); void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, Vector buffer, int* length, int* decimal_point) { - ASSERT(v > 0); - ASSERT(!Double(v).IsSpecial()); + DOUBLE_CONVERSION_ASSERT(v > 0); + DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial()); uint64_t significand; int exponent; bool lower_boundary_is_closer; if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) { float f = static_cast(v); - ASSERT(f == v); + DOUBLE_CONVERSION_ASSERT(f == v); significand = Single(f).Significand(); exponent = Single(f).Exponent(); lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser(); @@ -134,7 +134,7 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, // 4e-324. In this case the denominator needs fewer than 324*4 binary digits. // The maximum double is 1.7976931348623157e308 which needs fewer than // 308*4 binary digits. - ASSERT(Bignum::kMaxSignificantBits >= 324*4); + DOUBLE_CONVERSION_ASSERT(Bignum::kMaxSignificantBits >= 324*4); InitialScaledStartValues(significand, exponent, lower_boundary_is_closer, estimated_power, need_boundary_deltas, &numerator, &denominator, @@ -163,7 +163,7 @@ void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, buffer, length); break; default: - UNREACHABLE(); + DOUBLE_CONVERSION_UNREACHABLE(); } buffer[*length] = '\0'; } @@ -195,7 +195,7 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, for (;;) { uint16_t digit; digit = numerator->DivideModuloIntBignum(*denominator); - ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive. + DOUBLE_CONVERSION_ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive. // digit = numerator / denominator (integer division). // numerator = numerator % denominator. buffer[(*length)++] = static_cast(digit + '0'); @@ -241,7 +241,7 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, // loop would have stopped earlier. // We still have an assert here in case the preconditions were not // satisfied. - ASSERT(buffer[(*length) - 1] != '9'); + DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9'); buffer[(*length) - 1]++; } else { // Halfway case. @@ -252,7 +252,7 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, if ((buffer[(*length) - 1] - '0') % 2 == 0) { // Round down => Do nothing. } else { - ASSERT(buffer[(*length) - 1] != '9'); + DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9'); buffer[(*length) - 1]++; } } @@ -264,9 +264,9 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, // Round up. // Note again that the last digit could not be '9' since this would have // stopped the loop earlier. - // We still have an ASSERT here, in case the preconditions were not + // We still have an DOUBLE_CONVERSION_ASSERT here, in case the preconditions were not // satisfied. - ASSERT(buffer[(*length) -1] != '9'); + DOUBLE_CONVERSION_ASSERT(buffer[(*length) -1] != '9'); buffer[(*length) - 1]++; return; } @@ -276,18 +276,18 @@ static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, // Let v = numerator / denominator < 10. // Then we generate 'count' digits of d = x.xxxxx... (without the decimal point) -// from left to right. Once 'count' digits have been produced we decide wether +// from left to right. Once 'count' digits have been produced we decide whether // to round up or down. Remainders of exactly .5 round upwards. Numbers such // as 9.999999 propagate a carry all the way, and change the // exponent (decimal_point), when rounding upwards. static void GenerateCountedDigits(int count, int* decimal_point, Bignum* numerator, Bignum* denominator, Vector buffer, int* length) { - ASSERT(count >= 0); + DOUBLE_CONVERSION_ASSERT(count >= 0); for (int i = 0; i < count - 1; ++i) { uint16_t digit; digit = numerator->DivideModuloIntBignum(*denominator); - ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive. + DOUBLE_CONVERSION_ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive. // digit = numerator / denominator (integer division). // numerator = numerator % denominator. buffer[i] = static_cast(digit + '0'); @@ -300,7 +300,7 @@ static void GenerateCountedDigits(int count, int* decimal_point, if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { digit++; } - ASSERT(digit <= 10); + DOUBLE_CONVERSION_ASSERT(digit <= 10); buffer[count - 1] = static_cast(digit + '0'); // Correct bad digits (in case we had a sequence of '9's). Propagate the // carry until we hat a non-'9' or til we reach the first digit. @@ -325,7 +325,7 @@ static void GenerateCountedDigits(int count, int* decimal_point, // Input verifies: 1 <= (numerator + delta) / denominator < 10. static void BignumToFixed(int requested_digits, int* decimal_point, Bignum* numerator, Bignum* denominator, - Vector(buffer), int* length) { + Vector buffer, int* length) { // Note that we have to look at more than just the requested_digits, since // a number could be rounded up. Example: v=0.5 with requested_digits=0. // Even though the power of v equals 0 we can't just stop here. @@ -341,7 +341,7 @@ static void BignumToFixed(int requested_digits, int* decimal_point, } else if (-(*decimal_point) == requested_digits) { // We only need to verify if the number rounds down or up. // Ex: 0.04 and 0.06 with requested_digits == 1. - ASSERT(*decimal_point == -requested_digits); + DOUBLE_CONVERSION_ASSERT(*decimal_point == -requested_digits); // Initially the fraction lies in range (1, 10]. Multiply the denominator // by 10 so that we can compare more easily. denominator->Times10(); @@ -370,7 +370,7 @@ static void BignumToFixed(int requested_digits, int* decimal_point, // Returns an estimation of k such that 10^(k-1) <= v < 10^k where // v = f * 2^exponent and 2^52 <= f < 2^53. // v is hence a normalized double with the given exponent. The output is an -// approximation for the exponent of the decimal approimation .digits * 10^k. +// approximation for the exponent of the decimal approximation .digits * 10^k. // // The result might undershoot by 1 in which case 10^k <= v < 10^k+1. // Note: this property holds for v's upper boundary m+ too. @@ -420,7 +420,7 @@ static void InitialScaledStartValuesPositiveExponent( Bignum* numerator, Bignum* denominator, Bignum* delta_minus, Bignum* delta_plus) { // A positive exponent implies a positive power. - ASSERT(estimated_power >= 0); + DOUBLE_CONVERSION_ASSERT(estimated_power >= 0); // Since the estimated_power is positive we simply multiply the denominator // by 10^estimated_power. @@ -506,7 +506,7 @@ static void InitialScaledStartValuesNegativeExponentNegativePower( // numerator = v * 10^-estimated_power * 2 * 2^-exponent. // Remember: numerator has been abused as power_ten. So no need to assign it // to itself. - ASSERT(numerator == power_ten); + DOUBLE_CONVERSION_ASSERT(numerator == power_ten); numerator->MultiplyByUInt64(significand); // denominator = 2 * 2^-exponent with exponent < 0. @@ -548,7 +548,7 @@ static void InitialScaledStartValuesNegativeExponentNegativePower( // // Let ep == estimated_power, then the returned values will satisfy: // v / 10^ep = numerator / denominator. -// v's boundarys m- and m+: +// v's boundaries m- and m+: // m- / 10^ep == v / 10^ep - delta_minus / denominator // m+ / 10^ep == v / 10^ep + delta_plus / denominator // Or in other words: diff --git a/deps/double-conversion/double-conversion/bignum.cc b/deps/double-conversion/double-conversion/bignum.cc index 8892de8f..d6745d75 100644 --- a/deps/double-conversion/double-conversion/bignum.cc +++ b/deps/double-conversion/double-conversion/bignum.cc @@ -25,141 +25,138 @@ // (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 "bignum.h" #include "utils.h" namespace double_conversion { -Bignum::Bignum() - : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) { - for (int i = 0; i < kBigitCapacity; ++i) { - bigits_[i] = 0; - } +Bignum::Chunk& Bignum::RawBigit(const int index) { + DOUBLE_CONVERSION_ASSERT(static_cast(index) < kBigitCapacity); + return bigits_buffer_[index]; +} + + +const Bignum::Chunk& Bignum::RawBigit(const int index) const { + DOUBLE_CONVERSION_ASSERT(static_cast(index) < kBigitCapacity); + return bigits_buffer_[index]; } template -static int BitSize(S value) { +static int BitSize(const S value) { (void) value; // Mark variable as used. return 8 * sizeof(value); } // Guaranteed to lie in one Bigit. -void Bignum::AssignUInt16(uint16_t value) { - ASSERT(kBigitSize >= BitSize(value)); +void Bignum::AssignUInt16(const uint16_t value) { + DOUBLE_CONVERSION_ASSERT(kBigitSize >= BitSize(value)); Zero(); - if (value == 0) return; - - EnsureCapacity(1); - bigits_[0] = value; - used_digits_ = 1; + if (value > 0) { + RawBigit(0) = value; + used_bigits_ = 1; + } } void Bignum::AssignUInt64(uint64_t value) { - const int kUInt64Size = 64; - Zero(); - if (value == 0) return; - - int needed_bigits = kUInt64Size / kBigitSize + 1; - EnsureCapacity(needed_bigits); - for (int i = 0; i < needed_bigits; ++i) { - bigits_[i] = value & kBigitMask; - value = value >> kBigitSize; + for(int i = 0; value > 0; ++i) { + RawBigit(i) = value & kBigitMask; + value >>= kBigitSize; + ++used_bigits_; } - used_digits_ = needed_bigits; - Clamp(); } void Bignum::AssignBignum(const Bignum& other) { exponent_ = other.exponent_; - for (int i = 0; i < other.used_digits_; ++i) { - bigits_[i] = other.bigits_[i]; + for (int i = 0; i < other.used_bigits_; ++i) { + RawBigit(i) = other.RawBigit(i); } - // Clear the excess digits (if there were any). - for (int i = other.used_digits_; i < used_digits_; ++i) { - bigits_[i] = 0; - } - used_digits_ = other.used_digits_; + used_bigits_ = other.used_bigits_; } -static uint64_t ReadUInt64(Vector buffer, - int from, - int digits_to_read) { +static uint64_t ReadUInt64(const Vector buffer, + const int from, + const int digits_to_read) { uint64_t result = 0; for (int i = from; i < from + digits_to_read; ++i) { - int digit = buffer[i] - '0'; - ASSERT(0 <= digit && digit <= 9); + const int digit = buffer[i] - '0'; + DOUBLE_CONVERSION_ASSERT(0 <= digit && digit <= 9); result = result * 10 + digit; } return result; } -void Bignum::AssignDecimalString(Vector value) { +void Bignum::AssignDecimalString(const Vector value) { // 2^64 = 18446744073709551616 > 10^19 - const int kMaxUint64DecimalDigits = 19; + static const int kMaxUint64DecimalDigits = 19; Zero(); int length = value.length(); - unsigned int pos = 0; + unsigned pos = 0; // Let's just say that each digit needs 4 bits. while (length >= kMaxUint64DecimalDigits) { - uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits); + const uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits); pos += kMaxUint64DecimalDigits; length -= kMaxUint64DecimalDigits; MultiplyByPowerOfTen(kMaxUint64DecimalDigits); AddUInt64(digits); } - uint64_t digits = ReadUInt64(value, pos, length); + const uint64_t digits = ReadUInt64(value, pos, length); MultiplyByPowerOfTen(length); AddUInt64(digits); Clamp(); } -static int HexCharValue(char c) { - if ('0' <= c && c <= '9') return c - '0'; - if ('a' <= c && c <= 'f') return 10 + c - 'a'; - ASSERT('A' <= c && c <= 'F'); +static uint64_t HexCharValue(const int c) { + if ('0' <= c && c <= '9') { + return c - '0'; + } + if ('a' <= c && c <= 'f') { + return 10 + c - 'a'; + } + DOUBLE_CONVERSION_ASSERT('A' <= c && c <= 'F'); return 10 + c - 'A'; } +// Unlike AssignDecimalString(), this function is "only" used +// for unit-tests and therefore not performance critical. void Bignum::AssignHexString(Vector value) { Zero(); - int length = value.length(); - - int needed_bigits = length * 4 / kBigitSize + 1; - EnsureCapacity(needed_bigits); - int string_index = length - 1; - for (int i = 0; i < needed_bigits - 1; ++i) { - // These bigits are guaranteed to be "full". - Chunk current_bigit = 0; - for (int j = 0; j < kBigitSize / 4; j++) { - current_bigit += HexCharValue(value[string_index--]) << (j * 4); + // Required capacity could be reduced by ignoring leading zeros. + EnsureCapacity(((value.length() * 4) + kBigitSize - 1) / kBigitSize); + DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >= kBigitSize + 4); // TODO: static_assert + // Accumulates converted hex digits until at least kBigitSize bits. + // Works with non-factor-of-four kBigitSizes. + uint64_t tmp = 0; + for (int cnt = 0; !value.is_empty(); value.pop_back()) { + tmp |= (HexCharValue(value.last()) << cnt); + if ((cnt += 4) >= kBigitSize) { + RawBigit(used_bigits_++) = (tmp & kBigitMask); + cnt -= kBigitSize; + tmp >>= kBigitSize; } - bigits_[i] = current_bigit; - } - used_digits_ = needed_bigits - 1; - - Chunk most_significant_bigit = 0; // Could be = 0; - for (int j = 0; j <= string_index; ++j) { - most_significant_bigit <<= 4; - most_significant_bigit += HexCharValue(value[j]); } - if (most_significant_bigit != 0) { - bigits_[used_digits_] = most_significant_bigit; - used_digits_++; + if (tmp > 0) { + DOUBLE_CONVERSION_ASSERT(tmp <= kBigitMask); + RawBigit(used_bigits_++) = (tmp & kBigitMask); } Clamp(); } -void Bignum::AddUInt64(uint64_t operand) { - if (operand == 0) return; +void Bignum::AddUInt64(const uint64_t operand) { + if (operand == 0) { + return; + } Bignum other; other.AssignUInt64(operand); AddBignum(other); @@ -167,8 +164,8 @@ void Bignum::AddUInt64(uint64_t operand) { void Bignum::AddBignum(const Bignum& other) { - ASSERT(IsClamped()); - ASSERT(other.IsClamped()); + DOUBLE_CONVERSION_ASSERT(IsClamped()); + DOUBLE_CONVERSION_ASSERT(other.IsClamped()); // If this has a greater exponent than other append zero-bigits to this. // After this call exponent_ <= other.exponent_. @@ -186,48 +183,52 @@ void Bignum::AddBignum(const Bignum& other) { // cccccccccccc 0000 // In both cases we might need a carry bigit. - EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_); + EnsureCapacity(1 + (std::max)(BigitLength(), other.BigitLength()) - exponent_); Chunk carry = 0; int bigit_pos = other.exponent_ - exponent_; - ASSERT(bigit_pos >= 0); - for (int i = 0; i < other.used_digits_; ++i) { - Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry; - bigits_[bigit_pos] = sum & kBigitMask; + DOUBLE_CONVERSION_ASSERT(bigit_pos >= 0); + for (int i = used_bigits_; i < bigit_pos; ++i) { + RawBigit(i) = 0; + } + for (int i = 0; i < other.used_bigits_; ++i) { + const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0; + const Chunk sum = my + other.RawBigit(i) + carry; + RawBigit(bigit_pos) = sum & kBigitMask; carry = sum >> kBigitSize; - bigit_pos++; + ++bigit_pos; } - while (carry != 0) { - Chunk sum = bigits_[bigit_pos] + carry; - bigits_[bigit_pos] = sum & kBigitMask; + const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0; + const Chunk sum = my + carry; + RawBigit(bigit_pos) = sum & kBigitMask; carry = sum >> kBigitSize; - bigit_pos++; + ++bigit_pos; } - used_digits_ = Max(bigit_pos, used_digits_); - ASSERT(IsClamped()); + used_bigits_ = (std::max)(bigit_pos, static_cast(used_bigits_)); + DOUBLE_CONVERSION_ASSERT(IsClamped()); } void Bignum::SubtractBignum(const Bignum& other) { - ASSERT(IsClamped()); - ASSERT(other.IsClamped()); + DOUBLE_CONVERSION_ASSERT(IsClamped()); + DOUBLE_CONVERSION_ASSERT(other.IsClamped()); // We require this to be bigger than other. - ASSERT(LessEqual(other, *this)); + DOUBLE_CONVERSION_ASSERT(LessEqual(other, *this)); Align(other); - int offset = other.exponent_ - exponent_; + const int offset = other.exponent_ - exponent_; Chunk borrow = 0; int i; - for (i = 0; i < other.used_digits_; ++i) { - ASSERT((borrow == 0) || (borrow == 1)); - Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow; - bigits_[i + offset] = difference & kBigitMask; + for (i = 0; i < other.used_bigits_; ++i) { + DOUBLE_CONVERSION_ASSERT((borrow == 0) || (borrow == 1)); + const Chunk difference = RawBigit(i + offset) - other.RawBigit(i) - borrow; + RawBigit(i + offset) = difference & kBigitMask; borrow = difference >> (kChunkSize - 1); } while (borrow != 0) { - Chunk difference = bigits_[i + offset] - borrow; - bigits_[i + offset] = difference & kBigitMask; + const Chunk difference = RawBigit(i + offset) - borrow; + RawBigit(i + offset) = difference & kBigitMask; borrow = difference >> (kChunkSize - 1); ++i; } @@ -235,91 +236,105 @@ void Bignum::SubtractBignum(const Bignum& other) { } -void Bignum::ShiftLeft(int shift_amount) { - if (used_digits_ == 0) return; - exponent_ += shift_amount / kBigitSize; - int local_shift = shift_amount % kBigitSize; - EnsureCapacity(used_digits_ + 1); +void Bignum::ShiftLeft(const int shift_amount) { + if (used_bigits_ == 0) { + return; + } + exponent_ += (shift_amount / kBigitSize); + const int local_shift = shift_amount % kBigitSize; + EnsureCapacity(used_bigits_ + 1); BigitsShiftLeft(local_shift); } -void Bignum::MultiplyByUInt32(uint32_t factor) { - if (factor == 1) return; +void Bignum::MultiplyByUInt32(const uint32_t factor) { + if (factor == 1) { + return; + } if (factor == 0) { Zero(); return; } - if (used_digits_ == 0) return; - + if (used_bigits_ == 0) { + return; + } // The product of a bigit with the factor is of size kBigitSize + 32. // Assert that this number + 1 (for the carry) fits into double chunk. - ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1); + DOUBLE_CONVERSION_ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1); DoubleChunk carry = 0; - for (int i = 0; i < used_digits_; ++i) { - DoubleChunk product = static_cast(factor) * bigits_[i] + carry; - bigits_[i] = static_cast(product & kBigitMask); + for (int i = 0; i < used_bigits_; ++i) { + const DoubleChunk product = static_cast(factor) * RawBigit(i) + carry; + RawBigit(i) = static_cast(product & kBigitMask); carry = (product >> kBigitSize); } while (carry != 0) { - EnsureCapacity(used_digits_ + 1); - bigits_[used_digits_] = carry & kBigitMask; - used_digits_++; + EnsureCapacity(used_bigits_ + 1); + RawBigit(used_bigits_) = carry & kBigitMask; + used_bigits_++; carry >>= kBigitSize; } } -void Bignum::MultiplyByUInt64(uint64_t factor) { - if (factor == 1) return; +void Bignum::MultiplyByUInt64(const uint64_t factor) { + if (factor == 1) { + return; + } if (factor == 0) { Zero(); return; } - ASSERT(kBigitSize < 32); + if (used_bigits_ == 0) { + return; + } + DOUBLE_CONVERSION_ASSERT(kBigitSize < 32); uint64_t carry = 0; - uint64_t low = factor & 0xFFFFFFFF; - uint64_t high = factor >> 32; - for (int i = 0; i < used_digits_; ++i) { - uint64_t product_low = low * bigits_[i]; - uint64_t product_high = high * bigits_[i]; - uint64_t tmp = (carry & kBigitMask) + product_low; - bigits_[i] = tmp & kBigitMask; + const uint64_t low = factor & 0xFFFFFFFF; + const uint64_t high = factor >> 32; + for (int i = 0; i < used_bigits_; ++i) { + const uint64_t product_low = low * RawBigit(i); + const uint64_t product_high = high * RawBigit(i); + const uint64_t tmp = (carry & kBigitMask) + product_low; + RawBigit(i) = tmp & kBigitMask; carry = (carry >> kBigitSize) + (tmp >> kBigitSize) + (product_high << (32 - kBigitSize)); } while (carry != 0) { - EnsureCapacity(used_digits_ + 1); - bigits_[used_digits_] = carry & kBigitMask; - used_digits_++; + EnsureCapacity(used_bigits_ + 1); + RawBigit(used_bigits_) = carry & kBigitMask; + used_bigits_++; carry >>= kBigitSize; } } -void Bignum::MultiplyByPowerOfTen(int exponent) { - const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d); - const uint16_t kFive1 = 5; - const uint16_t kFive2 = kFive1 * 5; - const uint16_t kFive3 = kFive2 * 5; - const uint16_t kFive4 = kFive3 * 5; - const uint16_t kFive5 = kFive4 * 5; - const uint16_t kFive6 = kFive5 * 5; - const uint32_t kFive7 = kFive6 * 5; - const uint32_t kFive8 = kFive7 * 5; - const uint32_t kFive9 = kFive8 * 5; - const uint32_t kFive10 = kFive9 * 5; - const uint32_t kFive11 = kFive10 * 5; - const uint32_t kFive12 = kFive11 * 5; - const uint32_t kFive13 = kFive12 * 5; - const uint32_t kFive1_to_12[] = +void Bignum::MultiplyByPowerOfTen(const int exponent) { + static const uint64_t kFive27 = DOUBLE_CONVERSION_UINT64_2PART_C(0x6765c793, fa10079d); + static const uint16_t kFive1 = 5; + static const uint16_t kFive2 = kFive1 * 5; + static const uint16_t kFive3 = kFive2 * 5; + static const uint16_t kFive4 = kFive3 * 5; + static const uint16_t kFive5 = kFive4 * 5; + static const uint16_t kFive6 = kFive5 * 5; + static const uint32_t kFive7 = kFive6 * 5; + static const uint32_t kFive8 = kFive7 * 5; + static const uint32_t kFive9 = kFive8 * 5; + static const uint32_t kFive10 = kFive9 * 5; + static const uint32_t kFive11 = kFive10 * 5; + static const uint32_t kFive12 = kFive11 * 5; + static const uint32_t kFive13 = kFive12 * 5; + static const uint32_t kFive1_to_12[] = { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6, kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 }; - ASSERT(exponent >= 0); - if (exponent == 0) return; - if (used_digits_ == 0) return; + DOUBLE_CONVERSION_ASSERT(exponent >= 0); + if (exponent == 0) { + return; + } + if (used_bigits_ == 0) { + return; + } // We shift by exponent at the end just before returning. int remaining_exponent = exponent; while (remaining_exponent >= 27) { @@ -338,8 +353,8 @@ void Bignum::MultiplyByPowerOfTen(int exponent) { void Bignum::Square() { - ASSERT(IsClamped()); - int product_length = 2 * used_digits_; + DOUBLE_CONVERSION_ASSERT(IsClamped()); + const int product_length = 2 * used_bigits_; EnsureCapacity(product_length); // Comba multiplication: compute each column separately. @@ -354,64 +369,64 @@ void Bignum::Square() { // // Assert that the additional number of bits in a DoubleChunk are enough to // sum up used_digits of Bigit*Bigit. - if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) { - UNIMPLEMENTED(); + if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_bigits_) { + DOUBLE_CONVERSION_UNIMPLEMENTED(); } DoubleChunk accumulator = 0; // First shift the digits so we don't overwrite them. - int copy_offset = used_digits_; - for (int i = 0; i < used_digits_; ++i) { - bigits_[copy_offset + i] = bigits_[i]; + const int copy_offset = used_bigits_; + for (int i = 0; i < used_bigits_; ++i) { + RawBigit(copy_offset + i) = RawBigit(i); } // We have two loops to avoid some 'if's in the loop. - for (int i = 0; i < used_digits_; ++i) { + for (int i = 0; i < used_bigits_; ++i) { // Process temporary digit i with power i. // The sum of the two indices must be equal to i. int bigit_index1 = i; int bigit_index2 = 0; // Sum all of the sub-products. while (bigit_index1 >= 0) { - Chunk chunk1 = bigits_[copy_offset + bigit_index1]; - Chunk chunk2 = bigits_[copy_offset + bigit_index2]; + const Chunk chunk1 = RawBigit(copy_offset + bigit_index1); + const Chunk chunk2 = RawBigit(copy_offset + bigit_index2); accumulator += static_cast(chunk1) * chunk2; bigit_index1--; bigit_index2++; } - bigits_[i] = static_cast(accumulator) & kBigitMask; + RawBigit(i) = static_cast(accumulator) & kBigitMask; accumulator >>= kBigitSize; } - for (int i = used_digits_; i < product_length; ++i) { - int bigit_index1 = used_digits_ - 1; + for (int i = used_bigits_; i < product_length; ++i) { + int bigit_index1 = used_bigits_ - 1; int bigit_index2 = i - bigit_index1; // Invariant: sum of both indices is again equal to i. // Inner loop runs 0 times on last iteration, emptying accumulator. - while (bigit_index2 < used_digits_) { - Chunk chunk1 = bigits_[copy_offset + bigit_index1]; - Chunk chunk2 = bigits_[copy_offset + bigit_index2]; + while (bigit_index2 < used_bigits_) { + const Chunk chunk1 = RawBigit(copy_offset + bigit_index1); + const Chunk chunk2 = RawBigit(copy_offset + bigit_index2); accumulator += static_cast(chunk1) * chunk2; bigit_index1--; bigit_index2++; } - // The overwritten bigits_[i] will never be read in further loop iterations, + // The overwritten RawBigit(i) will never be read in further loop iterations, // because bigit_index1 and bigit_index2 are always greater - // than i - used_digits_. - bigits_[i] = static_cast(accumulator) & kBigitMask; + // than i - used_bigits_. + RawBigit(i) = static_cast(accumulator) & kBigitMask; accumulator >>= kBigitSize; } // Since the result was guaranteed to lie inside the number the // accumulator must be 0 now. - ASSERT(accumulator == 0); + DOUBLE_CONVERSION_ASSERT(accumulator == 0); // Don't forget to update the used_digits and the exponent. - used_digits_ = product_length; + used_bigits_ = product_length; exponent_ *= 2; Clamp(); } -void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { - ASSERT(base != 0); - ASSERT(power_exponent >= 0); +void Bignum::AssignPowerUInt16(uint16_t base, const int power_exponent) { + DOUBLE_CONVERSION_ASSERT(base != 0); + DOUBLE_CONVERSION_ASSERT(power_exponent >= 0); if (power_exponent == 0) { AssignUInt16(1); return; @@ -431,7 +446,7 @@ void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { tmp_base >>= 1; bit_size++; } - int final_size = bit_size * power_exponent; + const int final_size = bit_size * power_exponent; // 1 extra bigit for the shifting, and one for rounded final_size. EnsureCapacity(final_size / kBigitSize + 2); @@ -445,26 +460,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) { - uint64_t base_bits_mask = - ~((static_cast(1) << (64 - bit_size)) - 1); - bool high_bits_zero = (this_value & base_bits_mask) == 0; + DOUBLE_CONVERSION_ASSERT(bit_size > 0); + const uint64_t base_bits_mask = + ~((static_cast(1) << (64 - bit_size)) - 1); + const 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); } @@ -484,9 +500,9 @@ void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { // Precondition: this/other < 16bit. uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { - ASSERT(IsClamped()); - ASSERT(other.IsClamped()); - ASSERT(other.used_digits_ > 0); + DOUBLE_CONVERSION_ASSERT(IsClamped()); + DOUBLE_CONVERSION_ASSERT(other.IsClamped()); + DOUBLE_CONVERSION_ASSERT(other.used_bigits_ > 0); // Easy case: if we have less digits than the divisor than the result is 0. // Note: this handles the case where this == 0, too. @@ -504,34 +520,34 @@ uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { // This naive approach is extremely inefficient if `this` divided by other // is big. This function is implemented for doubleToString where // the result should be small (less than 10). - ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16)); - ASSERT(bigits_[used_digits_ - 1] < 0x10000); + DOUBLE_CONVERSION_ASSERT(other.RawBigit(other.used_bigits_ - 1) >= ((1 << kBigitSize) / 16)); + DOUBLE_CONVERSION_ASSERT(RawBigit(used_bigits_ - 1) < 0x10000); // Remove the multiples of the first digit. // Example this = 23 and other equals 9. -> Remove 2 multiples. - result += static_cast(bigits_[used_digits_ - 1]); - SubtractTimes(other, bigits_[used_digits_ - 1]); + result += static_cast(RawBigit(used_bigits_ - 1)); + SubtractTimes(other, RawBigit(used_bigits_ - 1)); } - ASSERT(BigitLength() == other.BigitLength()); + DOUBLE_CONVERSION_ASSERT(BigitLength() == other.BigitLength()); // Both bignums are at the same length now. // Since other has more than 0 digits we know that the access to - // bigits_[used_digits_ - 1] is safe. - Chunk this_bigit = bigits_[used_digits_ - 1]; - Chunk other_bigit = other.bigits_[other.used_digits_ - 1]; + // RawBigit(used_bigits_ - 1) is safe. + const Chunk this_bigit = RawBigit(used_bigits_ - 1); + const Chunk other_bigit = other.RawBigit(other.used_bigits_ - 1); - if (other.used_digits_ == 1) { + if (other.used_bigits_ == 1) { // Shortcut for easy (and common) case. int quotient = this_bigit / other_bigit; - bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient; - ASSERT(quotient < 0x10000); + RawBigit(used_bigits_ - 1) = this_bigit - other_bigit * quotient; + DOUBLE_CONVERSION_ASSERT(quotient < 0x10000); result += static_cast(quotient); Clamp(); return result; } - int division_estimate = this_bigit / (other_bigit + 1); - ASSERT(division_estimate < 0x10000); + const int division_estimate = this_bigit / (other_bigit + 1); + DOUBLE_CONVERSION_ASSERT(division_estimate < 0x10000); result += static_cast(division_estimate); SubtractTimes(other, division_estimate); @@ -551,7 +567,7 @@ uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { template static int SizeInHexChars(S number) { - ASSERT(number > 0); + DOUBLE_CONVERSION_ASSERT(number > 0); int result = 0; while (number != 0) { number >>= 4; @@ -561,29 +577,35 @@ static int SizeInHexChars(S number) { } -static char HexCharOfValue(int value) { - ASSERT(0 <= value && value <= 16); - if (value < 10) return static_cast(value + '0'); +static char HexCharOfValue(const int value) { + DOUBLE_CONVERSION_ASSERT(0 <= value && value <= 16); + if (value < 10) { + return static_cast(value + '0'); + } return static_cast(value - 10 + 'A'); } -bool Bignum::ToHexString(char* buffer, int buffer_size) const { - ASSERT(IsClamped()); +bool Bignum::ToHexString(char* buffer, const int buffer_size) const { + DOUBLE_CONVERSION_ASSERT(IsClamped()); // Each bigit must be printable as separate hex-character. - ASSERT(kBigitSize % 4 == 0); - const int kHexCharsPerBigit = kBigitSize / 4; + DOUBLE_CONVERSION_ASSERT(kBigitSize % 4 == 0); + static const int kHexCharsPerBigit = kBigitSize / 4; - if (used_digits_ == 0) { - if (buffer_size < 2) return false; + if (used_bigits_ == 0) { + if (buffer_size < 2) { + return false; + } buffer[0] = '0'; buffer[1] = '\0'; return true; } // We add 1 for the terminating '\0' character. - int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit + - SizeInHexChars(bigits_[used_digits_ - 1]) + 1; - if (needed_chars > buffer_size) return false; + const int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit + + SizeInHexChars(RawBigit(used_bigits_ - 1)) + 1; + if (needed_chars > buffer_size) { + return false; + } int string_index = needed_chars - 1; buffer[string_index--] = '\0'; for (int i = 0; i < exponent_; ++i) { @@ -591,15 +613,15 @@ bool Bignum::ToHexString(char* buffer, int buffer_size) const { buffer[string_index--] = '0'; } } - for (int i = 0; i < used_digits_ - 1; ++i) { - Chunk current_bigit = bigits_[i]; + for (int i = 0; i < used_bigits_ - 1; ++i) { + Chunk current_bigit = RawBigit(i); for (int j = 0; j < kHexCharsPerBigit; ++j) { buffer[string_index--] = HexCharOfValue(current_bigit & 0xF); current_bigit >>= 4; } } // And finally the last bigit. - Chunk most_significant_bigit = bigits_[used_digits_ - 1]; + Chunk most_significant_bigit = RawBigit(used_bigits_ - 1); while (most_significant_bigit != 0) { buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF); most_significant_bigit >>= 4; @@ -608,25 +630,37 @@ bool Bignum::ToHexString(char* buffer, int buffer_size) const { } -Bignum::Chunk Bignum::BigitAt(int index) const { - if (index >= BigitLength()) return 0; - if (index < exponent_) return 0; - return bigits_[index - exponent_]; +Bignum::Chunk Bignum::BigitOrZero(const int index) const { + if (index >= BigitLength()) { + return 0; + } + if (index < exponent_) { + return 0; + } + return RawBigit(index - exponent_); } int Bignum::Compare(const Bignum& a, const Bignum& b) { - ASSERT(a.IsClamped()); - ASSERT(b.IsClamped()); - int bigit_length_a = a.BigitLength(); - int bigit_length_b = b.BigitLength(); - if (bigit_length_a < bigit_length_b) return -1; - if (bigit_length_a > bigit_length_b) return +1; - for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) { - Chunk bigit_a = a.BigitAt(i); - Chunk bigit_b = b.BigitAt(i); - if (bigit_a < bigit_b) return -1; - if (bigit_a > bigit_b) return +1; + DOUBLE_CONVERSION_ASSERT(a.IsClamped()); + DOUBLE_CONVERSION_ASSERT(b.IsClamped()); + const int bigit_length_a = a.BigitLength(); + const int bigit_length_b = b.BigitLength(); + if (bigit_length_a < bigit_length_b) { + return -1; + } + if (bigit_length_a > bigit_length_b) { + return +1; + } + for (int i = bigit_length_a - 1; i >= (std::min)(a.exponent_, b.exponent_); --i) { + const Chunk bigit_a = a.BigitOrZero(i); + const Chunk bigit_b = b.BigitOrZero(i); + if (bigit_a < bigit_b) { + return -1; + } + if (bigit_a > bigit_b) { + return +1; + } // Otherwise they are equal up to this digit. Try the next digit. } return 0; @@ -634,14 +668,18 @@ int Bignum::Compare(const Bignum& a, const Bignum& b) { int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) { - ASSERT(a.IsClamped()); - ASSERT(b.IsClamped()); - ASSERT(c.IsClamped()); + DOUBLE_CONVERSION_ASSERT(a.IsClamped()); + DOUBLE_CONVERSION_ASSERT(b.IsClamped()); + DOUBLE_CONVERSION_ASSERT(c.IsClamped()); if (a.BigitLength() < b.BigitLength()) { return PlusCompare(b, a, c); } - if (a.BigitLength() + 1 < c.BigitLength()) return -1; - if (a.BigitLength() > c.BigitLength()) return +1; + if (a.BigitLength() + 1 < c.BigitLength()) { + return -1; + } + if (a.BigitLength() > c.BigitLength()) { + return +1; + } // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one // of 'a'. @@ -651,92 +689,83 @@ int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) { Chunk borrow = 0; // Starting at min_exponent all digits are == 0. So no need to compare them. - int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_); + const int min_exponent = (std::min)((std::min)(a.exponent_, b.exponent_), c.exponent_); for (int i = c.BigitLength() - 1; i >= min_exponent; --i) { - Chunk chunk_a = a.BigitAt(i); - Chunk chunk_b = b.BigitAt(i); - Chunk chunk_c = c.BigitAt(i); - Chunk sum = chunk_a + chunk_b; + const Chunk chunk_a = a.BigitOrZero(i); + const Chunk chunk_b = b.BigitOrZero(i); + const Chunk chunk_c = c.BigitOrZero(i); + const Chunk sum = chunk_a + chunk_b; if (sum > chunk_c + borrow) { return +1; } else { borrow = chunk_c + borrow - sum; - if (borrow > 1) return -1; + if (borrow > 1) { + return -1; + } borrow <<= kBigitSize; } } - if (borrow == 0) return 0; + if (borrow == 0) { + return 0; + } return -1; } void Bignum::Clamp() { - while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) { - used_digits_--; + while (used_bigits_ > 0 && RawBigit(used_bigits_ - 1) == 0) { + used_bigits_--; } - if (used_digits_ == 0) { + if (used_bigits_ == 0) { // Zero. exponent_ = 0; } } -bool Bignum::IsClamped() const { - return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0; -} - - -void Bignum::Zero() { - for (int i = 0; i < used_digits_; ++i) { - bigits_[i] = 0; - } - used_digits_ = 0; - exponent_ = 0; -} - - void Bignum::Align(const Bignum& other) { if (exponent_ > other.exponent_) { - // If "X" represents a "hidden" digit (by the exponent) then we are in the + // If "X" represents a "hidden" bigit (by the exponent) then we are in the // following case (a == this, b == other): // a: aaaaaaXXXX or a: aaaaaXXX // b: bbbbbbX b: bbbbbbbbXX // We replace some of the hidden digits (X) of a with 0 digits. // a: aaaaaa000X or a: aaaaa0XX - int zero_digits = exponent_ - other.exponent_; - EnsureCapacity(used_digits_ + zero_digits); - for (int i = used_digits_ - 1; i >= 0; --i) { - bigits_[i + zero_digits] = bigits_[i]; + const int zero_bigits = exponent_ - other.exponent_; + EnsureCapacity(used_bigits_ + zero_bigits); + for (int i = used_bigits_ - 1; i >= 0; --i) { + RawBigit(i + zero_bigits) = RawBigit(i); } - for (int i = 0; i < zero_digits; ++i) { - bigits_[i] = 0; + for (int i = 0; i < zero_bigits; ++i) { + RawBigit(i) = 0; } - used_digits_ += zero_digits; - exponent_ -= zero_digits; - ASSERT(used_digits_ >= 0); - ASSERT(exponent_ >= 0); + used_bigits_ += zero_bigits; + exponent_ -= zero_bigits; + + DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0); + DOUBLE_CONVERSION_ASSERT(exponent_ >= 0); } } -void Bignum::BigitsShiftLeft(int shift_amount) { - ASSERT(shift_amount < kBigitSize); - ASSERT(shift_amount >= 0); +void Bignum::BigitsShiftLeft(const int shift_amount) { + DOUBLE_CONVERSION_ASSERT(shift_amount < kBigitSize); + DOUBLE_CONVERSION_ASSERT(shift_amount >= 0); Chunk carry = 0; - for (int i = 0; i < used_digits_; ++i) { - Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount); - bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask; + for (int i = 0; i < used_bigits_; ++i) { + const Chunk new_carry = RawBigit(i) >> (kBigitSize - shift_amount); + RawBigit(i) = ((RawBigit(i) << shift_amount) + carry) & kBigitMask; carry = new_carry; } if (carry != 0) { - bigits_[used_digits_] = carry; - used_digits_++; + RawBigit(used_bigits_) = carry; + used_bigits_++; } } -void Bignum::SubtractTimes(const Bignum& other, int factor) { - ASSERT(exponent_ <= other.exponent_); +void Bignum::SubtractTimes(const Bignum& other, const int factor) { + DOUBLE_CONVERSION_ASSERT(exponent_ <= other.exponent_); if (factor < 3) { for (int i = 0; i < factor; ++i) { SubtractBignum(other); @@ -744,19 +773,21 @@ void Bignum::SubtractTimes(const Bignum& other, int factor) { return; } Chunk borrow = 0; - int exponent_diff = other.exponent_ - exponent_; - for (int i = 0; i < other.used_digits_; ++i) { - DoubleChunk product = static_cast(factor) * other.bigits_[i]; - DoubleChunk remove = borrow + product; - Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask); - bigits_[i + exponent_diff] = difference & kBigitMask; + const int exponent_diff = other.exponent_ - exponent_; + for (int i = 0; i < other.used_bigits_; ++i) { + const DoubleChunk product = static_cast(factor) * other.RawBigit(i); + const DoubleChunk remove = borrow + product; + const Chunk difference = RawBigit(i + exponent_diff) - (remove & kBigitMask); + RawBigit(i + exponent_diff) = difference & kBigitMask; borrow = static_cast((difference >> (kChunkSize - 1)) + (remove >> kBigitSize)); } - for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) { - if (borrow == 0) return; - Chunk difference = bigits_[i] - borrow; - bigits_[i] = difference & kBigitMask; + for (int i = other.used_bigits_ + exponent_diff; i < used_bigits_; ++i) { + if (borrow == 0) { + return; + } + const Chunk difference = RawBigit(i) - borrow; + RawBigit(i) = difference & kBigitMask; borrow = difference >> (kChunkSize - 1); } Clamp(); diff --git a/deps/double-conversion/double-conversion/bignum.h b/deps/double-conversion/double-conversion/bignum.h index c385f223..14d1ca86 100644 --- a/deps/double-conversion/double-conversion/bignum.h +++ b/deps/double-conversion/double-conversion/bignum.h @@ -39,26 +39,27 @@ class Bignum { // exponent. static const int kMaxSignificantBits = 3584; - Bignum(); - void AssignUInt16(uint16_t value); + Bignum() : used_bigits_(0), exponent_(0) {} + + void AssignUInt16(const uint16_t value); void AssignUInt64(uint64_t value); void AssignBignum(const Bignum& other); - void AssignDecimalString(Vector value); - void AssignHexString(Vector value); + void AssignDecimalString(const Vector value); + void AssignHexString(const Vector value); - void AssignPowerUInt16(uint16_t base, int exponent); + void AssignPowerUInt16(uint16_t base, const int exponent); - void AddUInt64(uint64_t operand); + void AddUInt64(const uint64_t operand); void AddBignum(const Bignum& other); // Precondition: this >= other. void SubtractBignum(const Bignum& other); void Square(); - void ShiftLeft(int shift_amount); - void MultiplyByUInt32(uint32_t factor); - void MultiplyByUInt64(uint64_t factor); - void MultiplyByPowerOfTen(int exponent); + void ShiftLeft(const int shift_amount); + void MultiplyByUInt32(const uint32_t factor); + void MultiplyByUInt64(const uint64_t factor); + void MultiplyByPowerOfTen(const int exponent); void Times10() { return MultiplyByUInt32(10); } // Pseudocode: // int result = this / other; @@ -66,7 +67,7 @@ class Bignum { // In the worst case this function is in O(this/other). uint16_t DivideModuloIntBignum(const Bignum& other); - bool ToHexString(char* buffer, int buffer_size) const; + bool ToHexString(char* buffer, const int buffer_size) const; // Returns // -1 if a < b, @@ -110,33 +111,40 @@ class Bignum { // grow. There are no checks if the stack-allocated space is sufficient. static const int kBigitCapacity = kMaxSignificantBits / kBigitSize; - void EnsureCapacity(int size) { + static void EnsureCapacity(const int size) { if (size > kBigitCapacity) { - UNREACHABLE(); + DOUBLE_CONVERSION_UNREACHABLE(); } } void Align(const Bignum& other); void Clamp(); - bool IsClamped() const; - void Zero(); + bool IsClamped() const { + return used_bigits_ == 0 || RawBigit(used_bigits_ - 1) != 0; + } + void Zero() { + used_bigits_ = 0; + exponent_ = 0; + } // Requires this to have enough capacity (no tests done). - // Updates used_digits_ if necessary. + // Updates used_bigits_ if necessary. // shift_amount must be < kBigitSize. - void BigitsShiftLeft(int shift_amount); - // BigitLength includes the "hidden" digits encoded in the exponent. - int BigitLength() const { return used_digits_ + exponent_; } - Chunk BigitAt(int index) const; - void SubtractTimes(const Bignum& other, int factor); - + void BigitsShiftLeft(const int shift_amount); + // BigitLength includes the "hidden" bigits encoded in the exponent. + int BigitLength() const { return used_bigits_ + exponent_; } + Chunk& RawBigit(const int index); + const Chunk& RawBigit(const int index) const; + Chunk BigitOrZero(const int index) const; + void SubtractTimes(const Bignum& other, const int factor); + + // The Bignum's value is value(bigits_buffer_) * 2^(exponent_ * kBigitSize), + // where the value of the buffer consists of the lower kBigitSize bits of + // the first used_bigits_ Chunks in bigits_buffer_, first chunk has lowest + // significant bits. + int16_t used_bigits_; + int16_t exponent_; Chunk bigits_buffer_[kBigitCapacity]; - // A vector backed by bigits_buffer_. This way accesses to the array are - // checked for out-of-bounds errors. - Vector bigits_; - int used_digits_; - // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize). - int exponent_; - - DISALLOW_COPY_AND_ASSIGN(Bignum); + + DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Bignum); }; } // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/cached-powers.cc b/deps/double-conversion/double-conversion/cached-powers.cc index 2b43f064..56bdfc9d 100644 --- a/deps/double-conversion/double-conversion/cached-powers.cc +++ b/deps/double-conversion/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 "utils.h" @@ -35,6 +35,8 @@ namespace double_conversion { +namespace PowersOfTenCache { + struct CachedPower { uint64_t significand; int16_t binary_exponent; @@ -42,103 +44,99 @@ struct CachedPower { }; static const CachedPower kCachedPowers[] = { - {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348}, - {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340}, - {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332}, - {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324}, - {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316}, - {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308}, - {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300}, - {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284}, - {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276}, - {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268}, - {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252}, - {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244}, - {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236}, - {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228}, - {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220}, - {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212}, - {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204}, - {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196}, - {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188}, - {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180}, - {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164}, - {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156}, - {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140}, - {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132}, - {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124}, - {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116}, - {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108}, - {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100}, - {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84}, - {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76}, - {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68}, - {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60}, - {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52}, - {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36}, - {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20}, - {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12}, - {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4}, - {UINT64_2PART_C(0x9c400000, 00000000), -50, 4}, - {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12}, - {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20}, - {UINT64_2PART_C(0x813f3978, f8940984), 30, 28}, - {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36}, - {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52}, - {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60}, - {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68}, - {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76}, - {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84}, - {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92}, - {UINT64_2PART_C(0x924d692c, a61be758), 269, 100}, - {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108}, - {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116}, - {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124}, - {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132}, - {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140}, - {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148}, - {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156}, - {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164}, - {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172}, - {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180}, - {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188}, - {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196}, - {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204}, - {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212}, - {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220}, - {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228}, - {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244}, - {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252}, - {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260}, - {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268}, - {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276}, - {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284}, - {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292}, - {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300}, - {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316}, - {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324}, - {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332}, - {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xef340a98, 172aace5), -715, -196}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xaa242499, 697392d3), -183, -36}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xd1b71758, e219652c), -77, -4}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9c400000, 00000000), -50, 4}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x813f3978, f8940984), 30, 28}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x924d692c, a61be758), 269, 100}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xa59bc234, db398c25), 508, 172}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xd01fef10, a657842c), 800, 260}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332}, + {DOUBLE_CONVERSION_UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, }; static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent. static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) -// Difference between the decimal exponents in the table above. -const int PowersOfTenCache::kDecimalExponentDistance = 8; -const int PowersOfTenCache::kMinDecimalExponent = -348; -const int PowersOfTenCache::kMaxDecimalExponent = 340; -void PowersOfTenCache::GetCachedPowerForBinaryExponentRange( +void GetCachedPowerForBinaryExponentRange( int min_exponent, int max_exponent, DiyFp* power, @@ -148,28 +146,30 @@ void PowersOfTenCache::GetCachedPowerForBinaryExponentRange( int foo = kCachedPowersOffset; int index = (foo + static_cast(k) - 1) / kDecimalExponentDistance + 1; - ASSERT(0 <= index && index < static_cast(ARRAY_SIZE(kCachedPowers))); + DOUBLE_CONVERSION_ASSERT(0 <= index && index < static_cast(DOUBLE_CONVERSION_ARRAY_SIZE(kCachedPowers))); CachedPower cached_power = kCachedPowers[index]; - ASSERT(min_exponent <= cached_power.binary_exponent); + DOUBLE_CONVERSION_ASSERT(min_exponent <= cached_power.binary_exponent); (void) max_exponent; // Mark variable as used. - ASSERT(cached_power.binary_exponent <= max_exponent); + DOUBLE_CONVERSION_ASSERT(cached_power.binary_exponent <= max_exponent); *decimal_exponent = cached_power.decimal_exponent; *power = DiyFp(cached_power.significand, cached_power.binary_exponent); } -void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent, - DiyFp* power, - int* found_exponent) { - ASSERT(kMinDecimalExponent <= requested_exponent); - ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance); +void GetCachedPowerForDecimalExponent(int requested_exponent, + DiyFp* power, + int* found_exponent) { + DOUBLE_CONVERSION_ASSERT(kMinDecimalExponent <= requested_exponent); + DOUBLE_CONVERSION_ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance); int index = (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance; CachedPower cached_power = kCachedPowers[index]; *power = DiyFp(cached_power.significand, cached_power.binary_exponent); *found_exponent = cached_power.decimal_exponent; - ASSERT(*found_exponent <= requested_exponent); - ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance); + DOUBLE_CONVERSION_ASSERT(*found_exponent <= requested_exponent); + DOUBLE_CONVERSION_ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance); } +} // namespace PowersOfTenCache + } // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/cached-powers.h b/deps/double-conversion/double-conversion/cached-powers.h index 61a50614..f38c26d2 100644 --- a/deps/double-conversion/double-conversion/cached-powers.h +++ b/deps/double-conversion/double-conversion/cached-powers.h @@ -32,32 +32,32 @@ namespace double_conversion { -class PowersOfTenCache { - public: +namespace PowersOfTenCache { // Not all powers of ten are cached. The decimal exponent of two neighboring // cached numbers will differ by kDecimalExponentDistance. - static const int kDecimalExponentDistance; + static const int kDecimalExponentDistance = 8; - static const int kMinDecimalExponent; - static const int kMaxDecimalExponent; + static const int kMinDecimalExponent = -348; + static const int kMaxDecimalExponent = 340; // Returns a cached power-of-ten with a binary exponent in the range // [min_exponent; max_exponent] (boundaries included). - static void GetCachedPowerForBinaryExponentRange(int min_exponent, - int max_exponent, - DiyFp* power, - int* decimal_exponent); + void GetCachedPowerForBinaryExponentRange(int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent); // Returns a cached power of ten x ~= 10^k such that // k <= decimal_exponent < k + kCachedPowersDecimalDistance. // The given decimal_exponent must satisfy // kMinDecimalExponent <= requested_exponent, and // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance. - static void GetCachedPowerForDecimalExponent(int requested_exponent, - DiyFp* power, - int* found_exponent); -}; + void GetCachedPowerForDecimalExponent(int requested_exponent, + DiyFp* power, + int* found_exponent); + +} // namespace PowersOfTenCache } // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/diy-fp.cc b/deps/double-conversion/double-conversion/diy-fp.cc deleted file mode 100644 index ddd1891b..00000000 --- a/deps/double-conversion/double-conversion/diy-fp.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (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 "diy-fp.h" -#include "utils.h" - -namespace double_conversion { - -void DiyFp::Multiply(const DiyFp& other) { - // Simply "emulates" a 128 bit multiplication. - // However: the resulting number only contains 64 bits. The least - // significant 64 bits are only used for rounding the most significant 64 - // bits. - const uint64_t kM32 = 0xFFFFFFFFU; - uint64_t a = f_ >> 32; - uint64_t b = f_ & kM32; - uint64_t c = other.f_ >> 32; - uint64_t d = other.f_ & kM32; - uint64_t ac = a * c; - uint64_t bc = b * c; - uint64_t ad = a * d; - uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32); - // By adding 1U << 31 to tmp we round the final result. - // Halfway cases will be round up. - tmp += 1U << 31; - uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); - e_ += other.e_ + 64; - f_ = result_f; -} - -} // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/diy-fp.h b/deps/double-conversion/double-conversion/diy-fp.h index 2edf3467..a2200c4d 100644 --- a/deps/double-conversion/double-conversion/diy-fp.h +++ b/deps/double-conversion/double-conversion/diy-fp.h @@ -36,36 +36,55 @@ namespace double_conversion { // with a uint64 significand and an int exponent. Normalized DiyFp numbers will // have the most significant bit of the significand set. // Multiplication and Subtraction do not normalize their results. -// DiyFp are not designed to contain special doubles (NaN and Infinity). +// DiyFp store only non-negative numbers and are not designed to contain special +// doubles (NaN and Infinity). class DiyFp { public: static const int kSignificandSize = 64; DiyFp() : f_(0), e_(0) {} - DiyFp(uint64_t significand, int exponent) : f_(significand), e_(exponent) {} + DiyFp(const uint64_t significand, const int32_t exponent) : f_(significand), e_(exponent) {} - // this = this - other. + // this -= other. // The exponents of both numbers must be the same and the significand of this - // must be bigger than the significand of other. + // must be greater or equal than the significand of other. // The result will not be normalized. void Subtract(const DiyFp& other) { - ASSERT(e_ == other.e_); - ASSERT(f_ >= other.f_); + DOUBLE_CONVERSION_ASSERT(e_ == other.e_); + DOUBLE_CONVERSION_ASSERT(f_ >= other.f_); f_ -= other.f_; } // Returns a - b. - // The exponents of both numbers must be the same and this must be bigger - // than other. The result will not be normalized. + // The exponents of both numbers must be the same and a must be greater + // or equal than b. The result will not be normalized. static DiyFp Minus(const DiyFp& a, const DiyFp& b) { DiyFp result = a; result.Subtract(b); return result; } - - // this = this * other. - void Multiply(const DiyFp& other); + // this *= other. + void Multiply(const DiyFp& other) { + // Simply "emulates" a 128 bit multiplication. + // However: the resulting number only contains 64 bits. The least + // significant 64 bits are only used for rounding the most significant 64 + // bits. + const uint64_t kM32 = 0xFFFFFFFFU; + const uint64_t a = f_ >> 32; + const uint64_t b = f_ & kM32; + const uint64_t c = other.f_ >> 32; + const uint64_t d = other.f_ & kM32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + // By adding 1U << 31 to tmp we round the final result. + // Halfway cases will be rounded up. + const uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32) + (1U << 31); + e_ += other.e_ + 64; + f_ = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + } // returns a * b; static DiyFp Times(const DiyFp& a, const DiyFp& b) { @@ -75,13 +94,13 @@ class DiyFp { } void Normalize() { - ASSERT(f_ != 0); + DOUBLE_CONVERSION_ASSERT(f_ != 0); uint64_t significand = f_; - int exponent = e_; + int32_t exponent = e_; - // This method is mainly called for normalizing boundaries. In general - // boundaries need to be shifted by 10 bits. We thus optimize for this case. - const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000); + // This method is mainly called for normalizing boundaries. In general, + // boundaries need to be shifted by 10 bits, and we optimize for this case. + const uint64_t k10MSBits = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFC00000, 00000000); while ((significand & k10MSBits) == 0) { significand <<= 10; exponent -= 10; @@ -101,16 +120,16 @@ class DiyFp { } uint64_t f() const { return f_; } - int e() const { return e_; } + int32_t e() const { return e_; } void set_f(uint64_t new_value) { f_ = new_value; } - void set_e(int new_value) { e_ = new_value; } + void set_e(int32_t new_value) { e_ = new_value; } private: - static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000); + static const uint64_t kUint64MSB = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000); uint64_t f_; - int e_; + int32_t e_; }; } // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/double-conversion.h b/deps/double-conversion/double-conversion/double-conversion.h index 6bdfa8d2..6e8884d8 100644 --- a/deps/double-conversion/double-conversion/double-conversion.h +++ b/deps/double-conversion/double-conversion/double-conversion.h @@ -28,516 +28,7 @@ #ifndef DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ #define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ -#include "utils.h" - -namespace double_conversion { - -class DoubleToStringConverter { - public: - // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint - // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the - // function returns false. - static const int kMaxFixedDigitsBeforePoint = 60; - static const int kMaxFixedDigitsAfterPoint = 60; - - // When calling ToExponential with a requested_digits - // parameter > kMaxExponentialDigits then the function returns false. - static const int kMaxExponentialDigits = 120; - - // When calling ToPrecision with a requested_digits - // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits - // then the function returns false. - static const int kMinPrecisionDigits = 1; - static const int kMaxPrecisionDigits = 120; - - enum Flags { - NO_FLAGS = 0, - EMIT_POSITIVE_EXPONENT_SIGN = 1, - EMIT_TRAILING_DECIMAL_POINT = 2, - EMIT_TRAILING_ZERO_AFTER_POINT = 4, - UNIQUE_ZERO = 8 - }; - - // Flags should be a bit-or combination of the possible Flags-enum. - // - NO_FLAGS: no special flags. - // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent - // form, emits a '+' for positive exponents. Example: 1.2e+2. - // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is - // converted into decimal format then a trailing decimal point is appended. - // Example: 2345.0 is converted to "2345.". - // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point - // emits a trailing '0'-character. This flag requires the - // EXMIT_TRAILING_DECIMAL_POINT flag. - // Example: 2345.0 is converted to "2345.0". - // - UNIQUE_ZERO: "-0.0" is converted to "0.0". - // - // Infinity symbol and nan_symbol provide the string representation for these - // special values. If the string is NULL and the special value is encountered - // then the conversion functions return false. - // - // The exponent_character is used in exponential representations. It is - // usually 'e' or 'E'. - // - // When converting to the shortest representation the converter will - // represent input numbers in decimal format if they are in the interval - // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ - // (lower boundary included, greater boundary excluded). - // Example: with decimal_in_shortest_low = -6 and - // decimal_in_shortest_high = 21: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // When converting to precision mode the converter may add - // max_leading_padding_zeroes before returning the number in exponential - // format. - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - DoubleToStringConverter(int flags, - const char* infinity_symbol, - const char* nan_symbol, - char exponent_character, - int decimal_in_shortest_low, - int decimal_in_shortest_high, - int max_leading_padding_zeroes_in_precision_mode, - int max_trailing_padding_zeroes_in_precision_mode) - : flags_(flags), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol), - exponent_character_(exponent_character), - decimal_in_shortest_low_(decimal_in_shortest_low), - decimal_in_shortest_high_(decimal_in_shortest_high), - max_leading_padding_zeroes_in_precision_mode_( - max_leading_padding_zeroes_in_precision_mode), - max_trailing_padding_zeroes_in_precision_mode_( - max_trailing_padding_zeroes_in_precision_mode) { - // When 'trailing zero after the point' is set, then 'trailing point' - // must be set too. - ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || - !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); - } - - // Returns a converter following the EcmaScript specification. - static const DoubleToStringConverter& EcmaScriptConverter(); - - // Computes the shortest string of digits that correctly represent the input - // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high - // (see constructor) it then either returns a decimal representation, or an - // exponential representation. - // Example with decimal_in_shortest_low = -6, - // decimal_in_shortest_high = 21, - // EMIT_POSITIVE_EXPONENT_SIGN activated, and - // EMIT_TRAILING_DECIMAL_POINT deactived: - // ToShortest(0.000001) -> "0.000001" - // ToShortest(0.0000001) -> "1e-7" - // ToShortest(111111111111111111111.0) -> "111111111111111110000" - // ToShortest(100000000000000000000.0) -> "100000000000000000000" - // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" - // - // Note: the conversion may round the output if the returned string - // is accurate enough to uniquely identify the input-number. - // For example the most precise representation of the double 9e59 equals - // "899999999999999918767229449717619953810131273674690656206848", but - // the converter will return the shorter (but still correct) "9e59". - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except when the input value is special and no infinity_symbol or - // nan_symbol has been given to the constructor. - bool ToShortest(double value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST); - } - - // Same as ToShortest, but for single-precision floats. - bool ToShortestSingle(float value, StringBuilder* result_builder) const { - return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); - } - - - // Computes a decimal representation with a fixed number of digits after the - // decimal point. The last emitted digit is rounded. - // - // Examples: - // ToFixed(3.12, 1) -> "3.1" - // ToFixed(3.1415, 3) -> "3.142" - // ToFixed(1234.56789, 4) -> "1234.5679" - // ToFixed(1.23, 5) -> "1.23000" - // ToFixed(0.1, 4) -> "0.1000" - // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" - // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" - // ToFixed(0.1, 17) -> "0.10000000000000001" - // - // If requested_digits equals 0, then the tail of the result depends on - // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples, for requested_digits == 0, - // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be - // - false and false: then 123.45 -> 123 - // 0.678 -> 1 - // - true and false: then 123.45 -> 123. - // 0.678 -> 1. - // - true and true: then 123.45 -> 123.0 - // 0.678 -> 1.0 - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'value' > 10^kMaxFixedDigitsBeforePoint, or - // - 'requested_digits' > kMaxFixedDigitsAfterPoint. - // The last two conditions imply that the result will never contain more than - // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters - // (one additional character for the sign, and one for the decimal point). - bool ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes a representation in exponential format with requested_digits - // after the decimal point. The last emitted digit is rounded. - // If requested_digits equals -1, then the shortest exponential representation - // is computed. - // - // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and - // exponent_character set to 'e'. - // ToExponential(3.12, 1) -> "3.1e0" - // ToExponential(5.0, 3) -> "5.000e0" - // ToExponential(0.001, 2) -> "1.00e-3" - // ToExponential(3.1415, -1) -> "3.1415e0" - // ToExponential(3.1415, 4) -> "3.1415e0" - // ToExponential(3.1415, 3) -> "3.142e0" - // ToExponential(123456789000000, 3) -> "1.235e14" - // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" - // ToExponential(1000000000000000019884624838656.0, 32) -> - // "1.00000000000000001988462483865600e30" - // ToExponential(1234, 0) -> "1e3" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - 'requested_digits' > kMaxExponentialDigits. - // The last condition implies that the result will never contain more than - // kMaxExponentialDigits + 8 characters (the sign, the digit before the - // decimal point, the decimal point, the exponent character, the - // exponent's sign, and at most 3 exponent digits). - bool ToExponential(double value, - int requested_digits, - StringBuilder* result_builder) const; - - // Computes 'precision' leading digits of the given 'value' and returns them - // either in exponential or decimal format, depending on - // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the - // constructor). - // The last computed digit is rounded. - // - // Example with max_leading_padding_zeroes_in_precision_mode = 6. - // ToPrecision(0.0000012345, 2) -> "0.0000012" - // ToPrecision(0.00000012345, 2) -> "1.2e-7" - // Similarily the converter may add up to - // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid - // returning an exponential representation. A zero added by the - // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: - // ToPrecision(230.0, 2) -> "230" - // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. - // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. - // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no - // EMIT_TRAILING_ZERO_AFTER_POINT: - // ToPrecision(123450.0, 6) -> "123450" - // ToPrecision(123450.0, 5) -> "123450" - // ToPrecision(123450.0, 4) -> "123500" - // ToPrecision(123450.0, 3) -> "123000" - // ToPrecision(123450.0, 2) -> "1.2e5" - // - // Returns true if the conversion succeeds. The conversion always succeeds - // except for the following cases: - // - the input value is special and no infinity_symbol or nan_symbol has - // been provided to the constructor, - // - precision < kMinPericisionDigits - // - precision > kMaxPrecisionDigits - // The last condition implies that the result will never contain more than - // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the - // exponent character, the exponent's sign, and at most 3 exponent digits). - bool ToPrecision(double value, - int precision, - StringBuilder* result_builder) const; - - enum DtoaMode { - // Produce the shortest correct representation. - // For example the output of 0.299999999999999988897 is (the less accurate - // but correct) 0.3. - SHORTEST, - // Same as SHORTEST, but for single-precision floats. - SHORTEST_SINGLE, - // Produce a fixed number of digits after the decimal point. - // For instance fixed(0.1, 4) becomes 0.1000 - // If the input number is big, the output will be big. - FIXED, - // Fixed number of digits (independent of the decimal point). - PRECISION - }; - - // The maximal number of digits that are needed to emit a double in base 10. - // A higher precision can be achieved by using more digits, but the shortest - // accurate representation of any double will never use more digits than - // kBase10MaximalLength. - // Note that DoubleToAscii null-terminates its input. So the given buffer - // 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. - // - // The result should be interpreted as buffer * 10^(point-length). - // - // 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 - // (together with the correct exponent) then reading this number will give - // 'v' again. The buffer will choose the representation that is closest to - // 'v'. If there are two at the same distance, than the one farther away - // from 0 is chosen (halfway cases - ending with 5 - are rounded up). - // In this mode the 'requested_digits' parameter is ignored. - // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. - // - FIXED: produces digits necessary to print a given number with - // 'requested_digits' digits after the decimal point. The produced digits - // might be too short in which case the caller has to fill the remainder - // with '0's. - // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. - // Halfway cases are rounded towards +/-Infinity (away from 0). The call - // toFixed(0.15, 2) thus returns buffer="2", point=0. - // The returned buffer may contain digits that would be truncated from the - // shortest representation of the input. - // - PRECISION: produces 'requested_digits' where the first digit is not '0'. - // Even though the length of produced digits usually equals - // 'requested_digits', the function is allowed to return fewer digits, in - // which case the caller has to fill the missing digits with '0's. - // Halfway cases are again rounded away from 0. - // DoubleToAscii expects the given buffer to be big enough to hold all - // digits and a terminating null-character. In SHORTEST-mode it expects a - // buffer of at least kBase10MaximalLength + 1. In all other modes the - // requested_digits parameter and the padding-zeroes limit the size of the - // output. Don't forget the decimal point, the exponent character and the - // terminating null-character when computing the maximal output size. - // The given length is only used in debug mode to ensure the buffer is big - // enough. - static void DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, - int buffer_length, - bool* sign, - int* length, - int* point); - - private: - // Implementation for ToShortest and ToShortestSingle. - bool ToShortestIeeeNumber(double value, - StringBuilder* result_builder, - DtoaMode mode) const; - - // If the value is a special value (NaN or Infinity) constructs the - // corresponding string using the configured infinity/nan-symbol. - // If either of them is NULL or the value is not special then the - // function returns false. - bool HandleSpecialValues(double value, StringBuilder* result_builder) const; - // Constructs an exponential representation (i.e. 1.234e56). - // The given exponent assumes a decimal point after the first decimal digit. - void CreateExponentialRepresentation(const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const; - // Creates a decimal representation (i.e 1234.5678). - void CreateDecimalRepresentation(const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, - StringBuilder* result_builder) const; - - const int flags_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - const char exponent_character_; - const int decimal_in_shortest_low_; - const int decimal_in_shortest_high_; - const int max_leading_padding_zeroes_in_precision_mode_; - const int max_trailing_padding_zeroes_in_precision_mode_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); -}; - - -class StringToDoubleConverter { - public: - // Enumeration for allowing octals and ignoring junk when converting - // strings to numbers. - enum Flags { - NO_FLAGS = 0, - ALLOW_HEX = 1, - ALLOW_OCTALS = 2, - ALLOW_TRAILING_JUNK = 4, - ALLOW_LEADING_SPACES = 8, - ALLOW_TRAILING_SPACES = 16, - ALLOW_SPACES_AFTER_SIGN = 32 - }; - - // 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. - // Ex: StringToDouble("0x1234") -> 4660.0 - // In StringToDouble("0x1234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, - // the string will not be parsed as "0" followed by junk. - // - // - ALLOW_OCTALS: recognizes the prefix "0" for octals: - // If a sequence of octal digits starts with '0', then the number is - // read as octal integer. Octal numbers may only be integers. - // Ex: StringToDouble("01234") -> 668.0 - // StringToDouble("012349") -> 12349.0 // Not a sequence of octal - // // digits. - // In StringToDouble("01234.56") the characters ".56" are trailing - // junk. The result of the call is hence dependent on - // the ALLOW_TRAILING_JUNK flag and/or the junk value. - // In StringToDouble("01234e56") the characters "e56" are trailing - // junk, too. - // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of - // a double literal. - // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces, - // new-lines, and tabs. - // - ALLOW_TRAILING_SPACES: ignore trailing whitespace. - // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign. - // Ex: StringToDouble("- 123.2") -> -123.2. - // StringToDouble("+ 123.2") -> 123.2 - // - // 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 - // containing only spaces is converted to the 'empty_string_value', too. - // - // junk_string_value is returned when - // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not - // part of a double-literal) is found. - // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a - // double literal. - // - // infinity_symbol and nan_symbol are strings that are used to detect - // inputs that represent infinity and NaN. They can be null, in which case - // they are ignored. - // The conversion routine first reads any possible signs. Then it compares the - // following character of the input-string with the first character of - // the infinity, and nan-symbol. If either matches, the function assumes, that - // a match has been found, and expects the following input characters to match - // the remaining characters of the special-value symbol. - // This means that the following restrictions apply to special-value symbols: - // - they must not start with signs ('+', or '-'), - // - they must not have the same first character. - // - they must not start with digits. - // - // Examples: - // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = "infinity", - // nan_symbol = "nan": - // StringToDouble("0x1234") -> 4660.0. - // StringToDouble("0x1234K") -> 4660.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> NaN // junk_string_value. - // StringToDouble(" 1") -> NaN // junk_string_value. - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("-123.45") -> -123.45. - // StringToDouble("--123.45") -> NaN // junk_string_value. - // StringToDouble("123e45") -> 123e45. - // StringToDouble("123E45") -> 123e45. - // StringToDouble("123e+45") -> 123e45. - // StringToDouble("123E-45") -> 123e-45. - // StringToDouble("123e") -> 123.0 // trailing junk ignored. - // StringToDouble("123e-") -> 123.0 // trailing junk ignored. - // StringToDouble("+NaN") -> NaN // NaN string literal. - // StringToDouble("-infinity") -> -inf. // infinity literal. - // StringToDouble("Infinity") -> NaN // junk_string_value. - // - // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, - // empty_string_value = 0.0, - // junk_string_value = NaN, - // infinity_symbol = NULL, - // nan_symbol = NULL: - // StringToDouble("0x1234") -> NaN // junk_string_value. - // StringToDouble("01234") -> 668.0. - // StringToDouble("") -> 0.0 // empty_string_value. - // StringToDouble(" ") -> 0.0 // empty_string_value. - // StringToDouble(" 1") -> 1.0 - // StringToDouble("0x") -> NaN // junk_string_value. - // StringToDouble("0123e45") -> NaN // junk_string_value. - // StringToDouble("01239E45") -> 1239e45. - // StringToDouble("-infinity") -> NaN // junk_string_value. - // StringToDouble("NaN") -> NaN // junk_string_value. - StringToDoubleConverter(int flags, - double empty_string_value, - double junk_string_value, - const char* infinity_symbol, - const char* nan_symbol) - : flags_(flags), - empty_string_value_(empty_string_value), - junk_string_value_(junk_string_value), - infinity_symbol_(infinity_symbol), - nan_symbol_(nan_symbol) { - } - - // Performs the conversion. - // The output parameter 'processed_characters_count' is set to the number - // of characters that have been processed to read the number. - // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included - // in the 'processed_characters_count'. Trailing junk is never included. - double StringToDouble(const char* buffer, - int length, - int* processed_characters_count) const; - - // Same as StringToDouble above but for 16 bit characters. - double StringToDouble(const uc16* buffer, - int length, - int* processed_characters_count) const; - - // Same as StringToDouble but reads a float. - // Note that this is not equivalent to static_cast(StringToDouble(...)) - // due to potential double-rounding. - float StringToFloat(const char* buffer, - int length, - int* processed_characters_count) const; - - // Same as StringToFloat above but for 16 bit characters. - float StringToFloat(const uc16* buffer, - int length, - int* processed_characters_count) const; - - private: - const int flags_; - const double empty_string_value_; - const double junk_string_value_; - const char* const infinity_symbol_; - const char* const nan_symbol_; - - template - double StringToIeee(Iterator start_pointer, - int length, - bool read_as_double, - int* processed_characters_count) const; - - DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); -}; - -} // namespace double_conversion +#include "string-to-double.h" +#include "double-to-string.h" #endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_ diff --git a/deps/double-conversion/double-conversion/double-to-string.cc b/deps/double-conversion/double-conversion/double-to-string.cc new file mode 100644 index 00000000..bb369fe8 --- /dev/null +++ b/deps/double-conversion/double-conversion/double-to-string.cc @@ -0,0 +1,440 @@ +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 "double-to-string.h" + +#include "bignum-dtoa.h" +#include "fast-dtoa.h" +#include "fixed-dtoa.h" +#include "ieee.h" +#include "utils.h" + +namespace double_conversion { + +const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() { + int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN; + static DoubleToStringConverter converter(flags, + "Infinity", + "NaN", + 'e', + -6, 21, + 6, 0); + return converter; +} + + +bool DoubleToStringConverter::HandleSpecialValues( + double value, + StringBuilder* result_builder) const { + Double double_inspect(value); + if (double_inspect.IsInfinite()) { + if (infinity_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false; + if (value < 0) { + result_builder->AddCharacter('-'); + } + result_builder->AddString(infinity_symbol_); + return true; + } + if (double_inspect.IsNan()) { + if (nan_symbol_ == DOUBLE_CONVERSION_NULLPTR) return false; + result_builder->AddString(nan_symbol_); + return true; + } + return false; +} + + +void DoubleToStringConverter::CreateExponentialRepresentation( + const char* decimal_digits, + int length, + int exponent, + StringBuilder* result_builder) const { + DOUBLE_CONVERSION_ASSERT(length != 0); + result_builder->AddCharacter(decimal_digits[0]); + if (length != 1) { + result_builder->AddCharacter('.'); + result_builder->AddSubstring(&decimal_digits[1], length-1); + } + result_builder->AddCharacter(exponent_character_); + if (exponent < 0) { + result_builder->AddCharacter('-'); + exponent = -exponent; + } else { + if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { + result_builder->AddCharacter('+'); + } + } + DOUBLE_CONVERSION_ASSERT(exponent < 1e4); + // Changing this constant requires updating the comment of DoubleToStringConverter constructor + const int kMaxExponentLength = 5; + char buffer[kMaxExponentLength + 1]; + buffer[kMaxExponentLength] = '\0'; + int first_char_pos = kMaxExponentLength; + if (exponent == 0) { + buffer[--first_char_pos] = '0'; + } else { + while (exponent > 0) { + buffer[--first_char_pos] = '0' + (exponent % 10); + exponent /= 10; + } + } + // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength) + // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2 + while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) { + buffer[--first_char_pos] = '0'; + } + result_builder->AddSubstring(&buffer[first_char_pos], + kMaxExponentLength - first_char_pos); +} + + +void DoubleToStringConverter::CreateDecimalRepresentation( + const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + StringBuilder* result_builder) const { + // Create a representation that is padded with zeros if needed. + if (decimal_point <= 0) { + // "0.00000decimal_rep" or "0.000decimal_rep00". + result_builder->AddCharacter('0'); + if (digits_after_point > 0) { + result_builder->AddCharacter('.'); + result_builder->AddPadding('0', -decimal_point); + DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point)); + result_builder->AddSubstring(decimal_digits, length); + int remaining_digits = digits_after_point - (-decimal_point) - length; + result_builder->AddPadding('0', remaining_digits); + } + } else if (decimal_point >= length) { + // "decimal_rep0000.00000" or "decimal_rep.0000". + result_builder->AddSubstring(decimal_digits, length); + result_builder->AddPadding('0', decimal_point - length); + if (digits_after_point > 0) { + result_builder->AddCharacter('.'); + result_builder->AddPadding('0', digits_after_point); + } + } else { + // "decima.l_rep000". + DOUBLE_CONVERSION_ASSERT(digits_after_point > 0); + result_builder->AddSubstring(decimal_digits, decimal_point); + result_builder->AddCharacter('.'); + DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point); + result_builder->AddSubstring(&decimal_digits[decimal_point], + length - decimal_point); + int remaining_digits = digits_after_point - (length - decimal_point); + result_builder->AddPadding('0', remaining_digits); + } + if (digits_after_point == 0) { + if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { + result_builder->AddCharacter('.'); + } + if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { + result_builder->AddCharacter('0'); + } + } +} + + +bool DoubleToStringConverter::ToShortestIeeeNumber( + double value, + StringBuilder* result_builder, + DoubleToStringConverter::DtoaMode mode) const { + DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE); + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result_builder); + } + + int decimal_point; + bool sign; + const int kDecimalRepCapacity = kBase10MaximalLength + 1; + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + + DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + + bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; + if (sign && (value != 0.0 || !unique_zero)) { + result_builder->AddCharacter('-'); + } + + int exponent = decimal_point - 1; + if ((decimal_in_shortest_low_ <= exponent) && + (exponent < decimal_in_shortest_high_)) { + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, + decimal_point, + (std::max)(0, decimal_rep_length - decimal_point), + result_builder); + } else { + CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, + result_builder); + } + return true; +} + + +bool DoubleToStringConverter::ToFixed(double value, + int requested_digits, + StringBuilder* result_builder) const { + DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint == 60); + const double kFirstNonFixed = 1e60; + + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result_builder); + } + + if (requested_digits > kMaxFixedDigitsAfterPoint) return false; + if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; + + // Find a sufficiently precise decimal representation of n. + int decimal_point; + bool sign; + // Add space for the '\0' byte. + const int kDecimalRepCapacity = + kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + DoubleToAscii(value, FIXED, requested_digits, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + + bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); + if (sign && (value != 0.0 || !unique_zero)) { + result_builder->AddCharacter('-'); + } + + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, + requested_digits, result_builder); + return true; +} + + +bool DoubleToStringConverter::ToExponential( + double value, + int requested_digits, + StringBuilder* result_builder) const { + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result_builder); + } + + if (requested_digits < -1) return false; + if (requested_digits > kMaxExponentialDigits) return false; + + int decimal_point; + bool sign; + // Add space for digit before the decimal point and the '\0' character. + const int kDecimalRepCapacity = kMaxExponentialDigits + 2; + DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength); + char decimal_rep[kDecimalRepCapacity]; +#ifndef NDEBUG + // Problem: there is an assert in StringBuilder::AddSubstring() that + // will pass this buffer to strlen(), and this buffer is not generally + // null-terminated. + memset(decimal_rep, 0, sizeof(decimal_rep)); +#endif + int decimal_rep_length; + + if (requested_digits == -1) { + DoubleToAscii(value, SHORTEST, 0, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + } else { + DoubleToAscii(value, PRECISION, requested_digits + 1, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1); + + for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { + decimal_rep[i] = '0'; + } + decimal_rep_length = requested_digits + 1; + } + + bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); + if (sign && (value != 0.0 || !unique_zero)) { + result_builder->AddCharacter('-'); + } + + int exponent = decimal_point - 1; + CreateExponentialRepresentation(decimal_rep, + decimal_rep_length, + exponent, + result_builder); + return true; +} + + +bool DoubleToStringConverter::ToPrecision(double value, + int precision, + StringBuilder* result_builder) const { + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result_builder); + } + + if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { + return false; + } + + // Find a sufficiently precise decimal representation of n. + int decimal_point; + bool sign; + // Add one for the terminating null character. + const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + + DoubleToAscii(value, PRECISION, precision, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision); + + bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); + if (sign && (value != 0.0 || !unique_zero)) { + result_builder->AddCharacter('-'); + } + + // The exponent if we print the number as x.xxeyyy. That is with the + // decimal point after the first digit. + int exponent = decimal_point - 1; + + int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; + bool as_exponential = + (-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || + (decimal_point - precision + extra_zero > + max_trailing_padding_zeroes_in_precision_mode_); + if ((flags_ & NO_TRAILING_ZERO) != 0) { + // Truncate trailing zeros that occur after the decimal point (if exponential, + // that is everything after the first digit). + int stop = as_exponential ? 1 : std::max(1, decimal_point); + while (decimal_rep_length > stop && decimal_rep[decimal_rep_length - 1] == '0') { + --decimal_rep_length; + } + // Clamp precision to avoid the code below re-adding the zeros. + precision = std::min(precision, decimal_rep_length); + } + if (as_exponential) { + // Fill buffer to contain 'precision' digits. + // Usually the buffer is already at the correct length, but 'DoubleToAscii' + // is allowed to return less characters. + for (int i = decimal_rep_length; i < precision; ++i) { + decimal_rep[i] = '0'; + } + + CreateExponentialRepresentation(decimal_rep, + precision, + exponent, + result_builder); + } else { + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, + (std::max)(0, precision - decimal_point), + result_builder); + } + return true; +} + + +static BignumDtoaMode DtoaToBignumDtoaMode( + DoubleToStringConverter::DtoaMode dtoa_mode) { + switch (dtoa_mode) { + case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; + case DoubleToStringConverter::SHORTEST_SINGLE: + return BIGNUM_DTOA_SHORTEST_SINGLE; + case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; + case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; + default: + DOUBLE_CONVERSION_UNREACHABLE(); + } +} + + +void DoubleToStringConverter::DoubleToAscii(double v, + DtoaMode mode, + int requested_digits, + char* buffer, + int buffer_length, + bool* sign, + int* length, + int* point) { + Vector vector(buffer, buffer_length); + DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial()); + DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0); + + if (Double(v).Sign() < 0) { + *sign = true; + v = -v; + } else { + *sign = false; + } + + if (mode == PRECISION && requested_digits == 0) { + vector[0] = '\0'; + *length = 0; + return; + } + + if (v == 0) { + vector[0] = '0'; + vector[1] = '\0'; + *length = 1; + *point = 1; + return; + } + + bool fast_worked; + switch (mode) { + case SHORTEST: + fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); + break; + case SHORTEST_SINGLE: + fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0, + vector, length, point); + break; + case FIXED: + fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); + break; + case PRECISION: + fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, + vector, length, point); + break; + default: + fast_worked = false; + DOUBLE_CONVERSION_UNREACHABLE(); + } + if (fast_worked) return; + + // If the fast dtoa didn't succeed use the slower bignum version. + BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); + BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); + vector[*length] = '\0'; +} + +} // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/double-to-string.h b/deps/double-conversion/double-conversion/double-to-string.h new file mode 100644 index 00000000..04a4ac38 --- /dev/null +++ b/deps/double-conversion/double-conversion/double-to-string.h @@ -0,0 +1,445 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef DOUBLE_CONVERSION_DOUBLE_TO_STRING_H_ +#define DOUBLE_CONVERSION_DOUBLE_TO_STRING_H_ + +#include "utils.h" + +namespace double_conversion { + +class DoubleToStringConverter { + public: + // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint + // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the + // function returns false. + static const int kMaxFixedDigitsBeforePoint = 60; + static const int kMaxFixedDigitsAfterPoint = 100; + + // When calling ToExponential with a requested_digits + // parameter > kMaxExponentialDigits then the function returns false. + static const int kMaxExponentialDigits = 120; + + // When calling ToPrecision with a requested_digits + // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits + // then the function returns false. + static const int kMinPrecisionDigits = 1; + static const int kMaxPrecisionDigits = 120; + + // The maximal number of digits that are needed to emit a double in base 10. + // A higher precision can be achieved by using more digits, but the shortest + // accurate representation of any double will never use more digits than + // kBase10MaximalLength. + // Note that DoubleToAscii null-terminates its input. So the given buffer + // should be at least kBase10MaximalLength + 1 characters long. + static const int kBase10MaximalLength = 17; + + // The maximal number of digits that are needed to emit a single in base 10. + // A higher precision can be achieved by using more digits, but the shortest + // accurate representation of any single will never use more digits than + // kBase10MaximalLengthSingle. + static const int kBase10MaximalLengthSingle = 9; + + // The length of the longest string that 'ToShortest' can produce when the + // converter is instantiated with EcmaScript defaults (see + // 'EcmaScriptConverter') + // This value does not include the trailing '\0' character. + // This amount of characters is needed for negative values that hit the + // 'decimal_in_shortest_low' limit. For example: "-0.0000033333333333333333" + static const int kMaxCharsEcmaScriptShortest = 25; + + enum Flags { + NO_FLAGS = 0, + EMIT_POSITIVE_EXPONENT_SIGN = 1, + EMIT_TRAILING_DECIMAL_POINT = 2, + EMIT_TRAILING_ZERO_AFTER_POINT = 4, + UNIQUE_ZERO = 8, + NO_TRAILING_ZERO = 16 + }; + + // Flags should be a bit-or combination of the possible Flags-enum. + // - NO_FLAGS: no special flags. + // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent + // form, emits a '+' for positive exponents. Example: 1.2e+2. + // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is + // converted into decimal format then a trailing decimal point is appended. + // Example: 2345.0 is converted to "2345.". + // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point + // emits a trailing '0'-character. This flag requires the + // EMIT_TRAILING_DECIMAL_POINT flag. + // Example: 2345.0 is converted to "2345.0". + // - UNIQUE_ZERO: "-0.0" is converted to "0.0". + // - NO_TRAILING_ZERO: Trailing zeros are removed from the fractional portion + // of the result in precision mode. Matches printf's %g. + // When EMIT_TRAILING_ZERO_AFTER_POINT is also given, one trailing zero is + // preserved. + // + // Infinity symbol and nan_symbol provide the string representation for these + // special values. If the string is NULL and the special value is encountered + // then the conversion functions return false. + // + // The exponent_character is used in exponential representations. It is + // usually 'e' or 'E'. + // + // When converting to the shortest representation the converter will + // represent input numbers in decimal format if they are in the interval + // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[ + // (lower boundary included, greater boundary excluded). + // Example: with decimal_in_shortest_low = -6 and + // decimal_in_shortest_high = 21: + // ToShortest(0.000001) -> "0.000001" + // ToShortest(0.0000001) -> "1e-7" + // ToShortest(111111111111111111111.0) -> "111111111111111110000" + // ToShortest(100000000000000000000.0) -> "100000000000000000000" + // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" + // + // When converting to precision mode the converter may add + // max_leading_padding_zeroes before returning the number in exponential + // format. + // Example with max_leading_padding_zeroes_in_precision_mode = 6. + // ToPrecision(0.0000012345, 2) -> "0.0000012" + // ToPrecision(0.00000012345, 2) -> "1.2e-7" + // Similarly the converter may add up to + // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid + // returning an exponential representation. A zero added by the + // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: + // ToPrecision(230.0, 2) -> "230" + // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. + // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. + // + // The min_exponent_width is used for exponential representations. + // The converter adds leading '0's to the exponent until the exponent + // is at least min_exponent_width digits long. + // The min_exponent_width is clamped to 5. + // As such, the exponent may never have more than 5 digits in total. + DoubleToStringConverter(int flags, + const char* infinity_symbol, + const char* nan_symbol, + char exponent_character, + int decimal_in_shortest_low, + int decimal_in_shortest_high, + int max_leading_padding_zeroes_in_precision_mode, + int max_trailing_padding_zeroes_in_precision_mode, + int min_exponent_width = 0) + : flags_(flags), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol), + exponent_character_(exponent_character), + decimal_in_shortest_low_(decimal_in_shortest_low), + decimal_in_shortest_high_(decimal_in_shortest_high), + max_leading_padding_zeroes_in_precision_mode_( + max_leading_padding_zeroes_in_precision_mode), + max_trailing_padding_zeroes_in_precision_mode_( + max_trailing_padding_zeroes_in_precision_mode), + min_exponent_width_(min_exponent_width) { + // When 'trailing zero after the point' is set, then 'trailing point' + // must be set too. + DOUBLE_CONVERSION_ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || + !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); + } + + // Returns a converter following the EcmaScript specification. + // + // Flags: UNIQUE_ZERO and EMIT_POSITIVE_EXPONENT_SIGN. + // Special values: "Infinity" and "NaN". + // Lower case 'e' for exponential values. + // decimal_in_shortest_low: -6 + // decimal_in_shortest_high: 21 + // max_leading_padding_zeroes_in_precision_mode: 6 + // max_trailing_padding_zeroes_in_precision_mode: 0 + static const DoubleToStringConverter& EcmaScriptConverter(); + + // Computes the shortest string of digits that correctly represent the input + // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high + // (see constructor) it then either returns a decimal representation, or an + // exponential representation. + // Example with decimal_in_shortest_low = -6, + // decimal_in_shortest_high = 21, + // EMIT_POSITIVE_EXPONENT_SIGN activated, and + // EMIT_TRAILING_DECIMAL_POINT deactivated: + // ToShortest(0.000001) -> "0.000001" + // ToShortest(0.0000001) -> "1e-7" + // ToShortest(111111111111111111111.0) -> "111111111111111110000" + // ToShortest(100000000000000000000.0) -> "100000000000000000000" + // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21" + // + // Note: the conversion may round the output if the returned string + // is accurate enough to uniquely identify the input-number. + // For example the most precise representation of the double 9e59 equals + // "899999999999999918767229449717619953810131273674690656206848", but + // the converter will return the shorter (but still correct) "9e59". + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except when the input value is special and no infinity_symbol or + // nan_symbol has been given to the constructor. + // + // The length of the longest result is the maximum of the length of the + // following string representations (each with possible examples): + // - NaN and negative infinity: "NaN", "-Infinity", "-inf". + // - -10^(decimal_in_shortest_high - 1): + // "-100000000000000000000", "-1000000000000000.0" + // - the longest string in range [0; -10^decimal_in_shortest_low]. Generally, + // this string is 3 + kBase10MaximalLength - decimal_in_shortest_low. + // (Sign, '0', decimal point, padding zeroes for decimal_in_shortest_low, + // and the significant digits). + // "-0.0000033333333333333333", "-0.0012345678901234567" + // - the longest exponential representation. (A negative number with + // kBase10MaximalLength significant digits). + // "-1.7976931348623157e+308", "-1.7976931348623157E308" + // In addition, the buffer must be able to hold the trailing '\0' character. + bool ToShortest(double value, StringBuilder* result_builder) const { + return ToShortestIeeeNumber(value, result_builder, SHORTEST); + } + + // Same as ToShortest, but for single-precision floats. + bool ToShortestSingle(float value, StringBuilder* result_builder) const { + return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE); + } + + + // Computes a decimal representation with a fixed number of digits after the + // decimal point. The last emitted digit is rounded. + // + // Examples: + // ToFixed(3.12, 1) -> "3.1" + // ToFixed(3.1415, 3) -> "3.142" + // ToFixed(1234.56789, 4) -> "1234.5679" + // ToFixed(1.23, 5) -> "1.23000" + // ToFixed(0.1, 4) -> "0.1000" + // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00" + // ToFixed(0.1, 30) -> "0.100000000000000005551115123126" + // ToFixed(0.1, 17) -> "0.10000000000000001" + // + // If requested_digits equals 0, then the tail of the result depends on + // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT. + // Examples, for requested_digits == 0, + // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be + // - false and false: then 123.45 -> 123 + // 0.678 -> 1 + // - true and false: then 123.45 -> 123. + // 0.678 -> 1. + // - true and true: then 123.45 -> 123.0 + // 0.678 -> 1.0 + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - 'value' > 10^kMaxFixedDigitsBeforePoint, or + // - 'requested_digits' > kMaxFixedDigitsAfterPoint. + // The last two conditions imply that the result for non-special values never + // contains more than + // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters + // (one additional character for the sign, and one for the decimal point). + // In addition, the buffer must be able to hold the trailing '\0' character. + bool ToFixed(double value, + int requested_digits, + StringBuilder* result_builder) const; + + // Computes a representation in exponential format with requested_digits + // after the decimal point. The last emitted digit is rounded. + // If requested_digits equals -1, then the shortest exponential representation + // is computed. + // + // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and + // exponent_character set to 'e'. + // ToExponential(3.12, 1) -> "3.1e0" + // ToExponential(5.0, 3) -> "5.000e0" + // ToExponential(0.001, 2) -> "1.00e-3" + // ToExponential(3.1415, -1) -> "3.1415e0" + // ToExponential(3.1415, 4) -> "3.1415e0" + // ToExponential(3.1415, 3) -> "3.142e0" + // ToExponential(123456789000000, 3) -> "1.235e14" + // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30" + // ToExponential(1000000000000000019884624838656.0, 32) -> + // "1.00000000000000001988462483865600e30" + // ToExponential(1234, 0) -> "1e3" + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - 'requested_digits' > kMaxExponentialDigits. + // + // The last condition implies that the result never contains more than + // kMaxExponentialDigits + 8 characters (the sign, the digit before the + // decimal point, the decimal point, the exponent character, the + // exponent's sign, and at most 3 exponent digits). + // In addition, the buffer must be able to hold the trailing '\0' character. + bool ToExponential(double value, + int requested_digits, + StringBuilder* result_builder) const; + + + // Computes 'precision' leading digits of the given 'value' and returns them + // either in exponential or decimal format, depending on + // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the + // constructor). + // The last computed digit is rounded. + // + // Example with max_leading_padding_zeroes_in_precision_mode = 6. + // ToPrecision(0.0000012345, 2) -> "0.0000012" + // ToPrecision(0.00000012345, 2) -> "1.2e-7" + // Similarly the converter may add up to + // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid + // returning an exponential representation. A zero added by the + // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 1: + // ToPrecision(230.0, 2) -> "230" + // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT. + // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT. + // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no + // EMIT_TRAILING_ZERO_AFTER_POINT: + // ToPrecision(123450.0, 6) -> "123450" + // ToPrecision(123450.0, 5) -> "123450" + // ToPrecision(123450.0, 4) -> "123500" + // ToPrecision(123450.0, 3) -> "123000" + // ToPrecision(123450.0, 2) -> "1.2e5" + // + // Returns true if the conversion succeeds. The conversion always succeeds + // except for the following cases: + // - the input value is special and no infinity_symbol or nan_symbol has + // been provided to the constructor, + // - precision < kMinPericisionDigits + // - precision > kMaxPrecisionDigits + // + // The last condition implies that the result never contains more than + // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the + // exponent character, the exponent's sign, and at most 3 exponent digits). + // In addition, the buffer must be able to hold the trailing '\0' character. + bool ToPrecision(double value, + int precision, + StringBuilder* result_builder) const; + + enum DtoaMode { + // Produce the shortest correct representation. + // For example the output of 0.299999999999999988897 is (the less accurate + // but correct) 0.3. + SHORTEST, + // Same as SHORTEST, but for single-precision floats. + SHORTEST_SINGLE, + // Produce a fixed number of digits after the decimal point. + // For instance fixed(0.1, 4) becomes 0.1000 + // If the input number is big, the output will be big. + FIXED, + // Fixed number of digits (independent of the decimal point). + PRECISION + }; + + // 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 + // (together with the correct exponent) then reading this number will give + // 'v' again. The buffer will choose the representation that is closest to + // 'v'. If there are two at the same distance, than the one farther away + // from 0 is chosen (halfway cases - ending with 5 - are rounded up). + // In this mode the 'requested_digits' parameter is ignored. + // - SHORTEST_SINGLE: same as SHORTEST but with single-precision. + // - FIXED: produces digits necessary to print a given number with + // 'requested_digits' digits after the decimal point. The produced digits + // might be too short in which case the caller has to fill the remainder + // with '0's. + // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2. + // Halfway cases are rounded towards +/-Infinity (away from 0). The call + // toFixed(0.15, 2) thus returns buffer="2", point=0. + // The returned buffer may contain digits that would be truncated from the + // shortest representation of the input. + // - PRECISION: produces 'requested_digits' where the first digit is not '0'. + // Even though the length of produced digits usually equals + // 'requested_digits', the function is allowed to return fewer digits, in + // which case the caller has to fill the missing digits with '0's. + // Halfway cases are again rounded away from 0. + // DoubleToAscii expects the given buffer to be big enough to hold all + // digits and a terminating null-character. In SHORTEST-mode it expects a + // buffer of at least kBase10MaximalLength + 1. In all other modes the + // requested_digits parameter and the padding-zeroes limit the size of the + // output. Don't forget the decimal point, the exponent character and the + // terminating null-character when computing the maximal output size. + // The given length is only used in debug mode to ensure the buffer is big + // enough. + static void DoubleToAscii(double v, + DtoaMode mode, + int requested_digits, + char* buffer, + int buffer_length, + bool* sign, + int* length, + int* point); + + private: + // Implementation for ToShortest and ToShortestSingle. + bool ToShortestIeeeNumber(double value, + StringBuilder* result_builder, + DtoaMode mode) const; + + // If the value is a special value (NaN or Infinity) constructs the + // corresponding string using the configured infinity/nan-symbol. + // If either of them is NULL or the value is not special then the + // function returns false. + bool HandleSpecialValues(double value, StringBuilder* result_builder) const; + // Constructs an exponential representation (i.e. 1.234e56). + // The given exponent assumes a decimal point after the first decimal digit. + void CreateExponentialRepresentation(const char* decimal_digits, + int length, + int exponent, + StringBuilder* result_builder) const; + // Creates a decimal representation (i.e 1234.5678). + void CreateDecimalRepresentation(const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + StringBuilder* result_builder) const; + + const int flags_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + const char exponent_character_; + const int decimal_in_shortest_low_; + const int decimal_in_shortest_high_; + const int max_leading_padding_zeroes_in_precision_mode_; + const int max_trailing_padding_zeroes_in_precision_mode_; + const int min_exponent_width_; + + DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); +}; + +} // namespace double_conversion + +#endif // DOUBLE_CONVERSION_DOUBLE_TO_STRING_H_ diff --git a/deps/double-conversion/double-conversion/fast-dtoa.cc b/deps/double-conversion/double-conversion/fast-dtoa.cc index 2425afa3..d7a23984 100644 --- a/deps/double-conversion/double-conversion/fast-dtoa.cc +++ b/deps/double-conversion/double-conversion/fast-dtoa.cc @@ -138,7 +138,7 @@ static bool RoundWeed(Vector buffer, // Conceptually rest ~= too_high - buffer // We need to do the following tests in this order to avoid over- and // underflows. - ASSERT(rest <= unsafe_interval); + DOUBLE_CONVERSION_ASSERT(rest <= unsafe_interval); while (rest < small_distance && // Negated condition 1 unsafe_interval - rest >= ten_kappa && // Negated condition 2 (rest + ten_kappa < small_distance || // buffer{-1} > w_high @@ -184,7 +184,7 @@ static bool RoundWeedCounted(Vector buffer, uint64_t ten_kappa, uint64_t unit, int* kappa) { - ASSERT(rest < ten_kappa); + DOUBLE_CONVERSION_ASSERT(rest < ten_kappa); // The following tests are done in a specific order to avoid overflows. They // will work correctly with any uint64 values of rest < ten_kappa and unit. // @@ -232,7 +232,7 @@ static bool RoundWeedCounted(Vector buffer, // Precondition: number < (1 << (number_bits + 1)). // Inspired by the method for finding an integer log base 10 from here: -// https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 +// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 static unsigned int const kSmallPowersOfTen[] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; @@ -241,7 +241,7 @@ static void BiggestPowerTen(uint32_t number, int number_bits, uint32_t* power, int* exponent_plus_one) { - ASSERT(number < (1u << (number_bits + 1))); + DOUBLE_CONVERSION_ASSERT(number < (1u << (number_bits + 1))); // 1233/4096 is approximately 1/lg(10). int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12); // We increment to skip over the first entry in the kPowersOf10 table. @@ -303,9 +303,9 @@ static bool DigitGen(DiyFp low, Vector buffer, int* length, int* kappa) { - ASSERT(low.e() == w.e() && w.e() == high.e()); - ASSERT(low.f() + 1 <= high.f() - 1); - ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); + DOUBLE_CONVERSION_ASSERT(low.e() == w.e() && w.e() == high.e()); + DOUBLE_CONVERSION_ASSERT(low.f() + 1 <= high.f() - 1); + DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); // low, w and high are imprecise, but by less than one ulp (unit in the last // place). // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that @@ -347,7 +347,7 @@ static bool DigitGen(DiyFp low, // that is smaller than integrals. while (*kappa > 0) { int digit = integrals / divisor; - ASSERT(digit <= 9); + DOUBLE_CONVERSION_ASSERT(digit <= 9); buffer[*length] = static_cast('0' + digit); (*length)++; integrals %= divisor; @@ -374,16 +374,16 @@ static bool DigitGen(DiyFp low, // data (like the interval or 'unit'), too. // Note that the multiplication by 10 does not overflow, because w.e >= -60 // and thus one.e >= -60. - ASSERT(one.e() >= -60); - ASSERT(fractionals < one.f()); - ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); + DOUBLE_CONVERSION_ASSERT(one.e() >= -60); + DOUBLE_CONVERSION_ASSERT(fractionals < one.f()); + DOUBLE_CONVERSION_ASSERT(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); for (;;) { fractionals *= 10; unit *= 10; unsafe_interval.set_f(unsafe_interval.f() * 10); // Integer division by one. int digit = static_cast(fractionals >> -one.e()); - ASSERT(digit <= 9); + DOUBLE_CONVERSION_ASSERT(digit <= 9); buffer[*length] = static_cast('0' + digit); (*length)++; fractionals &= one.f() - 1; // Modulo by one. @@ -430,9 +430,9 @@ static bool DigitGenCounted(DiyFp w, Vector buffer, int* length, int* kappa) { - ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); - ASSERT(kMinimalTargetExponent >= -60); - ASSERT(kMaximalTargetExponent <= -32); + DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); + DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent >= -60); + DOUBLE_CONVERSION_ASSERT(kMaximalTargetExponent <= -32); // w is assumed to have an error less than 1 unit. Whenever w is scaled we // also scale its error. uint64_t w_error = 1; @@ -458,7 +458,7 @@ static bool DigitGenCounted(DiyFp w, // that is smaller than 'integrals'. while (*kappa > 0) { int digit = integrals / divisor; - ASSERT(digit <= 9); + DOUBLE_CONVERSION_ASSERT(digit <= 9); buffer[*length] = static_cast('0' + digit); (*length)++; requested_digits--; @@ -484,15 +484,15 @@ static bool DigitGenCounted(DiyFp w, // data (the 'unit'), too. // Note that the multiplication by 10 does not overflow, because w.e >= -60 // and thus one.e >= -60. - ASSERT(one.e() >= -60); - ASSERT(fractionals < one.f()); - ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); + DOUBLE_CONVERSION_ASSERT(one.e() >= -60); + DOUBLE_CONVERSION_ASSERT(fractionals < one.f()); + DOUBLE_CONVERSION_ASSERT(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); while (requested_digits > 0 && fractionals > w_error) { fractionals *= 10; w_error *= 10; // Integer division by one. int digit = static_cast(fractionals >> -one.e()); - ASSERT(digit <= 9); + DOUBLE_CONVERSION_ASSERT(digit <= 9); buffer[*length] = static_cast('0' + digit); (*length)++; requested_digits--; @@ -530,11 +530,11 @@ static bool Grisu3(double v, if (mode == FAST_DTOA_SHORTEST) { Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus); } else { - ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE); + DOUBLE_CONVERSION_ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE); float single_v = static_cast(v); Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus); } - ASSERT(boundary_plus.e() == w.e()); + DOUBLE_CONVERSION_ASSERT(boundary_plus.e() == w.e()); DiyFp ten_mk; // Cached power of ten: 10^-k int mk; // -k int ten_mk_minimal_binary_exponent = @@ -545,7 +545,7 @@ static bool Grisu3(double v, ten_mk_minimal_binary_exponent, ten_mk_maximal_binary_exponent, &ten_mk, &mk); - ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DOUBLE_CONVERSION_ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + DiyFp::kSignificandSize) && (kMaximalTargetExponent >= w.e() + ten_mk.e() + DiyFp::kSignificandSize)); @@ -559,13 +559,13 @@ static bool Grisu3(double v, // In other words: let f = scaled_w.f() and e = scaled_w.e(), then // (f-1) * 2^e < w*10^k < (f+1) * 2^e DiyFp scaled_w = DiyFp::Times(w, ten_mk); - ASSERT(scaled_w.e() == + DOUBLE_CONVERSION_ASSERT(scaled_w.e() == boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize); // In theory it would be possible to avoid some recomputations by computing // the difference between w and boundary_minus/plus (a power of 2) and to // compute scaled_boundary_minus/plus by subtracting/adding from // scaled_w. However the code becomes much less readable and the speed - // enhancements are not terriffic. + // enhancements are not terrific. DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk); DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk); @@ -573,7 +573,7 @@ static bool Grisu3(double v, // v == (double) (scaled_w * 10^-mk). // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an // integer than it will be updated. For instance if scaled_w == 1.23 then - // the buffer will be filled with "123" und the decimal_exponent will be + // the buffer will be filled with "123" and the decimal_exponent will be // decreased by 2. int kappa; bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus, @@ -604,7 +604,7 @@ static bool Grisu3Counted(double v, ten_mk_minimal_binary_exponent, ten_mk_maximal_binary_exponent, &ten_mk, &mk); - ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DOUBLE_CONVERSION_ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + DiyFp::kSignificandSize) && (kMaximalTargetExponent >= w.e() + ten_mk.e() + DiyFp::kSignificandSize)); @@ -638,8 +638,8 @@ bool FastDtoa(double v, Vector buffer, int* length, int* decimal_point) { - ASSERT(v > 0); - ASSERT(!Double(v).IsSpecial()); + DOUBLE_CONVERSION_ASSERT(v > 0); + DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial()); bool result = false; int decimal_exponent = 0; @@ -653,7 +653,7 @@ bool FastDtoa(double v, buffer, length, &decimal_exponent); break; default: - UNREACHABLE(); + DOUBLE_CONVERSION_UNREACHABLE(); } if (result) { *decimal_point = *length + decimal_exponent; diff --git a/deps/double-conversion/double-conversion/fixed-dtoa.cc b/deps/double-conversion/double-conversion/fixed-dtoa.cc index 78378c51..e739b198 100644 --- a/deps/double-conversion/double-conversion/fixed-dtoa.cc +++ b/deps/double-conversion/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 "fixed-dtoa.h" #include "ieee.h" @@ -53,11 +53,11 @@ class UInt128 { accumulator >>= 32; accumulator = accumulator + (high_bits_ >> 32) * multiplicand; high_bits_ = (accumulator << 32) + part; - ASSERT((accumulator >> 32) == 0); + DOUBLE_CONVERSION_ASSERT((accumulator >> 32) == 0); } void Shift(int shift_amount) { - ASSERT(-64 <= shift_amount && shift_amount <= 64); + DOUBLE_CONVERSION_ASSERT(-64 <= shift_amount && shift_amount <= 64); if (shift_amount == 0) { return; } else if (shift_amount == -64) { @@ -230,13 +230,13 @@ static void RoundUp(Vector buffer, int* length, int* decimal_point) { static void FillFractionals(uint64_t fractionals, int exponent, int fractional_count, Vector buffer, int* length, int* decimal_point) { - ASSERT(-128 <= exponent && exponent <= 0); + DOUBLE_CONVERSION_ASSERT(-128 <= exponent && exponent <= 0); // 'fractionals' is a fixed-point number, with binary point at bit // (-exponent). Inside the function the non-converted remainder of fractionals // is a fixed-point number, with binary point at bit 'point'. if (-exponent <= 64) { // One 64 bit number is sufficient. - ASSERT(fractionals >> 56 == 0); + DOUBLE_CONVERSION_ASSERT(fractionals >> 56 == 0); int point = -exponent; for (int i = 0; i < fractional_count; ++i) { if (fractionals == 0) break; @@ -253,17 +253,18 @@ static void FillFractionals(uint64_t fractionals, int exponent, fractionals *= 5; point--; int digit = static_cast(fractionals >> point); - ASSERT(digit <= 9); + DOUBLE_CONVERSION_ASSERT(digit <= 9); buffer[*length] = static_cast('0' + digit); (*length)++; fractionals -= static_cast(digit) << point; } // If the first bit after the point is set we have to round up. - if (((fractionals >> (point - 1)) & 1) == 1) { + DOUBLE_CONVERSION_ASSERT(fractionals == 0 || point - 1 >= 0); + if ((fractionals != 0) && ((fractionals >> (point - 1)) & 1) == 1) { RoundUp(buffer, length, decimal_point); } } else { // We need 128 bits. - ASSERT(64 < -exponent && -exponent <= 128); + DOUBLE_CONVERSION_ASSERT(64 < -exponent && -exponent <= 128); UInt128 fractionals128 = UInt128(fractionals, 0); fractionals128.Shift(-exponent - 64); int point = 128; @@ -275,7 +276,7 @@ static void FillFractionals(uint64_t fractionals, int exponent, fractionals128.Multiply(5); point--; int digit = fractionals128.DivModPowerOf2(point); - ASSERT(digit <= 9); + DOUBLE_CONVERSION_ASSERT(digit <= 9); buffer[*length] = static_cast('0' + digit); (*length)++; } @@ -334,7 +335,7 @@ bool FastFixedDtoa(double v, // The quotient delivers the first digits, and the remainder fits into a 64 // bit number. // Dividing by 10^17 is equivalent to dividing by 5^17*2^17. - const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17 + const uint64_t kFive17 = DOUBLE_CONVERSION_UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17 uint64_t divisor = kFive17; int divisor_power = 17; uint64_t dividend = significand; @@ -382,7 +383,7 @@ bool FastFixedDtoa(double v, } else if (exponent < -128) { // This configuration (with at most 20 digits) means that all digits must be // 0. - ASSERT(fractional_count <= 20); + DOUBLE_CONVERSION_ASSERT(fractional_count <= 20); buffer[0] = '\0'; *length = 0; *decimal_point = -fractional_count; @@ -394,8 +395,8 @@ bool FastFixedDtoa(double v, TrimZeros(buffer, length, decimal_point); buffer[*length] = '\0'; if ((*length) == 0) { - // The string is empty and the decimal_point thus has no importance. Mimick - // Gay's dtoa and and set it to -fractional_count. + // The string is empty and the decimal_point thus has no importance. Mimic + // Gay's dtoa and set it to -fractional_count. *decimal_point = -fractional_count; } return true; diff --git a/deps/double-conversion/double-conversion/ieee.h b/deps/double-conversion/double-conversion/ieee.h index b14cf4f7..9203f4d5 100644 --- a/deps/double-conversion/double-conversion/ieee.h +++ b/deps/double-conversion/double-conversion/ieee.h @@ -41,12 +41,15 @@ static float uint32_to_float(uint32_t d32) { return BitCast(d32); } // Helper functions for doubles. class Double { public: - static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000); - static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000); - static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); - static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000); + static const uint64_t kSignMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000); + static const uint64_t kExponentMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000); + static const uint64_t kSignificandMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + static const uint64_t kHiddenBit = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); + static const uint64_t kQuietNanBit = DOUBLE_CONVERSION_UINT64_2PART_C(0x00080000, 00000000); static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit. static const int kSignificandSize = 53; + static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; + static const int kMaxExponent = 0x7FF - kExponentBias; Double() : d64_(0) {} explicit Double(double d) : d64_(double_to_uint64(d)) {} @@ -57,14 +60,14 @@ class Double { // The value encoded by this Double must be greater or equal to +0.0. // It must not be special (infinity, or NaN). DiyFp AsDiyFp() const { - ASSERT(Sign() > 0); - ASSERT(!IsSpecial()); + DOUBLE_CONVERSION_ASSERT(Sign() > 0); + DOUBLE_CONVERSION_ASSERT(!IsSpecial()); return DiyFp(Significand(), Exponent()); } // The value encoded by this Double must be strictly greater than 0. DiyFp AsNormalizedDiyFp() const { - ASSERT(value() > 0.0); + DOUBLE_CONVERSION_ASSERT(value() > 0.0); uint64_t f = Significand(); int e = Exponent(); @@ -146,6 +149,23 @@ class Double { ((d64 & kSignificandMask) != 0); } + bool IsQuietNan() const { +#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__) + return IsNan() && ((AsUint64() & kQuietNanBit) == 0); +#else + return IsNan() && ((AsUint64() & kQuietNanBit) != 0); +#endif + } + + bool IsSignalingNan() const { +#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__) + return IsNan() && ((AsUint64() & kQuietNanBit) != 0); +#else + return IsNan() && ((AsUint64() & kQuietNanBit) == 0); +#endif + } + + bool IsInfinite() const { uint64_t d64 = AsUint64(); return ((d64 & kExponentMask) == kExponentMask) && @@ -160,7 +180,7 @@ class Double { // Precondition: the value encoded by this Double must be greater or equal // than +0.0. DiyFp UpperBoundary() const { - ASSERT(Sign() > 0); + DOUBLE_CONVERSION_ASSERT(Sign() > 0); return DiyFp(Significand() * 2 + 1, Exponent() - 1); } @@ -169,7 +189,7 @@ class Double { // exponent as m_plus. // Precondition: the value encoded by this Double must be greater than 0. void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { - ASSERT(value() > 0.0); + DOUBLE_CONVERSION_ASSERT(value() > 0.0); DiyFp v = this->AsDiyFp(); DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); DiyFp m_minus; @@ -222,11 +242,14 @@ class Double { } private: - static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; static const int kDenormalExponent = -kExponentBias + 1; - static const int kMaxExponent = 0x7FF - kExponentBias; - static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000); - static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000); + static const uint64_t kInfinity = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000); +#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__) + static const uint64_t kNaN = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF7FFFF, FFFFFFFF); +#else + static const uint64_t kNaN = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF80000, 00000000); +#endif + const uint64_t d64_; @@ -257,7 +280,7 @@ class Double { (biased_exponent << kPhysicalSignificandSize); } - DISALLOW_COPY_AND_ASSIGN(Double); + DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Double); }; class Single { @@ -266,6 +289,7 @@ class Single { static const uint32_t kExponentMask = 0x7F800000; static const uint32_t kSignificandMask = 0x007FFFFF; static const uint32_t kHiddenBit = 0x00800000; + static const uint32_t kQuietNanBit = 0x00400000; static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit. static const int kSignificandSize = 24; @@ -276,8 +300,8 @@ class Single { // The value encoded by this Single must be greater or equal to +0.0. // It must not be special (infinity, or NaN). DiyFp AsDiyFp() const { - ASSERT(Sign() > 0); - ASSERT(!IsSpecial()); + DOUBLE_CONVERSION_ASSERT(Sign() > 0); + DOUBLE_CONVERSION_ASSERT(!IsSpecial()); return DiyFp(Significand(), Exponent()); } @@ -324,6 +348,23 @@ class Single { ((d32 & kSignificandMask) != 0); } + bool IsQuietNan() const { +#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__) + return IsNan() && ((AsUint32() & kQuietNanBit) == 0); +#else + return IsNan() && ((AsUint32() & kQuietNanBit) != 0); +#endif + } + + bool IsSignalingNan() const { +#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__) + return IsNan() && ((AsUint32() & kQuietNanBit) != 0); +#else + return IsNan() && ((AsUint32() & kQuietNanBit) == 0); +#endif + } + + bool IsInfinite() const { uint32_t d32 = AsUint32(); return ((d32 & kExponentMask) == kExponentMask) && @@ -340,7 +381,7 @@ class Single { // exponent as m_plus. // Precondition: the value encoded by this Single must be greater than 0. void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { - ASSERT(value() > 0.0); + DOUBLE_CONVERSION_ASSERT(value() > 0.0); DiyFp v = this->AsDiyFp(); DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); DiyFp m_minus; @@ -358,7 +399,7 @@ class Single { // Precondition: the value encoded by this Single must be greater or equal // than +0.0. DiyFp UpperBoundary() const { - ASSERT(Sign() > 0); + DOUBLE_CONVERSION_ASSERT(Sign() > 0); return DiyFp(Significand() * 2 + 1, Exponent() - 1); } @@ -390,11 +431,15 @@ class Single { static const int kDenormalExponent = -kExponentBias + 1; static const int kMaxExponent = 0xFF - kExponentBias; static const uint32_t kInfinity = 0x7F800000; +#if (defined(__mips__) && !defined(__mips_nan2008)) || defined(__hppa__) + static const uint32_t kNaN = 0x7FBFFFFF; +#else static const uint32_t kNaN = 0x7FC00000; +#endif const uint32_t d32_; - DISALLOW_COPY_AND_ASSIGN(Single); + DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Single); }; } // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/double-conversion.cc b/deps/double-conversion/double-conversion/string-to-double.cc similarity index 54% rename from deps/double-conversion/double-conversion/double-conversion.cc rename to deps/double-conversion/double-conversion/string-to-double.cc index 6f21a012..972956ca 100644 --- a/deps/double-conversion/double-conversion/double-conversion.cc +++ b/deps/double-conversion/double-conversion/string-to-double.cc @@ -25,410 +25,79 @@ // (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 "double-conversion.h" +#include "string-to-double.h" -#include "bignum-dtoa.h" -#include "fast-dtoa.h" -#include "fixed-dtoa.h" #include "ieee.h" #include "strtod.h" #include "utils.h" -namespace double_conversion { - -const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() { - int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN; - static DoubleToStringConverter converter(flags, - "Infinity", - "NaN", - 'e', - -6, 21, - 6, 0); - return converter; -} - - -bool DoubleToStringConverter::HandleSpecialValues( - double value, - StringBuilder* result_builder) const { - Double double_inspect(value); - if (double_inspect.IsInfinite()) { - if (infinity_symbol_ == NULL) return false; - if (value < 0) { - result_builder->AddCharacter('-'); - } - result_builder->AddString(infinity_symbol_); - return true; - } - if (double_inspect.IsNan()) { - if (nan_symbol_ == NULL) return false; - result_builder->AddString(nan_symbol_); - return true; - } - return false; -} - - -void DoubleToStringConverter::CreateExponentialRepresentation( - const char* decimal_digits, - int length, - int exponent, - StringBuilder* result_builder) const { - ASSERT(length != 0); - result_builder->AddCharacter(decimal_digits[0]); - if (length != 1) { - result_builder->AddCharacter('.'); - result_builder->AddSubstring(&decimal_digits[1], length-1); - } - result_builder->AddCharacter(exponent_character_); - if (exponent < 0) { - result_builder->AddCharacter('-'); - exponent = -exponent; - } else { - if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { - result_builder->AddCharacter('+'); - } - } - if (exponent == 0) { - result_builder->AddCharacter('0'); - return; - } - ASSERT(exponent < 1e4); - const int kMaxExponentLength = 5; - char buffer[kMaxExponentLength + 1]; - buffer[kMaxExponentLength] = '\0'; - int first_char_pos = kMaxExponentLength; - while (exponent > 0) { - buffer[--first_char_pos] = '0' + (exponent % 10); - exponent /= 10; - } - result_builder->AddSubstring(&buffer[first_char_pos], - kMaxExponentLength - first_char_pos); -} - - -void DoubleToStringConverter::CreateDecimalRepresentation( - const char* decimal_digits, - int length, - int decimal_point, - int digits_after_point, - StringBuilder* result_builder) const { - // Create a representation that is padded with zeros if needed. - if (decimal_point <= 0) { - // "0.00000decimal_rep" or "0.000decimal_rep00". - result_builder->AddCharacter('0'); - if (digits_after_point > 0) { - result_builder->AddCharacter('.'); - result_builder->AddPadding('0', -decimal_point); - ASSERT(length <= digits_after_point - (-decimal_point)); - result_builder->AddSubstring(decimal_digits, length); - int remaining_digits = digits_after_point - (-decimal_point) - length; - result_builder->AddPadding('0', remaining_digits); - } - } else if (decimal_point >= length) { - // "decimal_rep0000.00000" or "decimal_rep.0000". - result_builder->AddSubstring(decimal_digits, length); - result_builder->AddPadding('0', decimal_point - length); - if (digits_after_point > 0) { - result_builder->AddCharacter('.'); - result_builder->AddPadding('0', digits_after_point); - } - } else { - // "decima.l_rep000". - ASSERT(digits_after_point > 0); - result_builder->AddSubstring(decimal_digits, decimal_point); - result_builder->AddCharacter('.'); - ASSERT(length - decimal_point <= digits_after_point); - result_builder->AddSubstring(&decimal_digits[decimal_point], - length - decimal_point); - int remaining_digits = digits_after_point - (length - decimal_point); - result_builder->AddPadding('0', remaining_digits); - } - if (digits_after_point == 0) { - if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { - result_builder->AddCharacter('.'); - } - if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { - result_builder->AddCharacter('0'); - } - } -} - - -bool DoubleToStringConverter::ToShortestIeeeNumber( - double value, - StringBuilder* result_builder, - DoubleToStringConverter::DtoaMode mode) const { - ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE); - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - int decimal_point; - bool sign; - const int kDecimalRepCapacity = kBase10MaximalLength + 1; - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - - DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - - bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - int exponent = decimal_point - 1; - if ((decimal_in_shortest_low_ <= exponent) && - (exponent < decimal_in_shortest_high_)) { - CreateDecimalRepresentation(decimal_rep, decimal_rep_length, - decimal_point, - Max(0, decimal_rep_length - decimal_point), - result_builder); - } else { - CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, - result_builder); - } - return true; -} - - -bool DoubleToStringConverter::ToFixed(double value, - int requested_digits, - StringBuilder* result_builder) const { - ASSERT(kMaxFixedDigitsBeforePoint == 60); - const double kFirstNonFixed = 1e60; +#ifdef _MSC_VER +# if _MSC_VER >= 1900 +// Fix MSVC >= 2015 (_MSC_VER == 1900) warning +// C4244: 'argument': conversion from 'const uc16' to 'char', possible loss of data +// against Advance and friends, when instantiated with **it as char, not uc16. + __pragma(warning(disable: 4244)) +# endif +# if _MSC_VER <= 1700 // VS2012, see IsDecimalDigitForRadix warning fix, below +# define VS2012_RADIXWARN +# endif +#endif - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } +namespace double_conversion { - if (requested_digits > kMaxFixedDigitsAfterPoint) return false; - if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; - - // Find a sufficiently precise decimal representation of n. - int decimal_point; - bool sign; - // Add space for the '\0' byte. - const int kDecimalRepCapacity = - kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - DoubleToAscii(value, FIXED, requested_digits, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - - bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } +namespace { - CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, - requested_digits, result_builder); - return true; +inline char ToLower(char ch) { + static const std::ctype& cType = + std::use_facet >(std::locale::classic()); + return cType.tolower(ch); } - -bool DoubleToStringConverter::ToExponential( - double value, - int requested_digits, - StringBuilder* result_builder) const { - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - if (requested_digits < -1) return false; - if (requested_digits > kMaxExponentialDigits) return false; - - int decimal_point; - bool sign; - // Add space for digit before the decimal point and the '\0' character. - const int kDecimalRepCapacity = kMaxExponentialDigits + 2; - ASSERT(kDecimalRepCapacity > kBase10MaximalLength); - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - - if (requested_digits == -1) { - DoubleToAscii(value, SHORTEST, 0, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - } else { - DoubleToAscii(value, PRECISION, requested_digits + 1, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - ASSERT(decimal_rep_length <= requested_digits + 1); - - for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { - decimal_rep[i] = '0'; - } - decimal_rep_length = requested_digits + 1; - } - - bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - int exponent = decimal_point - 1; - CreateExponentialRepresentation(decimal_rep, - decimal_rep_length, - exponent, - result_builder); - return true; +inline char Pass(char ch) { + return ch; } - -bool DoubleToStringConverter::ToPrecision(double value, - int precision, - StringBuilder* result_builder) const { - if (Double(value).IsSpecial()) { - return HandleSpecialValues(value, result_builder); - } - - if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { - return false; - } - - // Find a sufficiently precise decimal representation of n. - int decimal_point; - bool sign; - // Add one for the terminating null character. - const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; - char decimal_rep[kDecimalRepCapacity]; - int decimal_rep_length; - - DoubleToAscii(value, PRECISION, precision, - decimal_rep, kDecimalRepCapacity, - &sign, &decimal_rep_length, &decimal_point); - ASSERT(decimal_rep_length <= precision); - - bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); - if (sign && (value != 0.0 || !unique_zero)) { - result_builder->AddCharacter('-'); - } - - // The exponent if we print the number as x.xxeyyy. That is with the - // decimal point after the first digit. - int exponent = decimal_point - 1; - - int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; - if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || - (decimal_point - precision + extra_zero > - max_trailing_padding_zeroes_in_precision_mode_)) { - // Fill buffer to contain 'precision' digits. - // Usually the buffer is already at the correct length, but 'DoubleToAscii' - // is allowed to return less characters. - for (int i = decimal_rep_length; i < precision; ++i) { - decimal_rep[i] = '0'; +template +static inline bool ConsumeSubStringImpl(Iterator* current, + Iterator end, + const char* substring, + Converter converter) { + DOUBLE_CONVERSION_ASSERT(converter(**current) == *substring); + for (substring++; *substring != '\0'; substring++) { + ++*current; + if (*current == end || converter(**current) != *substring) { + return false; } - - CreateExponentialRepresentation(decimal_rep, - precision, - exponent, - result_builder); - } else { - CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, - Max(0, precision - decimal_point), - result_builder); } + ++*current; return true; } - -static BignumDtoaMode DtoaToBignumDtoaMode( - DoubleToStringConverter::DtoaMode dtoa_mode) { - switch (dtoa_mode) { - case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; - case DoubleToStringConverter::SHORTEST_SINGLE: - return BIGNUM_DTOA_SHORTEST_SINGLE; - case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; - case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; - default: - UNREACHABLE(); - } -} - - -void DoubleToStringConverter::DoubleToAscii(double v, - DtoaMode mode, - int requested_digits, - char* buffer, - int buffer_length, - bool* sign, - int* length, - int* point) { - Vector vector(buffer, buffer_length); - ASSERT(!Double(v).IsSpecial()); - ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0); - - if (Double(v).Sign() < 0) { - *sign = true; - v = -v; - } else { - *sign = false; - } - - if (mode == PRECISION && requested_digits == 0) { - vector[0] = '\0'; - *length = 0; - return; - } - - if (v == 0) { - vector[0] = '0'; - vector[1] = '\0'; - *length = 1; - *point = 1; - return; - } - - bool fast_worked; - switch (mode) { - case SHORTEST: - fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); - break; - case SHORTEST_SINGLE: - fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0, - vector, length, point); - break; - case FIXED: - fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); - break; - case PRECISION: - fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, - vector, length, point); - break; - default: - fast_worked = false; - UNREACHABLE(); - } - if (fast_worked) return; - - // If the fast dtoa didn't succeed use the slower bignum version. - BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); - BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); - vector[*length] = '\0'; -} - - // 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_insensitivity) { + if (allow_case_insensitivity) { + return ConsumeSubStringImpl(current, end, substring, ToLower); + } else { + return ConsumeSubStringImpl(current, end, substring, Pass); } - ++*current; - return true; } +// Consumes first character of the str is equal to ch +inline bool ConsumeFirstCharacter(char ch, + const char* str, + bool case_insensitivity) { + return case_insensitivity ? ToLower(ch) == str[0] : ch == str[0]; +} +} // namespace // Maximum number of significant digits in decimal representation. // The longest possible double in decimal representation is @@ -441,14 +110,14 @@ const int kMaxSignificantDigits = 772; static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 }; -static const int kWhitespaceTable7Length = ARRAY_SIZE(kWhitespaceTable7); +static const int kWhitespaceTable7Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable7); static const uc16 kWhitespaceTable16[] = { 160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279 }; -static const int kWhitespaceTable16Length = ARRAY_SIZE(kWhitespaceTable16); +static const int kWhitespaceTable16Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable16); static bool isWhitespace(int x) { @@ -492,9 +161,9 @@ static double SignedZero(bool sign) { // // The function is small and could be inlined, but VS2012 emitted a warning // because it constant-propagated the radix and concluded that the last -// condition was always true. By moving it into a separate function the -// compiler wouldn't warn anymore. -#if _MSC_VER +// condition was always true. Moving it into a separate function and +// suppressing optimisation keeps the compiler from warning. +#ifdef VS2012_RADIXWARN #pragma optimize("",off) static bool IsDecimalDigitForRadix(int c, int radix) { return '0' <= c && c <= '9' && (c - '0') < radix; @@ -502,7 +171,7 @@ static bool IsDecimalDigitForRadix(int c, int radix) { #pragma optimize("",on) #else static bool inline IsDecimalDigitForRadix(int c, int radix) { - return '0' <= c && c <= '9' && (c - '0') < radix; + return '0' <= c && c <= '9' && (c - '0') < radix; } #endif // Returns true if 'c' is a character digit that is valid for the given radix. @@ -516,17 +185,86 @@ static bool IsCharacterDigitForRadix(int c, int radix, char a_character) { return radix > 10 && c >= a_character && c < a_character + radix - 10; } +// Returns true, when the iterator is equal to end. +template +static bool Advance (Iterator* it, uc16 separator, int base, Iterator& end) { + if (separator == StringToDoubleConverter::kNoSeparator) { + ++(*it); + return *it == end; + } + if (!isDigit(**it, base)) { + ++(*it); + return *it == end; + } + ++(*it); + if (*it == end) return true; + if (*it + 1 == end) return false; + if (**it == separator && isDigit(*(*it + 1), base)) { + ++(*it); + } + return *it == end; +} + +// Checks whether the string in the range start-end is a hex-float string. +// This function assumes that the leading '0x'/'0X' is already consumed. +// +// Hex float strings are of one of the following forms: +// - hex_digits+ 'p' ('+'|'-')? exponent_digits+ +// - hex_digits* '.' hex_digits+ 'p' ('+'|'-')? exponent_digits+ +// - hex_digits+ '.' 'p' ('+'|'-')? exponent_digits+ +template +static bool IsHexFloatString(Iterator start, + Iterator end, + uc16 separator, + bool allow_trailing_junk) { + DOUBLE_CONVERSION_ASSERT(start != end); + + Iterator current = start; + + bool saw_digit = false; + while (isDigit(*current, 16)) { + saw_digit = true; + if (Advance(¤t, separator, 16, end)) return false; + } + if (*current == '.') { + if (Advance(¤t, separator, 16, end)) return false; + while (isDigit(*current, 16)) { + saw_digit = true; + if (Advance(¤t, separator, 16, end)) return false; + } + } + if (!saw_digit) return false; + if (*current != 'p' && *current != 'P') return false; + if (Advance(¤t, separator, 16, end)) return false; + if (*current == '+' || *current == '-') { + if (Advance(¤t, separator, 16, end)) return false; + } + if (!isDigit(*current, 10)) return false; + if (Advance(¤t, separator, 16, end)) return true; + while (isDigit(*current, 10)) { + if (Advance(¤t, separator, 16, end)) return true; + } + return allow_trailing_junk || !AdvanceToNonspace(¤t, end); +} + // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end. +// +// If parse_as_hex_float is true, then the string must be a valid +// hex-float. template static double RadixStringToIeee(Iterator* current, Iterator end, bool sign, + uc16 separator, + bool parse_as_hex_float, bool allow_trailing_junk, double junk_string_value, bool read_as_double, bool* result_is_junk) { - ASSERT(*current != end); + DOUBLE_CONVERSION_ASSERT(*current != end); + DOUBLE_CONVERSION_ASSERT(!parse_as_hex_float || + IsHexFloatString(*current, end, separator, allow_trailing_junk)); const int kDoubleSize = Double::kSignificandSize; const int kSingleSize = Single::kSignificandSize; @@ -534,27 +272,39 @@ static double RadixStringToIeee(Iterator* current, *result_is_junk = true; + int64_t number = 0; + int exponent = 0; + const int radix = (1 << radix_log_2); + // Whether we have encountered a '.' and are parsing the decimal digits. + // Only relevant if parse_as_hex_float is true. + bool post_decimal = false; + // Skip leading 0s. while (**current == '0') { - ++(*current); - if (*current == end) { + if (Advance(current, separator, radix, end)) { *result_is_junk = false; return SignedZero(sign); } } - int64_t number = 0; - int exponent = 0; - const int radix = (1 << radix_log_2); - - do { + while (true) { int digit; if (IsDecimalDigitForRadix(**current, radix)) { digit = static_cast(**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; + Advance(current, separator, radix, end); + DOUBLE_CONVERSION_ASSERT(*current != end); + continue; + } else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) { + break; } else { if (allow_trailing_junk || !AdvanceToNonspace(current, end)) { break; @@ -577,17 +327,26 @@ 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 (*current == end || !isDigit(**current, radix)) break; + if (Advance(current, separator, radix, end)) break; + if (parse_as_hex_float && **current == '.') { + // Just run over the '.'. We are just trying to see whether there is + // a non-zero digit somewhere. + Advance(current, separator, radix, end); + DOUBLE_CONVERSION_ASSERT(*current != end); + post_decimal = true; + } + if (!isDigit(**current, radix)) break; zero_tail = zero_tail && **current == '0'; - exponent += radix_log_2; + if (!post_decimal) exponent += radix_log_2; } - if (!allow_trailing_junk && AdvanceToNonspace(current, end)) { + if (!parse_as_hex_float && + !allow_trailing_junk && + AdvanceToNonspace(current, end)) { return junk_string_value; } @@ -609,15 +368,41 @@ 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); + DOUBLE_CONVERSION_ASSERT(number < ((int64_t)1 << kSignificandSize)); + DOUBLE_CONVERSION_ASSERT(static_cast(static_cast(number)) == number); *result_is_junk = false; - if (exponent == 0) { + if (parse_as_hex_float) { + DOUBLE_CONVERSION_ASSERT(**current == 'p' || **current == 'P'); + Advance(current, separator, radix, end); + DOUBLE_CONVERSION_ASSERT(*current != end); + bool is_negative = false; + if (**current == '+') { + Advance(current, separator, radix, end); + DOUBLE_CONVERSION_ASSERT(*current != end); + } else if (**current == '-') { + is_negative = true; + Advance(current, separator, radix, end); + DOUBLE_CONVERSION_ASSERT(*current != end); + } + int written_exponent = 0; + while (IsDecimalDigitForRadix(**current, 10)) { + // No need to read exponents if they are too big. That could potentially overflow + // the `written_exponent` variable. + if (abs(written_exponent) <= 100 * Double::kMaxExponent) { + written_exponent = 10 * written_exponent + **current - '0'; + } + if (Advance(current, separator, radix, end)) break; + } + if (is_negative) written_exponent = -written_exponent; + exponent += written_exponent; + } + + if (exponent == 0 || number == 0) { if (sign) { if (number == 0) return -0.0; number = -number; @@ -625,11 +410,11 @@ static double RadixStringToIeee(Iterator* current, return static_cast(number); } - ASSERT(number != 0); - return Double(DiyFp(number, exponent)).value(); + DOUBLE_CONVERSION_ASSERT(number != 0); + double result = Double(DiyFp(number, exponent)).value(); + return sign ? -result : result; } - template double StringToDoubleConverter::StringToIeee( Iterator input, @@ -645,6 +430,7 @@ double StringToDoubleConverter::StringToIeee( const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; + const bool allow_case_insensitivity = (flags_ & ALLOW_CASE_INSENSITIVITY) != 0; // To make sure that iterator dereferencing is valid the following // convention is used: @@ -667,11 +453,6 @@ double StringToDoubleConverter::StringToIeee( } } - // The longest form of simplified number is: "-.1eXXX\0". - const int kBufferSize = kMaxSignificantDigits + 10; - char buffer[kBufferSize]; // NOLINT: size is known at compile time. - int buffer_pos = 0; - // Exponent will be adjusted if insignificant digits of the integer part // or insignificant leading zeros of the fractional part are dropped. int exponent = 0; @@ -693,9 +474,9 @@ double StringToDoubleConverter::StringToIeee( current = next_non_space; } - if (infinity_symbol_ != NULL) { - if (*current == infinity_symbol_[0]) { - if (!ConsumeSubString(¤t, end, infinity_symbol_)) { + if (infinity_symbol_ != DOUBLE_CONVERSION_NULLPTR) { + if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensitivity)) { + if (!ConsumeSubString(¤t, end, infinity_symbol_, allow_case_insensitivity)) { return junk_string_value_; } @@ -706,15 +487,14 @@ double StringToDoubleConverter::StringToIeee( return junk_string_value_; } - ASSERT(buffer_pos == 0); *processed_characters_count = static_cast(current - input); return sign ? -Double::Infinity() : Double::Infinity(); } } - if (nan_symbol_ != NULL) { - if (*current == nan_symbol_[0]) { - if (!ConsumeSubString(¤t, end, nan_symbol_)) { + if (nan_symbol_ != DOUBLE_CONVERSION_NULLPTR) { + if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensitivity)) { + if (!ConsumeSubString(¤t, end, nan_symbol_, allow_case_insensitivity)) { return junk_string_value_; } @@ -725,7 +505,6 @@ double StringToDoubleConverter::StringToIeee( return junk_string_value_; } - ASSERT(buffer_pos == 0); *processed_characters_count = static_cast(current - input); return sign ? -Double::NaN() : Double::NaN(); } @@ -733,8 +512,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); } @@ -742,16 +520,25 @@ 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". + + if (current == end) return junk_string_value_; // "0x" + + bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) && + IsHexFloatString(current, end, separator_, allow_trailing_junk); + + if (!parse_as_hex_float && !isDigit(*current, 16)) { + return junk_string_value_; } bool result_is_junk; double result = RadixStringToIeee<4>(¤t, end, sign, + separator_, + parse_as_hex_float, allow_trailing_junk, junk_string_value_, read_as_double, @@ -765,8 +552,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); } @@ -775,10 +561,16 @@ double StringToDoubleConverter::StringToIeee( bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0; + // The longest form of simplified number is: "-.1eXXX\0". + const int kBufferSize = kMaxSignificantDigits + 10; + DOUBLE_CONVERSION_STACK_UNINITIALIZED char + buffer[kBufferSize]; // NOLINT: size is known at compile time. + int buffer_pos = 0; + // Copy significant digits of the integer part (if any) to the buffer. while (*current >= '0' && *current <= '9') { if (significant_digits < kMaxSignificantDigits) { - ASSERT(buffer_pos < kBufferSize); + DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize); buffer[buffer_pos++] = static_cast(*current); significant_digits++; // Will later check if it's an octal in the buffer. @@ -787,8 +579,7 @@ double StringToDoubleConverter::StringToIeee( nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; } octal = octal && *current < '8'; - ++current; - if (current == end) goto parsing_done; + if (Advance(¤t, separator_, 10, end)) goto parsing_done; } if (significant_digits == 0) { @@ -799,8 +590,7 @@ double StringToDoubleConverter::StringToIeee( if (octal && !allow_trailing_junk) return junk_string_value_; if (octal) goto parsing_done; - ++current; - if (current == end) { + if (Advance(¤t, separator_, 10, end)) { if (significant_digits == 0 && !leading_zero) { return junk_string_value_; } else { @@ -813,8 +603,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); } @@ -826,7 +615,7 @@ double StringToDoubleConverter::StringToIeee( // We don't emit a '.', but adjust the exponent instead. while (*current >= '0' && *current <= '9') { if (significant_digits < kMaxSignificantDigits) { - ASSERT(buffer_pos < kBufferSize); + DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize); buffer[buffer_pos++] = static_cast(*current); significant_digits++; exponent--; @@ -834,8 +623,7 @@ double StringToDoubleConverter::StringToIeee( // Ignore insignificant digits in the fractional part. nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; } - ++current; - if (current == end) goto parsing_done; + if (Advance(¤t, separator_, 10, end)) goto parsing_done; } } @@ -851,9 +639,11 @@ double StringToDoubleConverter::StringToIeee( if (*current == 'e' || *current == 'E') { if (octal && !allow_trailing_junk) return junk_string_value_; if (octal) goto parsing_done; + Iterator junk_begin = current; ++current; if (current == end) { if (allow_trailing_junk) { + current = junk_begin; goto parsing_done; } else { return junk_string_value_; @@ -865,6 +655,7 @@ double StringToDoubleConverter::StringToIeee( ++current; if (current == end) { if (allow_trailing_junk) { + current = junk_begin; goto parsing_done; } else { return junk_string_value_; @@ -874,6 +665,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_; @@ -881,7 +673,7 @@ double StringToDoubleConverter::StringToIeee( } const int max_exponent = INT_MAX / 2; - ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); + DOUBLE_CONVERSION_ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); int num = 0; do { // Check overflow. @@ -918,11 +710,13 @@ double StringToDoubleConverter::StringToIeee( result = RadixStringToIeee<3>(&start, buffer + buffer_pos, sign, + separator_, + false, // Don't parse as hex_float. allow_trailing_junk, junk_string_value_, read_as_double, &result_is_junk); - ASSERT(!result_is_junk); + DOUBLE_CONVERSION_ASSERT(!result_is_junk); *processed_characters_count = static_cast(current - input); return result; } @@ -932,14 +726,20 @@ double StringToDoubleConverter::StringToIeee( exponent--; } - ASSERT(buffer_pos < kBufferSize); + DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize); buffer[buffer_pos] = '\0'; + // Code above ensures there are no leading zeros and the buffer has fewer than + // kMaxSignificantDecimalDigits characters. Trim trailing zeros. + Vector chars(buffer, buffer_pos); + chars = TrimTrailingZeros(chars); + exponent += buffer_pos - chars.length(); + double converted; if (read_as_double) { - converted = Strtod(Vector(buffer, buffer_pos), exponent); + converted = StrtodTrimmed(chars, exponent); } else { - converted = Strtof(Vector(buffer, buffer_pos), exponent); + converted = StrtofTrimmed(chars, exponent); } *processed_characters_count = static_cast(current - input); return sign? -converted: converted; @@ -979,4 +779,40 @@ float StringToDoubleConverter::StringToFloat( processed_characters_count)); } + +template<> +double StringToDoubleConverter::StringTo( + const char* buffer, + int length, + int* processed_characters_count) const { + return StringToDouble(buffer, length, processed_characters_count); +} + + +template<> +float StringToDoubleConverter::StringTo( + const char* buffer, + int length, + int* processed_characters_count) const { + return StringToFloat(buffer, length, processed_characters_count); +} + + +template<> +double StringToDoubleConverter::StringTo( + const uc16* buffer, + int length, + int* processed_characters_count) const { + return StringToDouble(buffer, length, processed_characters_count); +} + + +template<> +float StringToDoubleConverter::StringTo( + const uc16* buffer, + int length, + int* processed_characters_count) const { + return StringToFloat(buffer, length, processed_characters_count); +} + } // namespace double_conversion diff --git a/deps/double-conversion/double-conversion/string-to-double.h b/deps/double-conversion/double-conversion/string-to-double.h new file mode 100644 index 00000000..fdf302d4 --- /dev/null +++ b/deps/double-conversion/double-conversion/string-to-double.h @@ -0,0 +1,238 @@ +// Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef DOUBLE_CONVERSION_STRING_TO_DOUBLE_H_ +#define DOUBLE_CONVERSION_STRING_TO_DOUBLE_H_ + +#include "utils.h" + +namespace double_conversion { + +class StringToDoubleConverter { + public: + // Enumeration for allowing octals and ignoring junk when converting + // strings to numbers. + enum Flags { + NO_FLAGS = 0, + ALLOW_HEX = 1, + ALLOW_OCTALS = 2, + ALLOW_TRAILING_JUNK = 4, + ALLOW_LEADING_SPACES = 8, + ALLOW_TRAILING_SPACES = 16, + ALLOW_SPACES_AFTER_SIGN = 32, + ALLOW_CASE_INSENSITIVITY = 64, + ALLOW_CASE_INSENSIBILITY = 64, // Deprecated + 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. + // Ex: StringToDouble("0x1234") -> 4660.0 + // In StringToDouble("0x1234.56") the characters ".56" are trailing + // junk. The result of the call is hence dependent on + // the ALLOW_TRAILING_JUNK flag and/or the junk value. + // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK, + // the string will not be parsed as "0" followed by junk. + // + // - ALLOW_OCTALS: recognizes the prefix "0" for octals: + // If a sequence of octal digits starts with '0', then the number is + // read as octal integer. Octal numbers may only be integers. + // Ex: StringToDouble("01234") -> 668.0 + // StringToDouble("012349") -> 12349.0 // Not a sequence of octal + // // digits. + // In StringToDouble("01234.56") the characters ".56" are trailing + // junk. The result of the call is hence dependent on + // the ALLOW_TRAILING_JUNK flag and/or the junk value. + // In StringToDouble("01234e56") the characters "e56" are trailing + // junk, too. + // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of + // a double literal. + // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces, + // new-lines, and tabs. + // - ALLOW_TRAILING_SPACES: ignore trailing whitespace. + // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign. + // Ex: StringToDouble("- 123.2") -> -123.2. + // StringToDouble("+ 123.2") -> 123.2 + // - ALLOW_CASE_INSENSITIVITY: 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 indented. + // + // 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 + // containing only spaces is converted to the 'empty_string_value', too. + // + // junk_string_value is returned when + // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not + // part of a double-literal) is found. + // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a + // double literal. + // + // infinity_symbol and nan_symbol are strings that are used to detect + // inputs that represent infinity and NaN. They can be null, in which case + // they are ignored. + // The conversion routine first reads any possible signs. Then it compares the + // following character of the input-string with the first character of + // the infinity, and nan-symbol. If either matches, the function assumes, that + // a match has been found, and expects the following input characters to match + // the remaining characters of the special-value symbol. + // This means that the following restrictions apply to special-value symbols: + // - they must not start with signs ('+', or '-'), + // - 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, + // junk_string_value = NaN, + // infinity_symbol = "infinity", + // nan_symbol = "nan": + // StringToDouble("0x1234") -> 4660.0. + // StringToDouble("0x1234K") -> 4660.0. + // StringToDouble("") -> 0.0 // empty_string_value. + // StringToDouble(" ") -> NaN // junk_string_value. + // StringToDouble(" 1") -> NaN // junk_string_value. + // StringToDouble("0x") -> NaN // junk_string_value. + // StringToDouble("-123.45") -> -123.45. + // StringToDouble("--123.45") -> NaN // junk_string_value. + // StringToDouble("123e45") -> 123e45. + // StringToDouble("123E45") -> 123e45. + // StringToDouble("123e+45") -> 123e45. + // StringToDouble("123E-45") -> 123e-45. + // StringToDouble("123e") -> 123.0 // trailing junk ignored. + // StringToDouble("123e-") -> 123.0 // trailing junk ignored. + // StringToDouble("+NaN") -> NaN // NaN string literal. + // StringToDouble("-infinity") -> -inf. // infinity literal. + // StringToDouble("Infinity") -> NaN // junk_string_value. + // + // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES, + // empty_string_value = 0.0, + // junk_string_value = NaN, + // infinity_symbol = NULL, + // nan_symbol = NULL: + // StringToDouble("0x1234") -> NaN // junk_string_value. + // StringToDouble("01234") -> 668.0. + // StringToDouble("") -> 0.0 // empty_string_value. + // StringToDouble(" ") -> 0.0 // empty_string_value. + // StringToDouble(" 1") -> 1.0 + // StringToDouble("0x") -> NaN // junk_string_value. + // StringToDouble("0123e45") -> NaN // junk_string_value. + // 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, + 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), + separator_(separator) { + } + + // Performs the conversion. + // The output parameter 'processed_characters_count' is set to the number + // of characters that have been processed to read the number. + // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included + // in the 'processed_characters_count'. Trailing junk is never included. + double StringToDouble(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble above but for 16 bit characters. + double StringToDouble(const uc16* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble but reads a float. + // Note that this is not equivalent to static_cast(StringToDouble(...)) + // due to potential double-rounding. + float StringToFloat(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToFloat above but for 16 bit characters. + float StringToFloat(const uc16* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringToDouble for T = double, and StringToFloat for T = float. + template + T StringTo(const char* buffer, + int length, + int* processed_characters_count) const; + + // Same as StringTo above but for 16 bit characters. + template + T StringTo(const uc16* buffer, + int length, + int* processed_characters_count) const; + + private: + const int flags_; + const double empty_string_value_; + const double junk_string_value_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + const uc16 separator_; + + template + double StringToIeee(Iterator start_pointer, + int length, + bool read_as_double, + int* processed_characters_count) const; + + DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); +}; + +} // namespace double_conversion + +#endif // DOUBLE_CONVERSION_STRING_TO_DOUBLE_H_ diff --git a/deps/double-conversion/double-conversion/strtod.cc b/deps/double-conversion/double-conversion/strtod.cc index 17abcbb2..5fb1b2f1 100644 --- a/deps/double-conversion/double-conversion/strtod.cc +++ b/deps/double-conversion/double-conversion/strtod.cc @@ -25,20 +25,22 @@ // (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 "strtod.h" #include "bignum.h" #include "cached-powers.h" #include "ieee.h" +#include "strtod.h" namespace double_conversion { +#if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) // 2^53 = 9007199254740992. // Any integer with at most 15 decimal digits will hence fit into a double // (which has a 53bit significand) without loss of precision. static const int kMaxExactDoubleIntegerDecimalDigits = 15; +#endif // #if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) // 2^64 = 18446744073709551616 > 10^19 static const int kMaxUint64DecimalDigits = 19; @@ -52,9 +54,10 @@ static const int kMaxDecimalPower = 309; static const int kMinDecimalPower = -324; // 2^64 = 18446744073709551616 -static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); +static const uint64_t kMaxUint64 = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); +#if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) static const double exact_powers_of_ten[] = { 1.0, // 10^0 10.0, @@ -81,7 +84,8 @@ static const double exact_powers_of_ten[] = { // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 10000000000000000000000.0 }; -static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); +static const int kExactPowersOfTenSize = DOUBLE_CONVERSION_ARRAY_SIZE(exact_powers_of_ten); +#endif // #if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) // Maximum number of significant digits in the decimal representation. // In fact the value is 772 (see conversions.cc), but to give us some margin @@ -97,17 +101,6 @@ static Vector TrimLeadingZeros(Vector buffer) { return Vector(buffer.start(), 0); } - -static Vector TrimTrailingZeros(Vector buffer) { - for (int i = buffer.length() - 1; i >= 0; --i) { - if (buffer[i] != '0') { - return buffer.SubVector(0, i + 1); - } - } - return Vector(buffer.start(), 0); -} - - static void CutToMaxSignificantDigits(Vector buffer, int exponent, char* significant_buffer, @@ -117,7 +110,7 @@ static void CutToMaxSignificantDigits(Vector buffer, } // The input buffer has been trimmed. Therefore the last digit must be // different from '0'. - ASSERT(buffer[buffer.length() - 1] != '0'); + DOUBLE_CONVERSION_ASSERT(buffer[buffer.length() - 1] != '0'); // Set the last digit to be non-zero. This is sufficient to guarantee // correct rounding. significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; @@ -138,7 +131,7 @@ static void TrimAndCut(Vector buffer, int exponent, exponent += left_trimmed.length() - right_trimmed.length(); if (right_trimmed.length() > kMaxSignificantDecimalDigits) { (void) space_size; // Mark variable as used. - ASSERT(space_size >= kMaxSignificantDecimalDigits); + DOUBLE_CONVERSION_ASSERT(space_size >= kMaxSignificantDecimalDigits); CutToMaxSignificantDigits(right_trimmed, exponent, buffer_copy_space, updated_exponent); *trimmed = Vector(buffer_copy_space, @@ -161,7 +154,7 @@ static uint64_t ReadUint64(Vector buffer, int i = 0; while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { int digit = buffer[i++] - '0'; - ASSERT(0 <= digit && digit <= 9); + DOUBLE_CONVERSION_ASSERT(0 <= digit && digit <= 9); result = 10 * result + digit; } *number_of_read_digits = i; @@ -198,14 +191,16 @@ static bool DoubleStrtod(Vector trimmed, int exponent, double* result) { #if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) + // Avoid "unused parameter" warnings + (void) trimmed; + (void) exponent; + (void) result; // On x86 the floating-point stack can be 64 or 80 bits wide. If it is // 80 bits wide (as is the case on Linux) then double-rounding occurs and the // result is not accurate. // We know that Windows32 uses 64 bits and is therefore accurate. - // 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. @@ -217,14 +212,14 @@ static bool DoubleStrtod(Vector trimmed, if (exponent < 0 && -exponent < kExactPowersOfTenSize) { // 10^-exponent fits into a double. *result = static_cast(ReadUint64(trimmed, &read_digits)); - ASSERT(read_digits == trimmed.length()); + DOUBLE_CONVERSION_ASSERT(read_digits == trimmed.length()); *result /= exact_powers_of_ten[-exponent]; return true; } if (0 <= exponent && exponent < kExactPowersOfTenSize) { // 10^exponent fits into a double. *result = static_cast(ReadUint64(trimmed, &read_digits)); - ASSERT(read_digits == trimmed.length()); + DOUBLE_CONVERSION_ASSERT(read_digits == trimmed.length()); *result *= exact_powers_of_ten[exponent]; return true; } @@ -236,34 +231,35 @@ static bool DoubleStrtod(Vector trimmed, // 10^remaining_digits. As a result the remaining exponent now fits // into a double too. *result = static_cast(ReadUint64(trimmed, &read_digits)); - ASSERT(read_digits == trimmed.length()); + DOUBLE_CONVERSION_ASSERT(read_digits == trimmed.length()); *result *= exact_powers_of_ten[remaining_digits]; *result *= exact_powers_of_ten[exponent - remaining_digits]; return true; } } return false; +#endif } // Returns 10^exponent as an exact DiyFp. // The given exponent must be in the range [1; kDecimalExponentDistance[. static DiyFp AdjustmentPowerOfTen(int exponent) { - ASSERT(0 < exponent); - ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); + DOUBLE_CONVERSION_ASSERT(0 < exponent); + DOUBLE_CONVERSION_ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); // Simply hardcode the remaining powers for the given decimal exponent // distance. - ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); + DOUBLE_CONVERSION_ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); switch (exponent) { - case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); - case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); - case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); - case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); - case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); - case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); - case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); + case 1: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xa0000000, 00000000), -60); + case 2: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xc8000000, 00000000), -57); + case 3: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xfa000000, 00000000), -54); + case 4: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x9c400000, 00000000), -50); + case 5: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xc3500000, 00000000), -47); + case 6: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xf4240000, 00000000), -44); + case 7: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x98968000, 00000000), -40); default: - UNREACHABLE(); + DOUBLE_CONVERSION_UNREACHABLE(); } } @@ -292,7 +288,7 @@ static bool DiyFpStrtod(Vector buffer, input.Normalize(); error <<= old_e - input.e(); - ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); + DOUBLE_CONVERSION_ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); if (exponent < PowersOfTenCache::kMinDecimalExponent) { *result = 0.0; return true; @@ -310,7 +306,7 @@ static bool DiyFpStrtod(Vector buffer, if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { // The product of input with the adjustment power fits into a 64 bit // integer. - ASSERT(DiyFp::kSignificandSize == 64); + DOUBLE_CONVERSION_ASSERT(DiyFp::kSignificandSize == 64); } else { // The adjustment power is exact. There is hence only an error of 0.5. error += kDenominator / 2; @@ -352,8 +348,8 @@ static bool DiyFpStrtod(Vector buffer, precision_digits_count -= shift_amount; } // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too. - ASSERT(DiyFp::kSignificandSize == 64); - ASSERT(precision_digits_count < 64); + DOUBLE_CONVERSION_ASSERT(DiyFp::kSignificandSize == 64); + DOUBLE_CONVERSION_ASSERT(precision_digits_count < 64); uint64_t one64 = 1; uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; uint64_t precision_bits = input.f() & precision_bits_mask; @@ -392,14 +388,14 @@ static bool DiyFpStrtod(Vector buffer, static int CompareBufferWithDiyFp(Vector buffer, int exponent, DiyFp diy_fp) { - ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); - ASSERT(buffer.length() + exponent > kMinDecimalPower); - ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); + DOUBLE_CONVERSION_ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); + DOUBLE_CONVERSION_ASSERT(buffer.length() + exponent > kMinDecimalPower); + DOUBLE_CONVERSION_ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); // Make sure that the Bignum will be able to hold all our numbers. // Our Bignum implementation has a separate field for exponents. Shifts will // consume at most one bigit (< 64 bits). // ln(10) == 3.3219... - ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); + DOUBLE_CONVERSION_ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); Bignum buffer_bignum; Bignum diy_fp_bignum; buffer_bignum.AssignDecimalString(buffer); @@ -445,18 +441,36 @@ static bool ComputeGuess(Vector trimmed, int exponent, return false; } -double Strtod(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; +static bool IsDigit(const char d) { + return ('0' <= d) && (d <= '9'); +} - double guess; - bool is_correct = ComputeGuess(trimmed, exponent, &guess); - if (is_correct) return guess; +static bool IsNonZeroDigit(const char d) { + return ('1' <= d) && (d <= '9'); +} + +#ifdef __has_cpp_attribute +#if __has_cpp_attribute(maybe_unused) +[[maybe_unused]] +#endif +#endif +static bool AssertTrimmedDigits(const Vector& buffer) { + for(int i = 0; i < buffer.length(); ++i) { + if(!IsDigit(buffer[i])) { + return false; + } + } + return (buffer.length() == 0) || (IsNonZeroDigit(buffer[0]) && IsNonZeroDigit(buffer[buffer.length()-1])); +} +double StrtodTrimmed(Vector trimmed, int exponent) { + DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits); + DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed)); + double guess; + const bool is_correct = ComputeGuess(trimmed, exponent, &guess); + if (is_correct) { + return guess; + } DiyFp upper_boundary = Double(guess).UpperBoundary(); int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); if (comparison < 0) { @@ -471,6 +485,39 @@ double Strtod(Vector buffer, int exponent) { } } +double Strtod(Vector buffer, int exponent) { + char copy_buffer[kMaxSignificantDecimalDigits]; + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + &trimmed, &updated_exponent); + return StrtodTrimmed(trimmed, updated_exponent); +} + +static float SanitizedDoubletof(double d) { + DOUBLE_CONVERSION_ASSERT(d >= 0.0); + // ASAN has a sanitize check that disallows casting doubles to floats if + // they are too big. + // https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks + // The behavior should be covered by IEEE 754, but some projects use this + // flag, so work around it. + float max_finite = 3.4028234663852885981170418348451692544e+38; + // The half-way point between the max-finite and infinity value. + // Since infinity has an even significand everything equal or greater than + // this value should become infinity. + double half_max_finite_infinity = + 3.40282356779733661637539395458142568448e+38; + if (d >= max_finite) { + if (d >= half_max_finite_infinity) { + return Single::Infinity(); + } else { + return max_finite; + } + } else { + return static_cast(d); + } +} + float Strtof(Vector buffer, int exponent) { char copy_buffer[kMaxSignificantDecimalDigits]; Vector trimmed; @@ -478,11 +525,17 @@ float Strtof(Vector buffer, int exponent) { TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, &trimmed, &updated_exponent); exponent = updated_exponent; + return StrtofTrimmed(trimmed, exponent); +} + +float StrtofTrimmed(Vector trimmed, int exponent) { + DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits); + DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed)); double double_guess; bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); - float float_guess = static_cast(double_guess); + float float_guess = SanitizedDoubletof(double_guess); if (float_guess == double_guess) { // This shortcut triggers for integer values. return float_guess; @@ -497,7 +550,7 @@ float Strtof(Vector buffer, int exponent) { // low-precision (3 digits): // when read from input: 123 // when rounded from high precision: 124. - // To do this we simply look at the neigbors of the correct result and see + // To do this we simply look at the neighbors of the correct result and see // if they would round to the same float. If the guess is not correct we have // to look at four values (since two different doubles could be the correct // double). @@ -505,18 +558,18 @@ 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); + DOUBLE_CONVERSION_ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); // If the guess doesn't lie near a single-precision boundary we can simply // return its float-value. @@ -524,11 +577,11 @@ float Strtof(Vector buffer, int exponent) { return float_guess; } - ASSERT((f1 != f2 && f2 == f3 && f3 == f4) || + DOUBLE_CONVERSION_ASSERT((f1 != f2 && f2 == f3 && f3 == f4) || (f1 == f2 && f2 != f3 && f3 == f4) || (f1 == f2 && f2 == f3 && f3 != f4)); - // guess and next are the two possible canditates (in the same way that + // guess and next are the two possible candidates (in the same way that // double_guess was the lower candidate for a double-precision guess). float guess = f1; float next = f4; diff --git a/deps/double-conversion/double-conversion/strtod.h b/deps/double-conversion/double-conversion/strtod.h index ed0293b8..77221fb9 100644 --- a/deps/double-conversion/double-conversion/strtod.h +++ b/deps/double-conversion/double-conversion/strtod.h @@ -40,6 +40,25 @@ double Strtod(Vector buffer, int exponent); // contain a dot or a sign. It must not start with '0', and must not be empty. float Strtof(Vector buffer, int exponent); +// Same as Strtod, but assumes that 'trimmed' is already trimmed, as if run +// through TrimAndCut. That is, 'trimmed' must have no leading or trailing +// zeros, must not be a lone zero, and must not have 'too many' digits. +double StrtodTrimmed(Vector trimmed, int exponent); + +// Same as Strtof, but assumes that 'trimmed' is already trimmed, as if run +// through TrimAndCut. That is, 'trimmed' must have no leading or trailing +// zeros, must not be a lone zero, and must not have 'too many' digits. +float StrtofTrimmed(Vector trimmed, int exponent); + +inline Vector TrimTrailingZeros(Vector buffer) { + for (int i = buffer.length() - 1; i >= 0; --i) { + if (buffer[i] != '0') { + return buffer.SubVector(0, i + 1); + } + } + return Vector(buffer.start(), 0); +} + } // namespace double_conversion #endif // DOUBLE_CONVERSION_STRTOD_H_ diff --git a/deps/double-conversion/double-conversion/utils.h b/deps/double-conversion/double-conversion/utils.h index 85b1ca48..4f4dd71b 100644 --- a/deps/double-conversion/double-conversion/utils.h +++ b/deps/double-conversion/double-conversion/utils.h @@ -28,17 +28,35 @@ #ifndef DOUBLE_CONVERSION_UTILS_H_ #define DOUBLE_CONVERSION_UTILS_H_ -#include -#include +// Use DOUBLE_CONVERSION_NON_PREFIXED_MACROS to get unprefixed macros as was +// the case in double-conversion releases prior to 3.1.6 -#include -#ifndef ASSERT -#define ASSERT(condition) \ - assert(condition); +#include +#include + +// For pre-C++11 compatibility +#if __cplusplus >= 201103L +#define DOUBLE_CONVERSION_NULLPTR nullptr +#else +#define DOUBLE_CONVERSION_NULLPTR NULL +#endif + +#include +#ifndef DOUBLE_CONVERSION_ASSERT +#define DOUBLE_CONVERSION_ASSERT(condition) \ + assert(condition) +#endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(ASSERT) +#define ASSERT DOUBLE_CONVERSION_ASSERT +#endif + +#ifndef DOUBLE_CONVERSION_UNIMPLEMENTED +#define DOUBLE_CONVERSION_UNIMPLEMENTED() (abort()) #endif -#ifndef UNIMPLEMENTED -#define UNIMPLEMENTED() (abort()) +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(UNIMPLEMENTED) +#define UNIMPLEMENTED DOUBLE_CONVERSION_UNIMPLEMENTED #endif + #ifndef DOUBLE_CONVERSION_NO_RETURN #ifdef _MSC_VER #define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn) @@ -46,16 +64,50 @@ #define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn)) #endif #endif -#ifndef UNREACHABLE +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(NO_RETURN) +#define NO_RETURN DOUBLE_CONVERSION_NO_RETURN +#endif + +#ifndef DOUBLE_CONVERSION_UNREACHABLE #ifdef _MSC_VER void DOUBLE_CONVERSION_NO_RETURN abort_noreturn(); inline void abort_noreturn() { abort(); } -#define UNREACHABLE() (abort_noreturn()) +#define DOUBLE_CONVERSION_UNREACHABLE() (abort_noreturn()) +#else +#define DOUBLE_CONVERSION_UNREACHABLE() (abort()) +#endif +#endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(UNREACHABLE) +#define UNREACHABLE DOUBLE_CONVERSION_UNREACHABLE +#endif + +// Not all compilers support __has_attribute and combining a check for both +// ifdef and __has_attribute on the same preprocessor line isn't portable. +#ifdef __has_attribute +# define DOUBLE_CONVERSION_HAS_ATTRIBUTE(x) __has_attribute(x) #else -#define UNREACHABLE() (abort()) +# define DOUBLE_CONVERSION_HAS_ATTRIBUTE(x) 0 +#endif + +#ifndef DOUBLE_CONVERSION_UNUSED +#if DOUBLE_CONVERSION_HAS_ATTRIBUTE(unused) +#define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) +#else +#define DOUBLE_CONVERSION_UNUSED #endif #endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(UNUSED) +#define UNUSED DOUBLE_CONVERSION_UNUSED +#endif +#if DOUBLE_CONVERSION_HAS_ATTRIBUTE(uninitialized) +#define DOUBLE_CONVERSION_STACK_UNINITIALIZED __attribute__((uninitialized)) +#else +#define DOUBLE_CONVERSION_STACK_UNINITIALIZED +#endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(STACK_UNINITIALIZED) +#define STACK_UNINITIALIZED DOUBLE_CONVERSION_STACK_UNINITIALIZED +#endif // Double operations detection based on target architecture. // Linux uses a 80bit wide floating point stack on x86. This induces double @@ -67,19 +119,41 @@ inline void abort_noreturn() { abort(); } // the output of the division with the expected result. (Inlining must be // disabled.) // On Linux,x86 89255e-22 != Div_double(89255.0/1e22) +// +// For example: +/* +// -- in div.c +double Div_double(double x, double y) { return x / y; } + +// -- in main.c +double Div_double(double x, double y); // Forward declaration. + +int main(int argc, char** argv) { + return Div_double(89255.0, 1e22) == 89255e-22; +} +*/ +// Run as follows ./main || echo "correct" +// +// If it prints "correct" then the architecture should be here, in the "correct" section. #if defined(_M_X64) || defined(__x86_64__) || \ - defined(__ARMEL__) || defined(__avr32__) || \ + defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \ defined(__hppa__) || defined(__ia64__) || \ defined(__mips__) || \ + defined(__loongarch__) || \ + defined(__nios2__) || defined(__ghs) || \ defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \ defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ defined(__sparc__) || defined(__sparc) || defined(__s390__) || \ defined(__SH4__) || defined(__alpha__) || \ - defined(_MIPS_ARCH_MIPS32R2) || \ - defined(__AARCH64EL__) || defined(__aarch64__) || defined(_M_ARM64) || \ - defined(__riscv) + defined(_MIPS_ARCH_MIPS32R2) || defined(__ARMEB__) ||\ + defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \ + defined(__riscv) || defined(__e2k__) || \ + defined(__or1k__) || defined(__arc__) || defined(__ARC64__) || \ + defined(__microblaze__) || defined(__XTENSA__) || \ + defined(__EMSCRIPTEN__) || defined(__wasm32__) #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) @@ -91,11 +165,8 @@ inline void abort_noreturn() { abort(); } #else #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 +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(CORRECT_DOUBLE_OPERATIONS) +#define CORRECT_DOUBLE_OPERATIONS DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS #endif #if defined(_WIN32) && !defined(__MINGW32__) @@ -120,27 +191,35 @@ typedef uint16_t uc16; // The following macro works on both 32 and 64-bit platforms. // Usage: instead of writing 0x1234567890123456 -// write UINT64_2PART_C(0x12345678,90123456); -#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) - +// write DOUBLE_CONVERSION_UINT64_2PART_C(0x12345678,90123456); +#define DOUBLE_CONVERSION_UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(UINT64_2PART_C) +#define UINT64_2PART_C DOUBLE_CONVERSION_UINT64_2PART_C +#endif -// The expression ARRAY_SIZE(a) is a compile-time constant of type +// The expression DOUBLE_CONVERSION_ARRAY_SIZE(a) is a compile-time constant of type // size_t which represents the number of elements of the given -// array. You should only use ARRAY_SIZE on statically allocated +// array. You should only use DOUBLE_CONVERSION_ARRAY_SIZE on statically allocated // arrays. -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) \ +#ifndef DOUBLE_CONVERSION_ARRAY_SIZE +#define DOUBLE_CONVERSION_ARRAY_SIZE(a) \ ((sizeof(a) / sizeof(*(a))) / \ static_cast(!(sizeof(a) % sizeof(*(a))))) #endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(ARRAY_SIZE) +#define ARRAY_SIZE DOUBLE_CONVERSION_ARRAY_SIZE +#endif // 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 DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN +#define DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) #endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(DC_DISALLOW_COPY_AND_ASSIGN) +#define DC_DISALLOW_COPY_AND_ASSIGN DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN +#endif // A macro to disallow all the implicit constructors, namely the // default constructor, copy constructor and operator= functions. @@ -148,33 +227,20 @@ 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 DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS +#define DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ TypeName(); \ - DISALLOW_COPY_AND_ASSIGN(TypeName) + DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName) +#endif +#if defined(DOUBLE_CONVERSION_NON_PREFIXED_MACROS) && !defined(DC_DISALLOW_IMPLICIT_CONSTRUCTORS) +#define DC_DISALLOW_IMPLICIT_CONSTRUCTORS DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS #endif namespace double_conversion { -static const int kCharSize = sizeof(char); - -// Returns the maximum of the two parameters. -template -static T Max(T a, T b) { - return a < b ? b : a; -} - - -// Returns the minimum of the two parameters. -template -static T Min(T a, T b) { - return a < b ? a : b; -} - - inline int StrLength(const char* string) { size_t length = strlen(string); - ASSERT(length == static_cast(static_cast(length))); + DOUBLE_CONVERSION_ASSERT(length == static_cast(static_cast(length))); return static_cast(length); } @@ -182,17 +248,17 @@ inline int StrLength(const char* string) { template class Vector { public: - Vector() : start_(NULL), length_(0) {} + Vector() : start_(DOUBLE_CONVERSION_NULLPTR), length_(0) {} Vector(T* data, int len) : start_(data), length_(len) { - ASSERT(len == 0 || (len > 0 && data != NULL)); + DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != DOUBLE_CONVERSION_NULLPTR)); } // Returns a vector using the same backing storage as this one, // spanning from and including 'from', to but not including 'to'. Vector SubVector(int from, int to) { - ASSERT(to <= length_); - ASSERT(from < to); - ASSERT(0 <= from); + DOUBLE_CONVERSION_ASSERT(to <= length_); + DOUBLE_CONVERSION_ASSERT(from < to); + DOUBLE_CONVERSION_ASSERT(0 <= from); return Vector(start() + from, to - from); } @@ -207,7 +273,7 @@ class Vector { // Access individual vector elements - checks bounds in debug mode. T& operator[](int index) const { - ASSERT(0 <= index && index < length_); + DOUBLE_CONVERSION_ASSERT(0 <= index && index < length_); return start_[index]; } @@ -215,6 +281,11 @@ class Vector { T& last() { return start_[length_ - 1]; } + void pop_back() { + DOUBLE_CONVERSION_ASSERT(!is_empty()); + --length_; + } + private: T* start_; int length_; @@ -235,7 +306,7 @@ class StringBuilder { // Get the current position in the builder. int position() const { - ASSERT(!is_finalized()); + DOUBLE_CONVERSION_ASSERT(!is_finalized()); return position_; } @@ -246,8 +317,8 @@ class StringBuilder { // 0-characters; use the Finalize() method to terminate the string // instead. void AddCharacter(char c) { - ASSERT(c != '\0'); - ASSERT(!is_finalized() && position_ < buffer_.length()); + DOUBLE_CONVERSION_ASSERT(c != '\0'); + DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length()); buffer_[position_++] = c; } @@ -260,9 +331,9 @@ class StringBuilder { // Add the first 'n' characters of the given string 's' to the // builder. The input string must have enough characters. void AddSubstring(const char* s, int n) { - ASSERT(!is_finalized() && position_ + n < buffer_.length()); - ASSERT(static_cast(n) <= strlen(s)); - memmove(&buffer_[position_], s, n * kCharSize); + DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ + n < buffer_.length()); + DOUBLE_CONVERSION_ASSERT(static_cast(n) <= strlen(s)); + memmove(&buffer_[position_], s, static_cast(n)); position_ += n; } @@ -277,13 +348,13 @@ class StringBuilder { // Finalize the string by 0-terminating it and returning the buffer. char* Finalize() { - ASSERT(!is_finalized() && position_ < buffer_.length()); + DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length()); buffer_[position_] = '\0'; // Make sure nobody managed to add a 0-character to the // buffer while building the string. - ASSERT(strlen(buffer_.start()) == static_cast(position_)); + DOUBLE_CONVERSION_ASSERT(strlen(buffer_.start()) == static_cast(position_)); position_ = -1; - ASSERT(is_finalized()); + DOUBLE_CONVERSION_ASSERT(is_finalized()); return buffer_.start(); } @@ -293,7 +364,7 @@ class StringBuilder { bool is_finalized() const { return position_ < 0; } - DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); + DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder); }; // The type-based aliasing rule allows the compiler to assume that pointers of @@ -321,11 +392,16 @@ class StringBuilder { // enough that it can no longer see that you have cast one pointer type to // another thus avoiding the warning. template -inline Dest BitCast(const Source& source) { +Dest BitCast(const Source& source) { // Compile time assertion: sizeof(Dest) == sizeof(Source) // A compile error here means your Dest and Source have different sizes. +#if __cplusplus >= 201103L + static_assert(sizeof(Dest) == sizeof(Source), + "source and destination size mismatch"); +#else DOUBLE_CONVERSION_UNUSED - typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; + typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; +#endif Dest dest; memmove(&dest, &source, sizeof(dest)); @@ -333,7 +409,7 @@ inline Dest BitCast(const Source& source) { } template -inline Dest BitCast(Source* source) { +Dest BitCast(Source* source) { return BitCast(reinterpret_cast(source)); } diff --git a/deps/double-conversion/double-conversionBuildTreeSettings.cmake.in b/deps/double-conversion/double-conversionBuildTreeSettings.cmake.in deleted file mode 100644 index f46705d6..00000000 --- a/deps/double-conversion/double-conversionBuildTreeSettings.cmake.in +++ /dev/null @@ -1,2 +0,0 @@ -set(double-conversion_INCLUDE_DIRS - "@PROJECT_SOURCE_DIR@/src") diff --git a/deps/double-conversion/double-conversionConfig.cmake.in b/deps/double-conversion/double-conversionConfig.cmake.in deleted file mode 100644 index 110df446..00000000 --- a/deps/double-conversion/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/deps/double-conversion/double-conversionConfigVersion.cmake.in b/deps/double-conversion/double-conversionConfigVersion.cmake.in deleted file mode 100644 index fc6254e9..00000000 --- a/deps/double-conversion/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() diff --git a/deps/double-conversion/msvc/double-conversion.vcxproj b/deps/double-conversion/msvc/double-conversion.vcxproj index 06c0a638..ae030222 100644 --- a/deps/double-conversion/msvc/double-conversion.vcxproj +++ b/deps/double-conversion/msvc/double-conversion.vcxproj @@ -147,24 +147,25 @@ - + - - + + - + + diff --git a/deps/double-conversion/msvc/double-conversion.vcxproj.filters b/deps/double-conversion/msvc/double-conversion.vcxproj.filters index fe58a684..3bcaddd0 100644 --- a/deps/double-conversion/msvc/double-conversion.vcxproj.filters +++ b/deps/double-conversion/msvc/double-conversion.vcxproj.filters @@ -24,19 +24,19 @@ Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files @@ -44,9 +44,6 @@ Header Files - - Header Files - Header Files @@ -71,5 +68,11 @@ Header Files + + Header Files + + + Header Files + diff --git a/deps/double-conversion/msvc/run_tests/run_tests.vcxproj b/deps/double-conversion/msvc/run_tests/run_tests.vcxproj index e2731d79..9dbda30c 100644 --- a/deps/double-conversion/msvc/run_tests/run_tests.vcxproj +++ b/deps/double-conversion/msvc/run_tests/run_tests.vcxproj @@ -109,6 +109,7 @@ _SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) false $(SolutionDir).. + /bigobj %(AdditionalOptions) Console diff --git a/deps/double-conversion/test/cctest/CMakeLists.txt b/deps/double-conversion/test/cctest/CMakeLists.txt index cdb5538a..29d93d3a 100644 --- a/deps/double-conversion/test/cctest/CMakeLists.txt +++ b/deps/double-conversion/test/cctest/CMakeLists.txt @@ -18,6 +18,9 @@ set(CCTEST_SRC add_executable(cctest ${CCTEST_SRC}) target_link_libraries(cctest double-conversion) +if(MSVC) + target_compile_options(cctest PRIVATE /bigobj) +endif() add_test(NAME test_bignum WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/deps/double-conversion/test/cctest/cctest.cc b/deps/double-conversion/test/cctest/cctest.cc index 6d85bfdf..96a4142a 100644 --- a/deps/double-conversion/test/cctest/cctest.cc +++ b/deps/double-conversion/test/cctest/cctest.cc @@ -33,6 +33,15 @@ CcTest* CcTest::last_ = NULL; +// The windows compiler doesn't like to use `strdup`, and claims it's a +// deprecated name. +// For simplicity just implement it ourselves. +static char* Strdup(const char* str) { + size_t len = strlen(str); + char* result = reinterpret_cast(malloc(len + 1)); + memcpy(result, str, len + 1); + return result; +} CcTest::CcTest(TestFunction* callback, const char* test_file, const char* test_name, const char* test_dependency, @@ -45,9 +54,9 @@ CcTest::CcTest(TestFunction* callback, const char* test_file, basename = strrchr(const_cast(test_file), '\\'); } if (!basename) { - basename = strdup(test_file); + basename = Strdup(test_file); } else { - basename = strdup(basename + 1); + basename = Strdup(basename + 1); } // Drop the extension, if there is one. char *extension = strrchr(basename, '.'); @@ -75,6 +84,17 @@ static void PrintTestList(CcTest* current) { int main(int argc, char* argv[]) { int tests_run = 0; bool print_run_count = true; + if (argc == 1) { + // Just run all the tests. + CcTest* test = CcTest::last(); + while (test != NULL) { + if (test->enabled()) { + test->Run(); + tests_run++; + } + test = test->prev(); + } + } for (int i = 1; i < argc; i++) { char* arg = argv[i]; if (strcmp(arg, "--list") == 0) { @@ -82,7 +102,7 @@ int main(int argc, char* argv[]) { print_run_count = false; } else { - char* arg_copy = strdup(arg); + char* arg_copy = Strdup(arg); char* testname = strchr(arg_copy, '/'); if (testname) { // Split the string in two by nulling the slash and then run @@ -115,7 +135,7 @@ int main(int argc, char* argv[]) { test = test->prev(); } } - delete[] arg_copy; + free(arg_copy); } } if (print_run_count && tests_run != 1) diff --git a/deps/double-conversion/test/cctest/cctest.h b/deps/double-conversion/test/cctest/cctest.h index bd157a6d..6e1848c3 100644 --- a/deps/double-conversion/test/cctest/cctest.h +++ b/deps/double-conversion/test/cctest/cctest.h @@ -30,6 +30,7 @@ #include #include +#include #include "double-conversion/utils.h" @@ -69,11 +70,43 @@ static inline void CheckHelper(const char* file, #define CHECK_EQ(a, b) CheckEqualsHelper(__FILE__, __LINE__, #a, a, #b, b) -static inline void CheckEqualsHelper(const char* file, int line, - const char* expected_source, - const char* expected, - const char* value_source, - const char* value) { +template inline void PrintfValue(T x); +template<> inline void PrintfValue(int x) { printf("%d", x); } +template<> inline void PrintfValue(unsigned int x) { printf("%u", x); } +template<> inline void PrintfValue(short x) { printf("%hd", x); } +template<> inline void PrintfValue(unsigned short x) { printf("%hu", x); } +template<> inline void PrintfValue(int64_t x) { printf("%" PRId64, x); } +template<> inline void PrintfValue(uint64_t x) { printf("%" PRIu64, x); } +template<> inline void PrintfValue(float x) { printf("%.30e", static_cast(x)); } +template<> inline void PrintfValue(double x) { printf("%.30e", x); } +template<> inline void PrintfValue(bool x) { printf("%s", x ? "true" : "false"); } + +template +inline void CheckEqualsHelper(const char* file, int line, + const char* expected_source, + T1 expected, + const char* value_source, + T2 value) { + // If expected and value are NaNs then expected != value. + if (expected != value && (expected == expected || value == value)) { + printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n", + file, line, expected_source, value_source); + printf("# Expected: "); + PrintfValue(expected); + printf("\n"); + printf("# Found: "); + PrintfValue(value); + printf("\n"); + abort(); + } +} + +template<> +inline void CheckEqualsHelper(const char* file, int line, + const char* expected_source, + const char* expected, + const char* value_source, + const char* value) { if ((expected == NULL && value != NULL) || (expected != NULL && value == NULL)) { abort(); @@ -88,36 +121,15 @@ static inline void CheckEqualsHelper(const char* file, int line, } } -static inline void CheckEqualsHelper(const char* file, int line, - const char* expected_source, - int expected, - const char* value_source, - int value) { - if (expected != value) { - printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n" - "# Expected: %d\n" - "# Found: %d\n", - file, line, expected_source, value_source, expected, value); - abort(); - } +template<> +inline void CheckEqualsHelper(const char* file, int line, + const char* expected_source, + const char* expected, + const char* value_source, + char* value) { + CheckEqualsHelper(file, line, expected_source, expected, value_source, static_cast(value)); } -static inline void CheckEqualsHelper(const char* file, int line, - const char* expected_source, - double expected, - const char* value_source, - double value) { - // If expected and value are NaNs then expected != value. - if (expected != value && (expected == expected || value == value)) { - printf("%s:%d:\n CHECK_EQ(%s, %s) failed\n" - "# Expected: %.30e\n" - "# Found: %.30e\n", - file, line, expected_source, value_source, expected, value); - abort(); - } -} - - class CcTest { public: typedef void (TestFunction)(); diff --git a/deps/double-conversion/test/cctest/checks.h b/deps/double-conversion/test/cctest/checks.h index 5ea59920..4b0a7032 100644 --- a/deps/double-conversion/test/cctest/checks.h +++ b/deps/double-conversion/test/cctest/checks.h @@ -35,21 +35,21 @@ extern "C" void V8_Fatal(const char* file, int line, const char* format, ...); void API_Fatal(const char* location, const char* format, ...); -// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during +// The FATAL, DOUBLE_CONVERSION_UNREACHABLE and DOUBLE_CONVERSION_UNIMPLEMENTED macros are useful during // development, but they should not be relied on in the final product. #ifdef DEBUG #define FATAL(msg) \ V8_Fatal(__FILE__, __LINE__, "%s", (msg)) -#define UNIMPLEMENTED() \ +#define DOUBLE_CONVERSION_UNIMPLEMENTED() \ V8_Fatal(__FILE__, __LINE__, "unimplemented code") -#define UNREACHABLE() \ +#define DOUBLE_CONVERSION_UNREACHABLE() \ V8_Fatal(__FILE__, __LINE__, "unreachable code") #else #define FATAL(msg) \ V8_Fatal("", 0, "%s", (msg)) -#define UNIMPLEMENTED() \ +#define DOUBLE_CONVERSION_UNIMPLEMENTED() \ V8_Fatal("", 0, "unimplemented code") -#define UNREACHABLE() ((void) 0) +#define DOUBLE_CONVERSION_UNREACHABLE() ((void) 0) #endif @@ -279,36 +279,36 @@ template class StaticAssertionHelper { }; SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__) -// The ASSERT macro is equivalent to CHECK except that it only +// The DOUBLE_CONVERSION_ASSERT macro is equivalent to CHECK except that it only // generates code in debug builds. #ifdef DEBUG -#define ASSERT_RESULT(expr) CHECK(expr) -#define ASSERT(condition) CHECK(condition) -#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2) -#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2) -#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2) -#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition) +#define DOUBLE_CONVERSION_ASSERT_RESULT(expr) CHECK(expr) +#define DOUBLE_CONVERSION_ASSERT(condition) CHECK(condition) +#define DOUBLE_CONVERSION_ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2) +#define DOUBLE_CONVERSION_ASSERT_NE(v1, v2) CHECK_NE(v1, v2) +#define DOUBLE_CONVERSION_ASSERT_GE(v1, v2) CHECK_GE(v1, v2) +#define SLOW_DOUBLE_CONVERSION_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition) #else -#define ASSERT_RESULT(expr) (expr) -#define ASSERT(condition) ((void) 0) -#define ASSERT_EQ(v1, v2) ((void) 0) -#define ASSERT_NE(v1, v2) ((void) 0) -#define ASSERT_GE(v1, v2) ((void) 0) -#define SLOW_ASSERT(condition) ((void) 0) +#define DOUBLE_CONVERSION_ASSERT_RESULT(expr) (expr) +#define DOUBLE_CONVERSION_ASSERT(condition) ((void) 0) +#define DOUBLE_CONVERSION_ASSERT_EQ(v1, v2) ((void) 0) +#define DOUBLE_CONVERSION_ASSERT_NE(v1, v2) ((void) 0) +#define DOUBLE_CONVERSION_ASSERT_GE(v1, v2) ((void) 0) +#define SLOW_DOUBLE_CONVERSION_ASSERT(condition) ((void) 0) #endif // Static asserts has no impact on runtime performance, so they can be // safely enabled in release mode. Moreover, the ((void) 0) expression // obeys different syntax rules than typedef's, e.g. it can't appear // inside class declaration, this leads to inconsistency between debug // and release compilation modes behaviour. -#define STATIC_ASSERT(test) STATIC_CHECK(test) +#define STATIC_DOUBLE_CONVERSION_ASSERT(test) STATIC_CHECK(test) -#define ASSERT_TAG_ALIGNED(address) \ - ASSERT((reinterpret_cast(address) & kHeapObjectTagMask) == 0) +#define DOUBLE_CONVERSION_ASSERT_TAG_ALIGNED(address) \ + DOUBLE_CONVERSION_ASSERT((reinterpret_cast(address) & kHeapObjectTagMask) == 0) -#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0) +#define DOUBLE_CONVERSION_ASSERT_SIZE_TAG_ALIGNED(size) DOUBLE_CONVERSION_ASSERT((size & kHeapObjectTagMask) == 0) -#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p) +#define DOUBLE_CONVERSION_ASSERT_NOT_NULL(p) DOUBLE_CONVERSION_ASSERT_NE(NULL, p) #endif // V8_CHECKS_H_ diff --git a/deps/double-conversion/test/cctest/test-bignum-dtoa.cc b/deps/double-conversion/test/cctest/test-bignum-dtoa.cc index 86494647..670e5c48 100644 --- a/deps/double-conversion/test/cctest/test-bignum-dtoa.cc +++ b/deps/double-conversion/test/cctest/test-bignum-dtoa.cc @@ -43,7 +43,7 @@ using namespace double_conversion; // Removes trailing '0' digits. // Can return the empty string if all digits are 0. static void TrimRepresentation(Vector representation) { - int len = strlen(representation.start()); + int len = static_cast(strlen(representation.start())); int i; for (i = len - 1; i >= 0; --i) { if (representation[i] != '0') break; @@ -191,7 +191,12 @@ TEST(BignumDtoaVariousDoubles) { CHECK_EQ("35844466", buffer.start()); CHECK_EQ(299, point); - uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000); + BignumDtoa(1e-23, BIGNUM_DTOA_SHORTEST, 0, + buffer, &length, &point); + CHECK_EQ("1", buffer.start()); + CHECK_EQ(-22, point); + + uint64_t smallest_normal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); double v = Double(smallest_normal64).value(); BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point); CHECK_EQ("22250738585072014", buffer.start()); @@ -203,7 +208,7 @@ TEST(BignumDtoaVariousDoubles) { CHECK_EQ("22250738585072013831", buffer.start()); CHECK_EQ(-307, point); - uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + uint64_t largest_denormal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); v = Double(largest_denormal64).value(); BignumDtoa(v, BIGNUM_DTOA_SHORTEST, 0, buffer, &length, &point); CHECK_EQ("2225073858507201", buffer.start()); diff --git a/deps/double-conversion/test/cctest/test-bignum.cc b/deps/double-conversion/test/cctest/test-bignum.cc index 84c4a09f..f27dbc76 100644 --- a/deps/double-conversion/test/cctest/test-bignum.cc +++ b/deps/double-conversion/test/cctest/test-bignum.cc @@ -39,12 +39,14 @@ using namespace double_conversion; static const int kBufferSize = 1024; static void AssignHexString(Bignum* bignum, const char* str) { - bignum->AssignHexString(Vector(str, strlen(str))); + int len = static_cast(strlen(str)); + bignum->AssignHexString(Vector(str, len)); } static void AssignDecimalString(Bignum* bignum, const char* str) { - bignum->AssignDecimalString(Vector(str, strlen(str))); + int len = static_cast(strlen(str)); + bignum->AssignDecimalString(Vector(str, len)); } @@ -81,12 +83,12 @@ TEST(Assign) { CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("12345678", buffer); - uint64_t big = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); + uint64_t big = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); bignum.AssignUInt64(big); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("FFFFFFFFFFFFFFFF", buffer); - big = UINT64_2PART_C(0x12345678, 9ABCDEF0); + big = DOUBLE_CONVERSION_UINT64_2PART_C(0x12345678, 9ABCDEF0); bignum.AssignUInt64(big); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("123456789ABCDEF0", buffer); @@ -206,49 +208,49 @@ TEST(AddUInt64) { CHECK_EQ("1000000000000000000000FFFF", buffer); AssignHexString(&bignum, "0"); - bignum.AddUInt64(UINT64_2PART_C(0xA, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xA, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("A00000000", buffer); AssignHexString(&bignum, "1"); - bignum.AddUInt64(UINT64_2PART_C(0xA, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xA, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("A00000001", buffer); AssignHexString(&bignum, "1"); - bignum.AddUInt64(UINT64_2PART_C(0x100, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0x100, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("10000000001", buffer); AssignHexString(&bignum, "1"); - bignum.AddUInt64(UINT64_2PART_C(0xFFFF, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFF, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("FFFF00000001", buffer); AssignHexString(&bignum, "FFFFFFF"); - bignum.AddUInt64(UINT64_2PART_C(0x1, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0x1, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("10FFFFFFF", buffer); AssignHexString(&bignum, "10000000000000000000000000000000000000000000"); - bignum.AddUInt64(UINT64_2PART_C(0xFFFF, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFF, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("10000000000000000000000000000000FFFF00000000", buffer); AssignHexString(&bignum, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); - bignum.AddUInt64(UINT64_2PART_C(0x1, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0x1, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("1000000000000000000000000000000000000FFFFFFFF", buffer); bignum.AssignUInt16(0x1); bignum.ShiftLeft(100); - bignum.AddUInt64(UINT64_2PART_C(0x1, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0x1, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("10000000000000000100000000", buffer); bignum.AssignUInt16(0x1); bignum.ShiftLeft(100); - bignum.AddUInt64(UINT64_2PART_C(0xFFFF, 00000000)); + bignum.AddUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFF, 00000000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("10000000000000FFFF00000000", buffer); } @@ -314,9 +316,13 @@ TEST(AddBignum) { CHECK_EQ("10000000000001000000000000", buffer); other.ShiftLeft(64); - // other == "10000000000000000000000000000" + CHECK(other.ToHexString(buffer, kBufferSize)); + CHECK_EQ("10000000000000000000000000000", buffer); bignum.AssignUInt16(0x1); + CHECK(bignum.ToHexString(buffer, kBufferSize)); + CHECK_EQ("1", buffer); + bignum.AddBignum(other); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("10000000000000000000000000001", buffer); @@ -570,7 +576,7 @@ TEST(MultiplyUInt64) { CHECK_EQ("FFFF00000000000000", buffer); AssignHexString(&bignum, "100000000000000"); - bignum.MultiplyByUInt64(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF)); + bignum.MultiplyByUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("FFFFFFFFFFFFFFFF00000000000000", buffer); @@ -580,7 +586,7 @@ TEST(MultiplyUInt64) { CHECK_EQ("12333335552433", buffer); AssignHexString(&bignum, "1234567ABCD"); - bignum.MultiplyByUInt64(UINT64_2PART_C(0xFF, FFFFFFFF)); + bignum.MultiplyByUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFF, FFFFFFFF)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("1234567ABCBDCBA985433", buffer); @@ -600,7 +606,7 @@ TEST(MultiplyUInt64) { CHECK_EQ("EFFFFFFFFFFFFFFF1", buffer); AssignHexString(&bignum, "FFFFFFFFFFFFFFFF"); - bignum.MultiplyByUInt64(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF)); + bignum.MultiplyByUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("FFFFFFFFFFFFFFFE0000000000000001", buffer); @@ -635,12 +641,12 @@ TEST(MultiplyUInt64) { bignum.AssignUInt16(0xFFFF); bignum.ShiftLeft(100); // "FFFF0 0000 0000 0000 0000 0000 0000" - bignum.MultiplyByUInt64(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF)); + bignum.MultiplyByUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("FFFEFFFFFFFFFFFF00010000000000000000000000000", buffer); AssignDecimalString(&bignum, "15611230384529777"); - bignum.MultiplyByUInt64(UINT64_2PART_C(0x8ac72304, 89e80000)); + bignum.MultiplyByUInt64(DOUBLE_CONVERSION_UINT64_2PART_C(0x8ac72304, 89e80000)); CHECK(bignum.ToHexString(buffer, kBufferSize)); CHECK_EQ("1E10EE4B11D15A7F3DE7F3C7680000", buffer); } diff --git a/deps/double-conversion/test/cctest/test-conversions.cc b/deps/double-conversion/test/cctest/test-conversions.cc index 42bca876..00b8926c 100644 --- a/deps/double-conversion/test/cctest/test-conversions.cc +++ b/deps/double-conversion/test/cctest/test-conversions.cc @@ -1,4 +1,29 @@ // Copyright 2012 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 @@ -35,6 +60,10 @@ TEST(DoubleToShortest) { CHECK(dc.ToShortest(1e21, &builder)); CHECK_EQ("1e+21", builder.Finalize()); + builder.Reset(); + CHECK(dc.ToShortest(1e-23, &builder)); + CHECK_EQ("1e-23", builder.Finalize()); + builder.Reset(); CHECK(dc.ToShortest(1e20, &builder)); CHECK_EQ("100000000000000000000", builder.Finalize()); @@ -67,6 +96,90 @@ TEST(DoubleToShortest) { CHECK(dc.ToShortest(-0.0, &builder)); CHECK_EQ("0", builder.Finalize()); + // Test min_exponent_width + flags = DoubleToStringConverter::UNIQUE_ZERO | + DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; + DoubleToStringConverter dcExpWidth2(flags, NULL, NULL, 'e', -4, 6, 0, 0, 2); + + builder.Reset(); + CHECK(dcExpWidth2.ToShortest(11111111111.0, &builder)); + CHECK_EQ("1.1111111111e+10", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth2.ToShortest(1111111111.0, &builder)); + CHECK_EQ("1.111111111e+09", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth2.ToShortest(1111111.0, &builder)); + CHECK_EQ("1.111111e+06", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth2.ToShortest(111111.0, &builder)); + CHECK_EQ("111111", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth2.ToShortest(10000000000.0, &builder)); + CHECK_EQ("1e+10", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth2.ToShortest(1000000000.0, &builder)); + CHECK_EQ("1e+09", builder.Finalize()); + + DoubleToStringConverter dcExpWidth0(flags, NULL, NULL, 'e', -4, 6, 0, 0, 0); + + builder.Reset(); + CHECK(dcExpWidth0.ToShortest(11111111111.0, &builder)); + CHECK_EQ("1.1111111111e+10", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth0.ToShortest(1111111111.0, &builder)); + CHECK_EQ("1.111111111e+9", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth0.ToShortest(1111111.0, &builder)); + CHECK_EQ("1.111111e+6", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth0.ToShortest(111111.0, &builder)); + CHECK_EQ("111111", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth0.ToShortest(10000000000.0, &builder)); + CHECK_EQ("1e+10", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth0.ToShortest(1000000000.0, &builder)); + CHECK_EQ("1e+9", builder.Finalize()); + + // Set min_exponent_width to 100 is equal to 5, + // as kMaxExponentLength is defined to 5 in double-to-string.cc + DoubleToStringConverter dcExpWidth100(flags, NULL, NULL, 'e', -4, 6, 0, 0, 100); + + builder.Reset(); + CHECK(dcExpWidth100.ToShortest(11111111111.0, &builder)); + CHECK_EQ("1.1111111111e+00010", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth100.ToShortest(1111111111.0, &builder)); + CHECK_EQ("1.111111111e+00009", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth100.ToShortest(1111111.0, &builder)); + CHECK_EQ("1.111111e+00006", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth100.ToShortest(111111.0, &builder)); + CHECK_EQ("111111", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth100.ToShortest(10000000000.0, &builder)); + CHECK_EQ("1e+00010", builder.Finalize()); + + builder.Reset(); + CHECK(dcExpWidth100.ToShortest(1000000000.0, &builder)); + CHECK_EQ("1e+00009", builder.Finalize()); + // End of min_exponent_width testing + flags = DoubleToStringConverter::NO_FLAGS; DoubleToStringConverter dc2(flags, NULL, NULL, 'e', -1, 1, 0, 0); builder.Reset(); @@ -325,7 +438,7 @@ TEST(DoubleToShortestSingle) { TEST(DoubleToFixed) { - const int kBufferSize = 128; + const int kBufferSize = 168; char buffer[kBufferSize]; StringBuilder builder(buffer, kBufferSize); int flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | @@ -348,26 +461,99 @@ TEST(DoubleToFixed) { CHECK(dc.ToFixed(-0.0, 1, &builder)); CHECK_EQ("0.0", builder.Finalize()); - ASSERT(DoubleToStringConverter::kMaxFixedDigitsBeforePoint == 60); - ASSERT(DoubleToStringConverter::kMaxFixedDigitsAfterPoint == 60); + DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxFixedDigitsBeforePoint == 60); + DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxFixedDigitsAfterPoint == 100); + + // Most of the 100 digit tests were copied from + // https://searchfox.org/mozilla-central/source/js/src/tests/non262/Number/toFixed-values.js. + builder.Reset(); CHECK(dc.ToFixed( 0.0, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder)); - CHECK_EQ("0.000000000000000000000000000000000000000000000000000000000000", + CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", builder.Finalize()); builder.Reset(); CHECK(dc.ToFixed( 9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder)); CHECK_EQ("899999999999999918767229449717619953810131273674690656206848." - "000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", builder.Finalize()); builder.Reset(); CHECK(dc.ToFixed( -9e59, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder)); CHECK_EQ("-899999999999999918767229449717619953810131273674690656206848." - "000000000000000000000000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed( + 1e-100, DoubleToStringConverter::kMaxFixedDigitsAfterPoint, &builder)); + CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(0.3000000000000000444089209850062616169452667236328125, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("0.3000000000000000444089209850062616169452667236328125000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(1.5e-100, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(1.15e-99, // In reality: 1.14999999999999992147301128036734... + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(3.141592653589793, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(1.0, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(-123456.78, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("-123456.7799999999988358467817306518554687500000000000000000000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(123456.78, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("123456.7799999999988358467817306518554687500000000000000000000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(100000000000000000000.0, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("100000000000000000000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + builder.Finalize()); + + builder.Reset(); + CHECK(dc.ToFixed(-100000000000000000000.0, + DoubleToStringConverter::kMaxFixedDigitsAfterPoint, + &builder)); + CHECK_EQ("-100000000000000000000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", builder.Finalize()); builder.Reset(); @@ -524,6 +710,10 @@ TEST(DoubleToFixed) { CHECK(dc5.ToFixed(0.1, 30, &builder)); CHECK_EQ("0.100000000000000005551115123126", builder.Finalize()); + builder.Reset(); + CHECK(dc5.ToFixed(0.1, 100, &builder)); + CHECK_EQ("0.1000000000000000055511151231257827021181583404541015625000000000000000000000000000000000000000000000", builder.Finalize()); + builder.Reset(); CHECK(dc5.ToFixed(0.1, 17, &builder)); CHECK_EQ("0.10000000000000001", builder.Finalize()); @@ -634,7 +824,7 @@ TEST(DoubleToExponential) { CHECK(dc.ToExponential(-0.0, 2, &builder)); CHECK_EQ("0.00e+0", builder.Finalize()); - ASSERT(DoubleToStringConverter::kMaxExponentialDigits == 120); + DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxExponentialDigits == 120); builder.Reset(); CHECK(dc.ToExponential( 0.0, DoubleToStringConverter::kMaxExponentialDigits, &builder)); @@ -748,6 +938,33 @@ TEST(DoubleToExponential) { builder.Reset(); CHECK(dc4.ToExponential(-Double::NaN(), 1, &builder)); CHECK_EQ("NaN", builder.Finalize()); + + // Test min_exponent_width + DoubleToStringConverter dc5(flags, NULL, NULL, 'e', 0, 0, 0, 0, 2); + + builder.Reset(); + CHECK(dc5.ToExponential(11111111111.0, 6, &builder)); + CHECK_EQ("1.111111e10", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToExponential(1111111111.0, 6, &builder)); + CHECK_EQ("1.111111e09", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToExponential(1111111.0, 6, &builder)); + CHECK_EQ("1.111111e06", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToExponential(10000000000.0, 6, &builder)); + CHECK_EQ("1.000000e10", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToExponential(1000000000.0, 6, &builder)); + CHECK_EQ("1.000000e09", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToExponential(1.0, 6, &builder)); + CHECK_EQ("1.000000e00", builder.Finalize()); } @@ -761,7 +978,7 @@ TEST(DoubleToPrecision) { 0, 0, // Padding zeroes for shortest mode. 6, 0); // Padding zeroes for precision mode. - ASSERT(DoubleToStringConverter::kMinPrecisionDigits == 1); + DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMinPrecisionDigits == 1); CHECK(dc.ToPrecision(0.0, 1, &builder)); CHECK_EQ("0", builder.Finalize()); @@ -777,7 +994,7 @@ TEST(DoubleToPrecision) { CHECK(dc.ToPrecision(-0.0, 2, &builder)); CHECK_EQ("0.0", builder.Finalize()); - ASSERT(DoubleToStringConverter::kMaxPrecisionDigits == 120); + DOUBLE_CONVERSION_ASSERT(DoubleToStringConverter::kMaxPrecisionDigits == 120); builder.Reset(); CHECK(dc.ToPrecision( 0.0, DoubleToStringConverter::kMaxPrecisionDigits, &builder)); @@ -950,6 +1167,98 @@ TEST(DoubleToPrecision) { builder.Reset(); CHECK(dc7.ToPrecision(-Double::NaN(), 1, &builder)); CHECK_EQ("NaN", builder.Finalize()); + + // Test NO_TRAILING_ZERO and its interaction with other flags. + flags = DoubleToStringConverter::NO_TRAILING_ZERO; + DoubleToStringConverter dc9(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1); + flags = DoubleToStringConverter::NO_TRAILING_ZERO | + DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT; + DoubleToStringConverter dc10(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1); + flags = DoubleToStringConverter::NO_TRAILING_ZERO | + DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | + DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT; + DoubleToStringConverter dc11(flags, "Infinity", "NaN", 'e', 0, 0, 6, 1); + + builder.Reset(); + CHECK(dc9.ToPrecision(230.001, 5, &builder)); + CHECK_EQ("230", builder.Finalize()); + + builder.Reset(); + CHECK(dc10.ToPrecision(230.001, 5, &builder)); + CHECK_EQ("230.", builder.Finalize()); + + builder.Reset(); + CHECK(dc11.ToPrecision(230.001, 5, &builder)); + CHECK_EQ("230.0", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToPrecision(230.001, 5, &builder)); + CHECK_EQ("230.00", builder.Finalize()); + + builder.Reset(); + CHECK(dc9.ToPrecision(2300010, 5, &builder)); + CHECK_EQ("2.3e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc10.ToPrecision(2300010, 5, &builder)); + CHECK_EQ("2.3e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc11.ToPrecision(2300010, 5, &builder)); + CHECK_EQ("2.3e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToPrecision(2300010, 5, &builder)); + CHECK_EQ("2.3000e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc9.ToPrecision(0.02300010, 5, &builder)); + CHECK_EQ("0.023", builder.Finalize()); + + builder.Reset(); + CHECK(dc10.ToPrecision(0.02300010, 5, &builder)); + CHECK_EQ("0.023", builder.Finalize()); + + builder.Reset(); + CHECK(dc11.ToPrecision(0.02300010, 5, &builder)); + CHECK_EQ("0.023", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToPrecision(0.02300010, 5, &builder)); + CHECK_EQ("0.023000", builder.Finalize()); + + builder.Reset(); + CHECK(dc9.ToPrecision(2000010, 5, &builder)); + CHECK_EQ("2e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc10.ToPrecision(2000010, 5, &builder)); + CHECK_EQ("2e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc11.ToPrecision(2000010, 5, &builder)); + CHECK_EQ("2e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToPrecision(2000010, 5, &builder)); + CHECK_EQ("2.0000e6", builder.Finalize()); + + // Test that rounding up still works with NO_TRAILING_ZERO + builder.Reset(); + CHECK(dc9.ToPrecision(2000080, 5, &builder)); + CHECK_EQ("2.0001e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc10.ToPrecision(2000080, 5, &builder)); + CHECK_EQ("2.0001e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc11.ToPrecision(2000080, 5, &builder)); + CHECK_EQ("2.0001e6", builder.Finalize()); + + builder.Reset(); + CHECK(dc5.ToPrecision(2000080, 5, &builder)); + CHECK_EQ("2.0001e6", builder.Finalize()); } @@ -1720,9 +2029,37 @@ 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); + return result; +} + + +static double StrToD16(const char* str, int flags, + double empty_string_value, + int* processed_characters_count, bool* processed_all, + char char_separator, uc16 separator) { + uc16 str16[256]; + int length = -1; + for (int i = 0;; i++) { + if (str[i] == char_separator) { + str16[i] = separator; + } else { + str16[i] = str[i]; + } + if (str[i] == '\0') { + length = i; + break; + } + } + DOUBLE_CONVERSION_ASSERT(length < 256); + StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(), + NULL, NULL, separator); double result = converter.StringToDouble(str16, length, processed_characters_count); *processed_all = (length == *processed_characters_count); @@ -1731,24 +2068,26 @@ 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); - double result = converter.StringToDouble(str, strlen(str), + NULL, NULL, separator); + int len = static_cast(strlen(str)); + double result = converter.StringToDouble(str, len, processed_characters_count); *processed_all = ((strlen(str) == static_cast(*processed_characters_count))); uc16 buffer16[256]; - ASSERT(strlen(str) < ARRAY_SIZE(buffer16)); - int len = strlen(str); + DOUBLE_CONVERSION_ASSERT(strlen(str) < DOUBLE_CONVERSION_ARRAY_SIZE(buffer16)); for (int i = 0; i < len; i++) { buffer16[i] = str[i]; } int processed_characters_count16; bool processed_all16; double result16 = StrToD16(buffer16, len, flags, empty_string_value, - &processed_characters_count16, &processed_all16); + &processed_characters_count16, &processed_all16, + separator); CHECK_EQ(result, result16); CHECK_EQ(*processed_characters_count, processed_characters_count16); return result; @@ -1804,6 +2143,18 @@ TEST(StringToDoubleVarious) { CHECK_EQ(0, processed); + flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK; + + CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used)); + CHECK_EQ(processed, 3); + + CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used)); + CHECK_EQ(processed, 3); + + CHECK_EQ(123.0, StrToD("123e-a", flags, 0.0, &processed, &all_used)); + CHECK_EQ(processed, 3); + + flags = StringToDoubleConverter::ALLOW_LEADING_SPACES | StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN | StringToDoubleConverter::ALLOW_TRAILING_SPACES | @@ -2514,154 +2865,341 @@ TEST(StringToDoubleHexString) { CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0, &processed, &all_used)); CHECK_EQ(0, processed); -} - -TEST(StringToDoubleOctalString) { - int flags; - int processed; - bool all_used; - - flags = StringToDoubleConverter::ALLOW_OCTALS | - StringToDoubleConverter::ALLOW_LEADING_SPACES | - StringToDoubleConverter::ALLOW_TRAILING_SPACES | - StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN; - - CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used)); + CHECK_EQ(-5.634002666912405e+27, StrToD("-0x123456789012345678901234", + flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used)); + CHECK_EQ(72057594037927940.0, StrToD("0x100000000000001", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used)); + CHECK_EQ(72057594037927940.0, StrToD("0x100000000000000", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(123456789.0, - StrToD("0123456789", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000001", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000000", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("+01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352900000.0, StrToD("0x100000000000008001", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD("-01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000008000", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD(" 012", flags, 0.0, &processed, &all_used)); + CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018001", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD("\n012", flags, 0.0, &processed, &all_used)); + CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018000", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(0.0, StrToD(" 00", flags, 1.0, &processed, &all_used)); - CHECK(all_used); + flags = StringToDoubleConverter::ALLOW_HEX_FLOATS; - CHECK_EQ(0.0, StrToD("\t00", flags, 1.0, &processed, &all_used)); + CHECK_EQ(3.0, StrToD("0x3p0", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD(" 012", flags, 1.0, &processed, &all_used)); + CHECK_EQ(0.0, StrToD("0x.0p0", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD("\n012", flags, 1.0, &processed, &all_used)); + CHECK_EQ(3.0, StrToD("0x3.0p0", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(123456789.0, - StrToD(" 0123456789", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(3.0, StrToD("0x3.p0", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD(" 01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(-5.634002666912405e+27, StrToD("-0x123456789012345678901234p0", + flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("\n01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(72057594037927940.0, StrToD("0x100000000000001p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD(" + 01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(72057594037927940.0, StrToD("0x100000000000000p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD(" - 01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000001p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD("\n-\t01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000000000p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD(" 012 ", flags, 0.0, &processed, &all_used)); + CHECK_EQ(295147905179352900000.0, StrToD("0x100000000000008001p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(0.0, StrToD(" 00 ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(295147905179352830000.0, StrToD("0x100000000000008000p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD(" 012 ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018001p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(123456789.0, - StrToD(" 0123456789 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(295147905179352960000.0, StrToD("0x100000000000018000p0", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD(" 01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(4.722366482869645e+21, StrToD("0x100000000000000001p4", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD(" + 01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(4.722366482869645e+21, StrToD("0x100000000000000000p+4", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD(" - 01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(4.722366482869646e+21, StrToD("0x100000000000008001p04", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD("012 ", flags, 0.0, &processed, &all_used)); + CHECK_EQ(18446744073709552000.0, StrToD("0x100000000000008000p-4", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(18446744073709560000.0, StrToD("0x100000000000018001p-04", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(10.0, StrToD("012 ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(4.722366482869647e+21, StrToD("0x100000000000018000p4", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(123456789.0, - StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(Double::Infinity(), StrToD("0x1p2000", flags, 0.0, + &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(0.0, StrToD("0x1p-2000", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("+01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(-0.0, StrToD("-0x1p-2000", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD("-01234567", flags, Double::NaN(), &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(), + &processed, &all_used)); + CHECK_EQ(0, processed); - CHECK_EQ(Double::NaN(), - StrToD("01234567e0", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0, + &processed, &all_used)); CHECK_EQ(0, processed); + CHECK_EQ(Double::NaN(), StrToD(" 0x ", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); - flags = StringToDoubleConverter::ALLOW_OCTALS; - CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(Double::NaN(), StrToD(" 0x 3", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); - CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(Double::NaN(), StrToD("0x3g", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); - CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); - CHECK_EQ(123456789.0, - StrToD("0123456789", flags, Double::NaN(), &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(Double::NaN(), StrToD("0x3 foo", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD(" 0x3 foo", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("+ 0x3 foo", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("+", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("-", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("- -0x5", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("- +0x5", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("+ +0x5", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("0xp1", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), StrToD("0x.p1", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::Infinity(), StrToD("0x1.p10000000000000000", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD("0x1.p-10000000000000000", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); +} + + +TEST(StringToDoubleOctalString) { + int flags; + int processed; + bool all_used; + + flags = StringToDoubleConverter::ALLOW_OCTALS | + StringToDoubleConverter::ALLOW_LEADING_SPACES | + StringToDoubleConverter::ALLOW_TRAILING_SPACES | + StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN; + + CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(123456789.0, + StrToD("0123456789", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("+01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-342391.0, + StrToD("-01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD(" 012", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("\n012", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD(" 00", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD("\t00", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD(" 012", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("\n012", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(123456789.0, + StrToD(" 0123456789", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD(" 01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("\n01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD(" + 01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-342391.0, + StrToD(" - 01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-342391.0, + StrToD("\n-\t01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD(" 012 ", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD(" 00 ", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD(" 012 ", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(123456789.0, + StrToD(" 0123456789 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD(" 01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD(" + 01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-342391.0, + StrToD(" - 01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("012 ", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("012 ", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(123456789.0, + StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("+01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-342391.0, + StrToD("-01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(Double::NaN(), + StrToD("01234567e0", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(0, processed); + + + flags = StringToDoubleConverter::ALLOW_OCTALS; + CHECK_EQ(10.0, StrToD("012", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0, StrToD("00", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("012", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(123456789.0, + StrToD("0123456789", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); CHECK_EQ(342391.0, StrToD("01234567", flags, Double::NaN(), &processed, &all_used)); @@ -2992,76 +3530,458 @@ TEST(StringToDoubleOctalString) { CHECK_EQ(10.0, StrToD("012 ", flags, 0.0, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(0.0, StrToD("00 ", flags, 1.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(123456789.0, + StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(342391.0, + StrToD("+01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-342391.0, + StrToD("-01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(10.0, StrToD("012foo ", flags, 0.0, &processed, &all_used)); + CHECK_EQ(3, processed); + + CHECK_EQ(0.0, StrToD("00foo ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(2, processed); + + CHECK_EQ(123456789.0, + StrToD("0123456789foo ", flags, Double::NaN(), + &processed, &all_used)); + CHECK_EQ(10, processed); + + CHECK_EQ(342391.0, + StrToD("01234567foo ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(8, processed); + + CHECK_EQ(342391.0, + StrToD("+01234567foo", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(9, processed); + + CHECK_EQ(-342391.0, + StrToD("-01234567foo", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(9, processed); + + CHECK_EQ(10.0, StrToD("012 foo ", flags, 0.0, &processed, &all_used)); + CHECK_EQ(4, processed); + + CHECK_EQ(0.0, StrToD("00 foo ", flags, 1.0, &processed, &all_used)); + CHECK_EQ(3, processed); + + CHECK_EQ(123456789.0, + StrToD("0123456789 foo ", flags, Double::NaN(), + &processed, &all_used)); + CHECK_EQ(11, processed); + + CHECK_EQ(342391.0, + StrToD("01234567 foo ", flags, Double::NaN(), + &processed, &all_used)); + CHECK_EQ(9, processed); + + CHECK_EQ(342391.0, + StrToD("+01234567 foo", flags, Double::NaN(), + &processed, &all_used)); + CHECK_EQ(10, processed); + + CHECK_EQ(-342391.0, + StrToD("-01234567 foo", flags, Double::NaN(), + &processed, &all_used)); + CHECK_EQ(10, processed); +} + + +TEST(StringToDoubleSeparator) { + int flags; + int processed; + bool all_used; + uc16 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); + + separator = 0x202F; + char char_separator = '@'; + flags = StringToDoubleConverter::ALLOW_HEX | + StringToDoubleConverter::ALLOW_HEX_FLOATS | + StringToDoubleConverter::ALLOW_LEADING_SPACES | + StringToDoubleConverter::ALLOW_TRAILING_SPACES; + + CHECK_EQ(18.0, + StrToD16("0x1@2", flags, 0.0, &processed, &all_used, + char_separator, separator)); CHECK(all_used); - CHECK_EQ(123456789.0, - StrToD("0123456789 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(0.0, StrToD16("0x0@0", flags, 1.0, &processed, &all_used, + char_separator, separator)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("01234567 ", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(static_cast(0x123456789), + StrToD16("0x1@2@3@4@5@6@7@8@9", flags, Double::NaN(), + &processed, &all_used, char_separator, separator)); CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("+01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(18.0, StrToD16(" 0x1@2 ", flags, 0.0, + &processed, &all_used, char_separator, separator)); CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD("-01234567", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(static_cast(0xabcdef), + StrToD16("0xa@b@c@d@e@f", flags, 0.0, + &processed, &all_used, char_separator, separator)); CHECK(all_used); - CHECK_EQ(10.0, StrToD("012foo ", flags, 0.0, &processed, &all_used)); - CHECK_EQ(3, processed); - - CHECK_EQ(0.0, StrToD("00foo ", flags, 1.0, &processed, &all_used)); - CHECK_EQ(2, processed); - - CHECK_EQ(123456789.0, - StrToD("0123456789foo ", flags, Double::NaN(), - &processed, &all_used)); - CHECK_EQ(10, processed); - - CHECK_EQ(342391.0, - StrToD("01234567foo ", flags, Double::NaN(), &processed, &all_used)); - CHECK_EQ(8, processed); - - CHECK_EQ(342391.0, - StrToD("+01234567foo", flags, Double::NaN(), &processed, &all_used)); - CHECK_EQ(9, processed); - - CHECK_EQ(-342391.0, - StrToD("-01234567foo", flags, Double::NaN(), &processed, &all_used)); - CHECK_EQ(9, processed); + CHECK_EQ(Double::NaN(), + StrToD16("0x@1@2", flags, 0.0, + &processed, &all_used, char_separator, separator)); + CHECK_EQ(0, processed); - CHECK_EQ(10.0, StrToD("012 foo ", flags, 0.0, &processed, &all_used)); - CHECK_EQ(4, processed); + CHECK_EQ(Double::NaN(), + StrToD16("0@x0", flags, 1.0, + &processed, &all_used, char_separator, separator)); + CHECK_EQ(0, processed); - CHECK_EQ(0.0, StrToD("00 foo ", flags, 1.0, &processed, &all_used)); - CHECK_EQ(3, processed); + CHECK_EQ(Double::NaN(), + StrToD16("0x1@2@@3@4@5@6@7@8@9", flags, Double::NaN(), + &processed, &all_used, char_separator, separator)); + CHECK_EQ(0, processed); - CHECK_EQ(123456789.0, - StrToD("0123456789 foo ", flags, Double::NaN(), - &processed, &all_used)); - CHECK_EQ(11, processed); + CHECK_EQ(3.0, + StrToD16("0x0@3p0", flags, 0.0, &processed, &all_used, + char_separator, separator)); + CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("01234567 foo ", flags, Double::NaN(), - &processed, &all_used)); - CHECK_EQ(9, processed); + CHECK_EQ(0.0, + StrToD16("0x.0@0p0", flags, 0.0, &processed, &all_used, + char_separator, separator)); + CHECK(all_used); - CHECK_EQ(342391.0, - StrToD("+01234567 foo", flags, Double::NaN(), - &processed, &all_used)); - CHECK_EQ(10, processed); + CHECK_EQ(3.0, + StrToD16("0x3.0@0p0", flags, 0.0, &processed, &all_used, + char_separator, separator)); + CHECK(all_used); - CHECK_EQ(-342391.0, - StrToD("-01234567 foo", flags, Double::NaN(), - &processed, &all_used)); - CHECK_EQ(10, processed); + CHECK_EQ(3.0, + StrToD16("0x0@3.p0", flags, 0.0, &processed, &all_used, + char_separator, separator)); + CHECK(all_used); } - TEST(StringToDoubleSpecialValues) { int processed; int flags = StringToDoubleConverter::NO_FLAGS; @@ -3184,10 +4104,10 @@ TEST(StringToDoubleCommentExamples) { CHECK(all_used); CHECK_EQ(123.0, StrToD("123e", flags, 0.0, &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(processed, 3); CHECK_EQ(123.0, StrToD("123e-", flags, 0.0, &processed, &all_used)); - CHECK(all_used); + CHECK_EQ(processed, 3); { StringToDoubleConverter converter(flags, 0.0, 1.0, "infinity", "NaN"); @@ -3235,6 +4155,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); } @@ -3244,25 +4186,25 @@ static float StrToF16(const uc16* str16, int length, int flags, bool* processed_all) { StringToDoubleConverter converter(flags, empty_string_value, Double::NaN(), NULL, NULL); - double result = + float result = converter.StringToFloat(str16, length, processed_characters_count); *processed_all = (length == *processed_characters_count); return result; } -static double StrToF(const char* str, int flags, double empty_string_value, - int* processed_characters_count, bool* processed_all) { +static float StrToF(const char* str, int flags, double empty_string_value, + int* processed_characters_count, bool* processed_all) { StringToDoubleConverter converter(flags, empty_string_value, Single::NaN(), NULL, NULL); - float result = converter.StringToFloat(str, strlen(str), + int len = static_cast(strlen(str)); + float result = converter.StringToFloat(str, len, processed_characters_count); *processed_all = ((strlen(str) == static_cast(*processed_characters_count))); uc16 buffer16[256]; - ASSERT(strlen(str) < ARRAY_SIZE(buffer16)); - int len = strlen(str); + DOUBLE_CONVERSION_ASSERT(strlen(str) < DOUBLE_CONVERSION_ARRAY_SIZE(buffer16)); for (int i = 0; i < len; i++) { buffer16[i] = str[i]; } @@ -3740,13 +4682,30 @@ TEST(StringToFloatHexString) { CHECK_EQ(5.0f, StrToF(" + 0x5 ", flags, 0.0f, &processed, &all_used)); CHECK(all_used); - CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0f, + &processed, &all_used)); CHECK_EQ(0, processed); - CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0f, + &processed, &all_used)); CHECK_EQ(0, processed); - CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3p0", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x.0p0", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3.0p0", flags, 0.0f, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3.p0", flags, 0.0f, + &processed, &all_used)); CHECK_EQ(0, processed); flags = StringToDoubleConverter::ALLOW_HEX; @@ -3843,6 +4802,20 @@ TEST(StringToFloatHexString) { CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0f, &processed, &all_used)); CHECK_EQ(0, processed); + CHECK_EQ(Single::NaN(), StrToF("0x3p0", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x.0p0", flags, 0.0f, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3.0p0", flags, 0.0f, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3.p0", flags, 0.0f, + &processed, &all_used)); + CHECK_EQ(0, processed); + flags = StringToDoubleConverter::ALLOW_TRAILING_JUNK | StringToDoubleConverter::ALLOW_HEX; @@ -3965,6 +4938,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 | @@ -4053,6 +5039,156 @@ TEST(StringToFloatHexString) { CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0f, &processed, &all_used)); CHECK_EQ(0, processed); + + flags = StringToDoubleConverter::ALLOW_HEX_FLOATS; + + CHECK_EQ(3.0f, StrToF("0x3p0", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0f, StrToF("0x.0p0", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(3.0f, StrToF("0x3.0p0", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(3.0f, StrToF("0x3.p0", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-5634002804104940178441764864.0f, StrToF("-0x123456789012345678901234p0", + flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(134217728.0f, StrToF("0x8000001p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(134217728.0f, StrToF("0x8000000p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(549755813888.0f, StrToF("0x8000000001p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(549755813888.0f, StrToF("0x8000000000p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(549755879424.0f, StrToF("0x8000008001p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(549755813888.0f, StrToF("0x8000008000p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(549755944960.0f, StrToF("0x8000018001p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(549755944960.0f, StrToF("0x8000018000p0", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(8796093022208.0f, StrToF("0x8000000001p4", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(8796093022208.0f, StrToF("0x8000000000p+4", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(8796094070784.0f, StrToF("0x8000008001p04", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(34359738368.0f, StrToF("0x8000008000p-4", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(34359746560.0f, StrToF("0x8000018001p-04", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(8796095119360.0f, StrToF("0x8000018000p4", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(Single::Infinity(), StrToF("0x1p2000", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0f, StrToF("0x1p-2000", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(-0.0f, StrToF("-0x1p-2000", flags, 0.0, &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(), + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF(" 0x ", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF(" 0x 3", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3g", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x3 foo", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF(" 0x3 foo", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("+ 0x3 foo", flags, 0.0, + &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("+", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("-", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0xp1", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::NaN(), StrToF("0x.p1", flags, 0.0, &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Single::Infinity(), StrToF("0x1.p10000000000000000", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(0.0f, StrToF("0x1.p-10000000000000000", flags, 0.0, + &processed, &all_used)); + CHECK(all_used); } @@ -4700,7 +5836,7 @@ TEST(StringToDoubleFloatWhitespace) { kFigureSpace, kPunctuationSpace, kThinSpace, kHairSpace, kNarrowNoBreakSpace, kMediumMathematicalSpace, kIdeographicSpace, }; - const int kWhitespace16Length = ARRAY_SIZE(kWhitespace16); + const int kWhitespace16Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespace16); CHECK_EQ(-1.2, StrToD16(kWhitespace16, kWhitespace16Length, flags, Double::NaN(), &processed, &all_used)); @@ -4710,3 +5846,132 @@ TEST(StringToDoubleFloatWhitespace) { &processed, &all_used)); CHECK(all_used); } + + +TEST(StringToDoubleCaseInsensitiveSpecialValues) { + int processed = 0; + + int flags = StringToDoubleConverter::ALLOW_CASE_INSENSITIVITY | + 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); +} + + +TEST(StringToTemplate) { + // Test StringToDoubleConverter::StringTo. + + const StringToDoubleConverter converter(StringToDoubleConverter::ALLOW_HEX, 0.0, Double::NaN(), "inf", "nan"); + + // First simply check conversion from "0" and "1": + for (int i = 0; i <= 1; ++i) + { + const char c = '0' + i; + + int processed = 0; + CHECK_EQ(static_cast(i), converter.StringTo(&c, 1, &processed)); + CHECK_EQ(1, processed); + + processed = 0; + CHECK_EQ(static_cast(i), converter.StringTo(&c, 1, &processed)); + CHECK_EQ(1, processed); + + const uc16 buffer16[1] = { static_cast(c) }; + + processed = 0; + CHECK_EQ(static_cast(i), converter.StringTo(buffer16, 1, &processed)); + CHECK_EQ(1, processed); + + processed = 0; + CHECK_EQ(static_cast(i), converter.StringTo(buffer16, 1, &processed)); + CHECK_EQ(1, processed); + } + { + // A number that can be represented by a double, but not by a float. + // Allows testing that StringTo behaves like StringToDouble + // (and not like StringToFloat). + const char buffer[] = "1e+100"; + const int length = DOUBLE_CONVERSION_ARRAY_SIZE(buffer) - 1; + + int processed1 = 1; + int processed2 = 2; + + CHECK_EQ(converter.StringToDouble(buffer, length, &processed1), + converter.StringTo(buffer, length, &processed2)); + CHECK_EQ(processed1, processed2); + + uc16 buffer16[DOUBLE_CONVERSION_ARRAY_SIZE(buffer)]; + + for (int i = 0; i <= length; ++i) { + buffer16[i] = buffer[i]; + } + + processed1 = 1; + processed2 = 2; + + CHECK_EQ(converter.StringToDouble(buffer16, length, &processed1), + converter.StringTo(buffer16, length, &processed2)); + CHECK_EQ(processed1, processed2); + } + { + // The double rounding example from TEST(StringToFloatHexString), which + // yields a slightly different result from StringToFloat than from + // StringToDouble. Allows testing that StringTo behaves like + // StringToFloat (rather than like StringToDouble). + const char buffer[] = "0x100000100000008"; + const int length = DOUBLE_CONVERSION_ARRAY_SIZE(buffer) - 1; + + int processed1 = 1; + int processed2 = 2; + + CHECK_EQ(converter.StringToFloat(buffer, length, &processed1), + converter.StringTo(buffer, length, &processed2)); + CHECK_EQ(processed1, processed2); + + uc16 buffer16[DOUBLE_CONVERSION_ARRAY_SIZE(buffer)]; + + for (int i = 0; i <= length; ++i) { + buffer16[i] = buffer[i]; + } + + processed1 = 1; + processed2 = 2; + + CHECK_EQ(converter.StringToFloat(buffer16, length, &processed1), + converter.StringTo(buffer16, length, &processed2)); + CHECK_EQ(processed1, processed2); + } +} diff --git a/deps/double-conversion/test/cctest/test-diy-fp.cc b/deps/double-conversion/test/cctest/test-diy-fp.cc index 26038b1f..ece43798 100644 --- a/deps/double-conversion/test/cctest/test-diy-fp.cc +++ b/deps/double-conversion/test/cctest/test-diy-fp.cc @@ -1,4 +1,29 @@ // Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 @@ -34,20 +59,20 @@ TEST(Multiply) { CHECK(0 == diy_fp1.f()); // NOLINT CHECK_EQ(64, diy_fp1.e()); - diy_fp1 = DiyFp(UINT64_2PART_C(0x80000000, 00000000), 11); + diy_fp1 = DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000), 11); diy_fp2 = DiyFp(2, 13); product = DiyFp::Times(diy_fp1, diy_fp2); CHECK(1 == product.f()); // NOLINT CHECK_EQ(11 + 13 + 64, product.e()); // Test rounding. - diy_fp1 = DiyFp(UINT64_2PART_C(0x80000000, 00000001), 11); + diy_fp1 = DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000001), 11); diy_fp2 = DiyFp(1, 13); product = DiyFp::Times(diy_fp1, diy_fp2); CHECK(1 == product.f()); // NOLINT CHECK_EQ(11 + 13 + 64, product.e()); - diy_fp1 = DiyFp(UINT64_2PART_C(0x7fffffff, ffffffff), 11); + diy_fp1 = DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x7fffffff, ffffffff), 11); diy_fp2 = DiyFp(1, 13); product = DiyFp::Times(diy_fp1, diy_fp2); CHECK(0 == product.f()); // NOLINT @@ -56,10 +81,10 @@ TEST(Multiply) { // Halfway cases are allowed to round either way. So don't check for it. // Big numbers. - diy_fp1 = DiyFp(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF), 11); - diy_fp2 = DiyFp(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF), 13); + diy_fp1 = DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF), 11); + diy_fp2 = DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF), 13); // 128bit result: 0xfffffffffffffffe0000000000000001 product = DiyFp::Times(diy_fp1, diy_fp2); - CHECK(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFe) == product.f()); + CHECK(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFe) == product.f()); CHECK_EQ(11 + 13 + 64, product.e()); } diff --git a/deps/double-conversion/test/cctest/test-dtoa.cc b/deps/double-conversion/test/cctest/test-dtoa.cc index 03463366..8a364be4 100644 --- a/deps/double-conversion/test/cctest/test-dtoa.cc +++ b/deps/double-conversion/test/cctest/test-dtoa.cc @@ -66,7 +66,7 @@ static void DoubleToAscii(double v, DtoaMode test_mode, int requested_digits, // Removes trailing '0' digits. static void TrimRepresentation(Vector representation) { - int len = strlen(representation.start()); + int len = static_cast(strlen(representation.start())); int i; for (i = len - 1; i >= 0; --i) { if (representation[i] != '0') break; @@ -229,13 +229,13 @@ TEST(DtoaVariousDoubles) { DoubleToAscii(-2147483648.0, SHORTEST, 0, buffer, &sign, &length, &point); - CHECK_EQ(1, sign); + CHECK_EQ(true, sign); CHECK_EQ("2147483648", buffer.start()); CHECK_EQ(10, point); DoubleToAscii(-2147483648.0, SHORTEST_SINGLE, 0, buffer, &sign, &length, &point); - CHECK_EQ(1, sign); + CHECK_EQ(true, sign); CHECK_EQ("21474836", buffer.start()); CHECK_EQ(10, point); @@ -243,7 +243,7 @@ TEST(DtoaVariousDoubles) { DoubleToAscii(-2147483648.0, FIXED, 2, buffer, &sign, &length, &point); CHECK_GE(2, length - point); TrimRepresentation(buffer); - CHECK_EQ(1, sign); + CHECK_EQ(true, sign); CHECK_EQ("2147483648", buffer.start()); CHECK_EQ(10, point); @@ -251,25 +251,25 @@ TEST(DtoaVariousDoubles) { buffer, &sign, &length, &point); CHECK_GE(5, length); TrimRepresentation(buffer); - CHECK_EQ(1, sign); + CHECK_EQ(true, sign); CHECK_EQ("21475", buffer.start()); CHECK_EQ(10, point); DoubleToAscii(-3.5844466002796428e+298, SHORTEST, 0, buffer, &sign, &length, &point); - CHECK_EQ(1, sign); + CHECK_EQ(true, sign); CHECK_EQ("35844466002796428", buffer.start()); CHECK_EQ(299, point); DoubleToAscii(-3.5844466002796428e+298, PRECISION, 10, buffer, &sign, &length, &point); - CHECK_EQ(1, sign); + CHECK_EQ(true, sign); CHECK_GE(10, length); TrimRepresentation(buffer); CHECK_EQ("35844466", buffer.start()); CHECK_EQ(299, point); - uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000); + uint64_t smallest_normal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); double v = Double(smallest_normal64).value(); DoubleToAscii(v, SHORTEST, 0, buffer, &sign, &length, &point); CHECK_EQ("22250738585072014", buffer.start()); @@ -287,7 +287,7 @@ TEST(DtoaVariousDoubles) { CHECK_EQ("22250738585072013831", buffer.start()); CHECK_EQ(-307, point); - uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + uint64_t largest_denormal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); v = Double(largest_denormal64).value(); DoubleToAscii(v, SHORTEST, 0, buffer, &sign, &length, &point); CHECK_EQ("2225073858507201", buffer.start()); @@ -307,7 +307,7 @@ TEST(DtoaVariousDoubles) { DoubleToAscii(4128420500802942e-24, SHORTEST, 0, buffer, &sign, &length, &point); - CHECK_EQ(0, sign); + CHECK_EQ(false, sign); CHECK_EQ("4128420500802942", buffer.start()); CHECK_EQ(-8, point); diff --git a/deps/double-conversion/test/cctest/test-fast-dtoa.cc b/deps/double-conversion/test/cctest/test-fast-dtoa.cc index 31d47846..5fb8975b 100644 --- a/deps/double-conversion/test/cctest/test-fast-dtoa.cc +++ b/deps/double-conversion/test/cctest/test-fast-dtoa.cc @@ -1,4 +1,29 @@ // Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 @@ -18,7 +43,7 @@ static const int kBufferSize = 100; // Removes trailing '0' digits. static void TrimRepresentation(Vector representation) { - int len = strlen(representation.start()); + int len = static_cast(strlen(representation.start())); int i; for (i = len - 1; i >= 0; --i) { if (representation[i] != '0') break; @@ -79,7 +104,7 @@ TEST(FastDtoaShortestVariousDoubles) { CHECK_EQ(299, point); } - uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000); + uint64_t smallest_normal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); double v = Double(smallest_normal64).value(); status = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, &length, &point); if (status) { @@ -87,7 +112,7 @@ TEST(FastDtoaShortestVariousDoubles) { CHECK_EQ(-307, point); } - uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + uint64_t largest_denormal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); v = Double(largest_denormal64).value(); status = FastDtoa(v, FAST_DTOA_SHORTEST, 0, buffer, &length, &point); if (status) { @@ -244,14 +269,14 @@ TEST(FastDtoaPrecisionVariousDoubles) { CHECK_EQ("35844466", buffer.start()); CHECK_EQ(299, point); - uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000); + uint64_t smallest_normal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); double v = Double(smallest_normal64).value(); status = FastDtoa(v, FAST_DTOA_PRECISION, 17, buffer, &length, &point); CHECK(status); CHECK_EQ("22250738585072014", buffer.start()); CHECK_EQ(-307, point); - uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + uint64_t largest_denormal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); v = Double(largest_denormal64).value(); status = FastDtoa(v, FAST_DTOA_PRECISION, 17, buffer, &length, &point); CHECK(status); diff --git a/deps/double-conversion/test/cctest/test-fixed-dtoa.cc b/deps/double-conversion/test/cctest/test-fixed-dtoa.cc index 5ffac581..e66f3890 100644 --- a/deps/double-conversion/test/cctest/test-fixed-dtoa.cc +++ b/deps/double-conversion/test/cctest/test-fixed-dtoa.cc @@ -485,6 +485,10 @@ TEST(FastFixedVariousDoubles) { buffer, &length, &point)); CHECK_EQ("1000000000000000128", buffer.start()); CHECK_EQ(19, point); + + CHECK(FastFixedDtoa(2.10861548515811875e+15, 17, buffer, &length, &point)); + CHECK_EQ("210861548515811875", buffer.start()); + CHECK_EQ(16, point); } diff --git a/deps/double-conversion/test/cctest/test-ieee.cc b/deps/double-conversion/test/cctest/test-ieee.cc index c57e8cea..1358f74a 100644 --- a/deps/double-conversion/test/cctest/test-ieee.cc +++ b/deps/double-conversion/test/cctest/test-ieee.cc @@ -1,6 +1,32 @@ // Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 "cctest.h" #include "double-conversion/diy-fp.h" @@ -13,13 +39,13 @@ using namespace double_conversion; TEST(Uint64Conversions) { // Start by checking the byte-order. - uint64_t ordered = UINT64_2PART_C(0x01234567, 89ABCDEF); + uint64_t ordered = DOUBLE_CONVERSION_UINT64_2PART_C(0x01234567, 89ABCDEF); CHECK_EQ(3512700564088504e-318, Double(ordered).value()); - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); CHECK_EQ(5e-324, Double(min_double64).value()); - uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff); + uint64_t max_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x7fefffff, ffffffff); CHECK_EQ(1.7976931348623157e308, Double(max_double64).value()); } @@ -38,22 +64,22 @@ TEST(Uint32Conversions) { TEST(Double_AsDiyFp) { - uint64_t ordered = UINT64_2PART_C(0x01234567, 89ABCDEF); + uint64_t ordered = DOUBLE_CONVERSION_UINT64_2PART_C(0x01234567, 89ABCDEF); DiyFp diy_fp = Double(ordered).AsDiyFp(); CHECK_EQ(0x12 - 0x3FF - 52, diy_fp.e()); // The 52 mantissa bits, plus the implicit 1 in bit 52 as a UINT64. - CHECK(UINT64_2PART_C(0x00134567, 89ABCDEF) == diy_fp.f()); // NOLINT + CHECK(DOUBLE_CONVERSION_UINT64_2PART_C(0x00134567, 89ABCDEF) == diy_fp.f()); // NOLINT - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); diy_fp = Double(min_double64).AsDiyFp(); CHECK_EQ(-0x3FF - 52 + 1, diy_fp.e()); // This is a denormal; so no hidden bit. CHECK(1 == diy_fp.f()); // NOLINT - uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff); + uint64_t max_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x7fefffff, ffffffff); diy_fp = Double(max_double64).AsDiyFp(); CHECK_EQ(0x7FE - 0x3FF - 52, diy_fp.e()); - CHECK(UINT64_2PART_C(0x001fffff, ffffffff) == diy_fp.f()); // NOLINT + CHECK(DOUBLE_CONVERSION_UINT64_2PART_C(0x001fffff, ffffffff) == diy_fp.f()); // NOLINT } @@ -62,48 +88,48 @@ TEST(Single_AsDiyFp) { DiyFp diy_fp = Single(ordered).AsDiyFp(); CHECK_EQ(0x2 - 0x7F - 23, diy_fp.e()); // The 23 mantissa bits, plus the implicit 1 in bit 24 as a uint32_t. - CHECK_EQ(0xA34567, diy_fp.f()); + CHECK_EQ(0xA34567u, diy_fp.f()); uint32_t min_float32 = 0x00000001; diy_fp = Single(min_float32).AsDiyFp(); CHECK_EQ(-0x7F - 23 + 1, diy_fp.e()); // This is a denormal; so no hidden bit. - CHECK_EQ(1, diy_fp.f()); + CHECK_EQ(1u, diy_fp.f()); uint32_t max_float32 = 0x7f7fffff; diy_fp = Single(max_float32).AsDiyFp(); CHECK_EQ(0xFE - 0x7F - 23, diy_fp.e()); - CHECK_EQ(0x00ffffff, diy_fp.f()); + CHECK_EQ(0x00ffffffu, diy_fp.f()); } TEST(AsNormalizedDiyFp) { - uint64_t ordered = UINT64_2PART_C(0x01234567, 89ABCDEF); + uint64_t ordered = DOUBLE_CONVERSION_UINT64_2PART_C(0x01234567, 89ABCDEF); DiyFp diy_fp = Double(ordered).AsNormalizedDiyFp(); CHECK_EQ(0x12 - 0x3FF - 52 - 11, diy_fp.e()); - CHECK((UINT64_2PART_C(0x00134567, 89ABCDEF) << 11) == + CHECK((DOUBLE_CONVERSION_UINT64_2PART_C(0x00134567, 89ABCDEF) << 11) == diy_fp.f()); // NOLINT - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); diy_fp = Double(min_double64).AsNormalizedDiyFp(); CHECK_EQ(-0x3FF - 52 + 1 - 63, diy_fp.e()); // This is a denormal; so no hidden bit. - CHECK(UINT64_2PART_C(0x80000000, 00000000) == diy_fp.f()); // NOLINT + CHECK(DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000) == diy_fp.f()); // NOLINT - uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff); + uint64_t max_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x7fefffff, ffffffff); diy_fp = Double(max_double64).AsNormalizedDiyFp(); CHECK_EQ(0x7FE - 0x3FF - 52 - 11, diy_fp.e()); - CHECK((UINT64_2PART_C(0x001fffff, ffffffff) << 11) == + CHECK((DOUBLE_CONVERSION_UINT64_2PART_C(0x001fffff, ffffffff) << 11) == diy_fp.f()); // NOLINT } TEST(Double_IsDenormal) { - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); CHECK(Double(min_double64).IsDenormal()); - uint64_t bits = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + uint64_t bits = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); CHECK(Double(bits).IsDenormal()); - bits = UINT64_2PART_C(0x00100000, 00000000); + bits = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); CHECK(!Double(bits).IsDenormal()); } @@ -122,7 +148,7 @@ TEST(Double_IsSpecial) { CHECK(Double(Double::Infinity()).IsSpecial()); CHECK(Double(-Double::Infinity()).IsSpecial()); CHECK(Double(Double::NaN()).IsSpecial()); - uint64_t bits = UINT64_2PART_C(0xFFF12345, 00000000); + uint64_t bits = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFF12345, 00000000); CHECK(Double(bits).IsSpecial()); // Denormals are not special: CHECK(!Double(5e-324).IsSpecial()); @@ -172,7 +198,7 @@ TEST(Double_IsInfinite) { CHECK(!Double(-0.0).IsInfinite()); CHECK(!Double(1.0).IsInfinite()); CHECK(!Double(-1.0).IsInfinite()); - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); CHECK(!Double(min_double64).IsInfinite()); } @@ -192,7 +218,7 @@ TEST(Single_IsInfinite) { TEST(Double_IsNan) { CHECK(Double(Double::NaN()).IsNan()); - uint64_t other_nan = UINT64_2PART_C(0xFFFFFFFF, 00000001); + uint64_t other_nan = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, 00000001); CHECK(Double(other_nan).IsNan()); CHECK(!Double(Double::Infinity()).IsNan()); CHECK(!Double(-Double::Infinity()).IsNan()); @@ -200,7 +226,7 @@ TEST(Double_IsNan) { CHECK(!Double(-0.0).IsNan()); CHECK(!Double(1.0).IsNan()); CHECK(!Double(-1.0).IsNan()); - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); CHECK(!Double(min_double64).IsNan()); } @@ -226,7 +252,7 @@ TEST(Double_Sign) { CHECK_EQ(-1, Double(-Double::Infinity()).Sign()); CHECK_EQ(1, Double(0.0).Sign()); CHECK_EQ(-1, Double(-0.0).Sign()); - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); CHECK_EQ(1, Double(min_double64).Sign()); } @@ -264,7 +290,7 @@ TEST(Double_NormalizedBoundaries) { CHECK((1 << 9) == diy_fp.f() - boundary_minus.f()); // NOLINT CHECK((1 << 10) == boundary_plus.f() - diy_fp.f()); // NOLINT - uint64_t min_double64 = UINT64_2PART_C(0x00000000, 00000001); + uint64_t min_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00000000, 00000001); diy_fp = Double(min_double64).AsNormalizedDiyFp(); Double(min_double64).NormalizedBoundaries(&boundary_minus, &boundary_plus); CHECK_EQ(diy_fp.e(), boundary_minus.e()); @@ -276,7 +302,7 @@ TEST(Double_NormalizedBoundaries) { CHECK((static_cast(1) << 62) == diy_fp.f() - boundary_minus.f()); // NOLINT - uint64_t smallest_normal64 = UINT64_2PART_C(0x00100000, 00000000); + uint64_t smallest_normal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000); diy_fp = Double(smallest_normal64).AsNormalizedDiyFp(); Double(smallest_normal64).NormalizedBoundaries(&boundary_minus, &boundary_plus); @@ -287,7 +313,7 @@ TEST(Double_NormalizedBoundaries) { CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f()); CHECK((1 << 10) == diy_fp.f() - boundary_minus.f()); // NOLINT - uint64_t largest_denormal64 = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + uint64_t largest_denormal64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF); diy_fp = Double(largest_denormal64).AsNormalizedDiyFp(); Double(largest_denormal64).NormalizedBoundaries(&boundary_minus, &boundary_plus); @@ -296,7 +322,7 @@ TEST(Double_NormalizedBoundaries) { CHECK(diy_fp.f() - boundary_minus.f() == boundary_plus.f() - diy_fp.f()); CHECK((1 << 11) == diy_fp.f() - boundary_minus.f()); // NOLINT - uint64_t max_double64 = UINT64_2PART_C(0x7fefffff, ffffffff); + uint64_t max_double64 = DOUBLE_CONVERSION_UINT64_2PART_C(0x7fefffff, ffffffff); diy_fp = Double(max_double64).AsNormalizedDiyFp(); Double(max_double64).NormalizedBoundaries(&boundary_minus, &boundary_plus); CHECK_EQ(diy_fp.e(), boundary_minus.e()); @@ -398,7 +424,7 @@ TEST(NextDouble) { CHECK_EQ(4e-324, d2.NextDouble()); CHECK_EQ(-1.7976931348623157e308, Double(-Double::Infinity()).NextDouble()); CHECK_EQ(Double::Infinity(), - Double(UINT64_2PART_C(0x7fefffff, ffffffff)).NextDouble()); + Double(DOUBLE_CONVERSION_UINT64_2PART_C(0x7fefffff, ffffffff)).NextDouble()); } @@ -417,5 +443,25 @@ TEST(PreviousDouble) { CHECK_EQ(-4e-324, d2.PreviousDouble()); CHECK_EQ(1.7976931348623157e308, Double(Double::Infinity()).PreviousDouble()); CHECK_EQ(-Double::Infinity(), - Double(UINT64_2PART_C(0xffefffff, ffffffff)).PreviousDouble()); + Double(DOUBLE_CONVERSION_UINT64_2PART_C(0xffefffff, ffffffff)).PreviousDouble()); +} + +TEST(SignalingNan) { + Double nan(Double::NaN()); + CHECK(nan.IsNan()); + CHECK(nan.IsQuietNan()); + CHECK(Double(std::numeric_limits::quiet_NaN()).IsQuietNan()); + CHECK(Double(std::numeric_limits::signaling_NaN()).IsSignalingNan()); +} + +TEST(SignalingNanSingle) { + Single nan(Single::NaN()); + CHECK(nan.IsNan()); + CHECK(nan.IsQuietNan()); + CHECK(Single(std::numeric_limits::quiet_NaN()).IsQuietNan()); +#ifndef _MSC_VER + // Visual studio has a bug for generating signaling NaNs: + // https://developercommunity.visualstudio.com/t/stdnumeric-limitssignaling-nan-returns-quiet-nan/155064 + CHECK(Single(std::numeric_limits::signaling_NaN()).IsSignalingNan()); +#endif } diff --git a/deps/double-conversion/test/cctest/test-strtod.cc b/deps/double-conversion/test/cctest/test-strtod.cc index 1a6ac3b9..ee89138e 100644 --- a/deps/double-conversion/test/cctest/test-strtod.cc +++ b/deps/double-conversion/test/cctest/test-strtod.cc @@ -1,4 +1,29 @@ // Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 @@ -12,7 +37,8 @@ using namespace double_conversion; static Vector StringToVector(const char* str) { - return Vector(str, strlen(str)); + int len = static_cast(strlen(str)); + return Vector(str, len); } @@ -21,10 +47,19 @@ static double StrtodChar(const char* str, int exponent) { } +static double StrtodTrimmedChar(const char* str, int exponent) { + return StrtodTrimmed(StringToVector(str), exponent); +} + + static float StrtofChar(const char* str, int exponent) { return Strtof(StringToVector(str), exponent); } +static float StrtofTrimmedChar(const char* str, int exponent) { + return StrtofTrimmed(StringToVector(str), exponent); +} + TEST(Strtod) { Vector vector; @@ -350,6 +385,276 @@ TEST(Strtod) { } +TEST(StrtodTrimmed) { + Vector vector; + + vector = StringToVector("1"); + CHECK_EQ(1.0, StrtodTrimmed(vector, 0)); + CHECK_EQ(10.0, StrtodTrimmed(vector, 1)); + CHECK_EQ(100.0, StrtodTrimmed(vector, 2)); + CHECK_EQ(1e20, StrtodTrimmed(vector, 20)); + CHECK_EQ(1e22, StrtodTrimmed(vector, 22)); + CHECK_EQ(1e23, StrtodTrimmed(vector, 23)); + CHECK_EQ(1e35, StrtodTrimmed(vector, 35)); + CHECK_EQ(1e36, StrtodTrimmed(vector, 36)); + CHECK_EQ(1e37, StrtodTrimmed(vector, 37)); + CHECK_EQ(1e-1, StrtodTrimmed(vector, -1)); + CHECK_EQ(1e-2, StrtodTrimmed(vector, -2)); + CHECK_EQ(1e-5, StrtodTrimmed(vector, -5)); + CHECK_EQ(1e-20, StrtodTrimmed(vector, -20)); + CHECK_EQ(1e-22, StrtodTrimmed(vector, -22)); + CHECK_EQ(1e-23, StrtodTrimmed(vector, -23)); + CHECK_EQ(1e-25, StrtodTrimmed(vector, -25)); + CHECK_EQ(1e-39, StrtodTrimmed(vector, -39)); + + vector = StringToVector("2"); + CHECK_EQ(2.0, StrtodTrimmed(vector, 0)); + CHECK_EQ(20.0, StrtodTrimmed(vector, 1)); + CHECK_EQ(200.0, StrtodTrimmed(vector, 2)); + CHECK_EQ(2e20, StrtodTrimmed(vector, 20)); + CHECK_EQ(2e22, StrtodTrimmed(vector, 22)); + CHECK_EQ(2e23, StrtodTrimmed(vector, 23)); + CHECK_EQ(2e35, StrtodTrimmed(vector, 35)); + CHECK_EQ(2e36, StrtodTrimmed(vector, 36)); + CHECK_EQ(2e37, StrtodTrimmed(vector, 37)); + CHECK_EQ(2e-1, StrtodTrimmed(vector, -1)); + CHECK_EQ(2e-2, StrtodTrimmed(vector, -2)); + CHECK_EQ(2e-5, StrtodTrimmed(vector, -5)); + CHECK_EQ(2e-20, StrtodTrimmed(vector, -20)); + CHECK_EQ(2e-22, StrtodTrimmed(vector, -22)); + CHECK_EQ(2e-23, StrtodTrimmed(vector, -23)); + CHECK_EQ(2e-25, StrtodTrimmed(vector, -25)); + CHECK_EQ(2e-39, StrtodTrimmed(vector, -39)); + + vector = StringToVector("9"); + CHECK_EQ(9.0, StrtodTrimmed(vector, 0)); + CHECK_EQ(90.0, StrtodTrimmed(vector, 1)); + CHECK_EQ(900.0, StrtodTrimmed(vector, 2)); + CHECK_EQ(9e20, StrtodTrimmed(vector, 20)); + CHECK_EQ(9e22, StrtodTrimmed(vector, 22)); + CHECK_EQ(9e23, StrtodTrimmed(vector, 23)); + CHECK_EQ(9e35, StrtodTrimmed(vector, 35)); + CHECK_EQ(9e36, StrtodTrimmed(vector, 36)); + CHECK_EQ(9e37, StrtodTrimmed(vector, 37)); + CHECK_EQ(9e-1, StrtodTrimmed(vector, -1)); + CHECK_EQ(9e-2, StrtodTrimmed(vector, -2)); + CHECK_EQ(9e-5, StrtodTrimmed(vector, -5)); + CHECK_EQ(9e-20, StrtodTrimmed(vector, -20)); + CHECK_EQ(9e-22, StrtodTrimmed(vector, -22)); + CHECK_EQ(9e-23, StrtodTrimmed(vector, -23)); + CHECK_EQ(9e-25, StrtodTrimmed(vector, -25)); + CHECK_EQ(9e-39, StrtodTrimmed(vector, -39)); + + vector = StringToVector("12345"); + CHECK_EQ(12345.0, StrtodTrimmed(vector, 0)); + CHECK_EQ(123450.0, StrtodTrimmed(vector, 1)); + CHECK_EQ(1234500.0, StrtodTrimmed(vector, 2)); + CHECK_EQ(12345e20, StrtodTrimmed(vector, 20)); + CHECK_EQ(12345e22, StrtodTrimmed(vector, 22)); + CHECK_EQ(12345e23, StrtodTrimmed(vector, 23)); + CHECK_EQ(12345e30, StrtodTrimmed(vector, 30)); + CHECK_EQ(12345e31, StrtodTrimmed(vector, 31)); + CHECK_EQ(12345e32, StrtodTrimmed(vector, 32)); + CHECK_EQ(12345e35, StrtodTrimmed(vector, 35)); + CHECK_EQ(12345e36, StrtodTrimmed(vector, 36)); + CHECK_EQ(12345e37, StrtodTrimmed(vector, 37)); + CHECK_EQ(12345e-1, StrtodTrimmed(vector, -1)); + CHECK_EQ(12345e-2, StrtodTrimmed(vector, -2)); + CHECK_EQ(12345e-5, StrtodTrimmed(vector, -5)); + CHECK_EQ(12345e-20, StrtodTrimmed(vector, -20)); + CHECK_EQ(12345e-22, StrtodTrimmed(vector, -22)); + CHECK_EQ(12345e-23, StrtodTrimmed(vector, -23)); + CHECK_EQ(12345e-25, StrtodTrimmed(vector, -25)); + CHECK_EQ(12345e-39, StrtodTrimmed(vector, -39)); + + vector = StringToVector("12345678901234"); + CHECK_EQ(12345678901234.0, StrtodTrimmed(vector, 0)); + CHECK_EQ(123456789012340.0, StrtodTrimmed(vector, 1)); + CHECK_EQ(1234567890123400.0, StrtodTrimmed(vector, 2)); + CHECK_EQ(12345678901234e20, StrtodTrimmed(vector, 20)); + CHECK_EQ(12345678901234e22, StrtodTrimmed(vector, 22)); + CHECK_EQ(12345678901234e23, StrtodTrimmed(vector, 23)); + CHECK_EQ(12345678901234e30, StrtodTrimmed(vector, 30)); + CHECK_EQ(12345678901234e31, StrtodTrimmed(vector, 31)); + CHECK_EQ(12345678901234e32, StrtodTrimmed(vector, 32)); + CHECK_EQ(12345678901234e35, StrtodTrimmed(vector, 35)); + CHECK_EQ(12345678901234e36, StrtodTrimmed(vector, 36)); + CHECK_EQ(12345678901234e37, StrtodTrimmed(vector, 37)); + CHECK_EQ(12345678901234e-1, StrtodTrimmed(vector, -1)); + CHECK_EQ(12345678901234e-2, StrtodTrimmed(vector, -2)); + CHECK_EQ(12345678901234e-5, StrtodTrimmed(vector, -5)); + CHECK_EQ(12345678901234e-20, StrtodTrimmed(vector, -20)); + CHECK_EQ(12345678901234e-22, StrtodTrimmed(vector, -22)); + CHECK_EQ(12345678901234e-23, StrtodTrimmed(vector, -23)); + CHECK_EQ(12345678901234e-25, StrtodTrimmed(vector, -25)); + CHECK_EQ(12345678901234e-39, StrtodTrimmed(vector, -39)); + + vector = StringToVector("123456789012345"); + CHECK_EQ(123456789012345.0, StrtodTrimmed(vector, 0)); + CHECK_EQ(1234567890123450.0, StrtodTrimmed(vector, 1)); + CHECK_EQ(12345678901234500.0, StrtodTrimmed(vector, 2)); + CHECK_EQ(123456789012345e20, StrtodTrimmed(vector, 20)); + CHECK_EQ(123456789012345e22, StrtodTrimmed(vector, 22)); + CHECK_EQ(123456789012345e23, StrtodTrimmed(vector, 23)); + CHECK_EQ(123456789012345e35, StrtodTrimmed(vector, 35)); + CHECK_EQ(123456789012345e36, StrtodTrimmed(vector, 36)); + CHECK_EQ(123456789012345e37, StrtodTrimmed(vector, 37)); + CHECK_EQ(123456789012345e39, StrtodTrimmed(vector, 39)); + CHECK_EQ(123456789012345e-1, StrtodTrimmed(vector, -1)); + CHECK_EQ(123456789012345e-2, StrtodTrimmed(vector, -2)); + CHECK_EQ(123456789012345e-5, StrtodTrimmed(vector, -5)); + CHECK_EQ(123456789012345e-20, StrtodTrimmed(vector, -20)); + CHECK_EQ(123456789012345e-22, StrtodTrimmed(vector, -22)); + CHECK_EQ(123456789012345e-23, StrtodTrimmed(vector, -23)); + CHECK_EQ(123456789012345e-25, StrtodTrimmed(vector, -25)); + CHECK_EQ(123456789012345e-39, StrtodTrimmed(vector, -39)); + + CHECK_EQ(0.0, StrtodTrimmedChar("", 1324)); + CHECK_EQ(0.0, StrtodTrimmedChar("2", -324)); + CHECK_EQ(4e-324, StrtodTrimmedChar("3", -324)); + // It would be more readable to put non-zero literals on the left side (i.e. + // CHECK_EQ(1e-325, StrtodChar("1", -325))), but then Gcc complains that + // they are truncated to zero. + CHECK_EQ(0.0, StrtodTrimmedChar("1", -325)); + CHECK_EQ(0.0, StrtodTrimmedChar("1", -325)); + + // It would be more readable to put the literals (and not Double::Infinity()) + // on the left side (i.e. CHECK_EQ(1e309, StrtodChar("1", 309))), but then Gcc + // complains that the floating constant exceeds range of 'double'. + CHECK_EQ(Double::Infinity(), StrtodTrimmedChar("1", 309)); + CHECK_EQ(1e308, StrtodTrimmedChar("1", 308)); + CHECK_EQ(1234e305, StrtodTrimmedChar("1234", 305)); + CHECK_EQ(1234e304, StrtodTrimmedChar("1234", 304)); + CHECK_EQ(Double::Infinity(), StrtodTrimmedChar("18", 307)); + CHECK_EQ(17e307, StrtodTrimmedChar("17", 307)); + + CHECK_EQ(1.7976931348623157E+308, StrtodTrimmedChar("17976931348623157", 292)); + CHECK_EQ(1.7976931348623158E+308, StrtodTrimmedChar("17976931348623158", 292)); + CHECK_EQ(Double::Infinity(), StrtodTrimmedChar("17976931348623159", 292)); + + // The following number is the result of 89255.0/1e-22. Both floating-point + // numbers can be accurately represented with doubles. However on Linux,x86 + // the floating-point stack is set to 80bits and the double-rounding + // introduces an error. + CHECK_EQ(89255e-22, StrtodTrimmedChar("89255", -22)); + + // Some random values. + CHECK_EQ(358416272e-33, StrtodTrimmedChar("358416272", -33)); + CHECK_EQ(104110013277974872254e-225, + StrtodTrimmedChar("104110013277974872254", -225)); + + CHECK_EQ(123456789e108, StrtodTrimmedChar("123456789", 108)); + CHECK_EQ(123456789e109, StrtodTrimmedChar("123456789", 109)); + CHECK_EQ(123456789e110, StrtodTrimmedChar("123456789", 110)); + CHECK_EQ(123456789e111, StrtodTrimmedChar("123456789", 111)); + CHECK_EQ(123456789e112, StrtodTrimmedChar("123456789", 112)); + CHECK_EQ(123456789e113, StrtodTrimmedChar("123456789", 113)); + CHECK_EQ(123456789e114, StrtodTrimmedChar("123456789", 114)); + CHECK_EQ(123456789e115, StrtodTrimmedChar("123456789", 115)); + CHECK_EQ(1234567890123456789012345e108, + StrtodTrimmedChar("1234567890123456789012345", 108)); + CHECK_EQ(1234567890123456789012345e109, + StrtodTrimmedChar("1234567890123456789012345", 109)); + CHECK_EQ(1234567890123456789012345e110, + StrtodTrimmedChar("1234567890123456789012345", 110)); + CHECK_EQ(1234567890123456789012345e111, + StrtodTrimmedChar("1234567890123456789012345", 111)); + CHECK_EQ(1234567890123456789012345e112, + StrtodTrimmedChar("1234567890123456789012345", 112)); + CHECK_EQ(1234567890123456789012345e113, + StrtodTrimmedChar("1234567890123456789012345", 113)); + CHECK_EQ(1234567890123456789012345e114, + StrtodTrimmedChar("1234567890123456789012345", 114)); + CHECK_EQ(1234567890123456789012345e115, + StrtodTrimmedChar("1234567890123456789012345", 115)); + + CHECK_EQ(1234567890123456789052345e108, + StrtodTrimmedChar("1234567890123456789052345", 108)); + CHECK_EQ(1234567890123456789052345e109, + StrtodTrimmedChar("1234567890123456789052345", 109)); + CHECK_EQ(1234567890123456789052345e110, + StrtodTrimmedChar("1234567890123456789052345", 110)); + CHECK_EQ(1234567890123456789052345e111, + StrtodTrimmedChar("1234567890123456789052345", 111)); + CHECK_EQ(1234567890123456789052345e112, + StrtodTrimmedChar("1234567890123456789052345", 112)); + CHECK_EQ(1234567890123456789052345e113, + StrtodTrimmedChar("1234567890123456789052345", 113)); + CHECK_EQ(1234567890123456789052345e114, + StrtodTrimmedChar("1234567890123456789052345", 114)); + CHECK_EQ(1234567890123456789052345e115, + StrtodTrimmedChar("1234567890123456789052345", 115)); + + // Boundary cases. Boundaries themselves should round to even. + // + // 0x1FFFFFFFFFFFF * 2^3 = 72057594037927928 + // next: 72057594037927936 + // boundary: 72057594037927932 should round up. + CHECK_EQ(72057594037927928.0, StrtodTrimmedChar("72057594037927928", 0)); + CHECK_EQ(72057594037927936.0, StrtodTrimmedChar("72057594037927936", 0)); + CHECK_EQ(72057594037927936.0, StrtodTrimmedChar("72057594037927932", 0)); + CHECK_EQ(72057594037927928.0, StrtodTrimmedChar("7205759403792793199999", -5)); + CHECK_EQ(72057594037927936.0, StrtodTrimmedChar("7205759403792793200001", -5)); + + // 0x1FFFFFFFFFFFF * 2^10 = 9223372036854774784 + // next: 9223372036854775808 + // boundary: 9223372036854775296 should round up. + CHECK_EQ(9223372036854774784.0, StrtodTrimmedChar("9223372036854774784", 0)); + CHECK_EQ(9223372036854775808.0, StrtodTrimmedChar("9223372036854775808", 0)); + CHECK_EQ(9223372036854775808.0, StrtodTrimmedChar("9223372036854775296", 0)); + CHECK_EQ(9223372036854774784.0, StrtodTrimmedChar("922337203685477529599999", -5)); + CHECK_EQ(9223372036854775808.0, StrtodTrimmedChar("922337203685477529600001", -5)); + + // 0x1FFFFFFFFFFFF * 2^50 = 10141204801825834086073718800384 + // next: 10141204801825835211973625643008 + // boundary: 10141204801825834649023672221696 should round up. + CHECK_EQ(10141204801825834086073718800384.0, + StrtodTrimmedChar("10141204801825834086073718800384", 0)); + CHECK_EQ(10141204801825835211973625643008.0, + StrtodTrimmedChar("10141204801825835211973625643008", 0)); + CHECK_EQ(10141204801825835211973625643008.0, + StrtodTrimmedChar("10141204801825834649023672221696", 0)); + CHECK_EQ(10141204801825834086073718800384.0, + StrtodTrimmedChar("1014120480182583464902367222169599999", -5)); + CHECK_EQ(10141204801825835211973625643008.0, + StrtodTrimmedChar("1014120480182583464902367222169600001", -5)); + + // 0x1FFFFFFFFFFFF * 2^99 = 5708990770823838890407843763683279797179383808 + // next: 5708990770823839524233143877797980545530986496 + // boundary: 5708990770823839207320493820740630171355185152 + // The boundary should round up. + CHECK_EQ(5708990770823838890407843763683279797179383808.0, + StrtodTrimmedChar("5708990770823838890407843763683279797179383808", 0)); + CHECK_EQ(5708990770823839524233143877797980545530986496.0, + StrtodTrimmedChar("5708990770823839524233143877797980545530986496", 0)); + CHECK_EQ(5708990770823839524233143877797980545530986496.0, + StrtodTrimmedChar("5708990770823839207320493820740630171355185152", 0)); + CHECK_EQ(5708990770823838890407843763683279797179383808.0, + StrtodTrimmedChar("5708990770823839207320493820740630171355185151999", -3)); + CHECK_EQ(5708990770823839524233143877797980545530986496.0, + StrtodTrimmedChar("5708990770823839207320493820740630171355185152001", -3)); + + // The following test-cases got some public attention in early 2011 when they + // sent Java and PHP into an infinite loop. + CHECK_EQ(2.225073858507201e-308, StrtodTrimmedChar("22250738585072011", -324)); + CHECK_EQ(2.22507385850720138309e-308, + StrtodTrimmedChar("22250738585072011360574097967091319759348195463516456480" + "23426109724822222021076945516529523908135087914149158913" + "03962110687008643869459464552765720740782062174337998814" + "10632673292535522868813721490129811224514518898490572223" + "07285255133155755015914397476397983411801999323962548289" + "01710708185069063066665599493827577257201576306269066333" + "26475653000092458883164330377797918696120494973903778297" + "04905051080609940730262937128958950003583799967207254304" + "36028407889577179615094551674824347103070260914462157228" + "98802581825451803257070188608721131280795122334262883686" + "22321503775666622503982534335974568884423900265498198385" + "48794829220689472168983109969836584681402285424333066033" + "98508864458040010349339704275671864433837704860378616227" + "71738545623065874679014086723327636718751", -1076)); +} + + TEST(Strtof) { Vector vector; @@ -576,6 +881,194 @@ TEST(Strtof) { } +TEST(StrtofTrimmed) { + Vector vector; + + vector = StringToVector("1"); + CHECK_EQ(1.0f, StrtofTrimmed(vector, 0)); + CHECK_EQ(10.0f, StrtofTrimmed(vector, 1)); + CHECK_EQ(100.0f, StrtofTrimmed(vector, 2)); + CHECK_EQ(1e20f, StrtofTrimmed(vector, 20)); + CHECK_EQ(1e22f, StrtofTrimmed(vector, 22)); + CHECK_EQ(1e23f, StrtofTrimmed(vector, 23)); + CHECK_EQ(1e35f, StrtofTrimmed(vector, 35)); + CHECK_EQ(1e36f, StrtofTrimmed(vector, 36)); + CHECK_EQ(1e37f, StrtofTrimmed(vector, 37)); + CHECK_EQ(1e-1f, StrtofTrimmed(vector, -1)); + CHECK_EQ(1e-2f, StrtofTrimmed(vector, -2)); + CHECK_EQ(1e-5f, StrtofTrimmed(vector, -5)); + CHECK_EQ(1e-20f, StrtofTrimmed(vector, -20)); + CHECK_EQ(1e-22f, StrtofTrimmed(vector, -22)); + CHECK_EQ(1e-23f, StrtofTrimmed(vector, -23)); + CHECK_EQ(1e-25f, StrtofTrimmed(vector, -25)); + CHECK_EQ(1e-39f, StrtofTrimmed(vector, -39)); + + vector = StringToVector("2"); + CHECK_EQ(2.0f, StrtofTrimmed(vector, 0)); + CHECK_EQ(20.0f, StrtofTrimmed(vector, 1)); + CHECK_EQ(200.0f, StrtofTrimmed(vector, 2)); + CHECK_EQ(2e20f, StrtofTrimmed(vector, 20)); + CHECK_EQ(2e22f, StrtofTrimmed(vector, 22)); + CHECK_EQ(2e23f, StrtofTrimmed(vector, 23)); + CHECK_EQ(2e35f, StrtofTrimmed(vector, 35)); + CHECK_EQ(2e36f, StrtofTrimmed(vector, 36)); + CHECK_EQ(2e37f, StrtofTrimmed(vector, 37)); + CHECK_EQ(2e-1f, StrtofTrimmed(vector, -1)); + CHECK_EQ(2e-2f, StrtofTrimmed(vector, -2)); + CHECK_EQ(2e-5f, StrtofTrimmed(vector, -5)); + CHECK_EQ(2e-20f, StrtofTrimmed(vector, -20)); + CHECK_EQ(2e-22f, StrtofTrimmed(vector, -22)); + CHECK_EQ(2e-23f, StrtofTrimmed(vector, -23)); + CHECK_EQ(2e-25f, StrtofTrimmed(vector, -25)); + CHECK_EQ(2e-39f, StrtofTrimmed(vector, -39)); + + vector = StringToVector("9"); + CHECK_EQ(9.0f, StrtofTrimmed(vector, 0)); + CHECK_EQ(90.0f, StrtofTrimmed(vector, 1)); + CHECK_EQ(900.0f, StrtofTrimmed(vector, 2)); + CHECK_EQ(9e20f, StrtofTrimmed(vector, 20)); + CHECK_EQ(9e22f, StrtofTrimmed(vector, 22)); + CHECK_EQ(9e23f, StrtofTrimmed(vector, 23)); + CHECK_EQ(9e35f, StrtofTrimmed(vector, 35)); + CHECK_EQ(9e36f, StrtofTrimmed(vector, 36)); + CHECK_EQ(9e37f, StrtofTrimmed(vector, 37)); + CHECK_EQ(9e-1f, StrtofTrimmed(vector, -1)); + CHECK_EQ(9e-2f, StrtofTrimmed(vector, -2)); + CHECK_EQ(9e-5f, StrtofTrimmed(vector, -5)); + CHECK_EQ(9e-20f, StrtofTrimmed(vector, -20)); + CHECK_EQ(9e-22f, StrtofTrimmed(vector, -22)); + CHECK_EQ(9e-23f, StrtofTrimmed(vector, -23)); + CHECK_EQ(9e-25f, StrtofTrimmed(vector, -25)); + CHECK_EQ(9e-39f, StrtofTrimmed(vector, -39)); + + vector = StringToVector("12345"); + CHECK_EQ(12345.0f, StrtofTrimmed(vector, 0)); + CHECK_EQ(123450.0f, StrtofTrimmed(vector, 1)); + CHECK_EQ(1234500.0f, StrtofTrimmed(vector, 2)); + CHECK_EQ(12345e20f, StrtofTrimmed(vector, 20)); + CHECK_EQ(12345e22f, StrtofTrimmed(vector, 22)); + CHECK_EQ(12345e23f, StrtofTrimmed(vector, 23)); + CHECK_EQ(12345e30f, StrtofTrimmed(vector, 30)); + CHECK_EQ(12345e31f, StrtofTrimmed(vector, 31)); + CHECK_EQ(12345e32f, StrtofTrimmed(vector, 32)); + CHECK_EQ(12345e-1f, StrtofTrimmed(vector, -1)); + CHECK_EQ(12345e-2f, StrtofTrimmed(vector, -2)); + CHECK_EQ(12345e-5f, StrtofTrimmed(vector, -5)); + CHECK_EQ(12345e-20f, StrtofTrimmed(vector, -20)); + CHECK_EQ(12345e-22f, StrtofTrimmed(vector, -22)); + CHECK_EQ(12345e-23f, StrtofTrimmed(vector, -23)); + CHECK_EQ(12345e-25f, StrtofTrimmed(vector, -25)); + CHECK_EQ(12345e-39f, StrtofTrimmed(vector, -39)); + + vector = StringToVector("12345678901234"); + CHECK_EQ(12345678901234.0f, StrtofTrimmed(vector, 0)); + CHECK_EQ(123456789012340.0f, StrtofTrimmed(vector, 1)); + CHECK_EQ(1234567890123400.0f, StrtofTrimmed(vector, 2)); + CHECK_EQ(12345678901234e20f, StrtofTrimmed(vector, 20)); + CHECK_EQ(12345678901234e22f, StrtofTrimmed(vector, 22)); + CHECK_EQ(12345678901234e23f, StrtofTrimmed(vector, 23)); + CHECK_EQ(12345678901234e-1f, StrtofTrimmed(vector, -1)); + CHECK_EQ(12345678901234e-2f, StrtofTrimmed(vector, -2)); + CHECK_EQ(12345678901234e-5f, StrtofTrimmed(vector, -5)); + CHECK_EQ(12345678901234e-20f, StrtofTrimmed(vector, -20)); + CHECK_EQ(12345678901234e-22f, StrtofTrimmed(vector, -22)); + CHECK_EQ(12345678901234e-23f, StrtofTrimmed(vector, -23)); + CHECK_EQ(12345678901234e-25f, StrtofTrimmed(vector, -25)); + CHECK_EQ(12345678901234e-39f, StrtofTrimmed(vector, -39)); + + vector = StringToVector("123456789012345"); + CHECK_EQ(123456789012345.0f, StrtofTrimmed(vector, 0)); + CHECK_EQ(1234567890123450.0f, StrtofTrimmed(vector, 1)); + CHECK_EQ(12345678901234500.0f, StrtofTrimmed(vector, 2)); + CHECK_EQ(123456789012345e20f, StrtofTrimmed(vector, 20)); + CHECK_EQ(123456789012345e22f, StrtofTrimmed(vector, 22)); + CHECK_EQ(123456789012345e23f, StrtofTrimmed(vector, 23)); + CHECK_EQ(123456789012345e-1f, StrtofTrimmed(vector, -1)); + CHECK_EQ(123456789012345e-2f, StrtofTrimmed(vector, -2)); + CHECK_EQ(123456789012345e-5f, StrtofTrimmed(vector, -5)); + CHECK_EQ(123456789012345e-20f, StrtofTrimmed(vector, -20)); + CHECK_EQ(123456789012345e-22f, StrtofTrimmed(vector, -22)); + CHECK_EQ(123456789012345e-23f, StrtofTrimmed(vector, -23)); + CHECK_EQ(123456789012345e-25f, StrtofTrimmed(vector, -25)); + CHECK_EQ(123456789012345e-39f, StrtofTrimmed(vector, -39)); + + CHECK_EQ(0.0f, StrtofTrimmedChar("", 1324)); + CHECK_EQ(0.0f, StrtofTrimmedChar("2", -324)); + CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45)); + // It would be more readable to put non-zero literals on the left side (i.e. + // CHECK_EQ(1e-46, StrtofChar("1", -45))), but then Gcc complains that + // they are truncated to zero. + CHECK_EQ(0.0f, StrtofTrimmedChar("1", -46)); + CHECK_EQ(0.0f, StrtofTrimmedChar("1", -47)); + CHECK_EQ(1e-45f, StrtofTrimmedChar("1", -45)); + CHECK_EQ(1e-45f, StrtofTrimmedChar("8", -46)); + + // It would be more readable to put the literals (and not Double::Infinity()) + // on the left side (i.e. CHECK_EQ(3e38, StrtofChar("3", 38))), but then Gcc + // complains that the floating constant exceeds range of 'double'. + CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("3", 39)); + CHECK_EQ(3e38f, StrtofTrimmedChar("3", 38)); + CHECK_EQ(3401e35f, StrtofTrimmedChar("3401", 35)); + CHECK_EQ(3401e34f, StrtofTrimmedChar("3401", 34)); + CHECK_EQ(34e37f, StrtofTrimmedChar("34", 37)); + CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235676", 28)); + CHECK_EQ(3.4028234e+38f, StrtofTrimmedChar("34028235677", 28)); + CHECK_EQ(Single::Infinity(), StrtofTrimmedChar("34028235678", 28)); + + // The following number is the result of 89255.0/1e-22. Both floating-point + // numbers can be accurately represented with doubles. However on Linux,x86 + // the floating-point stack is set to 80bits and the double-rounding + // introduces an error. + CHECK_EQ(89255e-22f, StrtofTrimmedChar("89255", -22)); + + // Boundary cases. Boundaries themselves should round to even. + // + // 0x4f012334 = 2166567936 + // next: 2166568192 + // boundary: 2166568064 should round down. + CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166567936", 0)); + CHECK_EQ(2166568192.0f, StrtofTrimmedChar("2166568192", 0)); + CHECK_EQ(2166567936.0f, StrtofTrimmedChar("2166568064", 0)); + CHECK_EQ(2166567936.0f, StrtofTrimmedChar("216656806399999", -5)); + CHECK_EQ(2166568192.0f, StrtofTrimmedChar("216656806400001", -5)); + // Verify that we don't double round. + // Get the boundary of the boundary. + CHECK_EQ(2.1665680640000002384185791015625e9, 2166568064.0); + // Visual Studio gets this wrong and believes that these two numbers are the + // same doubles. We want to test our conversion and not the compiler. We + // therefore disable the check. +#ifndef _MSC_VER + CHECK(2.16656806400000023841857910156251e9 != 2166568064.0); +#endif + CHECK_EQ(2166568192.0f, StrtofTrimmedChar("21665680640000002384185791015625", -22)); + + // 0x4fffffff = 8589934080 + // next: 8589934592 + // boundary: 8589934336 should round up. + CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934592", 0)); + CHECK_EQ(8589934592.0f, StrtofTrimmedChar("8589934336", 0)); + CHECK_EQ(8589934080.0f, StrtofTrimmedChar("858993433599999", -5)); + CHECK_EQ(8589934592.0f, StrtofTrimmedChar("858993433600001", -5)); + // Verify that we don't double round. + // Get the boundary of the boundary. + // Visual Studio gets this wrong. To avoid failing tests because of a broken + // compiler we disable the following two tests. They were only testing the + // compiler. The real test is still active. +#ifndef _MSC_VER + CHECK_EQ(8.589934335999999523162841796875e+09, 8589934336.0); + CHECK(8.5899343359999995231628417968749e+09 != 8589934336.0); +#endif + CHECK_EQ(8589934080.0f, StrtofTrimmedChar("8589934335999999523162841796875", -21)); + + // 0x4f000000 = 2147483648 + // next: 2147483904 + // boundary: 2147483776 should round down. + CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483648", 0)); + CHECK_EQ(2147483904.0f, StrtofTrimmedChar("2147483904", 0)); + CHECK_EQ(2147483648.0f, StrtofTrimmedChar("2147483776", 0)); + CHECK_EQ(2147483648.0f, StrtofTrimmedChar("214748377599999", -5)); + CHECK_EQ(2147483904.0f, StrtofTrimmedChar("214748377600001", -5)); +} static int CompareBignumToDiyFp(const Bignum& bignum_digits, int bignum_exponent,