diff --git a/.bazelrc b/.bazelrc deleted file mode 100644 index f33ebf5..0000000 --- a/.bazelrc +++ /dev/null @@ -1 +0,0 @@ -build --cxxopt="--std=c++17" diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index ad6c345..0000000 --- a/.cirrus.yml +++ /dev/null @@ -1,22 +0,0 @@ - -task: - timeout_in: 120m - freebsd_instance: - matrix: - - image_family: freebsd-13-0-snap - - env: - ASSUME_ALWAYS_YES: YES - setup_script: - - pkg update -f - - pkg install bash - - pkg install cmake - - pkg install git - build_script: - - mkdir build - - cd build - - cmake -DFASTFLOAT_TEST=ON .. - - make - test_script: - - cd build - - ctest --output-on-failure -R basictest diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 58108c4..0000000 --- a/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ -BasedOnStyle: LLVM -SortIncludes: false -SeparateDefinitionBlocks: Always -MaxEmptyLinesToKeep: 1 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 17a55c1..0000000 --- a/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -build/* -Testing/* -.cache/ -compile_commands.json -bazel-* - -# Visual studio -.vs/ -Debug/ -Release/ -/out/ -*.sln -*.vcxproj -*.vcxproj.filters -*.vcxproj.user -*.psess -*.vspx -*.vsp -*.diagsession -*.hint - -# VS CMake -/out/ -/CMakeSettings.json diff --git a/docs/.nojekyll b/.nojekyll similarity index 100% rename from docs/.nojekyll rename to .nojekyll diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ae854ae..0000000 --- a/.travis.yml +++ /dev/null @@ -1,242 +0,0 @@ -language: cpp - -dist: bionic - -cache: - directories: - - $HOME/.dep_cache - -env: - global: - - fastfloat_DEPENDENCY_CACHE_DIR=$HOME/.dep_cache - -services: - - docker - -# the ppc64le and s390x images use cmake 3.10, but fast_float requires 3.11. -# so we compile cmake from source in those images. -# - tried the kitware ppa but that is using 3.10 as well -# - tried also using snap to get a more recent version but that failed with -# udev errors. - -matrix: - include: - - arch: ppc64le - os: linux - env: - - CMAKE_SRC="https://github.com/Kitware/CMake/releases/download/v3.11.4/cmake-3.11.4.tar.gz" - - - arch: s390x - os: linux - env: - - CMAKE_SRC="https://github.com/Kitware/CMake/releases/download/v3.11.4/cmake-3.11.4.tar.gz" - - - arch: amd64 - os: linux - - - arch: amd64 - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-8 - env: - - COMPILER="CC=gcc-8 && CXX=g++-8" - compiler: gcc-8 - - - arch: amd64 - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-9 - env: - - COMPILER="CC=gcc-9 && CXX=g++-9" - compiler: gcc-9 - - - arch: amd64 - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-10 - env: - - COMPILER="CC=gcc-10 && CXX=g++-10" - compiler: gcc-10 - - - arch: amd64 - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-10 - env: - - COMPILER="CC=gcc-10 && CXX=g++-10" - - SANITIZE="on" - compiler: gcc-10-sanitize - - - arch: amd64 - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-10 - env: - - COMPILER="CC=gcc-10 && CXX=g++-10" - - STATIC="on" - acompiler: gcc-10-static - - - arch: amd64 - os: linux - addons: - apt: - sources: - - llvm-toolchain-bionic-6.0 - packages: - - clang-6.0 - env: - - COMPILER="CC=clang-6.0 && CXX=clang++-6.0" - compiler: clang-6 - - - arch: amd64 - os: linux - addons: - apt: - sources: - - llvm-toolchain-bionic-7 - packages: - - clang-7 - env: - - COMPILER="CC=clang-7 && CXX=clang++-7" - compiler: clang-7 - - - arch: amd64 - os: linux - addons: - apt: - sources: - - llvm-toolchain-bionic-8 - packages: - - clang-8 - env: - - COMPILER="CC=clang-8 && CXX=clang++-8" - compiler: clang-8 - - - arch: amd64 - os: linux - addons: - apt: - sources: - - llvm-toolchain-bionic-9 - packages: - - clang-9 - env: - - COMPILER="CC=clang-9 && CXX=clang++-9" - compiler: clang-9 - - - arch: amd64 - os: linux - addons: - apt: - packages: - - clang-10 - sources: - - ubuntu-toolchain-r-test - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: - - COMPILER="CC=clang-10 && CXX=clang++-10" - compiler: clang-10 - - - arch: amd64 - os: linux - addons: - apt: - packages: - - clang-10 - sources: - - ubuntu-toolchain-r-test - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: - - COMPILER="CC=clang-10 && CXX=clang++-10" - - STATIC="on" - compiler: clang-10-static - - - arch: amd64 - os: linux - addons: - apt: - packages: - - clang-10 - sources: - - ubuntu-toolchain-r-test - - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main' - key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' - env: - - COMPILER="CC=clang-10 && CXX=clang++-10" - - SANITIZE="on" - compiler: clang-10-sanitize - - - arch: amd64 - os: linux - env: - - TOOLCHAIN="mips64" - - - arch: amd64 - os: linux - env: - - TOOLCHAIN="riscv64" - -before_install: - - eval "${COMPILER}" - - | - if [ "$TOOLCHAIN" != "" ] ; then - docker pull ahuszagh/cross:"$TOOLCHAIN" - fi - -install: - - | - if [ "$CMAKE_SRC" != "" ] ; then - set -x - set -e - sudo -E apt remove --purge cmake - sudo -E apt-get update - sudo -E apt-get install -y build-essential libssl-dev - mkdir cmake_src - pushd cmake_src - wget "$CMAKE_SRC" - tar xfz $(basename "$CMAKE_SRC") - pushd $(basename "$CMAKE_SRC" | sed "s:.tar.gz::") - ./bootstrap - make -j2 - sudo make install - popd - popd - set +x - fi - - echo ${PATH} - - which cmake - - cmake --version - - which ${CC} - - ${CC} --version - - which ${CXX} - - ${CXX} --version - -script: - - | - if [ "$TOOLCHAIN" != "" ] ; then - docker run -v "$(pwd)":/ff ahuszagh/cross:"$TOOLCHAIN" /bin/bash -c "cd ff && ci/script.sh $TOOLCHAIN" - else - ci/script.sh - fi diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 60c9425..0000000 --- a/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Daniel Lemire -João Paulo Magalhaes diff --git a/BUILD.bazel b/BUILD.bazel deleted file mode 100644 index b08e909..0000000 --- a/BUILD.bazel +++ /dev/null @@ -1,8 +0,0 @@ -load("@rules_cc//cc:cc_library.bzl", "cc_library") - -cc_library( - name = "fast_float", - hdrs = glob(["include/fast_float/*.h"]), - strip_include_prefix = "include", - visibility = ["//visibility:public"], -) diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index e7cedc2..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - - -project(fast_float VERSION 8.2.5 LANGUAGES CXX) -set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat") -set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) -option(FASTFLOAT_TEST "Enable tests" OFF) - -if(FASTFLOAT_TEST) - enable_testing() - add_subdirectory(tests) -else(FASTFLOAT_TEST) - message(STATUS "Tests are disabled. Set FASTFLOAT_TEST to ON to run tests.") -endif(FASTFLOAT_TEST) - -option(FASTFLOAT_SANITIZE "Sanitize addresses" OFF) - -if (NOT CMAKE_BUILD_TYPE) - if(FASTFLOAT_SANITIZE) - set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - else() - message(STATUS "No build type selected, default to Release") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - endif() -endif() - -option(FASTFLOAT_INSTALL "Enable install" ON) - -if(FASTFLOAT_INSTALL) - include(GNUInstallDirs) -endif() - -add_library(fast_float INTERFACE) - - -option(FASTFLOAT_BENCHMARKS "Enable benchmarks" OFF) -if(FASTFLOAT_BENCHMARKS) - add_subdirectory(benchmarks) -else(FASTFLOAT_BENCHMARKS) - message(STATUS "Benchmarks are disabled. Set FASTFLOAT_BENCHMARKS to ON to build benchmarks (assumes C++17).") -endif(FASTFLOAT_BENCHMARKS) - - -add_library(FastFloat::fast_float ALIAS fast_float) -target_include_directories( - fast_float - INTERFACE - $ - $ -) -target_compile_features(fast_float INTERFACE cxx_std_11) -if(FASTFLOAT_SANITIZE) - target_compile_options(fast_float INTERFACE -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all) - target_link_libraries(fast_float INTERFACE -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all) - if (CMAKE_COMPILER_IS_GNUCC) - target_link_libraries(fast_float INTERFACE -fuse-ld=gold) - endif() -endif() - -target_compile_options(fast_float INTERFACE $<$,$,19.10>>:/permissive->) - -if(FASTFLOAT_INSTALL) - include(CMakePackageConfigHelpers) - - set(FASTFLOAT_VERSION_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/module/FastFloatConfigVersion.cmake") - set(FASTFLOAT_PROJECT_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/module/FastFloatConfig.cmake") - set(FASTFLOAT_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/cmake/FastFloat") - - if(${CMAKE_VERSION} VERSION_LESS "3.14") - write_basic_package_version_file("${FASTFLOAT_VERSION_CONFIG}" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) - else() - write_basic_package_version_file("${FASTFLOAT_VERSION_CONFIG}" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion ARCH_INDEPENDENT) - endif() - configure_package_config_file("cmake/config.cmake.in" - "${FASTFLOAT_PROJECT_CONFIG}" - INSTALL_DESTINATION "${FASTFLOAT_CONFIG_INSTALL_DIR}") - - install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/fast_float" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") - install(FILES "${FASTFLOAT_PROJECT_CONFIG}" "${FASTFLOAT_VERSION_CONFIG}" DESTINATION "${FASTFLOAT_CONFIG_INSTALL_DIR}") - install(EXPORT ${PROJECT_NAME}-targets NAMESPACE FastFloat:: DESTINATION "${FASTFLOAT_CONFIG_INSTALL_DIR}") - - install(TARGETS fast_float - EXPORT ${PROJECT_NAME}-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) -endif() diff --git a/CONTRIBUTORS b/CONTRIBUTORS deleted file mode 100644 index 4b70555..0000000 --- a/CONTRIBUTORS +++ /dev/null @@ -1,11 +0,0 @@ -Eugene Golushkov -Maksim Kita -Marcin Wojdyr -Neal Richardson -Tim Paine -Fabio Pellacini -Lénárd Szolnoki -Jan Pharago -Maya Warrier -Taha Khokhar -Anders Dalvander diff --git a/LICENSE-APACHE b/LICENSE-APACHE deleted file mode 100644 index 26f4398..0000000 --- a/LICENSE-APACHE +++ /dev/null @@ -1,190 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2021 The fast_float authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/LICENSE-BOOST b/LICENSE-BOOST deleted file mode 100644 index 127a5bc..0000000 --- a/LICENSE-BOOST +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT deleted file mode 100644 index 2fb2a37..0000000 --- a/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -MIT License - -Copyright (c) 2021 The fast_float authors - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/MODULE.bazel b/MODULE.bazel deleted file mode 100644 index 9f63ac4..0000000 --- a/MODULE.bazel +++ /dev/null @@ -1,11 +0,0 @@ -"""fast_float number parsing library: 4x faster than strtod""" - -module( - name = "fast_float", - version = "8.2.4", - compatibility_level = 8, -) - -bazel_dep(name = "doctest", version = "2.4.11", dev_dependency = True) - -bazel_dep(name = "rules_cc", version = "0.2.17") diff --git a/README.md b/README.md index 5e44349..a55714c 100644 --- a/README.md +++ b/README.md @@ -1,635 +1,25 @@ +# fast_float website -## fast_float number parsing library: 4x faster than strtod +The source for . -[![Ubuntu 22.04 CI (GCC 11)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml) - -*Note: This library is for C++ users. C programmers should consider [ffc.h](https://github.com/kolemannix/ffc.h). It is a high-performance port of fast_float to C.* - - -The fast_float library provides fast header-only implementations for the C++ -from_chars functions for `float` and `double` types as well as integer types. -These functions convert ASCII strings representing decimal values (e.g., -`1.3e10`) into binary types. We provide exact rounding (including round to -even). In our experience, these `fast_float` functions many times faster than -comparable number-parsing functions from existing C++ standard libraries. - - -Specifically, `fast_float` provides the following two functions to parse -floating-point numbers with a C++17-like syntax (the library itself only -requires C++11): - -```C++ -from_chars_result from_chars(char const *first, char const *last, float &value, ...); -from_chars_result from_chars(char const *first, char const *last, double &value, ...); -``` -If they are available on your system, we also support fixed-width floating-point types such as `std::float64_t`, `std::float32_t`, `std::float16_t`, and `std::bfloat16_t`. - -You can also parse integer types such as `char`, `short`, `long`, `long long`, `unsigned char`, `unsigned short`, `unsigned long`, `unsigned long long`, `bool` (0/1), `int8_t`, `int16_t`, `int32_t`, `int64_t`, `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`. -```C++ -from_chars_result from_chars(char const *first, char const *last, int &value, ...); -from_chars_result from_chars(char const *first, char const *last, unsigned &value, ...); -``` - -The return type (`from_chars_result`) is defined as the struct: - -```C++ -struct from_chars_result { - char const *ptr; - std::errc ec; -}; -``` - -It parses the character sequence `[first, last)` for a number. It parses -floating-point numbers expecting a locale-independent format equivalent to the -C++17 from_chars function. The resulting floating-point value is the closest -floating-point values (using either `float` or `double`), using the "round to -even" convention for values that would otherwise fall right in-between two -values. That is, we provide exact parsing according to the IEEE standard. - -Given a successful parse, the pointer (`ptr`) in the returned value is set to -point right after the parsed number, and the `value` referenced is set to the -parsed value. In case of error, the returned `ec` contains a representative -error, otherwise the default (`std::errc()`) value is stored. - -The implementation does not throw and does not allocate memory (e.g., with `new` -or `malloc`). - -It will parse infinity and nan values. - -Example: - -```C++ -#include "fast_float/fast_float.h" -#include -#include - -int main() { - std::string input = "3.1416 xyz "; - double result; - auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; -} -``` - -Prior to C++26, checking for a successful `std::from_chars` conversion requires comparing the `from_chars_result::ec` member to `std::errc()`. As an extension `fast_float::from_chars` supports the improved C++26 API that allows checking the result by converting it to `bool`, like so: - -```cpp -#include "fast_float/fast_float.h" -#include -#include - -int main() { - std::string input = "3.1416 xyz "; - double result; - if(auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result)) { - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; - } - std::cerr << "failed to parse " << input << std::endl; - return EXIT_FAILURE; -} -``` - -You can parse delimited numbers: - -```C++ - std::string input = "234532.3426362,7869234.9823,324562.645"; - double result; - auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { - // check error - } - // we have result == 234532.3426362. - if (answer.ptr[0] != ',') { - // unexpected delimiter - } - answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), result); - if (answer.ec != std::errc()) { - // check error - } - // we have result == 7869234.9823. - if (answer.ptr[0] != ',') { - // unexpected delimiter - } - answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), result); - if (answer.ec != std::errc()) { - // check error - } - // we have result == 324562.645. -``` - -Like the C++17 standard, the `fast_float::from_chars` functions take an optional -last argument of the type `fast_float::chars_format`. It is a bitset value: we -check whether `fmt & fast_float::chars_format::fixed` and `fmt & -fast_float::chars_format::scientific` are set to determine whether we allow the -fixed point and scientific notation respectively. The default is -`fast_float::chars_format::general` which allows both `fixed` and `scientific`. - -The library seeks to follow the C++17 (see -[28.2.3.(6.1)](https://eel.is/c++draft/charconv.from.chars#6.1)) specification. - -* The `from_chars` function does not skip leading white-space characters (unless - `fast_float::chars_format::skip_white_space` is set). -* [A leading `+` sign](https://en.cppreference.com/w/cpp/utility/from_chars) is - forbidden (unless `fast_float::chars_format::allow_leading_plus` is set). -* It is generally impossible to represent a decimal value exactly as binary - floating-point number (`float` and `double` types). We seek the nearest value. - We round to an even mantissa when we are in-between two binary floating-point - numbers. - -Furthermore, we have the following restrictions: - -* We support `float` and `double`, but not `long double`. We also support - fixed-width floating-point types such as `std::float64_t`, `std::float32_t`, - `std::float16_t`, and `std::bfloat16_t`. -* We only support the decimal format: we do not support hexadecimal strings. -* For values that are very large positives or negatives (e.g., `1e9999`), we - represent them using a positive or negative infinity and the returned - `ec` is set to `std::errc::result_out_of_range`. -* For values that are very close to zero (e.g., `1e-9999`), we represent them - using a positive or negative zero and the returned `ec` is set to - `std::errc::result_out_of_range`. - -We support Visual Studio, macOS, Linux, freeBSD. We support big and little -endian. We support 32-bit and 64-bit systems. - -We assume that the rounding mode is set to nearest (`std::fegetround() == -FE_TONEAREST`). - -## Integer types - -You can also parse integer types using different bases (e.g., 2, 10, 16). The -following code will print the number 22250738585072012 three times: - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - uint64_t i; - std::string str = "22250738585072012"; - auto answer = fast_float::from_chars(str.data(), str.data() + str.size(), i); - if (answer.ec != std::errc()) { - std::cerr << "parsing failure\n"; - return EXIT_FAILURE; - } - std::cout << "parsed the number " << i << std::endl; - - std::string binstr = "1001111000011001110110111001001010110100111000110001100"; - - answer = fast_float::from_chars(binstr.data(), binstr.data() + binstr.size(), i, 2); - if (answer.ec != std::errc()) { - std::cerr << "parsing failure\n"; - return EXIT_FAILURE; - } - std::cout << "parsed the number " << i << std::endl; - - std::string hexstr = "4f0cedc95a718c"; - - answer = fast_float::from_chars(hexstr.data(), hexstr.data() + hexstr.size(), i, 16); - if (answer.ec != std::errc()) { - std::cerr << "parsing failure\n"; - return EXIT_FAILURE; - } - std::cout << "parsed the number " << i << std::endl; - return EXIT_SUCCESS; -} -``` - -## Behavior of result_out_of_range - -When parsing floating-point values, the numbers can sometimes be too small -(e.g., `1e-1000`) or too large (e.g., `1e1000`). The C language established the -precedent that these small values are out of range. In such cases, it is -customary to parse small values to zero and large values to infinity. That is -the behaviour of the C language (e.g., `stdtod`). That is the behaviour followed -by the fast_float library. - -Specifically, we follow Jonathan Wakely's interpretation of the standard: - -> In any case, the resulting value is one of at most two floating-point values -> closest to the value of the string matching the pattern. - -It is also the approach taken by the [Microsoft C++ -library](https://github.com/microsoft/STL/blob/62205ab155d093e71dd9588a78f02c5396c3c14b/tests/std/tests/P0067R5_charconv/test.cpp#L943-L946). - -Hence, we have the following examples: - -```cpp - double result = -1; - std::string str = "3e-1000"; - auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result); - // r.ec == std::errc::result_out_of_range - // r.ptr == str.data() + 7 - // result == 0 -``` - -```cpp - double result = -1; - std::string str = "3e1000"; - auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result); - // r.ec == std::errc::result_out_of_range - // r.ptr == str.data() + 6 - // result == std::numeric_limits::infinity() -``` - -Users who wish for the value to be left unmodified given -`std::errc::result_out_of_range` may do so by adding two lines of code: - -```cpp - double old_result = result; // make copy - auto r = fast_float::from_chars(start, end, result); - if (r.ec == std::errc::result_out_of_range) { result = old_result; } -``` - -## C++20: compile-time evaluation (constexpr) - -In C++20, you may use `fast_float::from_chars` to parse strings at compile-time, -as in the following example: - -```C++ -// consteval forces compile-time evaluation of the function in C++20. -consteval double parse(std::string_view input) { - double result; - auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { return -1.0; } - return result; -} - -// This function should compile to a function which -// merely returns 3.1415. -constexpr double constexptest() { - return parse("3.1415 input"); -} -``` - -## C++23: Fixed width floating-point types - -The library also supports fixed-width floating-point types such as -`std::float64_t`, `std::float32_t`, `std::float16_t`, and `std::bfloat16_t`. -E.g., you can write: - -```C++ -std::float32_t result; -auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); -``` - -## Non-ASCII Inputs - -We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the -following example: - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::u16string input = u"3.1416 xyz "; - double result; - auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; -} -``` - -## Advanced options: using commas as decimal separator, JSON and Fortran - -The C++ standard stipulate that `from_chars` has to be locale-independent. In -particular, the decimal separator has to be the period (`.`). However, some -users still want to use the `fast_float` library with in a locale-dependent -manner. Using a separate function called `from_chars_advanced`, we allow the -users to pass a `parse_options` instance which contains a custom decimal -separator (e.g., the comma). You may use it as follows. - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = "3,1416 xyz "; - double result; - fast_float::parse_options options{fast_float::chars_format::general, ','}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); - if ((answer.ec != std::errc()) || ((result != 3.1416))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; -} -``` - -### You can also parse Fortran-like inputs - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = "1d+4"; - double result; - fast_float::parse_options options{fast_float::chars_format::fortran}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); - if ((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; -} -``` - -### You may also enforce the JSON format ([RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259#section-6)) - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = "+.1"; // not valid - double result; - fast_float::parse_options options{fast_float::chars_format::json}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); - if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; } - return EXIT_SUCCESS; -} -``` - -By default the JSON format does not allow `inf`: - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = "inf"; // not valid in JSON - double result; - fast_float::parse_options options{fast_float::chars_format::json}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); - if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; } - return EXIT_SUCCESS; -} -``` - -You can allow it with a non-standard `json_or_infnan` variant: - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = "inf"; // not valid in JSON but we allow it with json_or_infnan - double result; - fast_float::parse_options options{fast_float::chars_format::json_or_infnan}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); - if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; return EXIT_FAILURE; } - return EXIT_SUCCESS; -} -``` - -## Multiplication of an integer by a power of 10 -An integer `W` can be multiplied by a power of ten `10^Q` and -converted to `double` with correctly rounded value -(in "round to nearest, tie to even" fashion) using -`fast_float::integer_times_pow10()`, e.g.: -```C++ -const uint64_t W = 12345678901234567; -const int Q = 23; -const double result = fast_float::integer_times_pow10(W, Q); -std::cout.precision(17); -std::cout << W << " * 10^" << Q << " = " << result << " (" - << (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n"; -``` -outputs -``` -12345678901234567 * 10^23 = 1.2345678901234567e+39 (==expected) -``` -`fast_float::integer_times_pow10()` gives the same result as -using `fast_float::from_chars()` when parsing the string `"WeQ"` -(in this example `"12345678901234567e23"`), -except `fast_float::integer_times_pow10()` does not report out-of-range errors, and -underflows to zero or overflows to infinity when the resulting value is -out of range. - -You can use template overloads to get the result converted to different -supported floating-point types: `float`, `double`, etc. -For example, to get result as `float` use -`fast_float::integer_times_pow10()` specialization: -```C++ -const uint64_t W = 12345678; -const int Q = 23; -const float result = fast_float::integer_times_pow10(W, Q); -std::cout.precision(9); -std::cout << "float: " << W << " * 10^" << Q << " = " << result << " (" - << (result == 12345678e23f ? "==" : "!=") << "expected)\n"; -``` -outputs -``` -float: 12345678 * 10^23 = 1.23456782e+30 (==expected) -``` - -Overloads of `fast_float::integer_times_pow10()` are provided for -signed and unsigned integer types: `int64_t`, `uint64_t`, etc. - - -## Users and Related Work - -The fast_float library is part of: - -* GCC (as of version 12): the `from_chars` function in GCC relies on fast_float, -* [Chromium](https://github.com/Chromium/Chromium), the engine behind Google - Chrome, Microsoft Edge, and Opera, -* Boost JSON, MySQL, etc. -* Blender -* [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's - web browser), -* [DuckDB](https://duckdb.org), -* [Apache Arrow](https://github.com/apache/arrow/pull/8494) where it multiplied - the number parsing speed by two or three times, -* [Google Jsonnet](https://github.com/google/jsonnet), -* [ClickHouse](https://github.com/ClickHouse/ClickHouse). - -The fastfloat algorithm is part of the [LLVM standard -libraries](https://github.com/llvm/llvm-project/commit/87c016078ad72c46505461e4ff8bfa04819fe7ba). -There is a [derived implementation part of -AdaCore](https://github.com/AdaCore/VSS). The [SerenityOS operating -system](https://github.com/SerenityOS/serenity/commit/53b7f5e6a11e663c83df8030c3171c5945cb75ec) -has a derived implementation that is inherited by the [Ladybird -Browser](https://github.com/LadybirdBrowser/ladybird). - -Packages ------- - -[![Packaging status](https://repology.org/badge/vertical-allrepos/fast-float.svg)](https://repology.org/project/fast-float/versions) - - -## References - -* Daniel Lemire, [Number Parsing at a Gigabyte per - Second](https://arxiv.org/abs/2101.11408), Software: Practice and Experience - 51 (8), 2021. -* Noble Mushtak, Daniel Lemire, [Fast Number Parsing Without - Fallback](https://arxiv.org/abs/2212.06644), Software: Practice and Experience - 53 (7), 2023. - -## Other programming languages - -* [There is an R binding](https://github.com/eddelbuettel/rcppfastfloat) called - `rcppfastfloat`. -* [There is a Rust port of the fast_float - library](https://github.com/aldanor/fast-float-rust/) called - `fast-float-rust`. -* [There is a Java port of the fast_float - library](https://github.com/wrandelshofer/FastDoubleParser) called - `FastDoubleParser`. It used for important systems such as - [Jackson](https://github.com/FasterXML/jackson-core). -* [There is a C# port of the fast_float - library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`. -* [There is a plain C port of the fast_float library](https://github.com/kolemannix/ffc.h) called ffc.h - -## How fast is it? - -It can parse random floating-point numbers at a speed of 1 GB/s on some systems. -We find that it is often twice as fast as the best available competitor, and -many times faster than many standard-library implementations. - -fast_float is many times faster than many standard-library
-implementations +Static HTML, CSS, and a small JS file — no build step required. To preview +locally, serve this directory with any static file server, for example: ```bash -$ ./build/benchmarks/benchmark -# parsing random integers in the range [0,1) -volume = 2.09808 MB -netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s -doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s -strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s -abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s -fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s +python3 -m http.server -d docs 8080 +# then open http://localhost:8080/ ``` -See the [Benchmarking](#benchmarking) section for instructions on how to run our benchmarks. +## How the version number stays current -## Video +The displayed release version is kept fresh by two independent mechanisms: -[![Go Systems 2020](https://img.youtube.com/vi/AVXgvlMeIm4/0.jpg)](https://www.youtube.com/watch?v=AVXgvlMeIm4) +1. **Build-time substitution.** The `Deploy GitHub Pages` workflow + (`.github/workflows/pages.yml`) replaces every occurrence of the literal + `8.2.5` in `index.html` with the latest GitHub release tag before + publishing. The workflow runs on every push to `main` that touches + `docs/**`, on every published release, and can be dispatched manually. -## Using as a CMake dependency - -This library is header-only by design. The CMake file provides the `fast_float` -target which is merely a pointer to the `include` directory. - -If you drop the `fast_float` repository in your CMake project, you should be -able to use it in this manner: - -```cmake -add_subdirectory(fast_float) -target_link_libraries(myprogram PUBLIC fast_float) -``` - -Or you may want to retrieve the dependency automatically if you have a -sufficiently recent version of CMake (3.11 or better at least): - -```cmake -FetchContent_Declare( - fast_float - GIT_REPOSITORY https://github.com/fastfloat/fast_float.git - GIT_TAG tags/v8.2.5 - GIT_SHALLOW TRUE) - -FetchContent_MakeAvailable(fast_float) -target_link_libraries(myprogram PUBLIC fast_float) -``` - -You should change the `GIT_TAG` line so that you recover the version you wish to -use. - -You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so: - -```cmake -CPMAddPackage( - NAME fast_float - GITHUB_REPOSITORY "fastfloat/fast_float" - GIT_TAG v8.2.5) -``` - -## Using as single header - -The script `script/amalgamate.py` may be used to generate a single header -version of the library if so desired. Just run the script from the root -directory of this repository. You can customize the license type and output file -if desired as described in the command line help. - -You may directly download automatically generated single-header files: - - - -## Benchmarking - -The project has its own benchmarks with realistic data inputs. Under Linux or macOS, -you can use it as follows if your system supports C++17: - -``` -cmake -B build -D FASTFLOAT_BENCHMARKS=ON -cmake --build build -./build/benchmarks/realbenchmark -``` - -Importantly, by default, the benchmark is built in Release mode. - -The instructions are similar under Windows. - -Under Linux and macOS, it is recommended to run the benchmarks in a privileged manner to get access -to hardware performance counters. You may be able to do so with the `sudo` command -in some cases: - -``` -sudo ./build/benchmarks/realbenchmark -``` - -If you have a text file containing one number per line (`myfile.txt`), you can run a benchmark over it like so: -``` -cmake -B build -D FASTFLOAT_BENCHMARKS=ON -cmake --build build -./build/benchmarks/realbenchmark myfile.txt -``` - - -## Packages - -* The fast_float library is part of the [Conan package - manager](https://conan.io/center/recipes/fast_float). -* It is part of the [brew package - manager](https://formulae.brew.sh/formula/fast_float). -* fast_float is available on [xmake](https://xmake.io) repository. -* Some Linux distribution like Fedora include fast_float (e.g., as - `fast_float-devel`). - -## Credit - -Though this work is inspired by many different people, this work benefited -especially from exchanges with Michael Eisel, who motivated the original -research with his key insights, and with Nigel Tao who provided invaluable -feedback. Rémy Oudompheng first implemented a fast path we use in the case of -long digits. - -The library includes code adapted from Google Wuffs (written by Nigel Tao) which -was originally published under the Apache 2.0 license. - -## Stars - - -[![Star History Chart](https://api.star-history.com/svg?repos=fastfloat/fast_float&type=Date)](https://www.star-history.com/#fastfloat/fast_float&Date) - -## License - - -Licensed under either of Apache License, Version -2.0 or MIT license or BOOST license. - - -
- - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this repository by you, as defined in the Apache-2.0 license, -shall be triple licensed as above, without any additional terms or conditions. - +2. **Client-side refresh.** `assets/app.js` queries the GitHub Releases API + on page load and overwrites any element marked with `data-version`. This + means visitors see the very latest tag even between deploys. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 87c4c9b..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,7 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -Please use the following contact information for reporting a vulnerability: - -- [Daniel Lemire](https://github.com/lemire) - daniel@lemire.me diff --git a/docs/assets/app.js b/assets/app.js similarity index 98% rename from docs/assets/app.js rename to assets/app.js index 241a7a8..3f0420d 100644 --- a/docs/assets/app.js +++ b/assets/app.js @@ -63,7 +63,7 @@ } // ---------- Live version refresh from GitHub Releases ---------- - // The build-time workflow substitutes {{VERSION}} in the HTML; this + // The build-time workflow substitutes 8.2.5 in the HTML; this // additionally refreshes the displayed version in the browser so the // site always reflects the very latest release without redeploying. const versionNodes = document.querySelectorAll("[data-version]"); diff --git a/docs/assets/logo.svg b/assets/logo.svg similarity index 100% rename from docs/assets/logo.svg rename to assets/logo.svg diff --git a/docs/assets/style.css b/assets/style.css similarity index 100% rename from docs/assets/style.css rename to assets/style.css diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt deleted file mode 100644 index 81ea92a..0000000 --- a/benchmarks/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -include(FetchContent) - -FetchContent_Declare( - counters - GIT_REPOSITORY https://github.com/lemire/counters.git - GIT_TAG v2.2.0 -) - -FetchContent_MakeAvailable(counters) - -add_executable(realbenchmark benchmark.cpp) -target_link_libraries(realbenchmark PRIVATE counters::counters) -add_executable(bench_ip bench_ip.cpp) -add_executable(bench_uint16 bench_uint16.cpp) -target_link_libraries(bench_ip PRIVATE counters::counters) -target_link_libraries(bench_uint16 PRIVATE counters::counters) - -set_property( - TARGET realbenchmark - PROPERTY CXX_STANDARD 17) -set_property( - TARGET bench_ip - PROPERTY CXX_STANDARD 17) -set_property( - TARGET bench_uint16 - PROPERTY CXX_STANDARD 17) -target_link_libraries(realbenchmark PUBLIC fast_float) -target_link_libraries(bench_ip PUBLIC fast_float) -target_link_libraries(bench_uint16 PUBLIC fast_float) - -include(ExternalProject) - -# Define the external project -ExternalProject_Add(simple_fastfloat_benchmark - GIT_REPOSITORY https://github.com/lemire/simple_fastfloat_benchmark.git - GIT_TAG master # or specify a particular commit/tag/branch - SOURCE_DIR ${CMAKE_BINARY_DIR}/simple_fastfloat_benchmark - BINARY_DIR ${CMAKE_BINARY_DIR}/simple_fastfloat_benchmark-build - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" -) -set(DATA_DIR ${CMAKE_BINARY_DIR}/simple_fastfloat_benchmark/data) - -add_custom_target(CopyData ALL - COMMAND ${CMAKE_COMMAND} -E copy_directory ${DATA_DIR} ${CMAKE_CURRENT_BINARY_DIR}/data - DEPENDS simple_fastfloat_benchmark -) -add_dependencies(realbenchmark CopyData) -target_compile_definitions(realbenchmark PUBLIC BENCHMARK_DATA_DIR="${CMAKE_CURRENT_BINARY_DIR}/data") diff --git a/benchmarks/bench_ip.cpp b/benchmarks/bench_ip.cpp deleted file mode 100644 index 825a6b0..0000000 --- a/benchmarks/bench_ip.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "counters/bench.h" -#include "fast_float/fast_float.h" -#include -#include -#include -#include -#include -#include -#include -#include - -void pretty_print(size_t volume, size_t bytes, std::string name, - counters::event_aggregate agg) { - if (agg.inner_count > 1) { - printf("# (inner count: %d)\n", agg.inner_count); - } - printf("%-40s : ", name.c_str()); - printf(" %5.2f GB/s ", bytes / agg.fastest_elapsed_ns()); - printf(" %5.1f Mip/s ", volume * 1000.0 / agg.fastest_elapsed_ns()); - printf(" %5.2f ns/ip ", agg.fastest_elapsed_ns() / volume); - if (counters::event_collector().has_events()) { - printf(" %5.2f GHz ", agg.fastest_cycles() / agg.fastest_elapsed_ns()); - printf(" %5.2f c/ip ", agg.fastest_cycles() / volume); - printf(" %5.2f i/ip ", agg.fastest_instructions() / volume); - printf(" %5.2f c/b ", agg.fastest_cycles() / bytes); - printf(" %5.2f i/b ", agg.fastest_instructions() / bytes); - printf(" %5.2f i/c ", agg.fastest_instructions() / agg.fastest_cycles()); - } - printf("\n"); -} - -fastfloat_really_inline const char *seek_ip_end(const char *p, - const char *pend) { - const char *current = p; - size_t count = 0; - for (; current != pend; ++current) { - if (*current == '.') { - count++; - if (count == 3) { - ++current; - break; - } - } - } - while (current != pend) { - if (*current <= '9' && *current >= '0') { - ++current; - } else { - break; - } - } - return current; -} - -enum class parse_method { standard, fast_float }; - -template -fastfloat_really_inline std::pair -simple_parse_ip_line(const char *p, const char *pend) { - const char *current = p; - uint32_t ip = 0; - for (int i = 0; i < 4; ++i) { - uint8_t value; - if constexpr (use_standard == parse_method::standard) { - auto r = std::from_chars(current, pend, value); - if (r.ec != std::errc()) { - return {false, 0}; - } - current = r.ptr; - } else if constexpr (use_standard == parse_method::fast_float) { - auto r = fast_float::from_chars(current, pend, value); - if (r.ec != std::errc()) { - return {false, 0}; - } - current = r.ptr; - } - ip = (ip << 8) | value; - if (i < 3) { - if (current == pend || *current++ != '.') { - return {false, 0}; - } - } - } - return {true, ip}; -} - -static std::string make_ip_line(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { - std::string s; - s.reserve(16); - s += std::to_string(a); - s += '.'; - s += std::to_string(b); - s += '.'; - s += std::to_string(c); - s += '.'; - s += std::to_string(d); - s += '\n'; - return s; -} - -int main() { - constexpr size_t N = 15000; - std::mt19937 rng(1234); - std::uniform_int_distribution dist(0, 255); - - std::string buf; - constexpr size_t ip_size = 16; - buf.reserve(N * ip_size); - - for (size_t i = 0; i < N; ++i) { - uint8_t a = (uint8_t)dist(rng); - uint8_t b = (uint8_t)dist(rng); - uint8_t c = (uint8_t)dist(rng); - uint8_t d = (uint8_t)dist(rng); - std::string ip_line = make_ip_line(a, b, c, d); - ip_line.resize(ip_size, ' '); // pad to fixed size - buf.append(ip_line); - } - - // sentinel to allow 4-byte loads at end - buf.append(4, '\0'); - - const size_t bytes = buf.size() - 4; // exclude sentinel from throughput - const size_t volume = N; - - volatile uint32_t sink = 0; - std::string buffer(ip_size * N, ' '); - - pretty_print(volume, bytes, "memcpy baseline", counters::bench([&]() { - std::memcpy((char *)buffer.data(), buf.data(), bytes); - })); - - pretty_print(volume, bytes, "just_seek_ip_end (no parse)", - counters::bench([&]() { - const char *p = buf.data(); - const char *pend = buf.data() + bytes; - uint32_t sum = 0; - int ok = 0; - for (size_t i = 0; i < N; ++i) { - const char *q = seek_ip_end(p, pend); - sum += (uint32_t)(q - p); - p += ip_size; - } - sink += sum; - })); - - pretty_print(volume, bytes, "parse_ip_std_fromchars", counters::bench([&]() { - const char *p = buf.data(); - const char *pend = buf.data() + bytes; - uint32_t sum = 0; - int ok = 0; - for (size_t i = 0; i < N; ++i) { - auto [ok, ip] = - simple_parse_ip_line(p, pend); - sum += ip; - if (!ok) { - std::abort(); - } - p += ip_size; - } - sink += sum; - })); - - pretty_print(volume, bytes, "parse_ip_fastfloat", counters::bench([&]() { - const char *p = buf.data(); - const char *pend = buf.data() + bytes; - uint32_t sum = 0; - int ok = 0; - for (size_t i = 0; i < N; ++i) { - auto [ok, ip] = - simple_parse_ip_line(p, pend); - sum += ip; - if (!ok) { - std::abort(); - } - p += ip_size; - } - sink += sum; - })); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/benchmarks/bench_uint16.cpp b/benchmarks/bench_uint16.cpp deleted file mode 100644 index c4cef81..0000000 --- a/benchmarks/bench_uint16.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "counters/bench.h" -#include "fast_float/fast_float.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void pretty_print(size_t volume, size_t bytes, std::string name, - counters::event_aggregate agg) { - if (agg.inner_count > 1) { - printf("# (inner count: %d)\n", agg.inner_count); - } - printf("%-40s : ", name.c_str()); - printf(" %5.2f GB/s ", bytes / agg.fastest_elapsed_ns()); - printf(" %5.1f Mip/s ", volume * 1000.0 / agg.fastest_elapsed_ns()); - printf(" %5.2f ns/ip ", agg.fastest_elapsed_ns() / volume); - if (counters::event_collector().has_events()) { - printf(" %5.2f GHz ", agg.fastest_cycles() / agg.fastest_elapsed_ns()); - printf(" %5.2f c/ip ", agg.fastest_cycles() / volume); - printf(" %5.2f i/ip ", agg.fastest_instructions() / volume); - printf(" %5.2f c/b ", agg.fastest_cycles() / bytes); - printf(" %5.2f i/b ", agg.fastest_instructions() / bytes); - printf(" %5.2f i/c ", agg.fastest_instructions() / agg.fastest_cycles()); - } - printf("\n"); -} - -enum class parse_method { standard, fast_float }; - -void validate(const std::string &buffer, const std::vector &expected, - char delimiter) { - const char *p = buffer.data(); - const char *pend = p + buffer.size(); - - for (size_t i = 0; i < expected.size(); i++) { - uint16_t val; - auto r = fast_float::from_chars(p, pend, val); - if (r.ec != std::errc() || val != expected[i]) { - printf("Validation failed at index %zu: expected %u, got %u\n", i, - expected[i], val); - std::abort(); - } - p = r.ptr; - if (i + 1 < expected.size()) { - if (p >= pend || *p != delimiter) { - printf("Validation failed at index %zu: delimiter mismatch\n", i); - std::abort(); - } - ++p; - } - } - - if (p != pend) { - printf("Validation failed: trailing bytes remain\n"); - std::abort(); - } - printf("Validation passed!\n"); -} - -int main() { - constexpr size_t N = 500000; - constexpr char delimiter = ','; - std::mt19937 rng(1234); - std::uniform_int_distribution dist(0, 65535); - - std::vector expected; - expected.reserve(N); - - std::string buffer; - buffer.reserve(N * 6); // up to 5 digits + delimiter - - for (size_t i = 0; i < N; ++i) { - uint16_t val = (uint16_t)dist(rng); - expected.push_back(val); - std::string s = std::to_string(val); - buffer.append(s); - if (i + 1 < N) { - buffer.push_back(delimiter); - } - } - - size_t total_bytes = buffer.size(); - - validate(buffer, expected, delimiter); - - volatile uint64_t sink = 0; - - pretty_print(N, total_bytes, "parse_uint16_std_fromchars", - counters::bench([&]() { - uint64_t sum = 0; - const char *p = buffer.data(); - const char *pend = p + buffer.size(); - for (size_t i = 0; i < N; ++i) { - uint16_t value = 0; - auto r = std::from_chars(p, pend, value); - if (r.ec != std::errc()) - std::abort(); - sum += value; - p = r.ptr; - if (i + 1 < N) { - if (p >= pend || *p != delimiter) - std::abort(); - ++p; - } - } - if (p != pend) - std::abort(); - sink += sum; - })); - - pretty_print(N, total_bytes, "parse_uint16_fastfloat", counters::bench([&]() { - uint64_t sum = 0; - const char *p = buffer.data(); - const char *pend = p + buffer.size(); - for (size_t i = 0; i < N; ++i) { - uint16_t value = 0; - auto r = fast_float::from_chars(p, pend, value); - if (r.ec != std::errc()) - std::abort(); - sum += value; - p = r.ptr; - if (i + 1 < N) { - if (p >= pend || *p != delimiter) - std::abort(); - ++p; - } - } - if (p != pend) - std::abort(); - sink += sum; - })); - - return EXIT_SUCCESS; -} diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp deleted file mode 100644 index d90038e..0000000 --- a/benchmarks/benchmark.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#if defined(__linux__) || (__APPLE__ && __aarch64__) -#define USING_COUNTERS -#endif -#include "counters/event_counter.h" -#include -#include "fast_float/fast_float.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -template -double findmax_fastfloat64(std::vector> &s) { - double answer = 0; - double x = 0; - for (auto &st : s) { - auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); - if (p == st.data()) { - throw std::runtime_error("bug in findmax_fastfloat"); - } - answer = answer > x ? answer : x; - } - return answer; -} - -template -double findmax_fastfloat32(std::vector> &s) { - float answer = 0; - float x = 0; - for (auto &st : s) { - auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); - if (p == st.data()) { - throw std::runtime_error("bug in findmax_fastfloat"); - } - answer = answer > x ? answer : x; - } - return answer; -} - -counters::event_collector collector{}; - -#ifdef USING_COUNTERS -template -std::vector -time_it_ns(std::vector> &lines, T const &function, - size_t repeat) { - std::vector aggregate; - bool printed_bug = false; - for (size_t i = 0; i < repeat; i++) { - collector.start(); - double ts = function(lines); - if (ts == 0 && !printed_bug) { - printf("bug\n"); - printed_bug = true; - } - aggregate.push_back(collector.end()); - } - return aggregate; -} - -void pretty_print(double volume, size_t number_of_floats, std::string name, - std::vector events) { - double volumeMB = volume / (1024. * 1024.); - double average_ns{0}; - double min_ns{DBL_MAX}; - double cycles_min{DBL_MAX}; - double instructions_min{DBL_MAX}; - double cycles_avg{0}; - double instructions_avg{0}; - double branches_min{0}; - double branches_avg{0}; - double branch_misses_min{0}; - double branch_misses_avg{0}; - for (counters::event_count e : events) { - double ns = e.elapsed_ns(); - average_ns += ns; - min_ns = min_ns < ns ? min_ns : ns; - - double cycles = e.cycles(); - cycles_avg += cycles; - cycles_min = cycles_min < cycles ? cycles_min : cycles; - - double instructions = e.instructions(); - instructions_avg += instructions; - instructions_min = - instructions_min < instructions ? instructions_min : instructions; - - double branches = e.branches(); - branches_avg += branches; - branches_min = branches_min < branches ? branches_min : branches; - - double branch_misses = e.branch_misses(); - branch_misses_avg += branch_misses; - branch_misses_min = - branch_misses_min < branch_misses ? branch_misses_min : branch_misses; - } - cycles_avg /= events.size(); - instructions_avg /= events.size(); - average_ns /= events.size(); - branches_avg /= events.size(); - printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), - volumeMB * 1000000000 / min_ns, - (average_ns - min_ns) * 100.0 / average_ns); - printf("%8.2f Mfloat/s ", number_of_floats * 1000 / min_ns); - if (instructions_min > 0) { - printf(" %8.2f i/B %8.2f i/f (+/- %.1f %%) ", instructions_min / volume, - instructions_min / number_of_floats, - (instructions_avg - instructions_min) * 100.0 / instructions_avg); - - printf(" %8.2f c/B %8.2f c/f (+/- %.1f %%) ", cycles_min / volume, - cycles_min / number_of_floats, - (cycles_avg - cycles_min) * 100.0 / cycles_avg); - printf(" %8.2f i/c ", instructions_min / cycles_min); - printf(" %8.2f b/f ", branches_avg / number_of_floats); - printf(" %8.2f bm/f ", branch_misses_avg / number_of_floats); - printf(" %8.2f GHz ", cycles_min / min_ns); - } - printf("\n"); -} -#else -template -std::pair -time_it_ns(std::vector> &lines, T const &function, - size_t repeat) { - std::chrono::high_resolution_clock::time_point t1, t2; - double average = 0; - double min_value = DBL_MAX; - bool printed_bug = false; - for (size_t i = 0; i < repeat; i++) { - t1 = std::chrono::high_resolution_clock::now(); - double ts = function(lines); - if (ts == 0 && !printed_bug) { - printf("bug\n"); - printed_bug = true; - } - t2 = std::chrono::high_resolution_clock::now(); - double dif = - std::chrono::duration_cast(t2 - t1).count(); - average += dif; - min_value = min_value < dif ? min_value : dif; - } - average /= repeat; - return std::make_pair(min_value, average); -} - -void pretty_print(double volume, size_t number_of_floats, std::string name, - std::pair result) { - double volumeMB = volume / (1024. * 1024.); - printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), - volumeMB * 1000000000 / result.first, - (result.second - result.first) * 100.0 / result.second); - printf("%8.2f Mfloat/s ", number_of_floats * 1000 / result.first); - printf(" %8.2f ns/f \n", double(result.first) / number_of_floats); -} -#endif - -// this is okay, all chars are ASCII -inline std::u16string widen(std::string line) { - std::u16string u16line; - u16line.resize(line.size()); - for (size_t i = 0; i < line.size(); ++i) { - u16line[i] = char16_t(line[i]); - } - return u16line; -} - -std::vector widen(const std::vector &lines) { - std::vector u16lines; - u16lines.reserve(lines.size()); - for (auto const &line : lines) { - u16lines.push_back(widen(line)); - } - return u16lines; -} - -void process(std::vector &lines, size_t volume) { - size_t repeat = 1000; - double volumeMB = volume / (1024. * 1024.); - std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl; - pretty_print(volume, lines.size(), "fastfloat (64)", - time_it_ns(lines, findmax_fastfloat64, repeat)); - pretty_print(volume, lines.size(), "fastfloat (32)", - time_it_ns(lines, findmax_fastfloat32, repeat)); - - std::vector lines16 = widen(lines); - volume = 2 * volume; - volumeMB = volume / (1024. * 1024.); - std::cout << "UTF-16 volume = " << volumeMB << " MB " << std::endl; - pretty_print(volume, lines.size(), "fastfloat (64)", - time_it_ns(lines16, findmax_fastfloat64, repeat)); - pretty_print(volume, lines.size(), "fastfloat (32)", - time_it_ns(lines16, findmax_fastfloat32, repeat)); -} - -void fileload(std::string filename) { - std::ifstream inputfile(filename); - if (!inputfile) { - std::cerr << "can't open " << filename << std::endl; - return; - } - std::cout << "#### " << std::endl; - std::cout << "# reading " << filename << std::endl; - std::cout << "#### " << std::endl; - std::string line; - std::vector lines; - lines.reserve(10000); // let us reserve plenty of memory. - size_t volume = 0; - while (getline(inputfile, line)) { - volume += line.size(); - lines.push_back(line); - } - std::cout << "# read " << lines.size() << " lines " << std::endl; - process(lines, volume); -} - -int main(int argc, char **argv) { - if (collector.has_events()) { - std::cout << "# Using hardware counters" << std::endl; - } else { -#if defined(__linux__) || (__APPLE__ && __aarch64__) - std::cout << "# Hardware counters not available, try to run in privileged " - "mode (e.g., sudo)." - << std::endl; -#endif - } - if (argc > 1) { - fileload(argv[1]); - return EXIT_SUCCESS; - } - fileload(std::string(BENCHMARK_DATA_DIR) + "/canada.txt"); - fileload(std::string(BENCHMARK_DATA_DIR) + "/mesh.txt"); - return EXIT_SUCCESS; -} diff --git a/ci/script.sh b/ci/script.sh deleted file mode 100755 index c9894c7..0000000 --- a/ci/script.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -TOOLCHAIN="$1" - -mkdir build -cd build - -if [ "$TOOLCHAIN" != "" ] ; then - cmake -DFASTFLOAT_TEST=ON .. -DCMAKE_TOOLCHAIN_FILE=/toolchains/"$TOOLCHAIN".cmake -else - cmake -DFASTFLOAT_TEST=ON .. -fi -make -j 2 -if [ "$TOOLCHAIN" != "" ] ; then - qemu-"$TOOLCHAIN" tests/basictest -else - ctest --output-on-failure -R basictest -fi diff --git a/clang-format-ignore.txt b/clang-format-ignore.txt deleted file mode 100644 index e69de29..0000000 diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in deleted file mode 100644 index 035dc0f..0000000 --- a/cmake/config.cmake.in +++ /dev/null @@ -1,4 +0,0 @@ -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") -check_required_components("@PROJECT_NAME@") diff --git a/cmake/toolchains-ci/riscv64-linux-gnu.cmake b/cmake/toolchains-ci/riscv64-linux-gnu.cmake deleted file mode 100644 index ed58a2d..0000000 --- a/cmake/toolchains-ci/riscv64-linux-gnu.cmake +++ /dev/null @@ -1,4 +0,0 @@ -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR riscv64) - -set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-riscv64-static") diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 640a9cb..0000000 --- a/docs/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# fast_float website - -The source for . - -Static HTML, CSS, and a small JS file — no build step required. To preview -locally, serve this directory with any static file server, for example: - -```bash -python3 -m http.server -d docs 8080 -# then open http://localhost:8080/ -``` - -## How the version number stays current - -The displayed release version is kept fresh by two independent mechanisms: - -1. **Build-time substitution.** The `Deploy GitHub Pages` workflow - (`.github/workflows/pages.yml`) replaces every occurrence of the literal - `{{VERSION}}` in `index.html` with the latest GitHub release tag before - publishing. The workflow runs on every push to `main` that touches - `docs/**`, on every published release, and can be dispatched manually. - -2. **Client-side refresh.** `assets/app.js` queries the GitHub Releases API - on page load and overwrites any element marked with `data-version`. This - means visitors see the very latest tag even between deploys. diff --git a/fuzz/build.sh b/fuzz/build.sh deleted file mode 100644 index cce114d..0000000 --- a/fuzz/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -$CXX $CFLAGS $CXXFLAGS \ - -I $SRC/fast_float/include \ - -c $SRC/fast_float/fuzz/from_chars.cc -o from_chars.o - -$CXX $CFLAGS $CXXFLAGS $LIB_FUZZING_ENGINE from_chars.o \ - -o $OUT/from_chars - -# Build unit tests -cmake -DFASTFLOAT_TEST=ON -DCMAKE_EXE_LINKER_FLAGS="-lpthread" -make diff --git a/fuzz/from_chars.cc b/fuzz/from_chars.cc deleted file mode 100644 index 35fe9fe..0000000 --- a/fuzz/from_chars.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include "fast_float/fast_float.h" -#include -#include -#include - -fast_float::chars_format arbitrary_format(FuzzedDataProvider &fdp) { - using fast_float::chars_format; - switch (fdp.ConsumeIntegralInRange(0, 3)) { - case 0: - return chars_format::scientific; - break; - case 1: - return chars_format::fixed; - break; - case 2: - return chars_format::fixed; - break; - } - return chars_format::general; -} - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) { - FuzzedDataProvider fdp(data, size); - fast_float::chars_format format = arbitrary_format(fdp); - double result_d = 0.0; - std::string input_d = fdp.ConsumeRandomLengthString(128); - auto answer = fast_float::from_chars( - input_d.data(), input_d.data() + input_d.size(), result_d, format); - std::string input_f = fdp.ConsumeRandomLengthString(128); - float result_f = 0.0; - answer = fast_float::from_chars( - input_f.data(), input_f.data() + input_f.size(), result_f, format); - int result_i = 0; - std::string input_i = fdp.ConsumeRandomLengthString(128); - answer = fast_float::from_chars(input_i.data(), - input_i.data() + input_i.size(), result_i); - return 0; -} \ No newline at end of file diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h deleted file mode 100644 index 12c2fdd..0000000 --- a/include/fast_float/ascii_number.h +++ /dev/null @@ -1,766 +0,0 @@ -#ifndef FASTFLOAT_ASCII_NUMBER_H -#define FASTFLOAT_ASCII_NUMBER_H - -#include -#include -#include -#include -#include -#include - -#include "float_common.h" - -#ifdef FASTFLOAT_SSE2 -#include -#endif - -#ifdef FASTFLOAT_NEON -#include -#endif - -namespace fast_float { - -template fastfloat_really_inline constexpr bool has_simd_opt() { -#ifdef FASTFLOAT_HAS_SIMD - return std::is_same::value; -#else - return false; -#endif -} - -// Next function can be micro-optimized, but compilers are entirely -// able to optimize it well. -template -fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { - return (unsigned)(c - UC('0')) <= 9u; -} - -fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { - return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 | - (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 | - (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 | - (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56; -} - -fastfloat_really_inline constexpr uint32_t byteswap_32(uint32_t val) { - return (val >> 24) | ((val >> 8) & 0x0000FF00u) | ((val << 8) & 0x00FF0000u) | - (val << 24); -} - -// Read 8 UC into a u64. Truncates UC if not char. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t -read8_to_u64(UC const *chars) { - if (cpp20_and_in_constexpr() || !std::is_same::value) { - uint64_t val = 0; - for (int i = 0; i < 8; ++i) { - val |= uint64_t(uint8_t(*chars)) << (i * 8); - ++chars; - } - return val; - } - uint64_t val; - ::memcpy(&val, chars, sizeof(uint64_t)); -#if FASTFLOAT_IS_BIG_ENDIAN == 1 - // Need to read as-if the number was in little-endian order. - val = byteswap(val); -#endif - return val; -} - -// Read 4 UC into a u32. Truncates UC if not char. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t -read4_to_u32(UC const *chars) { - if (cpp20_and_in_constexpr() || !std::is_same::value) { - uint32_t val = 0; - for (int i = 0; i < 4; ++i) { - val |= uint32_t(uint8_t(*chars)) << (i * 8); - ++chars; - } - return val; - } - uint32_t val; - ::memcpy(&val, chars, sizeof(uint32_t)); -#if FASTFLOAT_IS_BIG_ENDIAN == 1 - val = byteswap_32(val); -#endif - return val; -} -#ifdef FASTFLOAT_SSE2 - -fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { - FASTFLOAT_SIMD_DISABLE_WARNINGS - __m128i const packed = _mm_packus_epi16(data, data); -#ifdef FASTFLOAT_64BIT - return uint64_t(_mm_cvtsi128_si64(packed)); -#else - uint64_t value; - // Visual Studio + older versions of GCC don't support _mm_storeu_si64 - _mm_storel_epi64(reinterpret_cast<__m128i *>(&value), packed); - return value; -#endif - FASTFLOAT_SIMD_RESTORE_WARNINGS -} - -fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { - FASTFLOAT_SIMD_DISABLE_WARNINGS - return simd_read8_to_u64( - _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); - FASTFLOAT_SIMD_RESTORE_WARNINGS -} - -#elif defined(FASTFLOAT_NEON) - -fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) { - FASTFLOAT_SIMD_DISABLE_WARNINGS - uint8x8_t utf8_packed = vmovn_u16(data); - return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); - FASTFLOAT_SIMD_RESTORE_WARNINGS -} - -fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { - FASTFLOAT_SIMD_DISABLE_WARNINGS - return simd_read8_to_u64( - vld1q_u16(reinterpret_cast(chars))); - FASTFLOAT_SIMD_RESTORE_WARNINGS -} - -#endif // FASTFLOAT_SSE2 - -// MSVC SFINAE is broken pre-VS2017 -#if defined(_MSC_VER) && _MSC_VER <= 1900 -template -#else -template ()) = 0> -#endif -// dummy for compile -uint64_t simd_read8_to_u64(UC const *) { - return 0; -} - -// credit @aqrit -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t -parse_eight_digits_unrolled(uint64_t val) { - uint64_t const mask = 0x000000FF000000FF; - uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) - uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) - val -= 0x3030303030303030; - val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; - val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; - return uint32_t(val); -} - -// Call this if chars are definitely 8 digits. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t -parse_eight_digits_unrolled(UC const *chars) noexcept { - if (cpp20_and_in_constexpr() || !has_simd_opt()) { - return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay - } - return parse_eight_digits_unrolled(simd_read8_to_u64(chars)); -} - -// credit @aqrit -fastfloat_really_inline constexpr bool -is_made_of_eight_digits_fast(uint64_t val) noexcept { - return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & - 0x8080808080808080)); -} - -fastfloat_really_inline constexpr bool -is_made_of_four_digits_fast(uint32_t val) noexcept { - return !((((val + 0x46464646) | (val - 0x30303030)) & 0x80808080)); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t -parse_four_digits_unrolled(uint32_t val) noexcept { - val -= 0x30303030; - val = (val * 10) + (val >> 8); - return (((val & 0x00FF00FF) * 0x00640001) >> 16) & 0xFFFF; -} - -#ifdef FASTFLOAT_HAS_SIMD - -// Call this if chars might not be 8 digits. -// Using this style (instead of is_made_of_eight_digits_fast() then -// parse_eight_digits_unrolled()) ensures we don't load SIMD registers twice. -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -simd_parse_if_eight_digits_unrolled(char16_t const *chars, - uint64_t &i) noexcept { - if (cpp20_and_in_constexpr()) { - return false; - } -#ifdef FASTFLOAT_SSE2 - FASTFLOAT_SIMD_DISABLE_WARNINGS - __m128i const data = - _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); - - // (x - '0') <= 9 - // http://0x80.pl/articles/simd-parsing-int-sequences.html - __m128i const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720)); - __m128i const t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759)); - - if (_mm_movemask_epi8(t1) == 0) { - i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); - return true; - } else - return false; - FASTFLOAT_SIMD_RESTORE_WARNINGS -#elif defined(FASTFLOAT_NEON) - FASTFLOAT_SIMD_DISABLE_WARNINGS - uint16x8_t const data = vld1q_u16(reinterpret_cast(chars)); - - // (x - '0') <= 9 - // http://0x80.pl/articles/simd-parsing-int-sequences.html - uint16x8_t const t0 = vsubq_u16(data, vmovq_n_u16('0')); - uint16x8_t const mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1)); - - if (vminvq_u16(mask) == 0xFFFF) { - i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); - return true; - } else - return false; - FASTFLOAT_SIMD_RESTORE_WARNINGS -#else - (void)chars; - (void)i; - return false; -#endif // FASTFLOAT_SSE2 -} - -#endif // FASTFLOAT_HAS_SIMD - -// MSVC SFINAE is broken pre-VS2017 -#if defined(_MSC_VER) && _MSC_VER <= 1900 -template -#else -template ()) = 0> -#endif -// dummy for compile -bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { - return 0; -} - -template ::value) = 0> -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -loop_parse_if_eight_digits(UC const *&p, UC const *const pend, uint64_t &i) { - if (!has_simd_opt()) { - return; - } - while ((std::distance(p, pend) >= 8) && - simd_parse_if_eight_digits_unrolled( - p, i)) { // in rare cases, this will overflow, but that's ok - p += 8; - } -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -loop_parse_if_eight_digits(char const *&p, char const *const pend, - uint64_t &i) { - // optimizes better than parse_if_eight_digits_unrolled() for UC = char. - while ((std::distance(p, pend) >= 8) && - is_made_of_eight_digits_fast(read8_to_u64(p))) { - i = i * 100000000 + - parse_eight_digits_unrolled(read8_to_u64( - p)); // in rare cases, this will overflow, but that's ok - p += 8; - } -} - -enum class parse_error { - no_error, - // [JSON-only] The minus sign must be followed by an integer. - missing_integer_after_sign, - // A sign must be followed by an integer or dot. - missing_integer_or_dot_after_sign, - // [JSON-only] The integer part must not have leading zeros. - leading_zeros_in_integer_part, - // [JSON-only] The integer part must have at least one digit. - no_digits_in_integer_part, - // [JSON-only] If there is a decimal point, there must be digits in the - // fractional part. - no_digits_in_fractional_part, - // The mantissa must have at least one digit. - no_digits_in_mantissa, - // Scientific notation requires an exponential part. - missing_exponential_part, -}; - -template struct parsed_number_string_t { - int64_t exponent{0}; - uint64_t mantissa{0}; - UC const *lastmatch{nullptr}; - bool negative{false}; - bool valid{false}; - bool too_many_digits{false}; - // contains the range of the significant digits - span integer{}; // non-nullable - span fraction{}; // nullable - parse_error error{parse_error::no_error}; -}; - -using byte_span = span; -using parsed_number_string = parsed_number_string_t; - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t -report_parse_error(UC const *p, parse_error error) { - parsed_number_string_t answer; - answer.valid = false; - answer.lastmatch = p; - answer.error = error; - return answer; -} - -// Assuming that you use no more than 19 digits, this will -// parse an ASCII string. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t -parse_number_string(UC const *p, UC const *pend, - parse_options_t options) noexcept { - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - UC const decimal_point = options.decimal_point; - - parsed_number_string_t answer; - answer.valid = false; - answer.too_many_digits = false; - // assume p < pend, so dereference without checks; - answer.negative = (*p == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || (uint64_t(fmt & chars_format::allow_leading_plus) && - !basic_json_fmt && *p == UC('+'))) { - ++p; - if (p == pend) { - return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); - } - FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { - if (!is_integer(*p)) { // a sign must be followed by an integer - return report_parse_error(p, - parse_error::missing_integer_after_sign); - } - } - else { - if (!is_integer(*p) && - (*p != - decimal_point)) { // a sign must be followed by an integer or the dot - return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); - } - } - } - UC const *const start_digits = p; - - uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) - - while ((p != pend) && is_integer(*p)) { - // a multiplication by 10 is cheaper than an arbitrary integer - // multiplication - i = 10 * i + - uint64_t(*p - - UC('0')); // might overflow, we will handle the overflow later - ++p; - } - UC const *const end_of_integer_part = p; - int64_t digit_count = int64_t(end_of_integer_part - start_digits); - answer.integer = span(start_digits, size_t(digit_count)); - FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { - // at least 1 digit in integer part, without leading zeros - if (digit_count == 0) { - return report_parse_error(p, parse_error::no_digits_in_integer_part); - } - if ((start_digits[0] == UC('0') && digit_count > 1)) { - return report_parse_error(start_digits, - parse_error::leading_zeros_in_integer_part); - } - } - - int64_t exponent = 0; - bool const has_decimal_point = (p != pend) && (*p == decimal_point); - if (has_decimal_point) { - ++p; - UC const *before = p; - // can occur at most twice without overflowing, but let it occur more, since - // for integers with many digits, digit parsing is the primary bottleneck. - loop_parse_if_eight_digits(p, pend, i); - - while ((p != pend) && is_integer(*p)) { - uint8_t digit = uint8_t(*p - UC('0')); - ++p; - i = i * 10 + digit; // in rare cases, this will overflow, but that's ok - } - exponent = before - p; - answer.fraction = span(before, size_t(p - before)); - digit_count -= exponent; - } - FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { - // at least 1 digit in fractional part - if (has_decimal_point && exponent == 0) { - return report_parse_error(p, - parse_error::no_digits_in_fractional_part); - } - } - else if (digit_count == 0) { // we must have encountered at least one integer! - return report_parse_error(p, parse_error::no_digits_in_mantissa); - } - int64_t exp_number = 0; // explicit exponential part - if ((uint64_t(fmt & chars_format::scientific) && (p != pend) && - ((UC('e') == *p) || (UC('E') == *p))) || - (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p)))) { - UC const *location_of_e = p; - if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || - (UC('D') == *p)) { - ++p; - } - bool neg_exp = false; - if ((p != pend) && (UC('-') == *p)) { - neg_exp = true; - ++p; - } else if ((p != pend) && - (UC('+') == - *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) - ++p; - } - if ((p == pend) || !is_integer(*p)) { - if (!uint64_t(fmt & chars_format::fixed)) { - // The exponential part is invalid for scientific notation, so it must - // be a trailing token for fixed notation. However, fixed notation is - // disabled, so report a scientific notation error. - return report_parse_error(p, parse_error::missing_exponential_part); - } - // Otherwise, we will be ignoring the 'e'. - p = location_of_e; - } else { - while ((p != pend) && is_integer(*p)) { - uint8_t digit = uint8_t(*p - UC('0')); - if (exp_number < 0x10000000) { - exp_number = 10 * exp_number + digit; - } - ++p; - } - if (neg_exp) { - exp_number = -exp_number; - } - exponent += exp_number; - } - } else { - // If it scientific and not fixed, we have to bail out. - if (uint64_t(fmt & chars_format::scientific) && - !uint64_t(fmt & chars_format::fixed)) { - return report_parse_error(p, parse_error::missing_exponential_part); - } - } - answer.lastmatch = p; - answer.valid = true; - - // If we frequently had to deal with long strings of digits, - // we could extend our code by using a 128-bit integer instead - // of a 64-bit integer. However, this is uncommon. - // - // We can deal with up to 19 digits. - if (digit_count > 19) { // this is uncommon - // It is possible that the integer had an overflow. - // We have to handle the case where we have 0.0000somenumber. - // We need to be mindful of the case where we only have zeroes... - // E.g., 0.000000000...000. - UC const *start = start_digits; - while ((start != pend) && (*start == UC('0') || *start == decimal_point)) { - if (*start == UC('0')) { - digit_count--; - } - start++; - } - - if (digit_count > 19) { - answer.too_many_digits = true; - // Let us start again, this time, avoiding overflows. - // We don't need to call if is_integer, since we use the - // pre-tokenized spans from above. - i = 0; - p = answer.integer.ptr; - UC const *int_end = p + answer.integer.len(); - uint64_t const minimal_nineteen_digit_integer{1000000000000000000}; - while ((i < minimal_nineteen_digit_integer) && (p != int_end)) { - i = i * 10 + uint64_t(*p - UC('0')); - ++p; - } - if (i >= minimal_nineteen_digit_integer) { // We have a big integer - exponent = end_of_integer_part - p + exp_number; - } else { // We have a value with a fractional component. - p = answer.fraction.ptr; - UC const *frac_end = p + answer.fraction.len(); - while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) { - i = i * 10 + uint64_t(*p - UC('0')); - ++p; - } - exponent = answer.fraction.ptr - p + exp_number; - } - // We have now corrected both exponent and i, to a truncated value - } - } - answer.exponent = exponent; - answer.mantissa = i; - return answer; -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t -parse_int_string(UC const *p, UC const *pend, T &value, - parse_options_t options) { - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - int const base = options.base; - - from_chars_result_t answer; - - UC const *const first = p; - - bool const negative = (*p == UC('-')); -#ifdef FASTFLOAT_VISUAL_STUDIO -#pragma warning(push) -#pragma warning(disable : 4127) -#endif - if (!std::is_signed::value && negative) { -#ifdef FASTFLOAT_VISUAL_STUDIO -#pragma warning(pop) -#endif - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - if ((*p == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { - ++p; - } - - UC const *const start_num = p; - - while (p != pend && *p == UC('0')) { - ++p; - } - - bool const has_leading_zeros = p > start_num; - - UC const *const start_digits = p; - - FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - if (base == 10) { - const size_t len = (size_t)(pend - p); - if (len == 0) { - if (has_leading_zeros) { - value = 0; - answer.ec = std::errc(); - answer.ptr = p; - } else { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - } - return answer; - } - - uint32_t digits; - -#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST - if (std::is_constant_evaluated()) { - uint8_t str[4]{}; - for (size_t j = 0; j < 4 && j < len; ++j) { - str[j] = static_cast(p[j]); - } - digits = std::bit_cast(str); -#if FASTFLOAT_IS_BIG_ENDIAN - digits = byteswap_32(digits); -#endif - } -#else - if (false) { - } -#endif - else if (len >= 4) { - ::memcpy(&digits, p, 4); -#if FASTFLOAT_IS_BIG_ENDIAN - digits = byteswap_32(digits); -#endif - } else { - uint32_t b0 = static_cast(p[0]); - uint32_t b1 = (len > 1) ? static_cast(p[1]) : 0xFFu; - uint32_t b2 = (len > 2) ? static_cast(p[2]) : 0xFFu; - uint32_t b3 = 0xFFu; - digits = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); - } - - uint32_t magic = - ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; - uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32 - uint32_t nd = (tz == 32) ? 4 : (tz >> 3); - nd = (uint32_t)(nd < len ? nd : len); - if (nd == 0) { - if (has_leading_zeros) { - value = 0; - answer.ec = std::errc(); - answer.ptr = p; - return answer; - } - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - if (nd > 3) { - const UC *q = p + nd; - size_t rem = len - nd; - while (rem) { - if (*q < UC('0') || *q > UC('9')) - break; - ++q; - --rem; - } - answer.ec = std::errc::result_out_of_range; - answer.ptr = q; - return answer; - } - - digits ^= 0x30303030u; - digits <<= ((4 - nd) * 8); - - uint32_t check = ((digits >> 24) & 0xff) | ((digits >> 8) & 0xff00) | - ((digits << 8) & 0xff0000); - if (check > 0x00020505) { - answer.ec = std::errc::result_out_of_range; - answer.ptr = p + nd; - return answer; - } - value = (uint8_t)((0x640a01 * digits) >> 24); - answer.ec = std::errc(); - answer.ptr = p + nd; - return answer; - } - } - - FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - if (base == 10) { - const size_t len = size_t(pend - p); - if (len == 0) { - if (has_leading_zeros) { - value = 0; - answer.ec = std::errc(); - answer.ptr = p; - } else { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - } - return answer; - } - - if (len >= 4) { - uint32_t digits = read4_to_u32(p); - if (is_made_of_four_digits_fast(digits)) { - uint32_t v = parse_four_digits_unrolled(digits); - if (len >= 5 && is_integer(p[4])) { - v = v * 10 + uint32_t(p[4] - '0'); - if (len >= 6 && is_integer(p[5])) { - answer.ec = std::errc::result_out_of_range; - const UC *q = p + 5; - while (q != pend && is_integer(*q)) { - q++; - } - answer.ptr = q; - return answer; - } - if (v > 65535) { - answer.ec = std::errc::result_out_of_range; - answer.ptr = p + 5; - return answer; - } - value = uint16_t(v); - answer.ec = std::errc(); - answer.ptr = p + 5; - return answer; - } - // 4 digits - value = uint16_t(v); - answer.ec = std::errc(); - answer.ptr = p + 4; - return answer; - } - } - } - } - - uint64_t i = 0; - if (base == 10) { - loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible - } - while (p != pend) { - uint8_t digit = ch_to_digit(*p); - if (digit >= base) { - break; - } - i = uint64_t(base) * i + digit; // might overflow, check this later - p++; - } - - size_t digit_count = size_t(p - start_digits); - - if (digit_count == 0) { - if (has_leading_zeros) { - value = 0; - answer.ec = std::errc(); - answer.ptr = p; - } else { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - } - return answer; - } - - answer.ptr = p; - - // check u64 overflow - size_t max_digits = max_digits_u64(base); - if (digit_count > max_digits) { - answer.ec = std::errc::result_out_of_range; - return answer; - } - // this check can be eliminated for all other types, but they will all require - // a max_digits(base) equivalent - if (digit_count == max_digits && i < min_safe_u64(base)) { - answer.ec = std::errc::result_out_of_range; - return answer; - } - - // check other types overflow - if (!std::is_same::value) { - if (i > uint64_t(std::numeric_limits::max()) + uint64_t(negative)) { - answer.ec = std::errc::result_out_of_range; - return answer; - } - } - - if (negative) { -#ifdef FASTFLOAT_VISUAL_STUDIO -#pragma warning(push) -#pragma warning(disable : 4146) -#endif - // this weird workaround is required because: - // - converting unsigned to signed when its value is greater than signed max - // is UB pre-C++23. - // - reinterpret_casting (~i + 1) would work, but it is not constexpr - // this is always optimized into a neg instruction (note: T is an integer - // type) - value = T(-std::numeric_limits::max() - - T(i - uint64_t(std::numeric_limits::max()))); -#ifdef FASTFLOAT_VISUAL_STUDIO -#pragma warning(pop) -#endif - } else { - value = T(i); - } - - answer.ec = std::errc(); - return answer; -} - -} // namespace fast_float - -#endif diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h deleted file mode 100644 index 74901e3..0000000 --- a/include/fast_float/bigint.h +++ /dev/null @@ -1,638 +0,0 @@ -#ifndef FASTFLOAT_BIGINT_H -#define FASTFLOAT_BIGINT_H - -#include -#include -#include -#include - -#include "float_common.h" - -namespace fast_float { - -// the limb width: we want efficient multiplication of double the bits in -// limb, or for 64-bit limbs, at least 64-bit multiplication where we can -// extract the high and low parts efficiently. this is every 64-bit -// architecture except for sparc, which emulates 128-bit multiplication. -// we might have platforms where `CHAR_BIT` is not 8, so let's avoid -// doing `8 * sizeof(limb)`. -#if defined(FASTFLOAT_64BIT) && !defined(__sparc) -#define FASTFLOAT_64BIT_LIMB 1 -typedef uint64_t limb; -constexpr size_t limb_bits = 64; -#else -#define FASTFLOAT_32BIT_LIMB -typedef uint32_t limb; -constexpr size_t limb_bits = 32; -#endif - -typedef span limb_span; - -// number of bits in a bigint. this needs to be at least the number -// of bits required to store the largest bigint, which is -// `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or -// ~3600 bits, so we round to 4000. -constexpr size_t bigint_bits = 4000; -constexpr size_t bigint_limbs = bigint_bits / limb_bits; - -// vector-like type that is allocated on the stack. the entire -// buffer is pre-allocated, and only the length changes. -template struct stackvec { - limb data[size]; - // we never need more than 150 limbs - uint16_t length{0}; - - stackvec() = default; - stackvec(stackvec const &) = delete; - stackvec &operator=(stackvec const &) = delete; - stackvec(stackvec &&) = delete; - stackvec &operator=(stackvec &&other) = delete; - - // create stack vector from existing limb span. - FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) { - FASTFLOAT_ASSERT(try_extend(s)); - } - - FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept { - FASTFLOAT_DEBUG_ASSERT(index < length); - return data[index]; - } - - FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept { - FASTFLOAT_DEBUG_ASSERT(index < length); - return data[index]; - } - - // index from the end of the container - FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept { - FASTFLOAT_DEBUG_ASSERT(index < length); - size_t rindex = length - index - 1; - return data[rindex]; - } - - // set the length, without bounds checking. - FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { - length = uint16_t(len); - } - - constexpr size_t len() const noexcept { return length; } - - constexpr bool is_empty() const noexcept { return length == 0; } - - constexpr size_t capacity() const noexcept { return size; } - - // append item to vector, without bounds checking - FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { - data[length] = value; - length++; - } - - // append item to vector, returning if item was added - FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept { - if (len() < capacity()) { - push_unchecked(value); - return true; - } else { - return false; - } - } - - // add items to the vector, from a span, without bounds checking - FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { - limb *ptr = data + length; - std::copy_n(s.ptr, s.len(), ptr); - set_len(len() + s.len()); - } - - // try to add items to the vector, returning if items were added - FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept { - if (len() + s.len() <= capacity()) { - extend_unchecked(s); - return true; - } else { - return false; - } - } - - // resize the vector, without bounds checking - // if the new size is longer than the vector, assign value to each - // appended item. - FASTFLOAT_CONSTEXPR20 - void resize_unchecked(size_t new_len, limb value) noexcept { - if (new_len > len()) { - size_t count = new_len - len(); - limb *first = data + len(); - limb *last = first + count; - ::std::fill(first, last, value); - set_len(new_len); - } else { - set_len(new_len); - } - } - - // try to resize the vector, returning if the vector was resized. - FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept { - if (new_len > capacity()) { - return false; - } else { - resize_unchecked(new_len, value); - return true; - } - } - - // check if any limbs are non-zero after the given index. - // this needs to be done in reverse order, since the index - // is relative to the most significant limbs. - FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept { - while (index < len()) { - if (rindex(index) != 0) { - return true; - } - index++; - } - return false; - } - - // normalize the big integer, so most-significant zero limbs are removed. - FASTFLOAT_CONSTEXPR14 void normalize() noexcept { - while (len() > 0 && rindex(0) == 0) { - length--; - } - } -}; - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t -empty_hi64(bool &truncated) noexcept { - truncated = false; - return 0; -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t -uint64_hi64(uint64_t r0, bool &truncated) noexcept { - truncated = false; - int shl = leading_zeroes(r0); - return r0 << shl; -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t -uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept { - int shl = leading_zeroes(r0); - if (shl == 0) { - truncated = r1 != 0; - return r0; - } else { - int shr = 64 - shl; - truncated = (r1 << shl) != 0; - return (r0 << shl) | (r1 >> shr); - } -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t -uint32_hi64(uint32_t r0, bool &truncated) noexcept { - return uint64_hi64(r0, truncated); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t -uint32_hi64(uint32_t r0, uint32_t r1, bool &truncated) noexcept { - uint64_t x0 = r0; - uint64_t x1 = r1; - return uint64_hi64((x0 << 32) | x1, truncated); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t -uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool &truncated) noexcept { - uint64_t x0 = r0; - uint64_t x1 = r1; - uint64_t x2 = r2; - return uint64_hi64(x0, (x1 << 32) | x2, truncated); -} - -// add two small integers, checking for overflow. -// we want an efficient operation. for msvc, where -// we don't have built-in intrinsics, this is still -// pretty fast. -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb -scalar_add(limb x, limb y, bool &overflow) noexcept { - limb z; -// gcc and clang -#if defined(__has_builtin) -#if __has_builtin(__builtin_add_overflow) - if (!cpp20_and_in_constexpr()) { - overflow = __builtin_add_overflow(x, y, &z); - return z; - } -#endif -#endif - - // generic, this still optimizes correctly on MSVC. - z = x + y; - overflow = z < x; - return z; -} - -// multiply two small integers, getting both the high and low bits. -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb -scalar_mul(limb x, limb y, limb &carry) noexcept { -#ifdef FASTFLOAT_64BIT_LIMB -#if defined(__SIZEOF_INT128__) - // GCC and clang both define it as an extension. - __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry); - carry = limb(z >> limb_bits); - return limb(z); -#else - // fallback, no native 128-bit integer multiplication with carry. - // on msvc, this optimizes identically, somehow. - value128 z = full_multiplication(x, y); - bool overflow; - z.low = scalar_add(z.low, carry, overflow); - z.high += uint64_t(overflow); // cannot overflow - carry = z.high; - return z.low; -#endif -#else - uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry); - carry = limb(z >> limb_bits); - return limb(z); -#endif -} - -// add scalar value to bigint starting from offset. -// used in grade school multiplication -template -inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, - size_t start) noexcept { - size_t index = start; - limb carry = y; - bool overflow; - while (carry != 0 && index < vec.len()) { - vec[index] = scalar_add(vec[index], carry, overflow); - carry = limb(overflow); - index += 1; - } - if (carry != 0) { - FASTFLOAT_TRY(vec.try_push(carry)); - } - return true; -} - -// add scalar value to bigint. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -small_add(stackvec &vec, limb y) noexcept { - return small_add_from(vec, y, 0); -} - -// multiply bigint by scalar value. -template -inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, - limb y) noexcept { - limb carry = 0; - for (size_t index = 0; index < vec.len(); index++) { - vec[index] = scalar_mul(vec[index], y, carry); - } - if (carry != 0) { - FASTFLOAT_TRY(vec.try_push(carry)); - } - return true; -} - -// add bigint to bigint starting from index. -// used in grade school multiplication -template -FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, - size_t start) noexcept { - // the effective x buffer is from `xstart..x.len()`, so exit early - // if we can't get that current range. - if (x.len() < start || y.len() > x.len() - start) { - FASTFLOAT_TRY(x.try_resize(y.len() + start, 0)); - } - - bool carry = false; - for (size_t index = 0; index < y.len(); index++) { - limb xi = x[index + start]; - limb yi = y[index]; - bool c1 = false; - bool c2 = false; - xi = scalar_add(xi, yi, c1); - if (carry) { - xi = scalar_add(xi, 1, c2); - } - x[index + start] = xi; - carry = c1 | c2; - } - - // handle overflow - if (carry) { - FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start)); - } - return true; -} - -// add bigint to bigint. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -large_add_from(stackvec &x, limb_span y) noexcept { - return large_add_from(x, y, 0); -} - -// grade-school multiplication algorithm -template -FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { - limb_span xs = limb_span(x.data, x.len()); - stackvec z(xs); - limb_span zs = limb_span(z.data, z.len()); - - if (y.len() != 0) { - limb y0 = y[0]; - FASTFLOAT_TRY(small_mul(x, y0)); - for (size_t index = 1; index < y.len(); index++) { - limb yi = y[index]; - stackvec zi; - if (yi != 0) { - // re-use the same buffer throughout - zi.set_len(0); - FASTFLOAT_TRY(zi.try_extend(zs)); - FASTFLOAT_TRY(small_mul(zi, yi)); - limb_span zis = limb_span(zi.data, zi.len()); - FASTFLOAT_TRY(large_add_from(x, zis, index)); - } - } - } - - x.normalize(); - return true; -} - -// grade-school multiplication algorithm -template -FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { - if (y.len() == 1) { - FASTFLOAT_TRY(small_mul(x, y[0])); - } else { - FASTFLOAT_TRY(long_mul(x, y)); - } - return true; -} - -template struct pow5_tables { - static constexpr uint32_t large_step = 135; - static constexpr uint64_t small_power_of_5[] = { - 1UL, - 5UL, - 25UL, - 125UL, - 625UL, - 3125UL, - 15625UL, - 78125UL, - 390625UL, - 1953125UL, - 9765625UL, - 48828125UL, - 244140625UL, - 1220703125UL, - 6103515625UL, - 30517578125UL, - 152587890625UL, - 762939453125UL, - 3814697265625UL, - 19073486328125UL, - 95367431640625UL, - 476837158203125UL, - 2384185791015625UL, - 11920928955078125UL, - 59604644775390625UL, - 298023223876953125UL, - 1490116119384765625UL, - 7450580596923828125UL, - }; -#ifdef FASTFLOAT_64BIT_LIMB - constexpr static limb large_power_of_5[] = { - 1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL, - 10482974169319127550UL, 198276706040285095UL}; -#else - constexpr static limb large_power_of_5[] = { - 4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U, - 1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U}; -#endif -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template constexpr uint32_t pow5_tables::large_step; - -template constexpr uint64_t pow5_tables::small_power_of_5[]; - -template constexpr limb pow5_tables::large_power_of_5[]; - -#endif - -// big integer type. implements a small subset of big integer -// arithmetic, using simple algorithms since asymptotically -// faster algorithms are slower for a small number of limbs. -// all operations assume the big-integer is normalized. -struct bigint : pow5_tables<> { - // storage of the limbs, in little-endian order. - stackvec vec; - - FASTFLOAT_CONSTEXPR20 bigint() : vec() {} - - bigint(bigint const &) = delete; - bigint &operator=(bigint const &) = delete; - bigint(bigint &&) = delete; - bigint &operator=(bigint &&other) = delete; - - FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() { -#ifdef FASTFLOAT_64BIT_LIMB - vec.push_unchecked(value); -#else - vec.push_unchecked(uint32_t(value)); - vec.push_unchecked(uint32_t(value >> 32)); -#endif - vec.normalize(); - } - - // get the high 64 bits from the vector, and if bits were truncated. - // this is to get the significant digits for the float. - FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool &truncated) const noexcept { -#ifdef FASTFLOAT_64BIT_LIMB - if (vec.len() == 0) { - return empty_hi64(truncated); - } else if (vec.len() == 1) { - return uint64_hi64(vec.rindex(0), truncated); - } else { - uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated); - truncated |= vec.nonzero(2); - return result; - } -#else - if (vec.len() == 0) { - return empty_hi64(truncated); - } else if (vec.len() == 1) { - return uint32_hi64(vec.rindex(0), truncated); - } else if (vec.len() == 2) { - return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated); - } else { - uint64_t result = - uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated); - truncated |= vec.nonzero(3); - return result; - } -#endif - } - - // compare two big integers, returning the large value. - // assumes both are normalized. if the return value is - // negative, other is larger, if the return value is - // positive, this is larger, otherwise they are equal. - // the limbs are stored in little-endian order, so we - // must compare the limbs in ever order. - FASTFLOAT_CONSTEXPR20 int compare(bigint const &other) const noexcept { - if (vec.len() > other.vec.len()) { - return 1; - } else if (vec.len() < other.vec.len()) { - return -1; - } else { - for (size_t index = vec.len(); index > 0; index--) { - limb xi = vec[index - 1]; - limb yi = other.vec[index - 1]; - if (xi > yi) { - return 1; - } else if (xi < yi) { - return -1; - } - } - return 0; - } - } - - // shift left each limb n bits, carrying over to the new limb - // returns true if we were able to shift all the digits. - FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept { - // Internally, for each item, we shift left by n, and add the previous - // right shifted limb-bits. - // For example, we transform (for u8) shifted left 2, to: - // b10100100 b01000010 - // b10 b10010001 b00001000 - FASTFLOAT_DEBUG_ASSERT(n != 0); - FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - - size_t shl = n; - size_t shr = limb_bits - shl; - limb prev = 0; - for (size_t index = 0; index < vec.len(); index++) { - limb xi = vec[index]; - vec[index] = (xi << shl) | (prev >> shr); - prev = xi; - } - - limb carry = prev >> shr; - if (carry != 0) { - return vec.try_push(carry); - } - return true; - } - - // move the limbs left by `n` limbs. - FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept { - FASTFLOAT_DEBUG_ASSERT(n != 0); - if (n + vec.len() > vec.capacity()) { - return false; - } else if (!vec.is_empty()) { - // move limbs - limb *dst = vec.data + n; - limb const *src = vec.data; - std::copy_backward(src, src + vec.len(), dst + vec.len()); - // fill in empty limbs - limb *first = vec.data; - limb *last = first + n; - ::std::fill(first, last, 0); - vec.set_len(n + vec.len()); - return true; - } else { - return true; - } - } - - // move the limbs left by `n` bits. - FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { - size_t rem = n % limb_bits; - size_t div = n / limb_bits; - if (rem != 0) { - FASTFLOAT_TRY(shl_bits(rem)); - } - if (div != 0) { - FASTFLOAT_TRY(shl_limbs(div)); - } - return true; - } - - // get the number of leading zeros in the bigint. - FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept { - if (vec.is_empty()) { - return 0; - } else { -#ifdef FASTFLOAT_64BIT_LIMB - return leading_zeroes(vec.rindex(0)); -#else - // no use defining a specialized leading_zeroes for a 32-bit type. - uint64_t r0 = vec.rindex(0); - return leading_zeroes(r0 << 32); -#endif - } - } - - // get the number of bits in the bigint. - FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept { - int lz = ctlz(); - return int(limb_bits * vec.len()) - lz; - } - - FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } - - FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } - - // multiply as if by 2 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); } - - // multiply as if by 5 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept { - // multiply by a power of 5 - size_t large_length = sizeof(large_power_of_5) / sizeof(limb); - limb_span large = limb_span(large_power_of_5, large_length); - while (exp >= large_step) { - FASTFLOAT_TRY(large_mul(vec, large)); - exp -= large_step; - } -#ifdef FASTFLOAT_64BIT_LIMB - uint32_t small_step = 27; - limb max_native = 7450580596923828125UL; -#else - uint32_t small_step = 13; - limb max_native = 1220703125U; -#endif - while (exp >= small_step) { - FASTFLOAT_TRY(small_mul(vec, max_native)); - exp -= small_step; - } - if (exp != 0) { - // Work around clang bug https://godbolt.org/z/zedh7rrhc - // This is similar to https://github.com/llvm/llvm-project/issues/47746, - // except the workaround described there don't work here - FASTFLOAT_TRY(small_mul( - vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))); - } - - return true; - } - - // multiply as if by 10 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept { - FASTFLOAT_TRY(pow5(exp)); - return pow2(exp); - } -}; - -} // namespace fast_float - -#endif diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h deleted file mode 100644 index 6751afe..0000000 --- a/include/fast_float/constexpr_feature_detect.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H -#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H - -#ifdef __has_include -#if __has_include() -#include -#endif -#endif - -// Testing for https://wg21.link/N3652, adopted in C++14 -#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 -#define FASTFLOAT_CONSTEXPR14 constexpr -#else -#define FASTFLOAT_CONSTEXPR14 -#endif - -#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L -#define FASTFLOAT_HAS_BIT_CAST 1 -#else -#define FASTFLOAT_HAS_BIT_CAST 0 -#endif - -#if defined(__cpp_lib_is_constant_evaluated) && \ - __cpp_lib_is_constant_evaluated >= 201811L -#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 -#else -#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 -#endif - -#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L -#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) -#else -#define FASTFLOAT_IF_CONSTEXPR17(x) if (x) -#endif - -// Testing for relevant C++20 constexpr library features -#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \ - defined(__cpp_lib_constexpr_algorithms) && \ - __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/ -#define FASTFLOAT_CONSTEXPR20 constexpr -#define FASTFLOAT_IS_CONSTEXPR 1 -#else -#define FASTFLOAT_CONSTEXPR20 -#define FASTFLOAT_IS_CONSTEXPR 0 -#endif - -#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 0 -#else -#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 -#endif - -#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h deleted file mode 100644 index 9487682..0000000 --- a/include/fast_float/decimal_to_binary.h +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H -#define FASTFLOAT_DECIMAL_TO_BINARY_H - -#include "float_common.h" -#include "fast_table.h" -#include -#include -#include -#include -#include -#include - -namespace fast_float { - -// This will compute or rather approximate w * 5**q and return a pair of 64-bit -// words approximating the result, with the "high" part corresponding to the -// most significant bits and the low part corresponding to the least significant -// bits. -// -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 -compute_product_approximation(int64_t q, uint64_t w) { - int const index = 2 * int(q - powers::smallest_power_of_five); - // For small values of q, e.g., q in [0,27], the answer is always exact - // because The line value128 firstproduct = full_multiplication(w, - // power_of_five_128[index]); gives the exact answer. - value128 firstproduct = - full_multiplication(w, powers::power_of_five_128[index]); - static_assert((bit_precision >= 0) && (bit_precision <= 64), - " precision should be in (0,64]"); - constexpr uint64_t precision_mask = - (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) - : uint64_t(0xFFFFFFFFFFFFFFFF); - if ((firstproduct.high & precision_mask) == - precision_mask) { // could further guard with (lower + w < lower) - // regarding the second product, we only need secondproduct.high, but our - // expectation is that the compiler will optimize this extra work away if - // needed. - value128 secondproduct = - full_multiplication(w, powers::power_of_five_128[index + 1]); - firstproduct.low += secondproduct.high; - if (secondproduct.high > firstproduct.low) { - firstproduct.high++; - } - } - return firstproduct; -} - -namespace detail { -/** - * For q in (0,350), we have that - * f = (((152170 + 65536) * q ) >> 16); - * is equal to - * floor(p) + q - * where - * p = log(5**q)/log(2) = q * log(5)/log(2) - * - * For negative values of q in (-400,0), we have that - * f = (((152170 + 65536) * q ) >> 16); - * is equal to - * -ceil(p) + q - * where - * p = log(5**-q)/log(2) = -q * log(5)/log(2) - */ -constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept { - return (((152170 + 65536) * q) >> 16) + 63; -} -} // namespace detail - -// create an adjusted mantissa, biased by the invalid power2 -// for significant digits already multiplied by 10 ** q. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept { - int hilz = int(w >> 63) ^ 1; - adjusted_mantissa answer; - answer.mantissa = w << hilz; - int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); - answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + - invalid_am_bias); - return answer; -} - -// w * 10 ** q, without rounding the representation up. -// the power2 in the exponent will be adjusted by invalid_am_bias. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -compute_error(int64_t q, uint64_t w) noexcept { - int lz = leading_zeroes(w); - w <<= lz; - value128 product = - compute_product_approximation(q, w); - return compute_error_scaled(q, product.high, lz); -} - -// Computers w * 10 ** q. -// The returned value should be a valid number that simply needs to be -// packed. However, in some very rare cases, the computation will fail. In such -// cases, we return an adjusted_mantissa with a negative power of 2: the caller -// should recompute in such cases. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -compute_float(int64_t q, uint64_t w) noexcept { - adjusted_mantissa answer; - if ((w == 0) || (q < binary::smallest_power_of_ten())) { - answer.power2 = 0; - answer.mantissa = 0; - // result should be zero - return answer; - } - if (q > binary::largest_power_of_ten()) { - // we want to get infinity: - answer.power2 = binary::infinite_power(); - answer.mantissa = 0; - return answer; - } - // At this point in time q is in [powers::smallest_power_of_five, - // powers::largest_power_of_five]. - - // We want the most significant bit of i to be 1. Shift if needed. - int lz = leading_zeroes(w); - w <<= lz; - - // The required precision is binary::mantissa_explicit_bits() + 3 because - // 1. We need the implicit bit - // 2. We need an extra bit for rounding purposes - // 3. We might lose a bit due to the "upperbit" routine (result too small, - // requiring a shift) - - value128 product = - compute_product_approximation(q, w); - // The computed 'product' is always sufficient. - // Mathematical proof: - // Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to - // appear) See script/mushtak_lemire.py - - // The "compute_product_approximation" function can be slightly slower than a - // branchless approach: value128 product = compute_product(q, w); but in - // practice, we can win big with the compute_product_approximation if its - // additional branch is easily predicted. Which is best is data specific. - int upperbit = int(product.high >> 63); - int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; - - answer.mantissa = product.high >> shift; - - answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - - binary::minimum_exponent()); - if (answer.power2 <= 0) { // we have a subnormal? - // Here have that answer.power2 <= 0 so -answer.power2 >= 0 - if (-answer.power2 + 1 >= - 64) { // if we have more than 64 bits below the minimum exponent, you - // have a zero for sure. - answer.power2 = 0; - answer.mantissa = 0; - // result should be zero - return answer; - } - // next line is safe because -answer.power2 + 1 < 64 - answer.mantissa >>= -answer.power2 + 1; - // Thankfully, we can't have both "round-to-even" and subnormals because - // "round-to-even" only occurs for powers close to 0 in the 32-bit and - // and 64-bit case (with no more than 19 digits). - answer.mantissa += (answer.mantissa & 1); // round up - answer.mantissa >>= 1; - // There is a weird scenario where we don't have a subnormal but just. - // Suppose we start with 2.2250738585072013e-308, we end up - // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal - // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round - // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer - // subnormal, but we can only know this after rounding. - // So we only declare a subnormal if we are smaller than the threshold. - answer.power2 = - (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) - ? 0 - : 1; - return answer; - } - - // usually, we round *up*, but if we fall right in between and and we have an - // even basis, we need to round down - // We are only concerned with the cases where 5**q fits in single 64-bit word. - if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) && - (q <= binary::max_exponent_round_to_even()) && - ((answer.mantissa & 3) == 1)) { // we may fall between two floats! - // To be in-between two floats we need that in doing - // answer.mantissa = product.high >> (upperbit + 64 - - // binary::mantissa_explicit_bits() - 3); - // ... we dropped out only zeroes. But if this happened, then we can go - // back!!! - if ((answer.mantissa << shift) == product.high) { - answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up - } - } - - answer.mantissa += (answer.mantissa & 1); // round up - answer.mantissa >>= 1; - if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) { - answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits()); - answer.power2++; // undo previous addition - } - - answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits()); - if (answer.power2 >= binary::infinite_power()) { // infinity - answer.power2 = binary::infinite_power(); - answer.mantissa = 0; - } - return answer; -} - -} // namespace fast_float - -#endif diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h deleted file mode 100644 index c2c83b0..0000000 --- a/include/fast_float/digit_comparison.h +++ /dev/null @@ -1,454 +0,0 @@ -#ifndef FASTFLOAT_DIGIT_COMPARISON_H -#define FASTFLOAT_DIGIT_COMPARISON_H - -#include -#include -#include - -#include "float_common.h" -#include "bigint.h" -#include "ascii_number.h" - -namespace fast_float { - -// 1e0 to 1e19 -constexpr static uint64_t powers_of_ten_uint64[] = {1UL, - 10UL, - 100UL, - 1000UL, - 10000UL, - 100000UL, - 1000000UL, - 10000000UL, - 100000000UL, - 1000000000UL, - 10000000000UL, - 100000000000UL, - 1000000000000UL, - 10000000000000UL, - 100000000000000UL, - 1000000000000000UL, - 10000000000000000UL, - 100000000000000000UL, - 1000000000000000000UL, - 10000000000000000000UL}; - -// calculate the exponent, in scientific notation, of the number. -// this algorithm is not even close to optimized, but it has no practical -// effect on performance: in order to have a faster algorithm, we'd need -// to slow down performance for faster algorithms, and this is still fast. -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t -scientific_exponent(uint64_t mantissa, int32_t exponent) noexcept { - while (mantissa >= 10000) { - mantissa /= 10000; - exponent += 4; - } - while (mantissa >= 100) { - mantissa /= 100; - exponent += 2; - } - while (mantissa >= 10) { - mantissa /= 10; - exponent += 1; - } - return exponent; -} - -// this converts a native floating-point number to an extended-precision float. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -to_extended(T value) noexcept { - using equiv_uint = equiv_uint_t; - constexpr equiv_uint exponent_mask = binary_format::exponent_mask(); - constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); - constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); - - adjusted_mantissa am; - int32_t bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); - equiv_uint bits; -#if FASTFLOAT_HAS_BIT_CAST - bits = std::bit_cast(value); -#else - ::memcpy(&bits, &value, sizeof(T)); -#endif - if ((bits & exponent_mask) == 0) { - // denormal - am.power2 = 1 - bias; - am.mantissa = bits & mantissa_mask; - } else { - // normal - am.power2 = int32_t((bits & exponent_mask) >> - binary_format::mantissa_explicit_bits()); - am.power2 -= bias; - am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; - } - - return am; -} - -// get the extended precision value of the halfway point between b and b+u. -// we are given a native float that represents b, so we need to adjust it -// halfway between b and b+u. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -to_extended_halfway(T value) noexcept { - adjusted_mantissa am = to_extended(value); - am.mantissa <<= 1; - am.mantissa += 1; - am.power2 -= 1; - return am; -} - -// round an extended-precision float to the nearest machine float. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, - callback cb) noexcept { - int32_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; - if (-am.power2 >= mantissa_shift) { - // have a denormal float - int32_t shift = -am.power2 + 1; - cb(am, (shift < 64 ? shift : 64)); - // check for round-up: if rounding-nearest carried us to the hidden bit. - am.power2 = (am.mantissa < - (uint64_t(1) << binary_format::mantissa_explicit_bits())) - ? 0 - : 1; - return; - } - - // have a normal float, use the default shift. - cb(am, mantissa_shift); - - // check for carry - if (am.mantissa >= - (uint64_t(2) << binary_format::mantissa_explicit_bits())) { - am.mantissa = (uint64_t(1) << binary_format::mantissa_explicit_bits()); - am.power2++; - } - - // check for infinite: we could have carried to an infinite power - am.mantissa &= ~(uint64_t(1) << binary_format::mantissa_explicit_bits()); - if (am.power2 >= binary_format::infinite_power()) { - am.power2 = binary_format::infinite_power(); - am.mantissa = 0; - } -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -round_nearest_tie_even(adjusted_mantissa &am, int32_t shift, - callback cb) noexcept { - uint64_t const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1; - uint64_t const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1); - uint64_t truncated_bits = am.mantissa & mask; - bool is_above = truncated_bits > halfway; - bool is_halfway = truncated_bits == halfway; - - // shift digits into position - if (shift == 64) { - am.mantissa = 0; - } else { - am.mantissa >>= shift; - } - am.power2 += shift; - - bool is_odd = (am.mantissa & 1) == 1; - am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above)); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -round_down(adjusted_mantissa &am, int32_t shift) noexcept { - if (shift == 64) { - am.mantissa = 0; - } else { - am.mantissa >>= shift; - } - am.power2 += shift; -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -skip_zeros(UC const *&first, UC const *last) noexcept { - uint64_t val; - while (!cpp20_and_in_constexpr() && - std::distance(first, last) >= int_cmp_len()) { - ::memcpy(&val, first, sizeof(uint64_t)); - if (val != int_cmp_zeros()) { - break; - } - first += int_cmp_len(); - } - while (first != last) { - if (*first != UC('0')) { - break; - } - first++; - } -} - -// determine if any non-zero digits were truncated. -// all characters must be valid digits. -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -is_truncated(UC const *first, UC const *last) noexcept { - // do 8-bit optimizations, can just compare to 8 literal 0s. - uint64_t val; - while (!cpp20_and_in_constexpr() && - std::distance(first, last) >= int_cmp_len()) { - ::memcpy(&val, first, sizeof(uint64_t)); - if (val != int_cmp_zeros()) { - return true; - } - first += int_cmp_len(); - } - while (first != last) { - if (*first != UC('0')) { - return true; - } - ++first; - } - return false; -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -is_truncated(span s) noexcept { - return is_truncated(s.ptr, s.ptr + s.len()); -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -parse_eight_digits(UC const *&p, limb &value, size_t &counter, - size_t &count) noexcept { - value = value * 100000000 + parse_eight_digits_unrolled(p); - p += 8; - counter += 8; - count += 8; -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -parse_one_digit(UC const *&p, limb &value, size_t &counter, - size_t &count) noexcept { - value = value * 10 + limb(*p - UC('0')); - p++; - counter++; - count++; -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -add_native(bigint &big, limb power, limb value) noexcept { - big.mul(power); - big.add(value); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -round_up_bigint(bigint &big, size_t &count) noexcept { - // need to round-up the digits, but need to avoid rounding - // ....9999 to ...10000, which could cause a false halfway point. - add_native(big, 10, 1); - count++; -} - -// parse the significant digits into a big integer -template -inline FASTFLOAT_CONSTEXPR20 void -parse_mantissa(bigint &result, parsed_number_string_t &num, - size_t max_digits, size_t &digits) noexcept { - // try to minimize the number of big integer and scalar multiplication. - // therefore, try to parse 8 digits at a time, and multiply by the largest - // scalar value (9 or 19 digits) for each step. - size_t counter = 0; - digits = 0; - limb value = 0; -#ifdef FASTFLOAT_64BIT_LIMB - size_t step = 19; -#else - size_t step = 9; -#endif - - // process all integer digits. - UC const *p = num.integer.ptr; - UC const *pend = p + num.integer.len(); - skip_zeros(p, pend); - // process all digits, in increments of step per loop - while (p != pend) { - while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && - (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); - } - while (counter < step && p != pend && digits < max_digits) { - parse_one_digit(p, value, counter, digits); - } - if (digits == max_digits) { - // add the temporary value, then check if we've truncated any digits - add_native(result, limb(powers_of_ten_uint64[counter]), value); - bool truncated = is_truncated(p, pend); - if (num.fraction.ptr != nullptr) { - truncated |= is_truncated(num.fraction); - } - if (truncated) { - round_up_bigint(result, digits); - } - return; - } else { - add_native(result, limb(powers_of_ten_uint64[counter]), value); - counter = 0; - value = 0; - } - } - - // add our fraction digits, if they're available. - if (num.fraction.ptr != nullptr) { - p = num.fraction.ptr; - pend = p + num.fraction.len(); - if (digits == 0) { - skip_zeros(p, pend); - } - // process all digits, in increments of step per loop - while (p != pend) { - while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && - (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); - } - while (counter < step && p != pend && digits < max_digits) { - parse_one_digit(p, value, counter, digits); - } - if (digits == max_digits) { - // add the temporary value, then check if we've truncated any digits - add_native(result, limb(powers_of_ten_uint64[counter]), value); - bool truncated = is_truncated(p, pend); - if (truncated) { - round_up_bigint(result, digits); - } - return; - } else { - add_native(result, limb(powers_of_ten_uint64[counter]), value); - counter = 0; - value = 0; - } - } - } - - if (counter != 0) { - add_native(result, limb(powers_of_ten_uint64[counter]), value); - } -} - -template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { - FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); - adjusted_mantissa answer; - bool truncated; - answer.mantissa = bigmant.hi64(truncated); - int bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); - answer.power2 = bigmant.bit_length() - 64 + bias; - - round(answer, [truncated](adjusted_mantissa &a, int32_t shift) { - round_nearest_tie_even( - a, shift, - [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { - return is_above || (is_halfway && truncated) || - (is_odd && is_halfway); - }); - }); - - return answer; -} - -// the scaling here is quite simple: we have, for the real digits `m * 10^e`, -// and for the theoretical digits `n * 2^f`. Since `e` is always negative, -// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`. -// we then need to scale by `2^(f- e)`, and then the two significant digits -// are of the same magnitude. -template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( - bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept { - bigint &real_digits = bigmant; - int32_t real_exp = exponent; - - // get the value of `b`, rounded down, and get a bigint representation of b+h - adjusted_mantissa am_b = am; - // gcc7 buf: use a lambda to remove the noexcept qualifier bug with - // -Wnoexcept-type. - round(am_b, - [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); - T b; - to_float(false, am_b, b); - adjusted_mantissa theor = to_extended_halfway(b); - bigint theor_digits(theor.mantissa); - int32_t theor_exp = theor.power2; - - // scale real digits and theor digits to be same power. - int32_t pow2_exp = theor_exp - real_exp; - uint32_t pow5_exp = uint32_t(-real_exp); - if (pow5_exp != 0) { - FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); - } - if (pow2_exp > 0) { - FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp))); - } else if (pow2_exp < 0) { - FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp))); - } - - // compare digits, and use it to direct rounding - int ord = real_digits.compare(theor_digits); - adjusted_mantissa answer = am; - round(answer, [ord](adjusted_mantissa &a, int32_t shift) { - round_nearest_tie_even( - a, shift, [ord](bool is_odd, bool _, bool __) -> bool { - (void)_; // not needed, since we've done our comparison - (void)__; // not needed, since we've done our comparison - if (ord > 0) { - return true; - } else if (ord < 0) { - return false; - } else { - return is_odd; - } - }); - }); - - return answer; -} - -// parse the significant digits as a big integer to unambiguously round -// the significant digits. here, we are trying to determine how to round -// an extended float representation close to `b+h`, halfway between `b` -// (the float rounded-down) and `b+u`, the next positive float. this -// algorithm is always correct, and uses one of two approaches. when -// the exponent is positive relative to the significant digits (such as -// 1234), we create a big-integer representation, get the high 64-bits, -// determine if any lower bits are truncated, and use that to direct -// rounding. in case of a negative exponent relative to the significant -// digits (such as 1.2345), we create a theoretical representation of -// `b` as a big-integer type, scaled to the same binary exponent as -// the actual digits. we then compare the big integer representations -// of both, and use that to direct rounding. -template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -digit_comp(parsed_number_string_t &num, adjusted_mantissa am) noexcept { - // remove the invalid exponent bias - am.power2 -= invalid_am_bias; - - int32_t sci_exp = - scientific_exponent(num.mantissa, static_cast(num.exponent)); - size_t max_digits = binary_format::max_digits(); - size_t digits = 0; - bigint bigmant; - parse_mantissa(bigmant, num, max_digits, digits); - // can't underflow, since digits is at most max_digits. - int32_t exponent = sci_exp + 1 - int32_t(digits); - if (exponent >= 0) { - return positive_digit_comp(bigmant, exponent); - } else { - return negative_digit_comp(bigmant, am, exponent); - } -} - -} // namespace fast_float - -#endif diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h deleted file mode 100644 index eb822f5..0000000 --- a/include/fast_float/fast_float.h +++ /dev/null @@ -1,91 +0,0 @@ - -#ifndef FASTFLOAT_FAST_FLOAT_H -#define FASTFLOAT_FAST_FLOAT_H - -#include "float_common.h" - -namespace fast_float { -/** - * This function parses the character sequence [first,last) for a number. It - * parses floating-point numbers expecting a locale-indepent format equivalent - * to what is used by std::strtod in the default ("C") locale. The resulting - * floating-point value is the closest floating-point values (using either float - * or double), using the "round to even" convention for values that would - * otherwise fall right in-between two values. That is, we provide exact parsing - * according to the IEEE standard. - * - * Given a successful parse, the pointer (`ptr`) in the returned value is set to - * point right after the parsed number, and the `value` referenced is set to the - * parsed value. In case of error, the returned `ec` contains a representative - * error, otherwise the default (`std::errc()`) value is stored. - * - * The implementation does not throw and does not allocate memory (e.g., with - * `new` or `malloc`). - * - * Like the C++17 standard, the `fast_float::from_chars` functions take an - * optional last argument of the type `fast_float::chars_format`. It is a bitset - * value: we check whether `fmt & fast_float::chars_format::fixed` and `fmt & - * fast_float::chars_format::scientific` are set to determine whether we allow - * the fixed point and scientific notation respectively. The default is - * `fast_float::chars_format::general` which allows both `fixed` and - * `scientific`. - */ -template ::value)> -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, - chars_format fmt = chars_format::general) noexcept; - -/** - * Like from_chars, but accepts an `options` argument to govern number parsing. - * Both for floating-point types and integer types. - */ -template -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept; - -/** - * This function multiplies an integer number by a power of 10 and returns - * the result as a double precision floating-point value that is correctly - * rounded. The resulting floating-point value is the closest floating-point - * value, using the "round to nearest, tie to even" convention for values that - * would otherwise fall right in-between two values. That is, we provide exact - * conversion according to the IEEE standard. - * - * On overflow infinity is returned, on underflow 0 is returned. - * - * The implementation does not throw and does not allocate memory (e.g., with - * `new` or `malloc`). - */ -FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept; -FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept; - -/** - * This function is a template overload of `integer_times_pow10()` - * that returns a floating-point value of type `T` that is one of - * supported floating-point types (e.g. `double`, `float`). - */ -template -FASTFLOAT_CONSTEXPR20 - typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept; -template -FASTFLOAT_CONSTEXPR20 - typename std::enable_if::value, T>::type - integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept; - -/** - * from_chars for integer types. - */ -template ::value)> -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept; - -} // namespace fast_float - -#include "parse_number.h" -#endif // FASTFLOAT_FAST_FLOAT_H diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h deleted file mode 100644 index 69f9b2c..0000000 --- a/include/fast_float/fast_table.h +++ /dev/null @@ -1,708 +0,0 @@ -#ifndef FASTFLOAT_FAST_TABLE_H -#define FASTFLOAT_FAST_TABLE_H - -#include - -namespace fast_float { - -/** - * When mapping numbers from decimal to binary, - * we go from w * 10^q to m * 2^p but we have - * 10^q = 5^q * 2^q, so effectively - * we are trying to match - * w * 2^q * 5^q to m * 2^p. Thus the powers of two - * are not a concern since they can be represented - * exactly using the binary notation, only the powers of five - * affect the binary significand. - */ - -/** - * The smallest non-zero float (binary64) is 2^-1074. - * We take as input numbers of the form w x 10^q where w < 2^64. - * We have that w * 10^-343 < 2^(64-344) 5^-343 < 2^-1076. - * However, we have that - * (2^64-1) * 10^-342 = (2^64-1) * 2^-342 * 5^-342 > 2^-1074. - * Thus it is possible for a number of the form w * 10^-342 where - * w is a 64-bit value to be a non-zero floating-point number. - ********* - * Any number of form w * 10^309 where w>= 1 is going to be - * infinite in binary64 so we never need to worry about powers - * of 5 greater than 308. - */ -template struct powers_template { - - constexpr static int smallest_power_of_five = - binary_format::smallest_power_of_ten(); - constexpr static int largest_power_of_five = - binary_format::largest_power_of_ten(); - constexpr static int number_of_entries = - 2 * (largest_power_of_five - smallest_power_of_five + 1); - // Powers of five from 5^-342 all the way to 5^308 rounded toward one. - constexpr static uint64_t power_of_five_128[number_of_entries] = { - 0xeef453d6923bd65a, 0x113faa2906a13b3f, - 0x9558b4661b6565f8, 0x4ac7ca59a424c507, - 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, - 0xe95a99df8ace6f53, 0xf4d82c2c107973dc, - 0x91d8a02bb6c10594, 0x79071b9b8a4be869, - 0xb64ec836a47146f9, 0x9748e2826cdee284, - 0xe3e27a444d8d98b7, 0xfd1b1b2308169b25, - 0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7, - 0xb208ef855c969f4f, 0xbdbd2d335e51a935, - 0xde8b2b66b3bc4723, 0xad2c788035e61382, - 0x8b16fb203055ac76, 0x4c3bcb5021afcc31, - 0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d, - 0xd953e8624b85dd78, 0xd71d6dad34a2af0d, - 0x87d4713d6f33aa6b, 0x8672648c40e5ad68, - 0xa9c98d8ccb009506, 0x680efdaf511f18c2, - 0xd43bf0effdc0ba48, 0x212bd1b2566def2, - 0x84a57695fe98746d, 0x14bb630f7604b57, - 0xa5ced43b7e3e9188, 0x419ea3bd35385e2d, - 0xcf42894a5dce35ea, 0x52064cac828675b9, - 0x818995ce7aa0e1b2, 0x7343efebd1940993, - 0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8, - 0xca66fa129f9b60a6, 0xd41a26e077774ef6, - 0xfd00b897478238d0, 0x8920b098955522b4, - 0x9e20735e8cb16382, 0x55b46e5f5d5535b0, - 0xc5a890362fddbc62, 0xeb2189f734aa831d, - 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, - 0x9a6bb0aa55653b2d, 0x47b233c92125366e, - 0xc1069cd4eabe89f8, 0x999ec0bb696e840a, - 0xf148440a256e2c76, 0xc00670ea43ca250d, - 0x96cd2a865764dbca, 0x380406926a5e5728, - 0xbc807527ed3e12bc, 0xc605083704f5ecf2, - 0xeba09271e88d976b, 0xf7864a44c633682e, - 0x93445b8731587ea3, 0x7ab3ee6afbe0211d, - 0xb8157268fdae9e4c, 0x5960ea05bad82964, - 0xe61acf033d1a45df, 0x6fb92487298e33bd, - 0x8fd0c16206306bab, 0xa5d3b6d479f8e056, - 0xb3c4f1ba87bc8696, 0x8f48a4899877186c, - 0xe0b62e2929aba83c, 0x331acdabfe94de87, - 0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14, - 0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9, - 0xdb71e91432b1a24a, 0xc9e82cd9f69d6150, - 0x892731ac9faf056e, 0xbe311c083a225cd2, - 0xab70fe17c79ac6ca, 0x6dbd630a48aaf406, - 0xd64d3d9db981787d, 0x92cbbccdad5b108, - 0x85f0468293f0eb4e, 0x25bbf56008c58ea5, - 0xa76c582338ed2621, 0xaf2af2b80af6f24e, - 0xd1476e2c07286faa, 0x1af5af660db4aee1, - 0x82cca4db847945ca, 0x50d98d9fc890ed4d, - 0xa37fce126597973c, 0xe50ff107bab528a0, - 0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8, - 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a, - 0x9faacf3df73609b1, 0x77b191618c54e9ac, - 0xc795830d75038c1d, 0xd59df5b9ef6a2417, - 0xf97ae3d0d2446f25, 0x4b0573286b44ad1d, - 0x9becce62836ac577, 0x4ee367f9430aec32, - 0xc2e801fb244576d5, 0x229c41f793cda73f, - 0xf3a20279ed56d48a, 0x6b43527578c1110f, - 0x9845418c345644d6, 0x830a13896b78aaa9, - 0xbe5691ef416bd60c, 0x23cc986bc656d553, - 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8, - 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9, - 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53, - 0xe858ad248f5c22c9, 0xd1b3400f8f9cff68, - 0x91376c36d99995be, 0x23100809b9c21fa1, - 0xb58547448ffffb2d, 0xabd40a0c2832a78a, - 0xe2e69915b3fff9f9, 0x16c90c8f323f516c, - 0x8dd01fad907ffc3b, 0xae3da7d97f6792e3, - 0xb1442798f49ffb4a, 0x99cd11cfdf41779c, - 0xdd95317f31c7fa1d, 0x40405643d711d583, - 0x8a7d3eef7f1cfc52, 0x482835ea666b2572, - 0xad1c8eab5ee43b66, 0xda3243650005eecf, - 0xd863b256369d4a40, 0x90bed43e40076a82, - 0x873e4f75e2224e68, 0x5a7744a6e804a291, - 0xa90de3535aaae202, 0x711515d0a205cb36, - 0xd3515c2831559a83, 0xd5a5b44ca873e03, - 0x8412d9991ed58091, 0xe858790afe9486c2, - 0xa5178fff668ae0b6, 0x626e974dbe39a872, - 0xce5d73ff402d98e3, 0xfb0a3d212dc8128f, - 0x80fa687f881c7f8e, 0x7ce66634bc9d0b99, - 0xa139029f6a239f72, 0x1c1fffc1ebc44e80, - 0xc987434744ac874e, 0xa327ffb266b56220, - 0xfbe9141915d7a922, 0x4bf1ff9f0062baa8, - 0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9, - 0xc4ce17b399107c22, 0xcb550fb4384d21d3, - 0xf6019da07f549b2b, 0x7e2a53a146606a48, - 0x99c102844f94e0fb, 0x2eda7444cbfc426d, - 0xc0314325637a1939, 0xfa911155fefb5308, - 0xf03d93eebc589f88, 0x793555ab7eba27ca, - 0x96267c7535b763b5, 0x4bc1558b2f3458de, - 0xbbb01b9283253ca2, 0x9eb1aaedfb016f16, - 0xea9c227723ee8bcb, 0x465e15a979c1cadc, - 0x92a1958a7675175f, 0xbfacd89ec191ec9, - 0xb749faed14125d36, 0xcef980ec671f667b, - 0xe51c79a85916f484, 0x82b7e12780e7401a, - 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810, - 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15, - 0xdfbdcece67006ac9, 0x67a791e093e1d49a, - 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0, - 0xaecc49914078536d, 0x58fae9f773886e18, - 0xda7f5bf590966848, 0xaf39a475506a899e, - 0x888f99797a5e012d, 0x6d8406c952429603, - 0xaab37fd7d8f58178, 0xc8e5087ba6d33b83, - 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64, - 0x855c3be0a17fcd26, 0x5cf2eea09a55067f, - 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e, - 0xd0601d8efc57b08b, 0xf13b94daf124da26, - 0x823c12795db6ce57, 0x76c53d08d6b70858, - 0xa2cb1717b52481ed, 0x54768c4b0c64ca6e, - 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09, - 0xfe5d54150b090b02, 0xd3f93b35435d7c4c, - 0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf, - 0xc6b8e9b0709f109a, 0x359ab6419ca1091b, - 0xf867241c8cc6d4c0, 0xc30163d203c94b62, - 0x9b407691d7fc44f8, 0x79e0de63425dcf1d, - 0xc21094364dfb5636, 0x985915fc12f542e4, - 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d, - 0x979cf3ca6cec5b5a, 0xa705992ceecf9c42, - 0xbd8430bd08277231, 0x50c6ff782a838353, - 0xece53cec4a314ebd, 0xa4f8bf5635246428, - 0x940f4613ae5ed136, 0x871b7795e136be99, - 0xb913179899f68584, 0x28e2557b59846e3f, - 0xe757dd7ec07426e5, 0x331aeada2fe589cf, - 0x9096ea6f3848984f, 0x3ff0d2c85def7621, - 0xb4bca50b065abe63, 0xfed077a756b53a9, - 0xe1ebce4dc7f16dfb, 0xd3e8495912c62894, - 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c, - 0xb080392cc4349dec, 0xbd8d794d96aacfb3, - 0xdca04777f541c567, 0xecf0d7a0fc5583a0, - 0x89e42caaf9491b60, 0xf41686c49db57244, - 0xac5d37d5b79b6239, 0x311c2875c522ced5, - 0xd77485cb25823ac7, 0x7d633293366b828b, - 0x86a8d39ef77164bc, 0xae5dff9c02033197, - 0xa8530886b54dbdeb, 0xd9f57f830283fdfc, - 0xd267caa862a12d66, 0xd072df63c324fd7b, - 0x8380dea93da4bc60, 0x4247cb9e59f71e6d, - 0xa46116538d0deb78, 0x52d9be85f074e608, - 0xcd795be870516656, 0x67902e276c921f8b, - 0x806bd9714632dff6, 0xba1cd8a3db53b6, - 0xa086cfcd97bf97f3, 0x80e8a40eccd228a4, - 0xc8a883c0fdaf7df0, 0x6122cd128006b2cd, - 0xfad2a4b13d1b5d6c, 0x796b805720085f81, - 0x9cc3a6eec6311a63, 0xcbe3303674053bb0, - 0xc3f490aa77bd60fc, 0xbedbfc4411068a9c, - 0xf4f1b4d515acb93b, 0xee92fb5515482d44, - 0x991711052d8bf3c5, 0x751bdd152d4d1c4a, - 0xbf5cd54678eef0b6, 0xd262d45a78a0635d, - 0xef340a98172aace4, 0x86fb897116c87c34, - 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0, - 0xbae0a846d2195712, 0x8974836059cca109, - 0xe998d258869facd7, 0x2bd1a438703fc94b, - 0x91ff83775423cc06, 0x7b6306a34627ddcf, - 0xb67f6455292cbf08, 0x1a3bc84c17b1d542, - 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93, - 0x8e938662882af53e, 0x547eb47b7282ee9c, - 0xb23867fb2a35b28d, 0xe99e619a4f23aa43, - 0xdec681f9f4c31f31, 0x6405fa00e2ec94d4, - 0x8b3c113c38f9f37e, 0xde83bc408dd3dd04, - 0xae0b158b4738705e, 0x9624ab50b148d445, - 0xd98ddaee19068c76, 0x3badd624dd9b0957, - 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6, - 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c, - 0xd47487cc8470652b, 0x7647c3200069671f, - 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073, - 0xa5fb0a17c777cf09, 0xf468107100525890, - 0xcf79cc9db955c2cc, 0x7182148d4066eeb4, - 0x81ac1fe293d599bf, 0xc6f14cd848405530, - 0xa21727db38cb002f, 0xb8ada00e5a506a7c, - 0xca9cf1d206fdc03b, 0xa6d90811f0e4851c, - 0xfd442e4688bd304a, 0x908f4a166d1da663, - 0x9e4a9cec15763e2e, 0x9a598e4e043287fe, - 0xc5dd44271ad3cdba, 0x40eff1e1853f29fd, - 0xf7549530e188c128, 0xd12bee59e68ef47c, - 0x9a94dd3e8cf578b9, 0x82bb74f8301958ce, - 0xc13a148e3032d6e7, 0xe36a52363c1faf01, - 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1, - 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9, - 0xbcb2b812db11a5de, 0x7415d448f6b6f0e7, - 0xebdf661791d60f56, 0x111b495b3464ad21, - 0x936b9fcebb25c995, 0xcab10dd900beec34, - 0xb84687c269ef3bfb, 0x3d5d514f40eea742, - 0xe65829b3046b0afa, 0xcb4a5a3112a5112, - 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab, - 0xb3f4e093db73a093, 0x59ed216765690f56, - 0xe0f218b8d25088b8, 0x306869c13ec3532c, - 0x8c974f7383725573, 0x1e414218c73a13fb, - 0xafbd2350644eeacf, 0xe5d1929ef90898fa, - 0xdbac6c247d62a583, 0xdf45f746b74abf39, - 0x894bc396ce5da772, 0x6b8bba8c328eb783, - 0xab9eb47c81f5114f, 0x66ea92f3f326564, - 0xd686619ba27255a2, 0xc80a537b0efefebd, - 0x8613fd0145877585, 0xbd06742ce95f5f36, - 0xa798fc4196e952e7, 0x2c48113823b73704, - 0xd17f3b51fca3a7a0, 0xf75a15862ca504c5, - 0x82ef85133de648c4, 0x9a984d73dbe722fb, - 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba, - 0xcc963fee10b7d1b3, 0x318df905079926a8, - 0xffbbcfe994e5c61f, 0xfdf17746497f7052, - 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633, - 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0, - 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0, - 0x9c1661a651213e2d, 0x6bea10ca65c084e, - 0xc31bfa0fe5698db8, 0x486e494fcff30a62, - 0xf3e2f893dec3f126, 0x5a89dba3c3efccfa, - 0x986ddb5c6b3a76b7, 0xf89629465a75e01c, - 0xbe89523386091465, 0xf6bbb397f1135823, - 0xee2ba6c0678b597f, 0x746aa07ded582e2c, - 0x94db483840b717ef, 0xa8c2a44eb4571cdc, - 0xba121a4650e4ddeb, 0x92f34d62616ce413, - 0xe896a0d7e51e1566, 0x77b020baf9c81d17, - 0x915e2486ef32cd60, 0xace1474dc1d122e, - 0xb5b5ada8aaff80b8, 0xd819992132456ba, - 0xe3231912d5bf60e6, 0x10e1fff697ed6c69, - 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1, - 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2, - 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde, - 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b, - 0xad4ab7112eb3929d, 0x86c16c98d2c953c6, - 0xd89d64d57a607744, 0xe871c7bf077ba8b7, - 0x87625f056c7c4a8b, 0x11471cd764ad4972, - 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf, - 0xd389b47879823479, 0x4aff1d108d4ec2c3, - 0x843610cb4bf160cb, 0xcedf722a585139ba, - 0xa54394fe1eedb8fe, 0xc2974eb4ee658828, - 0xce947a3da6a9273e, 0x733d226229feea32, - 0x811ccc668829b887, 0x806357d5a3f525f, - 0xa163ff802a3426a8, 0xca07c2dcb0cf26f7, - 0xc9bcff6034c13052, 0xfc89b393dd02f0b5, - 0xfc2c3f3841f17c67, 0xbbac2078d443ace2, - 0x9d9ba7832936edc0, 0xd54b944b84aa4c0d, - 0xc5029163f384a931, 0xa9e795e65d4df11, - 0xf64335bcf065d37d, 0x4d4617b5ff4a16d5, - 0x99ea0196163fa42e, 0x504bced1bf8e4e45, - 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6, - 0xf07da27a82c37088, 0x5d767327bb4e5a4c, - 0x964e858c91ba2655, 0x3a6a07f8d510f86f, - 0xbbe226efb628afea, 0x890489f70a55368b, - 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e, - 0x92c8ae6b464fc96f, 0x3b0b8bc90012929d, - 0xb77ada0617e3bbcb, 0x9ce6ebb40173744, - 0xe55990879ddcaabd, 0xcc420a6a101d0515, - 0x8f57fa54c2a9eab6, 0x9fa946824a12232d, - 0xb32df8e9f3546564, 0x47939822dc96abf9, - 0xdff9772470297ebd, 0x59787e2b93bc56f7, - 0x8bfbea76c619ef36, 0x57eb4edb3c55b65a, - 0xaefae51477a06b03, 0xede622920b6b23f1, - 0xdab99e59958885c4, 0xe95fab368e45eced, - 0x88b402f7fd75539b, 0x11dbcb0218ebb414, - 0xaae103b5fcd2a881, 0xd652bdc29f26a119, - 0xd59944a37c0752a2, 0x4be76d3346f0495f, - 0x857fcae62d8493a5, 0x6f70a4400c562ddb, - 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952, - 0xd097ad07a71f26b2, 0x7e2000a41346a7a7, - 0x825ecc24c873782f, 0x8ed400668c0c28c8, - 0xa2f67f2dfa90563b, 0x728900802f0f32fa, - 0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9, - 0xfea126b7d78186bc, 0xe2f610c84987bfa8, - 0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9, - 0xc6ede63fa05d3143, 0x91503d1c79720dbb, - 0xf8a95fcf88747d94, 0x75a44c6397ce912a, - 0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba, - 0xc24452da229b021b, 0xfbe85badce996168, - 0xf2d56790ab41c2a2, 0xfae27299423fb9c3, - 0x97c560ba6b0919a5, 0xdccd879fc967d41a, - 0xbdb6b8e905cb600f, 0x5400e987bbc1c920, - 0xed246723473e3813, 0x290123e9aab23b68, - 0x9436c0760c86e30b, 0xf9a0b6720aaf6521, - 0xb94470938fa89bce, 0xf808e40e8d5b3e69, - 0xe7958cb87392c2c2, 0xb60b1d1230b20e04, - 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2, - 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3, - 0xe2280b6c20dd5232, 0x25c6da63c38de1b0, - 0x8d590723948a535f, 0x579c487e5a38ad0e, - 0xb0af48ec79ace837, 0x2d835a9df0c6d851, - 0xdcdb1b2798182244, 0xf8e431456cf88e65, - 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff, - 0xac8b2d36eed2dac5, 0xe272467e3d222f3f, - 0xd7adf884aa879177, 0x5b0ed81dcc6abb0f, - 0x86ccbb52ea94baea, 0x98e947129fc2b4e9, - 0xa87fea27a539e9a5, 0x3f2398d747b36224, - 0xd29fe4b18e88640e, 0x8eec7f0d19a03aad, - 0x83a3eeeef9153e89, 0x1953cf68300424ac, - 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7, - 0xcdb02555653131b6, 0x3792f412cb06794d, - 0x808e17555f3ebf11, 0xe2bbd88bbee40bd0, - 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4, - 0xc8de047564d20a8b, 0xf245825a5a445275, - 0xfb158592be068d2e, 0xeed6e2f0f0d56712, - 0x9ced737bb6c4183d, 0x55464dd69685606b, - 0xc428d05aa4751e4c, 0xaa97e14c3c26b886, - 0xf53304714d9265df, 0xd53dd99f4b3066a8, - 0x993fe2c6d07b7fab, 0xe546a8038efe4029, - 0xbf8fdb78849a5f96, 0xde98520472bdd033, - 0xef73d256a5c0f77c, 0x963e66858f6d4440, - 0x95a8637627989aad, 0xdde7001379a44aa8, - 0xbb127c53b17ec159, 0x5560c018580d5d52, - 0xe9d71b689dde71af, 0xaab8f01e6e10b4a6, - 0x9226712162ab070d, 0xcab3961304ca70e8, - 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22, - 0xe45c10c42a2b3b05, 0x8cb89a7db77c506a, - 0x8eb98a7a9a5b04e3, 0x77f3608e92adb242, - 0xb267ed1940f1c61c, 0x55f038b237591ed3, - 0xdf01e85f912e37a3, 0x6b6c46dec52f6688, - 0x8b61313bbabce2c6, 0x2323ac4b3b3da015, - 0xae397d8aa96c1b77, 0xabec975e0a0d081a, - 0xd9c7dced53c72255, 0x96e7bd358c904a21, - 0x881cea14545c7575, 0x7e50d64177da2e54, - 0xaa242499697392d2, 0xdde50bd1d5d0b9e9, - 0xd4ad2dbfc3d07787, 0x955e4ec64b44e864, - 0x84ec3c97da624ab4, 0xbd5af13bef0b113e, - 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e, - 0xcfb11ead453994ba, 0x67de18eda5814af2, - 0x81ceb32c4b43fcf4, 0x80eacf948770ced7, - 0xa2425ff75e14fc31, 0xa1258379a94d028d, - 0xcad2f7f5359a3b3e, 0x96ee45813a04330, - 0xfd87b5f28300ca0d, 0x8bca9d6e188853fc, - 0x9e74d1b791e07e48, 0x775ea264cf55347e, - 0xc612062576589dda, 0x95364afe032a819e, - 0xf79687aed3eec551, 0x3a83ddbd83f52205, - 0x9abe14cd44753b52, 0xc4926a9672793543, - 0xc16d9a0095928a27, 0x75b7053c0f178294, - 0xf1c90080baf72cb1, 0x5324c68b12dd6339, - 0x971da05074da7bee, 0xd3f6fc16ebca5e04, - 0xbce5086492111aea, 0x88f4bb1ca6bcf585, - 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6, - 0x9392ee8e921d5d07, 0x3aff322e62439fd0, - 0xb877aa3236a4b449, 0x9befeb9fad487c3, - 0xe69594bec44de15b, 0x4c2ebe687989a9b4, - 0x901d7cf73ab0acd9, 0xf9d37014bf60a11, - 0xb424dc35095cd80f, 0x538484c19ef38c95, - 0xe12e13424bb40e13, 0x2865a5f206b06fba, - 0x8cbccc096f5088cb, 0xf93f87b7442e45d4, - 0xafebff0bcb24aafe, 0xf78f69a51539d749, - 0xdbe6fecebdedd5be, 0xb573440e5a884d1c, - 0x89705f4136b4a597, 0x31680a88f8953031, - 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e, - 0xd6bf94d5e57a42bc, 0x3d32907604691b4d, - 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110, - 0xa7c5ac471b478423, 0xfcf80dc33721d54, - 0xd1b71758e219652b, 0xd3c36113404ea4a9, - 0x83126e978d4fdf3b, 0x645a1cac083126ea, - 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4, - 0xcccccccccccccccc, 0xcccccccccccccccd, - 0x8000000000000000, 0x0, - 0xa000000000000000, 0x0, - 0xc800000000000000, 0x0, - 0xfa00000000000000, 0x0, - 0x9c40000000000000, 0x0, - 0xc350000000000000, 0x0, - 0xf424000000000000, 0x0, - 0x9896800000000000, 0x0, - 0xbebc200000000000, 0x0, - 0xee6b280000000000, 0x0, - 0x9502f90000000000, 0x0, - 0xba43b74000000000, 0x0, - 0xe8d4a51000000000, 0x0, - 0x9184e72a00000000, 0x0, - 0xb5e620f480000000, 0x0, - 0xe35fa931a0000000, 0x0, - 0x8e1bc9bf04000000, 0x0, - 0xb1a2bc2ec5000000, 0x0, - 0xde0b6b3a76400000, 0x0, - 0x8ac7230489e80000, 0x0, - 0xad78ebc5ac620000, 0x0, - 0xd8d726b7177a8000, 0x0, - 0x878678326eac9000, 0x0, - 0xa968163f0a57b400, 0x0, - 0xd3c21bcecceda100, 0x0, - 0x84595161401484a0, 0x0, - 0xa56fa5b99019a5c8, 0x0, - 0xcecb8f27f4200f3a, 0x0, - 0x813f3978f8940984, 0x4000000000000000, - 0xa18f07d736b90be5, 0x5000000000000000, - 0xc9f2c9cd04674ede, 0xa400000000000000, - 0xfc6f7c4045812296, 0x4d00000000000000, - 0x9dc5ada82b70b59d, 0xf020000000000000, - 0xc5371912364ce305, 0x6c28000000000000, - 0xf684df56c3e01bc6, 0xc732000000000000, - 0x9a130b963a6c115c, 0x3c7f400000000000, - 0xc097ce7bc90715b3, 0x4b9f100000000000, - 0xf0bdc21abb48db20, 0x1e86d40000000000, - 0x96769950b50d88f4, 0x1314448000000000, - 0xbc143fa4e250eb31, 0x17d955a000000000, - 0xeb194f8e1ae525fd, 0x5dcfab0800000000, - 0x92efd1b8d0cf37be, 0x5aa1cae500000000, - 0xb7abc627050305ad, 0xf14a3d9e40000000, - 0xe596b7b0c643c719, 0x6d9ccd05d0000000, - 0x8f7e32ce7bea5c6f, 0xe4820023a2000000, - 0xb35dbf821ae4f38b, 0xdda2802c8a800000, - 0xe0352f62a19e306e, 0xd50b2037ad200000, - 0x8c213d9da502de45, 0x4526f422cc340000, - 0xaf298d050e4395d6, 0x9670b12b7f410000, - 0xdaf3f04651d47b4c, 0x3c0cdd765f114000, - 0x88d8762bf324cd0f, 0xa5880a69fb6ac800, - 0xab0e93b6efee0053, 0x8eea0d047a457a00, - 0xd5d238a4abe98068, 0x72a4904598d6d880, - 0x85a36366eb71f041, 0x47a6da2b7f864750, - 0xa70c3c40a64e6c51, 0x999090b65f67d924, - 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d, - 0x82818f1281ed449f, 0xbff8f10e7a8921a4, - 0xa321f2d7226895c7, 0xaff72d52192b6a0d, - 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490, - 0xfee50b7025c36a08, 0x2f236d04753d5b4, - 0x9f4f2726179a2245, 0x1d762422c946590, - 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5, - 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2, - 0x9b934c3b330c8577, 0x63cc55f49f88eb2f, - 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb, - 0xf316271c7fc3908a, 0x8bef464e3945ef7a, - 0x97edd871cfda3a56, 0x97758bf0e3cbb5ac, - 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317, - 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd, - 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a, - 0xb975d6b6ee39e436, 0xb3e2fd538e122b44, - 0xe7d34c64a9c85d44, 0x60dbbca87196b616, - 0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd, - 0xb51d13aea4a488dd, 0x6babab6398bdbe41, - 0xe264589a4dcdab14, 0xc696963c7eed2dd1, - 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2, - 0xb0de65388cc8ada8, 0x3b25a55f43294bcb, - 0xdd15fe86affad912, 0x49ef0eb713f39ebe, - 0x8a2dbf142dfcc7ab, 0x6e3569326c784337, - 0xacb92ed9397bf996, 0x49c2c37f07965404, - 0xd7e77a8f87daf7fb, 0xdc33745ec97be906, - 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3, - 0xa8acd7c0222311bc, 0xc40832ea0d68ce0c, - 0xd2d80db02aabd62b, 0xf50a3fa490c30190, - 0x83c7088e1aab65db, 0x792667c6da79e0fa, - 0xa4b8cab1a1563f52, 0x577001b891185938, - 0xcde6fd5e09abcf26, 0xed4c0226b55e6f86, - 0x80b05e5ac60b6178, 0x544f8158315b05b4, - 0xa0dc75f1778e39d6, 0x696361ae3db1c721, - 0xc913936dd571c84c, 0x3bc3a19cd1e38e9, - 0xfb5878494ace3a5f, 0x4ab48a04065c723, - 0x9d174b2dcec0e47b, 0x62eb0d64283f9c76, - 0xc45d1df942711d9a, 0x3ba5d0bd324f8394, - 0xf5746577930d6500, 0xca8f44ec7ee36479, - 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb, - 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e, - 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e, - 0x95d04aee3b80ece5, 0xbba1f1d158724a12, - 0xbb445da9ca61281f, 0x2a8a6e45ae8edc97, - 0xea1575143cf97226, 0xf52d09d71a3293bd, - 0x924d692ca61be758, 0x593c2626705f9c56, - 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c, - 0xe498f455c38b997a, 0xb6dfb9c0f956447, - 0x8edf98b59a373fec, 0x4724bd4189bd5eac, - 0xb2977ee300c50fe7, 0x58edec91ec2cb657, - 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed, - 0x8b865b215899f46c, 0xbd79e0d20082ee74, - 0xae67f1e9aec07187, 0xecd8590680a3aa11, - 0xda01ee641a708de9, 0xe80e6f4820cc9495, - 0x884134fe908658b2, 0x3109058d147fdcdd, - 0xaa51823e34a7eede, 0xbd4b46f0599fd415, - 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a, - 0x850fadc09923329e, 0x3e2cf6bc604ddb0, - 0xa6539930bf6bff45, 0x84db8346b786151c, - 0xcfe87f7cef46ff16, 0xe612641865679a63, - 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e, - 0xa26da3999aef7749, 0xe3be5e330f38f09d, - 0xcb090c8001ab551c, 0x5cadf5bfd3072cc5, - 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6, - 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa, - 0xc646d63501a1511d, 0xb281e1fd541501b8, - 0xf7d88bc24209a565, 0x1f225a7ca91a4226, - 0x9ae757596946075f, 0x3375788de9b06958, - 0xc1a12d2fc3978937, 0x52d6b1641c83ae, - 0xf209787bb47d6b84, 0xc0678c5dbd23a49a, - 0x9745eb4d50ce6332, 0xf840b7ba963646e0, - 0xbd176620a501fbff, 0xb650e5a93bc3d898, - 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe, - 0x93ba47c980e98cdf, 0xc66f336c36b10137, - 0xb8a8d9bbe123f017, 0xb80b0047445d4184, - 0xe6d3102ad96cec1d, 0xa60dc059157491e5, - 0x9043ea1ac7e41392, 0x87c89837ad68db2f, - 0xb454e4a179dd1877, 0x29babe4598c311fb, - 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a, - 0x8ce2529e2734bb1d, 0x1899e4a65f58660c, - 0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f, - 0xdc21a1171d42645d, 0x76707543f4fa1f73, - 0x899504ae72497eba, 0x6a06494a791c53a8, - 0xabfa45da0edbde69, 0x487db9d17636892, - 0xd6f8d7509292d603, 0x45a9d2845d3c42b6, - 0x865b86925b9bc5c2, 0xb8a2392ba45a9b2, - 0xa7f26836f282b732, 0x8e6cac7768d7141e, - 0xd1ef0244af2364ff, 0x3207d795430cd926, - 0x8335616aed761f1f, 0x7f44e6bd49e807b8, - 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6, - 0xcd036837130890a1, 0x36dba887c37a8c0f, - 0x802221226be55a64, 0xc2494954da2c9789, - 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c, - 0xc83553c5c8965d3d, 0x6f92829494e5acc7, - 0xfa42a8b73abbf48c, 0xcb772339ba1f17f9, - 0x9c69a97284b578d7, 0xff2a760414536efb, - 0xc38413cf25e2d70d, 0xfef5138519684aba, - 0xf46518c2ef5b8cd1, 0x7eb258665fc25d69, - 0x98bf2f79d5993802, 0xef2f773ffbd97a61, - 0xbeeefb584aff8603, 0xaafb550ffacfd8fa, - 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38, - 0x952ab45cfa97a0b2, 0xdd945a747bf26183, - 0xba756174393d88df, 0x94f971119aeef9e4, - 0xe912b9d1478ceb17, 0x7a37cd5601aab85d, - 0x91abb422ccb812ee, 0xac62e055c10ab33a, - 0xb616a12b7fe617aa, 0x577b986b314d6009, - 0xe39c49765fdf9d94, 0xed5a7e85fda0b80b, - 0x8e41ade9fbebc27d, 0x14588f13be847307, - 0xb1d219647ae6b31c, 0x596eb2d8ae258fc8, - 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb, - 0x8aec23d680043bee, 0x25de7bb9480d5854, - 0xada72ccc20054ae9, 0xaf561aa79a10ae6a, - 0xd910f7ff28069da4, 0x1b2ba1518094da04, - 0x87aa9aff79042286, 0x90fb44d2f05d0842, - 0xa99541bf57452b28, 0x353a1607ac744a53, - 0xd3fa922f2d1675f2, 0x42889b8997915ce8, - 0x847c9b5d7c2e09b7, 0x69956135febada11, - 0xa59bc234db398c25, 0x43fab9837e699095, - 0xcf02b2c21207ef2e, 0x94f967e45e03f4bb, - 0x8161afb94b44f57d, 0x1d1be0eebac278f5, - 0xa1ba1ba79e1632dc, 0x6462d92a69731732, - 0xca28a291859bbf93, 0x7d7b8f7503cfdcfe, - 0xfcb2cb35e702af78, 0x5cda735244c3d43e, - 0x9defbf01b061adab, 0x3a0888136afa64a7, - 0xc56baec21c7a1916, 0x88aaa1845b8fdd0, - 0xf6c69a72a3989f5b, 0x8aad549e57273d45, - 0x9a3c2087a63f6399, 0x36ac54e2f678864b, - 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd, - 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5, - 0x969eb7c47859e743, 0x9f644ae5a4b1b325, - 0xbc4665b596706114, 0x873d5d9f0dde1fee, - 0xeb57ff22fc0c7959, 0xa90cb506d155a7ea, - 0x9316ff75dd87cbd8, 0x9a7f12442d588f2, - 0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f, - 0xe5d3ef282a242e81, 0x8f1668c8a86da5fa, - 0x8fa475791a569d10, 0xf96e017d694487bc, - 0xb38d92d760ec4455, 0x37c981dcc395a9ac, - 0xe070f78d3927556a, 0x85bbe253f47b1417, - 0x8c469ab843b89562, 0x93956d7478ccec8e, - 0xaf58416654a6babb, 0x387ac8d1970027b2, - 0xdb2e51bfe9d0696a, 0x6997b05fcc0319e, - 0x88fcf317f22241e2, 0x441fece3bdf81f03, - 0xab3c2fddeeaad25a, 0xd527e81cad7626c3, - 0xd60b3bd56a5586f1, 0x8a71e223d8d3b074, - 0x85c7056562757456, 0xf6872d5667844e49, - 0xa738c6bebb12d16c, 0xb428f8ac016561db, - 0xd106f86e69d785c7, 0xe13336d701beba52, - 0x82a45b450226b39c, 0xecc0024661173473, - 0xa34d721642b06084, 0x27f002d7f95d0190, - 0xcc20ce9bd35c78a5, 0x31ec038df7b441f4, - 0xff290242c83396ce, 0x7e67047175a15271, - 0x9f79a169bd203e41, 0xf0062c6e984d386, - 0xc75809c42c684dd1, 0x52c07b78a3e60868, - 0xf92e0c3537826145, 0xa7709a56ccdf8a82, - 0x9bbcc7a142b17ccb, 0x88a66076400bb691, - 0xc2abf989935ddbfe, 0x6acff893d00ea435, - 0xf356f7ebf83552fe, 0x583f6b8c4124d43, - 0x98165af37b2153de, 0xc3727a337a8b704a, - 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c, - 0xeda2ee1c7064130c, 0x1162def06f79df73, - 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8, - 0xb9a74a0637ce2ee1, 0x6d953e2bd7173692, - 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437, - 0x910ab1d4db9914a0, 0x1d9c9892400a22a2, - 0xb54d5e4a127f59c8, 0x2503beb6d00cab4b, - 0xe2a0b5dc971f303a, 0x2e44ae64840fd61d, - 0x8da471a9de737e24, 0x5ceaecfed289e5d2, - 0xb10d8e1456105dad, 0x7425a83e872c5f47, - 0xdd50f1996b947518, 0xd12f124e28f77719, - 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f, - 0xace73cbfdc0bfb7b, 0x636cc64d1001550b, - 0xd8210befd30efa5a, 0x3c47f7e05401aa4e, - 0x8714a775e3e95c78, 0x65acfaec34810a71, - 0xa8d9d1535ce3b396, 0x7f1839a741a14d0d, - 0xd31045a8341ca07c, 0x1ede48111209a050, - 0x83ea2b892091e44d, 0x934aed0aab460432, - 0xa4e4b66b68b65d60, 0xf81da84d5617853f, - 0xce1de40642e3f4b9, 0x36251260ab9d668e, - 0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019, - 0xa1075a24e4421730, 0xb24cf65b8612f81f, - 0xc94930ae1d529cfc, 0xdee033f26797b627, - 0xfb9b7cd9a4a7443c, 0x169840ef017da3b1, - 0x9d412e0806e88aa5, 0x8e1f289560ee864e, - 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2, - 0xf5b5d7ec8acb58a2, 0xae10af696774b1db, - 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29, - 0xbff610b0cc6edd3f, 0x17fd090a58d32af3, - 0xeff394dcff8a948e, 0xddfc4b4cef07f5b0, - 0x95f83d0a1fb69cd9, 0x4abdaf101564f98e, - 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1, - 0xea53df5fd18d5513, 0x84c86189216dc5ed, - 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4, - 0xb7118682dbb66a77, 0x3fbc8c33221dc2a1, - 0xe4d5e82392a40515, 0xfabaf3feaa5334a, - 0x8f05b1163ba6832d, 0x29cb4d87f2a7400e, - 0xb2c71d5bca9023f8, 0x743e20e9ef511012, - 0xdf78e4b2bd342cf6, 0x914da9246b255416, - 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e, - 0xae9672aba3d0c320, 0xa184ac2473b529b1, - 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e, - 0x8865899617fb1871, 0x7e2fa67c7a658892, - 0xaa7eebfb9df9de8d, 0xddbb901b98feeab7, - 0xd51ea6fa85785631, 0x552a74227f3ea565, - 0x8533285c936b35de, 0xd53a88958f87275f, - 0xa67ff273b8460356, 0x8a892abaf368f137, - 0xd01fef10a657842c, 0x2d2b7569b0432d85, - 0x8213f56a67f6b29b, 0x9c3b29620e29fc73, - 0xa298f2c501f45f42, 0x8349f3ba91b47b8f, - 0xcb3f2f7642717713, 0x241c70a936219a73, - 0xfe0efb53d30dd4d7, 0xed238cd383aa0110, - 0x9ec95d1463e8a506, 0xf4363804324a40aa, - 0xc67bb4597ce2ce48, 0xb143c6053edcd0d5, - 0xf81aa16fdc1b81da, 0xdd94b7868e94050a, - 0x9b10a4e5e9913128, 0xca7cf2b4191c8326, - 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0, - 0xf24a01a73cf2dccf, 0xbc633b39673c8cec, - 0x976e41088617ca01, 0xd5be0503e085d813, - 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18, - 0xec9c459d51852ba2, 0xddf8e7d60ed1219e, - 0x93e1ab8252f33b45, 0xcabb90e5c942b503, - 0xb8da1662e7b00a17, 0x3d6a751f3b936243, - 0xe7109bfba19c0c9d, 0xcc512670a783ad4, - 0x906a617d450187e2, 0x27fb2b80668b24c5, - 0xb484f9dc9641e9da, 0xb1f9f660802dedf6, - 0xe1a63853bbd26451, 0x5e7873f8a0396973, - 0x8d07e33455637eb2, 0xdb0b487b6423e1e8, - 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62, - 0xdc5c5301c56b75f7, 0x7641a140cc7810fb, - 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d, - 0xac2820d9623bf429, 0x546345fa9fbdcd44, - 0xd732290fbacaf133, 0xa97c177947ad4095, - 0x867f59a9d4bed6c0, 0x49ed8eabcccc485d, - 0xa81f301449ee8c70, 0x5c68f256bfff5a74, - 0xd226fc195c6a2f8c, 0x73832eec6fff3111, - 0x83585d8fd9c25db7, 0xc831fd53c5ff7eab, - 0xa42e74f3d032f525, 0xba3e7ca8b77f5e55, - 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb, - 0x80444b5e7aa7cf85, 0x7980d163cf5b81b3, - 0xa0555e361951c366, 0xd7e105bcc332621f, - 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7, - 0xfa856334878fc150, 0xb14f98f6f0feb951, - 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3, - 0xc3b8358109e84f07, 0xa862f80ec4700c8, - 0xf4a642e14c6262c8, 0xcd27bb612758c0fa, - 0x98e7e9cccfbd7dbd, 0x8038d51cb897789c, - 0xbf21e44003acdd2c, 0xe0470a63e6bd56c3, - 0xeeea5d5004981478, 0x1858ccfce06cac74, - 0x95527a5202df0ccb, 0xf37801e0c43ebc8, - 0xbaa718e68396cffd, 0xd30560258f54e6ba, - 0xe950df20247c83fd, 0x47c6b82ef32a2069, - 0x91d28b7416cdd27e, 0x4cdc331d57fa5441, - 0xb6472e511c81471d, 0xe0133fe4adf8e952, - 0xe3d8f9e563a198e5, 0x58180fddd97723a6, - 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648, - }; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template -constexpr uint64_t - powers_template::power_of_five_128[number_of_entries]; - -#endif - -using powers = powers_template<>; - -} // namespace fast_float - -#endif diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h deleted file mode 100644 index 403eea1..0000000 --- a/include/fast_float/float_common.h +++ /dev/null @@ -1,1432 +0,0 @@ -#ifndef FASTFLOAT_FLOAT_COMMON_H -#define FASTFLOAT_FLOAT_COMMON_H - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __has_include -#if __has_include() && (__cplusplus > 202002L || (defined(_MSVC_LANG) && (_MSVC_LANG > 202002L))) -#include -#endif -#endif -#include "constexpr_feature_detect.h" - -#define FASTFLOAT_VERSION_MAJOR 8 -#define FASTFLOAT_VERSION_MINOR 2 -#define FASTFLOAT_VERSION_PATCH 5 - -#define FASTFLOAT_STRINGIZE_IMPL(x) #x -#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) - -#define FASTFLOAT_VERSION_STR \ - FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MAJOR) \ - "." FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MINOR) "." FASTFLOAT_STRINGIZE( \ - FASTFLOAT_VERSION_PATCH) - -#define FASTFLOAT_VERSION \ - (FASTFLOAT_VERSION_MAJOR * 10000 + FASTFLOAT_VERSION_MINOR * 100 + \ - FASTFLOAT_VERSION_PATCH) - -namespace fast_float { - -enum class chars_format : uint64_t; - -namespace detail { -constexpr chars_format basic_json_fmt = chars_format(1 << 5); -constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); -} // namespace detail - -enum class chars_format : uint64_t { - scientific = 1 << 0, - fixed = 1 << 2, - hex = 1 << 3, - no_infnan = 1 << 4, - // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 - json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan, - // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. - json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific, - fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific, - general = fixed | scientific, - allow_leading_plus = 1 << 7, - skip_white_space = 1 << 8, -}; - -template struct from_chars_result_t { - UC const *ptr; - std::errc ec; - - // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2497r0.html - constexpr explicit operator bool() const noexcept { - return ec == std::errc(); - } -}; - -using from_chars_result = from_chars_result_t; - -template struct parse_options_t { - constexpr explicit parse_options_t(chars_format fmt = chars_format::general, - UC dot = UC('.'), int b = 10) - : format(fmt), decimal_point(dot), base(b) {} - - /** Which number formats are accepted */ - chars_format format; - /** The character used as decimal point */ - UC decimal_point; - /** The base used for integers */ - int base; -}; - -using parse_options = parse_options_t; - -} // namespace fast_float - -#if FASTFLOAT_HAS_BIT_CAST -#include -#endif - -#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \ - defined(__MINGW64__) || defined(__s390x__) || \ - (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ - defined(__PPC64LE__)) || \ - defined(__loongarch64) || (defined(__riscv) && __riscv_xlen == 64)) -#define FASTFLOAT_64BIT 1 -#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \ - defined(__MINGW32__) || defined(__EMSCRIPTEN__) || \ - (defined(__riscv) && __riscv_xlen == 32)) -#define FASTFLOAT_32BIT 1 -#else - // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. -// We can never tell the register width, but the SIZE_MAX is a good -// approximation. UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max -// portability. -#if SIZE_MAX == 0xffff -#error Unknown platform (16-bit, unsupported) -#elif SIZE_MAX == 0xffffffff -#define FASTFLOAT_32BIT 1 -#elif SIZE_MAX == 0xffffffffffffffff -#define FASTFLOAT_64BIT 1 -#else -#error Unknown platform (not 32-bit, not 64-bit?) -#endif -#endif - -#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) || \ - (defined(_M_ARM64) && !defined(__MINGW32__)) -#include -#endif - -#if defined(_MSC_VER) && !defined(__clang__) -#define FASTFLOAT_VISUAL_STUDIO 1 -#endif - -#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ -#define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#elif defined _WIN32 -#define FASTFLOAT_IS_BIG_ENDIAN 0 -#else -#if defined(__APPLE__) || defined(__FreeBSD__) -#include -#elif defined(sun) || defined(__sun) -#include -#elif defined(__MVS__) -#include -#else -#ifdef __has_include -#if __has_include() -#include -#endif //__has_include() -#endif //__has_include -#endif -# -#ifndef __BYTE_ORDER__ -// safe choice -#define FASTFLOAT_IS_BIG_ENDIAN 0 -#endif -# -#ifndef __ORDER_LITTLE_ENDIAN__ -// safe choice -#define FASTFLOAT_IS_BIG_ENDIAN 0 -#endif -# -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define FASTFLOAT_IS_BIG_ENDIAN 0 -#else -#define FASTFLOAT_IS_BIG_ENDIAN 1 -#endif -#endif - -#if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ - (defined(_M_AMD64) || defined(_M_X64) || \ - (defined(_M_IX86_FP) && _M_IX86_FP == 2))) -#define FASTFLOAT_SSE2 1 -#endif - -#if defined(__aarch64__) || defined(_M_ARM64) -#define FASTFLOAT_NEON 1 -#endif - -#if defined(FASTFLOAT_SSE2) || defined(FASTFLOAT_NEON) -#define FASTFLOAT_HAS_SIMD 1 -#endif - -#if defined(__GNUC__) -// disable -Wcast-align=strict (GCC only) -#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wcast-align\"") -#else -#define FASTFLOAT_SIMD_DISABLE_WARNINGS -#endif - -#if defined(__GNUC__) -#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") -#else -#define FASTFLOAT_SIMD_RESTORE_WARNINGS -#endif - -#ifdef FASTFLOAT_VISUAL_STUDIO -#define fastfloat_really_inline __forceinline -#else -#define fastfloat_really_inline inline __attribute__((always_inline)) -#endif - -#ifndef FASTFLOAT_ASSERT -#define FASTFLOAT_ASSERT(x) \ - { ((void)(x)); } -#endif - -#ifndef FASTFLOAT_DEBUG_ASSERT -#define FASTFLOAT_DEBUG_ASSERT(x) \ - { ((void)(x)); } -#endif - -// rust style `try!()` macro, or `?` operator -#define FASTFLOAT_TRY(x) \ - { \ - if (!(x)) \ - return false; \ - } - -#define FASTFLOAT_ENABLE_IF(...) \ - typename std::enable_if<(__VA_ARGS__), int>::type - -namespace fast_float { - -fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() { -#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED - return std::is_constant_evaluated(); -#else - return false; -#endif -} - -template -struct is_supported_float_type - : std::integral_constant< - bool, std::is_same::value || std::is_same::value -#ifdef __STDCPP_FLOAT64_T__ - || std::is_same::value -#endif -#ifdef __STDCPP_FLOAT32_T__ - || std::is_same::value -#endif -#ifdef __STDCPP_FLOAT16_T__ - || std::is_same::value -#endif -#ifdef __STDCPP_BFLOAT16_T__ - || std::is_same::value -#endif - > { -}; - -template -using equiv_uint_t = typename std::conditional< - sizeof(T) == 1, uint8_t, - typename std::conditional< - sizeof(T) == 2, uint16_t, - typename std::conditional::type>::type>::type; - -template struct is_supported_integer_type : std::is_integral {}; - -template -struct is_supported_char_type - : std::integral_constant::value || - std::is_same::value || - std::is_same::value || - std::is_same::value -#ifdef __cpp_char8_t - || std::is_same::value -#endif - > { -}; - -template -inline FASTFLOAT_CONSTEXPR14 bool -fastfloat_strncasecmp3(UC const *actual_mixedcase, - UC const *expected_lowercase) { - uint64_t mask{0}; - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { - mask = 0x0020002000200020; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - mask = 0x0000002000000020; - } - else { - return false; - } - - uint64_t val1{0}, val2{0}; - if (cpp20_and_in_constexpr()) { - for (size_t i = 0; i < 3; i++) { - if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { - return false; - } - } - return true; - } else { - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) { - ::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 3 * sizeof(UC)); - val1 |= mask; - val2 |= mask; - return val1 == val2; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - return (actual_mixedcase[2] | 32) == (expected_lowercase[2]); - } - else { - return false; - } - } -} - -template -inline FASTFLOAT_CONSTEXPR14 bool -fastfloat_strncasecmp5(UC const *actual_mixedcase, - UC const *expected_lowercase) { - uint64_t mask{0}; - uint64_t val1{0}, val2{0}; - if (cpp20_and_in_constexpr()) { - for (size_t i = 0; i < 5; i++) { - if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { - return false; - } - } - return true; - } else { - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { - mask = 0x2020202020202020; - ::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 5 * sizeof(UC)); - val1 |= mask; - val2 |= mask; - return val1 == val2; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { - mask = 0x0020002000200020; - ::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 4 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - mask = 0x0000002000000020; - ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - ::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC)); - ::memcpy(&val2, expected_lowercase + 2, 2 * sizeof(UC)); - val1 |= mask; - if (val1 != val2) { - return false; - } - return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); - } - else { - return false; - } - } -} - -// Compares two ASCII strings in a case insensitive manner. -template -inline FASTFLOAT_CONSTEXPR14 bool -fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, - size_t length) { - uint64_t mask{0}; - FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { - mask = 0x0020002000200020; - } - else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { - mask = 0x0000002000000020; - } - else { - return false; - } - - if (cpp20_and_in_constexpr()) { - for (size_t i = 0; i < length; i++) { - if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { - return false; - } - } - return true; - } else { - uint64_t val1{0}, val2{0}; - size_t sz{8 / (sizeof(UC))}; - for (size_t i = 0; i < length; i += sz) { - val1 = val2 = 0; - sz = sz < (length - i) ? sz : length - i; - ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); - ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); - val1 |= mask; - val2 |= mask; - if (val1 != val2) { - return false; - } - } - return true; - } -} - -#ifndef FLT_EVAL_METHOD -#error "FLT_EVAL_METHOD should be defined, please include cfloat." -#endif - -// a pointer and a length to a contiguous block of memory -template struct span { - T const *ptr; - size_t length; - - constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {} - - constexpr span() : ptr(nullptr), length(0) {} - - constexpr size_t len() const noexcept { return length; } - - FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept { - FASTFLOAT_DEBUG_ASSERT(index < length); - return ptr[index]; - } -}; - -struct value128 { - uint64_t low; - uint64_t high; - - constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} - - constexpr value128() : low(0), high(0) {} -}; - -/* Helper C++14 constexpr generic implementation of leading_zeroes */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int -leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { - if (input_num & uint64_t(0xffffffff00000000)) { - input_num >>= 32; - last_bit |= 32; - } - if (input_num & uint64_t(0xffff0000)) { - input_num >>= 16; - last_bit |= 16; - } - if (input_num & uint64_t(0xff00)) { - input_num >>= 8; - last_bit |= 8; - } - if (input_num & uint64_t(0xf0)) { - input_num >>= 4; - last_bit |= 4; - } - if (input_num & uint64_t(0xc)) { - input_num >>= 2; - last_bit |= 2; - } - if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ - last_bit |= 1; - } - return 63 - last_bit; -} - -/* result might be undefined when input_num is zero */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int -leading_zeroes(uint64_t input_num) { - assert(input_num > 0); - if (cpp20_and_in_constexpr()) { - return leading_zeroes_generic(input_num); - } -#ifdef FASTFLOAT_VISUAL_STUDIO -#if defined(_M_X64) || defined(_M_ARM64) - unsigned long leading_zero = 0; - // Search the mask data from most significant bit (MSB) - // to least significant bit (LSB) for a set bit (1). - _BitScanReverse64(&leading_zero, input_num); - return (int)(63 - leading_zero); -#else - return leading_zeroes_generic(input_num); -#endif -#else - return __builtin_clzll(input_num); -#endif -} - -/* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int -countr_zero_generic_32(uint32_t input_num) { - if (input_num == 0) { - return 32; - } - int last_bit = 0; - if (!(input_num & 0x0000FFFF)) { - input_num >>= 16; - last_bit |= 16; - } - if (!(input_num & 0x00FF)) { - input_num >>= 8; - last_bit |= 8; - } - if (!(input_num & 0x0F)) { - input_num >>= 4; - last_bit |= 4; - } - if (!(input_num & 0x3)) { - input_num >>= 2; - last_bit |= 2; - } - if (!(input_num & 0x1)) { - last_bit |= 1; - } - return last_bit; -} - -/* count trailing zeroes for 32-bit integers */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int -countr_zero_32(uint32_t input_num) { - if (cpp20_and_in_constexpr()) { - return countr_zero_generic_32(input_num); - } -#ifdef FASTFLOAT_VISUAL_STUDIO - unsigned long trailing_zero = 0; - if (_BitScanForward(&trailing_zero, input_num)) { - return (int)trailing_zero; - } - return 32; -#else - return input_num == 0 ? 32 : __builtin_ctz(input_num); -#endif -} - -// slow emulation routine for 32-bit -fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) { - return x * (uint64_t)y; -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t -umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { - uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); - uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); - uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); - uint64_t adbc_carry = (uint64_t)(adbc < ad); - uint64_t lo = bd + (adbc << 32); - *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + - (adbc_carry << 32) + (uint64_t)(lo < bd); - return lo; -} - -#ifdef FASTFLOAT_32BIT - -// slow emulation routine for 32-bit -#if !defined(__MINGW64__) -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, - uint64_t cd, - uint64_t *hi) { - return umul128_generic(ab, cd, hi); -} -#endif // !__MINGW64__ - -#endif // FASTFLOAT_32BIT - -// compute 64-bit a*b -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 -full_multiplication(uint64_t a, uint64_t b) { - if (cpp20_and_in_constexpr()) { - value128 answer; - answer.low = umul128_generic(a, b, &answer.high); - return answer; - } - value128 answer; -#if defined(_M_ARM64) && !defined(__MINGW32__) - // ARM64 has native support for 64-bit multiplications, no need to emulate - // But MinGW on ARM64 doesn't have native support for 64-bit multiplications - answer.high = __umulh(a, b); - answer.low = a * b; -#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__) && \ - !defined(_M_ARM64) && !defined(__GNUC__)) - answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64 -#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__) - __uint128_t r = ((__uint128_t)a) * b; - answer.low = uint64_t(r); - answer.high = uint64_t(r >> 64); -#else - answer.low = umul128_generic(a, b, &answer.high); -#endif - return answer; -} - -struct adjusted_mantissa { - uint64_t mantissa{0}; - int32_t power2{0}; // a negative value indicates an invalid result - adjusted_mantissa() = default; - - constexpr bool operator==(adjusted_mantissa const &o) const { - return mantissa == o.mantissa && power2 == o.power2; - } - - constexpr bool operator!=(adjusted_mantissa const &o) const { - return mantissa != o.mantissa || power2 != o.power2; - } -}; - -// Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static int32_t invalid_am_bias = -0x8000; - -// used for binary_format_lookup_tables::max_mantissa -constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; - -template struct binary_format_lookup_tables; - -template struct binary_format : binary_format_lookup_tables { - using equiv_uint = equiv_uint_t; - - static constexpr int mantissa_explicit_bits(); - static constexpr int minimum_exponent(); - static constexpr int infinite_power(); - static constexpr int sign_index(); - static constexpr int - min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int max_exponent_fast_path(); - static constexpr int max_exponent_round_to_even(); - static constexpr int min_exponent_round_to_even(); - static constexpr uint64_t max_mantissa_fast_path(int64_t power); - static constexpr uint64_t - max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int largest_power_of_ten(); - static constexpr int smallest_power_of_ten(); - static constexpr T exact_power_of_ten(int64_t power); - static constexpr size_t max_digits(); - static constexpr equiv_uint exponent_mask(); - static constexpr equiv_uint mantissa_mask(); - static constexpr equiv_uint hidden_bit_mask(); -}; - -template struct binary_format_lookup_tables { - static constexpr double powers_of_ten[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, - 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; - - // Largest integer value v so that (5**index * v) <= 1<<53. - // 0x20000000000000 == 1 << 53 - static constexpr uint64_t max_mantissa[] = { - 0x20000000000000, - 0x20000000000000 / 5, - 0x20000000000000 / (5 * 5), - 0x20000000000000 / (5 * 5 * 5), - 0x20000000000000 / (5 * 5 * 5 * 5), - 0x20000000000000 / (constant_55555), - 0x20000000000000 / (constant_55555 * 5), - 0x20000000000000 / (constant_55555 * 5 * 5), - 0x20000000000000 / (constant_55555 * 5 * 5 * 5), - 0x20000000000000 / (constant_55555 * 5 * 5 * 5 * 5), - 0x20000000000000 / (constant_55555 * constant_55555), - 0x20000000000000 / (constant_55555 * constant_55555 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5), - 0x20000000000000 / - (constant_55555 * constant_55555 * constant_55555 * 5 * 5), - 0x20000000000000 / - (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5), - 0x20000000000000 / - (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5), - 0x20000000000000 / - (constant_55555 * constant_55555 * constant_55555 * constant_55555), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * - constant_55555 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * - constant_55555 * 5 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * - constant_55555 * 5 * 5 * 5), - 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * - constant_55555 * 5 * 5 * 5 * 5)}; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template -constexpr double binary_format_lookup_tables::powers_of_ten[]; - -template -constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; - -#endif - -template struct binary_format_lookup_tables { - static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, - 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; - - // Largest integer value v so that (5**index * v) <= 1<<24. - // 0x1000000 == 1<<24 - static constexpr uint64_t max_mantissa[] = { - 0x1000000, - 0x1000000 / 5, - 0x1000000 / (5 * 5), - 0x1000000 / (5 * 5 * 5), - 0x1000000 / (5 * 5 * 5 * 5), - 0x1000000 / (constant_55555), - 0x1000000 / (constant_55555 * 5), - 0x1000000 / (constant_55555 * 5 * 5), - 0x1000000 / (constant_55555 * 5 * 5 * 5), - 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5), - 0x1000000 / (constant_55555 * constant_55555), - 0x1000000 / (constant_55555 * constant_55555 * 5)}; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template -constexpr float binary_format_lookup_tables::powers_of_ten[]; - -template -constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; - -#endif - -template <> -inline constexpr int binary_format::min_exponent_fast_path() { -#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) - return 0; -#else - return -22; -#endif -} - -template <> -inline constexpr int binary_format::min_exponent_fast_path() { -#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) - return 0; -#else - return -10; -#endif -} - -template <> -inline constexpr int binary_format::mantissa_explicit_bits() { - return 52; -} - -template <> -inline constexpr int binary_format::mantissa_explicit_bits() { - return 23; -} - -template <> -inline constexpr int binary_format::max_exponent_round_to_even() { - return 23; -} - -template <> -inline constexpr int binary_format::max_exponent_round_to_even() { - return 10; -} - -template <> -inline constexpr int binary_format::min_exponent_round_to_even() { - return -4; -} - -template <> -inline constexpr int binary_format::min_exponent_round_to_even() { - return -17; -} - -template <> inline constexpr int binary_format::minimum_exponent() { - return -1023; -} - -template <> inline constexpr int binary_format::minimum_exponent() { - return -127; -} - -template <> inline constexpr int binary_format::infinite_power() { - return 0x7FF; -} - -template <> inline constexpr int binary_format::infinite_power() { - return 0xFF; -} - -template <> inline constexpr int binary_format::sign_index() { - return 63; -} - -template <> inline constexpr int binary_format::sign_index() { - return 31; -} - -template <> -inline constexpr int binary_format::max_exponent_fast_path() { - return 22; -} - -template <> -inline constexpr int binary_format::max_exponent_fast_path() { - return 10; -} - -template <> -inline constexpr uint64_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); -} - -template <> -inline constexpr uint64_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); -} - -// credit: Jakub Jelínek -#ifdef __STDCPP_FLOAT16_T__ -template struct binary_format_lookup_tables { - static constexpr std::float16_t powers_of_ten[] = {1e0f16, 1e1f16, 1e2f16, - 1e3f16, 1e4f16}; - - // Largest integer value v so that (5**index * v) <= 1<<11. - // 0x800 == 1<<11 - static constexpr uint64_t max_mantissa[] = {0x800, - 0x800 / 5, - 0x800 / (5 * 5), - 0x800 / (5 * 5 * 5), - 0x800 / (5 * 5 * 5 * 5), - 0x800 / (constant_55555)}; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template -constexpr std::float16_t - binary_format_lookup_tables::powers_of_ten[]; - -template -constexpr uint64_t - binary_format_lookup_tables::max_mantissa[]; - -#endif - -template <> -inline constexpr std::float16_t -binary_format::exact_power_of_ten(int64_t power) { - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)powers_of_ten[0], powers_of_ten[power]; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::exponent_mask() { - return 0x7C00; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::mantissa_mask() { - return 0x03FF; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::hidden_bit_mask() { - return 0x0400; -} - -template <> -inline constexpr int binary_format::max_exponent_fast_path() { - return 4; -} - -template <> -inline constexpr int binary_format::mantissa_explicit_bits() { - return 10; -} - -template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); -} - -template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { - // caller is responsible to ensure that - // power >= 0 && power <= 4 - // - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)max_mantissa[0], max_mantissa[power]; -} - -template <> -inline constexpr int binary_format::min_exponent_fast_path() { - return 0; -} - -template <> -inline constexpr int -binary_format::max_exponent_round_to_even() { - return 5; -} - -template <> -inline constexpr int -binary_format::min_exponent_round_to_even() { - return -22; -} - -template <> -inline constexpr int binary_format::minimum_exponent() { - return -15; -} - -template <> -inline constexpr int binary_format::infinite_power() { - return 0x1F; -} - -template <> inline constexpr int binary_format::sign_index() { - return 15; -} - -template <> -inline constexpr int binary_format::largest_power_of_ten() { - return 4; -} - -template <> -inline constexpr int binary_format::smallest_power_of_ten() { - return -27; -} - -template <> -inline constexpr size_t binary_format::max_digits() { - return 22; -} -#endif // __STDCPP_FLOAT16_T__ - -// credit: Jakub Jelínek -#ifdef __STDCPP_BFLOAT16_T__ -template struct binary_format_lookup_tables { - static constexpr std::bfloat16_t powers_of_ten[] = {1e0bf16, 1e1bf16, 1e2bf16, - 1e3bf16}; - - // Largest integer value v so that (5**index * v) <= 1<<8. - // 0x100 == 1<<8 - static constexpr uint64_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5), - 0x100 / (5 * 5 * 5), - 0x100 / (5 * 5 * 5 * 5)}; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template -constexpr std::bfloat16_t - binary_format_lookup_tables::powers_of_ten[]; - -template -constexpr uint64_t - binary_format_lookup_tables::max_mantissa[]; - -#endif - -template <> -inline constexpr std::bfloat16_t -binary_format::exact_power_of_ten(int64_t power) { - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)powers_of_ten[0], powers_of_ten[power]; -} - -template <> -inline constexpr int binary_format::max_exponent_fast_path() { - return 3; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::exponent_mask() { - return 0x7F80; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::mantissa_mask() { - return 0x007F; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::hidden_bit_mask() { - return 0x0080; -} - -template <> -inline constexpr int binary_format::mantissa_explicit_bits() { - return 7; -} - -template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); -} - -template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { - // caller is responsible to ensure that - // power >= 0 && power <= 3 - // - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)max_mantissa[0], max_mantissa[power]; -} - -template <> -inline constexpr int binary_format::min_exponent_fast_path() { - return 0; -} - -template <> -inline constexpr int -binary_format::max_exponent_round_to_even() { - return 3; -} - -template <> -inline constexpr int -binary_format::min_exponent_round_to_even() { - return -24; -} - -template <> -inline constexpr int binary_format::minimum_exponent() { - return -127; -} - -template <> -inline constexpr int binary_format::infinite_power() { - return 0xFF; -} - -template <> inline constexpr int binary_format::sign_index() { - return 15; -} - -template <> -inline constexpr int binary_format::largest_power_of_ten() { - return 38; -} - -template <> -inline constexpr int binary_format::smallest_power_of_ten() { - return -60; -} - -template <> -inline constexpr size_t binary_format::max_digits() { - return 98; -} -#endif // __STDCPP_BFLOAT16_T__ - -template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { - // caller is responsible to ensure that - // power >= 0 && power <= 22 - // - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)max_mantissa[0], max_mantissa[power]; -} - -template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { - // caller is responsible to ensure that - // power >= 0 && power <= 10 - // - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)max_mantissa[0], max_mantissa[power]; -} - -template <> -inline constexpr double -binary_format::exact_power_of_ten(int64_t power) { - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)powers_of_ten[0], powers_of_ten[power]; -} - -template <> -inline constexpr float binary_format::exact_power_of_ten(int64_t power) { - // Work around clang bug https://godbolt.org/z/zedh7rrhc - return (void)powers_of_ten[0], powers_of_ten[power]; -} - -template <> inline constexpr int binary_format::largest_power_of_ten() { - return 308; -} - -template <> inline constexpr int binary_format::largest_power_of_ten() { - return 38; -} - -template <> -inline constexpr int binary_format::smallest_power_of_ten() { - return -342; -} - -template <> inline constexpr int binary_format::smallest_power_of_ten() { - return -64; -} - -template <> inline constexpr size_t binary_format::max_digits() { - return 769; -} - -template <> inline constexpr size_t binary_format::max_digits() { - return 114; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::exponent_mask() { - return 0x7F800000; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::exponent_mask() { - return 0x7FF0000000000000; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::mantissa_mask() { - return 0x007FFFFF; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::mantissa_mask() { - return 0x000FFFFFFFFFFFFF; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::hidden_bit_mask() { - return 0x00800000; -} - -template <> -inline constexpr binary_format::equiv_uint -binary_format::hidden_bit_mask() { - return 0x0010000000000000; -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -to_float(bool negative, adjusted_mantissa am, T &value) { - using equiv_uint = equiv_uint_t; - equiv_uint word = equiv_uint(am.mantissa); - word = equiv_uint(word | equiv_uint(am.power2) - << binary_format::mantissa_explicit_bits()); - word = - equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); -#if FASTFLOAT_HAS_BIT_CAST - value = std::bit_cast(word); -#else - ::memcpy(&value, &word, sizeof(T)); -#endif -} - -template struct space_lut { - static constexpr bool value[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template constexpr bool space_lut::value[]; - -#endif - -template constexpr bool is_space(UC c) { - return c < 256 && space_lut<>::value[uint8_t(c)]; -} - -template static constexpr uint64_t int_cmp_zeros() { - static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), - "Unsupported character size"); - return (sizeof(UC) == 1) ? 0x3030303030303030 - : (sizeof(UC) == 2) - ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | - uint64_t(UC('0')) << 16 | UC('0')) - : (uint64_t(UC('0')) << 32 | UC('0')); -} - -template static constexpr int int_cmp_len() { - return sizeof(uint64_t) / sizeof(UC); -} - -template constexpr UC const *str_const_nan(); - -template <> constexpr char const *str_const_nan() { return "nan"; } - -template <> constexpr wchar_t const *str_const_nan() { return L"nan"; } - -template <> constexpr char16_t const *str_const_nan() { - return u"nan"; -} - -template <> constexpr char32_t const *str_const_nan() { - return U"nan"; -} - -#ifdef __cpp_char8_t -template <> constexpr char8_t const *str_const_nan() { - return u8"nan"; -} -#endif - -template constexpr UC const *str_const_inf(); - -template <> constexpr char const *str_const_inf() { return "infinity"; } - -template <> constexpr wchar_t const *str_const_inf() { - return L"infinity"; -} - -template <> constexpr char16_t const *str_const_inf() { - return u"infinity"; -} - -template <> constexpr char32_t const *str_const_inf() { - return U"infinity"; -} - -#ifdef __cpp_char8_t -template <> constexpr char8_t const *str_const_inf() { - return u8"infinity"; -} -#endif - -template struct int_luts { - static constexpr uint8_t chdigit[] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, - 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255}; - - static constexpr size_t maxdigits_u64[] = { - 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, - 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; - - static constexpr uint64_t min_safe_u64[] = { - 9223372036854775808ull, 12157665459056928801ull, 4611686018427387904, - 7450580596923828125, 4738381338321616896, 3909821048582988049, - 9223372036854775808ull, 12157665459056928801ull, 10000000000000000000ull, - 5559917313492231481, 2218611106740436992, 8650415919381337933, - 2177953337809371136, 6568408355712890625, 1152921504606846976, - 2862423051509815793, 6746640616477458432, 15181127029874798299ull, - 1638400000000000000, 3243919932521508681, 6221821273427820544, - 11592836324538749809ull, 876488338465357824, 1490116119384765625, - 2481152873203736576, 4052555153018976267, 6502111422497947648, - 10260628712958602189ull, 15943230000000000000ull, 787662783788549761, - 1152921504606846976, 1667889514952984961, 2386420683693101056, - 3379220508056640625, 4738381338321616896}; -}; - -#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE - -template constexpr uint8_t int_luts::chdigit[]; - -template constexpr size_t int_luts::maxdigits_u64[]; - -template constexpr uint64_t int_luts::min_safe_u64[]; - -#endif - -template -fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { - // wchar_t and char can be signed, so we need to be careful. - using UnsignedUC = typename std::make_unsigned::type; - return int_luts<>::chdigit[static_cast( - static_cast(c) & - static_cast( - -((static_cast(c) & ~0xFFull) == 0)))]; -} - -fastfloat_really_inline constexpr size_t max_digits_u64(int base) { - return int_luts<>::maxdigits_u64[base - 2]; -} - -// If a u64 is exactly max_digits_u64() in length, this is -// the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) { - return int_luts<>::min_safe_u64[base - 2]; -} - -static_assert(std::is_same, uint64_t>::value, - "equiv_uint should be uint64_t for double"); -static_assert(std::numeric_limits::is_iec559, - "double must fulfill the requirements of IEC 559 (IEEE 754)"); - -static_assert(std::is_same, uint32_t>::value, - "equiv_uint should be uint32_t for float"); -static_assert(std::numeric_limits::is_iec559, - "float must fulfill the requirements of IEC 559 (IEEE 754)"); - -#ifdef __STDCPP_FLOAT64_T__ -static_assert(std::is_same, uint64_t>::value, - "equiv_uint should be uint64_t for std::float64_t"); -static_assert( - std::numeric_limits::is_iec559, - "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)"); - -template <> -struct binary_format : public binary_format {}; -#endif // __STDCPP_FLOAT64_T__ - -#ifdef __STDCPP_FLOAT32_T__ -static_assert(std::is_same, uint32_t>::value, - "equiv_uint should be uint32_t for std::float32_t"); -static_assert( - std::numeric_limits::is_iec559, - "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)"); - -template <> -struct binary_format : public binary_format {}; -#endif // __STDCPP_FLOAT32_T__ - -#ifdef __STDCPP_FLOAT16_T__ -static_assert( - std::is_same::equiv_uint, uint16_t>::value, - "equiv_uint should be uint16_t for std::float16_t"); -static_assert( - std::numeric_limits::is_iec559, - "std::float16_t must fulfill the requirements of IEC 559 (IEEE 754)"); -#endif // __STDCPP_FLOAT16_T__ - -#ifdef __STDCPP_BFLOAT16_T__ -static_assert( - std::is_same::equiv_uint, uint16_t>::value, - "equiv_uint should be uint16_t for std::bfloat16_t"); -static_assert( - std::numeric_limits::is_iec559, - "std::bfloat16_t must fulfill the requirements of IEC 559 (IEEE 754)"); -#endif // __STDCPP_BFLOAT16_T__ - -constexpr chars_format operator~(chars_format rhs) noexcept { - using int_type = std::underlying_type::type; - return static_cast(~static_cast(rhs)); -} - -constexpr chars_format operator&(chars_format lhs, chars_format rhs) noexcept { - using int_type = std::underlying_type::type; - return static_cast(static_cast(lhs) & - static_cast(rhs)); -} - -constexpr chars_format operator|(chars_format lhs, chars_format rhs) noexcept { - using int_type = std::underlying_type::type; - return static_cast(static_cast(lhs) | - static_cast(rhs)); -} - -constexpr chars_format operator^(chars_format lhs, chars_format rhs) noexcept { - using int_type = std::underlying_type::type; - return static_cast(static_cast(lhs) ^ - static_cast(rhs)); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & -operator&=(chars_format &lhs, chars_format rhs) noexcept { - return lhs = (lhs & rhs); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & -operator|=(chars_format &lhs, chars_format rhs) noexcept { - return lhs = (lhs | rhs); -} - -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & -operator^=(chars_format &lhs, chars_format rhs) noexcept { - return lhs = (lhs ^ rhs); -} - -namespace detail { -// adjust for deprecated feature macros -constexpr chars_format adjust_for_feature_macros(chars_format fmt) { - return fmt -#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS - | chars_format::allow_leading_plus -#endif -#ifdef FASTFLOAT_SKIP_WHITE_SPACE - | chars_format::skip_white_space -#endif - ; -} -} // namespace detail -} // namespace fast_float - -#endif diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h deleted file mode 100644 index ff9c53d..0000000 --- a/include/fast_float/parse_number.h +++ /dev/null @@ -1,487 +0,0 @@ -#ifndef FASTFLOAT_PARSE_NUMBER_H -#define FASTFLOAT_PARSE_NUMBER_H - -#include "ascii_number.h" -#include "decimal_to_binary.h" -#include "digit_comparison.h" -#include "float_common.h" - -#include -#include -#include -#include - -namespace fast_float { - -namespace detail { -/** - * Special case +inf, -inf, nan, infinity, -infinity. - * The case comparisons could be made much faster given that we know that the - * strings a null-free and fixed. - **/ -template -from_chars_result_t - FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last, - T &value, chars_format fmt) noexcept { - from_chars_result_t answer{}; - answer.ptr = first; - answer.ec = std::errc(); // be optimistic - // assume first < last, so dereference without checks; - bool const minusSign = (*first == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*first == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && - (*first == UC('+')))) { - ++first; - } - if (last - first >= 3) { - if (fastfloat_strncasecmp3(first, str_const_nan())) { - answer.ptr = (first += 3); - value = minusSign ? -std::numeric_limits::quiet_NaN() - : std::numeric_limits::quiet_NaN(); - // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, - // C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan). - if (first != last && *first == UC('(')) { - for (UC const *ptr = first + 1; ptr != last; ++ptr) { - if (*ptr == UC(')')) { - answer.ptr = ptr + 1; // valid nan(n-char-seq-opt) - break; - } else if (!((UC('a') <= *ptr && *ptr <= UC('z')) || - (UC('A') <= *ptr && *ptr <= UC('Z')) || - (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_'))) - break; // forbidden char, not nan(n-char-seq-opt) - } - } - return answer; - } - if (fastfloat_strncasecmp3(first, str_const_inf())) { - if ((last - first >= 8) && - fastfloat_strncasecmp5(first + 3, str_const_inf() + 3)) { - answer.ptr = first + 8; - } else { - answer.ptr = first + 3; - } - value = minusSign ? -std::numeric_limits::infinity() - : std::numeric_limits::infinity(); - return answer; - } - } - answer.ec = std::errc::invalid_argument; - return answer; -} - -/** - * Returns true if the floating-pointing rounding mode is to 'nearest'. - * It is the default on most system. This function is meant to be inexpensive. - * Credit : @mwalcott3 - */ -fastfloat_really_inline bool rounds_to_nearest() noexcept { - // https://lemire.me/blog/2020/06/26/gcc-not-nearest/ -#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) - return false; -#endif - // See - // A fast function to check your floating-point rounding mode - // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/ - // - // This function is meant to be equivalent to : - // prior: #include - // return fegetround() == FE_TONEAREST; - // However, it is expected to be much faster than the fegetround() - // function call. - // - // The volatile keyword prevents the compiler from computing the function - // at compile-time. - // There might be other ways to prevent compile-time optimizations (e.g., - // asm). The value does not need to be std::numeric_limits::min(), any - // small value so that 1 + x should round to 1 would do (after accounting for - // excess precision, as in 387 instructions). - static float volatile fmin = std::numeric_limits::min(); - float fmini = fmin; // we copy it so that it gets loaded at most once. -// -// Explanation: -// Only when fegetround() == FE_TONEAREST do we have that -// fmin + 1.0f == 1.0f - fmin. -// -// FE_UPWARD: -// fmin + 1.0f > 1 -// 1.0f - fmin == 1 -// -// FE_DOWNWARD or FE_TOWARDZERO: -// fmin + 1.0f == 1 -// 1.0f - fmin < 1 -// -// Note: This may fail to be accurate if fast-math has been -// enabled, as rounding conventions may not apply. -#ifdef FASTFLOAT_VISUAL_STUDIO -#pragma warning(push) -// todo: is there a VS warning? -// see -// https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013 -#elif defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wfloat-equal" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - return (fmini + 1.0f == 1.0f - fmini); -#ifdef FASTFLOAT_VISUAL_STUDIO -#pragma warning(pop) -#elif defined(__clang__) -#pragma clang diagnostic pop -#elif defined(__GNUC__) -#pragma GCC diagnostic pop -#endif -} - -} // namespace detail - -template struct from_chars_caller { - template - FASTFLOAT_CONSTEXPR20 static from_chars_result_t - call(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { - return from_chars_advanced(first, last, value, options); - } -}; - -#ifdef __STDCPP_FLOAT32_T__ -template <> struct from_chars_caller { - template - FASTFLOAT_CONSTEXPR20 static from_chars_result_t - call(UC const *first, UC const *last, std::float32_t &value, - parse_options_t options) noexcept { - // if std::float32_t is defined, and we are in C++23 mode; macro set for - // float32; set value to float due to equivalence between float and - // float32_t - float val = 0.0f; - auto ret = from_chars_advanced(first, last, val, options); - value = val; - return ret; - } -}; -#endif - -#ifdef __STDCPP_FLOAT64_T__ -template <> struct from_chars_caller { - template - FASTFLOAT_CONSTEXPR20 static from_chars_result_t - call(UC const *first, UC const *last, std::float64_t &value, - parse_options_t options) noexcept { - // if std::float64_t is defined, and we are in C++23 mode; macro set for - // float64; set value as double due to equivalence between double and - // float64_t - double val = 0.0; - auto ret = from_chars_advanced(first, last, val, options); - value = val; - return ret; - } -}; -#endif - -template -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, - chars_format fmt /*= chars_format::general*/) noexcept { - return from_chars_caller::call(first, last, value, - parse_options_t(fmt)); -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative, - T &value) noexcept { - // The implementation of the Clinger's fast path is convoluted because - // we want round-to-nearest in all cases, irrespective of the rounding mode - // selected on the thread. - // We proceed optimistically, assuming that detail::rounds_to_nearest() - // returns true. - if (binary_format::min_exponent_fast_path() <= exponent && - exponent <= binary_format::max_exponent_fast_path()) { - // Unfortunately, the conventional Clinger's fast path is only possible - // when the system rounds to the nearest float. - // - // We expect the next branch to almost always be selected. - // We could check it first (before the previous branch), but - // there might be performance advantages at having the check - // be last. - if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { - // We have that fegetround() == FE_TONEAREST. - // Next is Clinger's fast path. - if (mantissa <= binary_format::max_mantissa_fast_path()) { - value = T(mantissa); - if (exponent < 0) { - value = value / binary_format::exact_power_of_ten(-exponent); - } else { - value = value * binary_format::exact_power_of_ten(exponent); - } - if (is_negative) { - value = -value; - } - return true; - } - } else { - // We do not have that fegetround() == FE_TONEAREST. - // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's - // proposal - if (exponent >= 0 && - mantissa <= binary_format::max_mantissa_fast_path(exponent)) { -#if defined(__clang__) || defined(FASTFLOAT_32BIT) - // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD - if (mantissa == 0) { - value = is_negative ? T(-0.) : T(0.); - return true; - } -#endif - value = T(mantissa) * binary_format::exact_power_of_ten(exponent); - if (is_negative) { - value = -value; - } - return true; - } - } - } - return false; -} - -/** - * This function overload takes parsed_number_string_t structure that is created - * and populated either by from_chars_advanced function taking chars range and - * parsing options or other parsing custom function implemented by user. - */ -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { - static_assert(is_supported_float_type::value, - "only some floating-point types are supported"); - static_assert(is_supported_char_type::value, - "only char, wchar_t, char16_t and char32_t are supported"); - - from_chars_result_t answer; - - answer.ec = std::errc(); // be optimistic - answer.ptr = pns.lastmatch; - - if (!pns.too_many_digits && - clinger_fast_path_impl(pns.mantissa, pns.exponent, pns.negative, value)) - return answer; - - adjusted_mantissa am = - compute_float>(pns.exponent, pns.mantissa); - if (pns.too_many_digits && am.power2 >= 0) { - if (am != compute_float>(pns.exponent, pns.mantissa + 1)) { - am = compute_error>(pns.exponent, pns.mantissa); - } - } - // If we called compute_float>(pns.exponent, pns.mantissa) - // and we have an invalid power (am.power2 < 0), then we need to go the long - // way around again. This is very uncommon. - if (am.power2 < 0) { - am = digit_comp(pns, am); - } - to_float(pns.negative, am, value); - // Test for over/underflow. - if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || - am.power2 == binary_format::infinite_power()) { - answer.ec = std::errc::result_out_of_range; - } - return answer; -} - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_float_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { - - static_assert(is_supported_float_type::value, - "only some floating-point types are supported"); - static_assert(is_supported_char_type::value, - "only char, wchar_t, char16_t and char32_t are supported"); - - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - - from_chars_result_t answer; - if (uint64_t(fmt & chars_format::skip_white_space)) { - while ((first != last) && fast_float::is_space(*first)) { - first++; - } - } - if (first == last) { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - parsed_number_string_t pns = - uint64_t(fmt & detail::basic_json_fmt) - ? parse_number_string(first, last, options) - : parse_number_string(first, last, options); - if (!pns.valid) { - if (uint64_t(fmt & chars_format::no_infnan)) { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } else { - return detail::parse_infnan(first, last, value, fmt); - } - } - - // call overload that takes parsed_number_string_t directly. - return from_chars_advanced(pns, value); -} - -template -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, int base) noexcept { - - static_assert(is_supported_integer_type::value, - "only integer types are supported"); - static_assert(is_supported_char_type::value, - "only char, wchar_t, char16_t and char32_t are supported"); - - parse_options_t options; - options.base = base; - return from_chars_advanced(first, last, value, options); -} - -template -FASTFLOAT_CONSTEXPR20 - typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept { - T value; - if (clinger_fast_path_impl(mantissa, decimal_exponent, false, value)) - return value; - - adjusted_mantissa am = - compute_float>(decimal_exponent, mantissa); - to_float(false, am, value); - return value; -} - -template -FASTFLOAT_CONSTEXPR20 - typename std::enable_if::value, T>::type - integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept { - const bool is_negative = mantissa < 0; - const uint64_t m = static_cast(is_negative ? -mantissa : mantissa); - - T value; - if (clinger_fast_path_impl(m, decimal_exponent, is_negative, value)) - return value; - - adjusted_mantissa am = compute_float>(decimal_exponent, m); - to_float(is_negative, am, value); - return value; -} - -FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept { - return integer_times_pow10(mantissa, decimal_exponent); -} - -FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept { - return integer_times_pow10(mantissa, decimal_exponent); -} - -// the following overloads are here to avoid surprising ambiguity for int, -// unsigned, etc. -template -FASTFLOAT_CONSTEXPR20 - typename std::enable_if::value && - std::is_integral::value && - !std::is_signed::value, - T>::type - integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), - decimal_exponent); -} - -template -FASTFLOAT_CONSTEXPR20 - typename std::enable_if::value && - std::is_integral::value && - std::is_signed::value, - T>::type - integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), - decimal_exponent); -} - -template -FASTFLOAT_CONSTEXPR20 typename std::enable_if< - std::is_integral::value && !std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), decimal_exponent); -} - -template -FASTFLOAT_CONSTEXPR20 typename std::enable_if< - std::is_integral::value && std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), decimal_exponent); -} - -template -FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_int_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { - - static_assert(is_supported_integer_type::value, - "only integer types are supported"); - static_assert(is_supported_char_type::value, - "only char, wchar_t, char16_t and char32_t are supported"); - - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - int const base = options.base; - - from_chars_result_t answer; - if (uint64_t(fmt & chars_format::skip_white_space)) { - while ((first != last) && fast_float::is_space(*first)) { - first++; - } - } - if (first == last || base < 2 || base > 36) { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - - return parse_int_string(first, last, value, options); -} - -template struct from_chars_advanced_caller { - static_assert(TypeIx > 0, "unsupported type"); -}; - -template <> struct from_chars_advanced_caller<1> { - template - fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t - call(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { - return from_chars_float_advanced(first, last, value, options); - } -}; - -template <> struct from_chars_advanced_caller<2> { - template - fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t - call(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { - return from_chars_int_advanced(first, last, value, options); - } -}; - -template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { - return from_chars_advanced_caller< - size_t(is_supported_float_type::value) + - 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, - options); -} - -} // namespace fast_float - -#endif diff --git a/docs/index.html b/index.html similarity index 98% rename from docs/index.html rename to index.html index fd2d17d..10fa268 100644 --- a/docs/index.html +++ b/index.html @@ -61,12 +61,12 @@ Get started View on GitHub - Download v{{VERSION}} + Download v8.2.5
- Latest release: v{{VERSION}} + Latest release: v8.2.5 Apache 2.0 MIT @@ -221,7 +221,7 @@ constexpr double pi = parse("3.1415"); // computed at compile time
FetchContent_Declare(
   fast_float
   GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
-  GIT_TAG tags/v{{VERSION}}
+  GIT_TAG tags/v8.2.5
   GIT_SHALLOW TRUE)
 FetchContent_MakeAvailable(fast_float)
 target_link_libraries(myprogram PUBLIC fast_float)
@@ -232,13 +232,13 @@ target_link_libraries(myprogram PUBLIC fast_float)
CPMAddPackage(
   NAME fast_float
   GITHUB_REPOSITORY "fastfloat/fast_float"
-  GIT_TAG v{{VERSION}})
+ GIT_TAG v8.2.5)

Single header

Download a pre-amalgamated header — no build system required.

-
curl -LO https://github.com/fastfloat/fast_float/releases/download/v{{VERSION}}/fast_float.h
+
curl -LO https://github.com/fastfloat/fast_float/releases/download/v8.2.5/fast_float.h
@@ -327,7 +327,7 @@ target_link_libraries(myprogram PUBLIC fast_float)
- Current release v{{VERSION}} + Current release v8.2.5 Maintained by the fast_float contributors.
diff --git a/script/amalgamate.py b/script/amalgamate.py deleted file mode 100644 index 78e9961..0000000 --- a/script/amalgamate.py +++ /dev/null @@ -1,122 +0,0 @@ -# text parts -processed_files = {} - -# authors -for filename in ["AUTHORS", "CONTRIBUTORS"]: - with open(filename, encoding="utf8") as f: - text = "" - for line in f: - if filename == "AUTHORS": - text += "// fast_float by " + line - if filename == "CONTRIBUTORS": - text += "// with contributions from " + line - processed_files[filename] = text + "//\n//\n" - -# licenses -for filename in ["LICENSE-MIT", "LICENSE-APACHE", "LICENSE-BOOST"]: - lines = [] - with open(filename, encoding="utf8") as f: - lines = f.readlines() - - # Retrieve subset required for inclusion in source - if filename == "LICENSE-APACHE": - lines = [" Copyright 2021 The fast_float authors\n", *lines[179:-1]] - - text = "" - for line in lines: - line = line.strip() - if len(line): - line = " " + line - text += "//" + line + "\n" - processed_files[filename] = text - -# code -for filename in [ - "constexpr_feature_detect.h", - "float_common.h", - "fast_float.h", - "ascii_number.h", - "fast_table.h", - "decimal_to_binary.h", - "bigint.h", - "digit_comparison.h", - "parse_number.h", -]: - with open("include/fast_float/" + filename, encoding="utf8") as f: - text = "" - for line in f: - if line.startswith('#include "'): - continue - text += line - processed_files[filename] = "\n" + text - -# command line -import argparse - -parser = argparse.ArgumentParser(description="Amalgamate fast_float.") -parser.add_argument( - "--license", - default="TRIPLE", - choices=["DUAL", "TRIPLE", "MIT", "APACHE", "BOOST"], - help="choose license", -) -parser.add_argument("--output", default="", help="output file (stdout if none") - -args = parser.parse_args() - - -def license_content(license_arg): - result = [] - if license_arg == "TRIPLE": - result += [ - "// Licensed under the Apache License, Version 2.0, or the\n", - "// MIT License or the Boost License. This file may not be copied,\n", - "// modified, or distributed except according to those terms.\n", - "//\n", - ] - if license_arg == "DUAL": - result += [ - "// Licensed under the Apache License, Version 2.0, or the\n", - "// MIT License at your option. This file may not be copied,\n", - "// modified, or distributed except according to those terms.\n", - "//\n", - ] - - if license_arg in ("DUAL", "TRIPLE", "MIT"): - result.append("// MIT License Notice\n//\n") - result.append(processed_files["LICENSE-MIT"]) - result.append("//\n") - if license_arg in ("DUAL", "TRIPLE", "APACHE"): - result.append("// Apache License (Version 2.0) Notice\n//\n") - result.append(processed_files["LICENSE-APACHE"]) - result.append("//\n") - if license_arg in ("TRIPLE", "BOOST"): - result.append("// BOOST License Notice\n//\n") - result.append(processed_files["LICENSE-BOOST"]) - result.append("//\n") - - return result - - -text = "".join( - [ - processed_files["AUTHORS"], - processed_files["CONTRIBUTORS"], - *license_content(args.license), - processed_files["constexpr_feature_detect.h"], - processed_files["float_common.h"], - processed_files["fast_float.h"], - processed_files["ascii_number.h"], - processed_files["fast_table.h"], - processed_files["decimal_to_binary.h"], - processed_files["bigint.h"], - processed_files["digit_comparison.h"], - processed_files["parse_number.h"], - ] -) - -if args.output: - with open(args.output, "wt", encoding="utf8") as f: - f.write(text) -else: - print(text) diff --git a/script/analysis.py b/script/analysis.py deleted file mode 100644 index 08f5c49..0000000 --- a/script/analysis.py +++ /dev/null @@ -1,38 +0,0 @@ -import sys -from math import floor - - -def log2(x): - """returns ceil(log2(x)))""" - y = 0 - while (1 << y) < x: - y = y + 1 - return y - - -for q in range(1, 17 + 1): - d = 5 ** q - b = 127 + log2(d) - t = 2 ** b - c = t // d + 1 - assert c < 2 ** 128 - assert c >= 2 ** 127 - K = 2 ** 127 - if not (c * K * d <= (K + 1) * t): - print(q) - top = floor(t / (c * d - t)) - sys.exit(-1) - -for q in range(18, 344 + 1): - d = 5 ** q - b = 64 + 2 * log2(d) - t = 2 ** b - c = t // d + 1 - assert c > 2 ** (64 + log2(d)) - K = 2 ** 64 - if not (c * K * d <= (K + 1) * t): - print(q) - top = floor(t / (c * d - t)) - sys.exit(-1) - -print("all good") diff --git a/script/mushtak_lemire.py b/script/mushtak_lemire.py deleted file mode 100644 index f03715c..0000000 --- a/script/mushtak_lemire.py +++ /dev/null @@ -1,81 +0,0 @@ -# -# Reference : -# Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback, Software: Practice and Experience 53 (6), 2023 https://arxiv.org/abs/2212.06644 -# - -all_tqs = [] - -# Generates all possible values of T[q] -# Appendix B of Number parsing at a gigabyte per second. -# Software: Practice and Experience 2021;51(8):1700–1727. -for q in range(-342, -27): - power5 = 5 ** -q - z = 0 - while (1 << z) < power5: - z += 1 - b = 2 * z + 2 * 64 - c = 2 ** b // power5 + 1 - while c >= (1 << 128): - c //= 2 - all_tqs.append(c) -for q in range(-27, 0): - power5 = 5 ** -q - z = 0 - while (1 << z) < power5: - z += 1 - b = z + 127 - c = 2 ** b // power5 + 1 - all_tqs.append(c) -for q in range(0, 308 + 1): - power5 = 5 ** q - while power5 < (1 << 127): - power5 *= 2 - while power5 >= (1 << 128): - power5 //= 2 - all_tqs.append(power5) - -# Returns the continued fraction of numer/denom as a list [a0; a1, a2, ..., an] -def continued_fraction(numer, denom): - # (look at page numbers in top-left, not PDF page numbers) - cf = [] - while denom != 0: - quot, rem = divmod(numer, denom) - cf.append(quot) - numer, denom = denom, rem - return cf - - -# Given a continued fraction [a0; a1, a2, ..., an], returns -# all the convergents of that continued fraction -# as pairs of the form (numer, denom), where numer/denom is -# a convergent of the continued fraction in simple form. -def convergents(cf): - p_n_minus_2 = 0 - q_n_minus_2 = 1 - p_n_minus_1 = 1 - q_n_minus_1 = 0 - convergents = [] - for a_n in cf: - p_n = a_n * p_n_minus_1 + p_n_minus_2 - q_n = a_n * q_n_minus_1 + q_n_minus_2 - convergents.append((p_n, q_n)) - p_n_minus_2, q_n_minus_2, p_n_minus_1, q_n_minus_1 = ( - p_n_minus_1, - q_n_minus_1, - p_n, - q_n, - ) - return convergents - - -# Enumerate through all the convergents of T[q] / 2^137 with denominators < 2^64 -found_solution = False -for j, tq in enumerate(all_tqs): - for _, w in convergents(continued_fraction(tq, 2 ** 137)): - if w >= 2 ** 64: - break - if (tq * w) % 2 ** 137 > 2 ** 137 - 2 ** 64: - print(f"SOLUTION: q={j-342} T[q]={tq} w={w}") - found_solution = True -if not found_solution: - print("No solutions!") diff --git a/script/release.py b/script/release.py deleted file mode 100755 index 4bcf6c8..0000000 --- a/script/release.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python3 -######################################################################## -# Generates a new release. -######################################################################## -import sys -import re -import subprocess -import io -import os -import fileinput - -if sys.version_info < (3, 0): - sys.stdout.write("Sorry, requires Python 3.x or better\n") - sys.exit(1) - - -def colored(r, g, b, text): - return f"\033[38;2;{r};{g};{b}m{text} \033[38;2;255;255;255m" - - -def extractnumbers(s): - return tuple(map(int, re.findall(r"(\d+)\.(\d+)\.(\d+)", str(s))[0])) - - -def toversionstring(major, minor, rev): - return f"{major}.{minor}.{rev}" - - -print("Calling git rev-parse --abbrev-ref HEAD") -pipe = subprocess.Popen( - ["git", "rev-parse", "--abbrev-ref", "HEAD"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, -) -branchresult = pipe.communicate()[0].decode().strip() - -if branchresult != "main": - print( - colored( - 255, - 0, - 0, - f"We recommend that you release on main, you are on '{branchresult}'", - ) - ) - -ret = subprocess.call(["git", "remote", "update"]) - -if ret != 0: - sys.exit(ret) -print("Calling git log HEAD.. --oneline") -pipe = subprocess.Popen( - ["git", "log", "HEAD..", "--oneline"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, -) -uptodateresult = pipe.communicate()[0].decode().strip() - -if len(uptodateresult) != 0: - print(uptodateresult) - sys.exit(-1) - -pipe = subprocess.Popen( - ["git", "rev-parse", "--show-toplevel"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, -) -maindir = pipe.communicate()[0].decode().strip() -scriptlocation = os.path.dirname(os.path.abspath(__file__)) - -print(f"repository: {maindir}") - -pipe = subprocess.Popen( - ["git", "describe", "--abbrev=0", "--tags"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, -) -versionresult = pipe.communicate()[0].decode().strip() - -print(f"last version: {versionresult}") -try: - currentv = extractnumbers(versionresult) -except: - currentv = [0, 0, 0] -if len(sys.argv) != 2: - nextv = (currentv[0], currentv[1], currentv[2] + 1) - print(f"please specify version number, e.g. {toversionstring(*nextv)}") - sys.exit(-1) -try: - newversion = extractnumbers(sys.argv[1]) - print(newversion) -except: - print(f"can't parse version number {sys.argv[1]}") - sys.exit(-1) - -print("checking that new version is valid") -if newversion[0] != currentv[0]: - assert newversion[0] == currentv[0] + 1 - assert newversion[1] == 0 - assert newversion[2] == 0 -elif newversion[1] != currentv[1]: - assert newversion[1] == currentv[1] + 1 - assert newversion[2] == 0 -else: - assert newversion[2] == currentv[2] + 1 - -atleastminor = (currentv[0] != newversion[0]) or (currentv[1] != newversion[1]) - -newmajorversionstring = str(newversion[0]) -newminorversionstring = str(newversion[1]) -newpatchversionstring = str(newversion[2]) -newversionstring = f"{newversion[0]}.{newversion[1]}.{newversion[2]}" -cmakefile = f"{maindir}{os.sep}CMakeLists.txt" - -for line in fileinput.input(cmakefile, inplace=1, backup=".bak"): - line = re.sub( - r"project\(fast_float VERSION \d+\.\d+\.\d+ LANGUAGES CXX\)", - f"project(fast_float VERSION {newversionstring} LANGUAGES CXX)", - line.rstrip(), - ) - print(line) - -print(f"modified {cmakefile}, a backup was made") - -versionfilerel = f"{os.sep}include{os.sep}fast_float{os.sep}float_common.h" -versionfile = f"{maindir}{versionfilerel}" - -for line in fileinput.input(versionfile, inplace=1, backup=".bak"): - line = re.sub( - r"#define FASTFLOAT_VERSION_MAJOR \d+", - f"#define FASTFLOAT_VERSION_MAJOR {newmajorversionstring}", - line.rstrip(), - ) - line = re.sub( - r"#define FASTFLOAT_VERSION_MINOR \d+", - f"#define FASTFLOAT_VERSION_MINOR {newminorversionstring}", - line.rstrip(), - ) - line = re.sub( - r"#define FASTFLOAT_VERSION_PATCH \d+", - f"#define FASTFLOAT_VERSION_PATCH {newpatchversionstring}", - line.rstrip(), - ) - print(line) - -print(f"{versionfile} modified") - -readmefile = f"{maindir}{os.sep}README.md" - -for line in fileinput.input(readmefile, inplace=1, backup=".bak"): - line = re.sub( - r"https://github.com/fastfloat/fast_float/releases/download/v(\d+\.\d+\.\d+)/fast_float.h", - f"https://github.com/fastfloat/fast_float/releases/download/v{newversionstring}/fast_float.h", - line.rstrip(), - ) - line = re.sub( - r"GIT_TAG tags/v(\d+\.\d+\.\d+)", - f"GIT_TAG tags/v{newversionstring}", - line.rstrip(), - ) - line = re.sub( - r"GIT_TAG v(\d+\.\d+\.\d+)\)", f"GIT_TAG v{newversionstring})", line.rstrip() - ) - print(line) - -print(f"modified {readmefile}, a backup was made") - -print("running amalgamate.py") -with open(f"{maindir}{os.sep}fast_float.h", "w") as outfile: - cp = subprocess.run( - [f"python3", f"{maindir}{os.sep}script{os.sep}amalgamate.py"], stdout=outfile - ) - -if cp.returncode != 0: - print("Failed to run amalgamate") -else: - print("amalgamate.py ran successfully") - print(f"You should upload {maindir}{os.sep}fast_float.h") - -print("Please run the tests before issuing a release.\n") -print( - f'to issue release, enter\n git commit -a && git push && git tag -a v{toversionstring(*newversion)} -m "version {toversionstring(*newversion)}" && git push --tags\n' -) diff --git a/script/run-clangcldocker.sh b/script/run-clangcldocker.sh deleted file mode 100755 index 62a1df5..0000000 --- a/script/run-clangcldocker.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -e -COMMAND=$* -SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" -MAINSOURCE=$SCRIPTPATH/.. -ALL_FILES=$(cd $MAINSOURCE && git ls-tree --full-tree --name-only -r HEAD | grep -e ".*\.\(c\|h\|cc\|cpp\|hh\)\$" | grep -vFf clang-format-ignore.txt) - -if clang-format-17 --version 2>/dev/null | grep -qF 'version 17.'; then - cd $MAINSOURCE; clang-format-17 --style=file --verbose -i "$@" $ALL_FILES - exit 0 -elif clang-format --version 2>/dev/null | grep -qF 'version 17.'; then - cd $MAINSOURCE; clang-format --style=file --verbose -i "$@" $ALL_FILES - exit 0 -fi -echo "Trying to use docker" -command -v docker >/dev/null 2>&1 || { echo >&2 "Please install docker. E.g., go to https://www.docker.com/products/docker-desktop Type 'docker' to diagnose the problem."; exit 1; } -docker info >/dev/null 2>&1 || { echo >&2 "Docker server is not running? type 'docker info'."; exit 1; } - -if [ -t 0 ]; then DOCKER_ARGS=-it; fi -docker pull kszonek/clang-format-17 - -docker run --rm $DOCKER_ARGS -v "$MAINSOURCE":"$MAINSOURCE":Z -w "$MAINSOURCE" -u "$(id -u $USER):$(id -g $USER)" kszonek/clang-format-17 --style=file --verbose -i "$@" $ALL_FILES diff --git a/script/table_generation.py b/script/table_generation.py deleted file mode 100644 index 223240f..0000000 --- a/script/table_generation.py +++ /dev/null @@ -1,32 +0,0 @@ -def format(number): - upper = number // (1 << 64) - lower = number % (1 << 64) - print("" + hex(upper) + "," + hex(lower) + ",") - - -for q in range(-342, 0): - power5 = 5 ** -q - z = 0 - while (1 << z) < power5: - z += 1 - if q >= -27: - b = z + 127 - c = 2 ** b // power5 + 1 - format(c) - else: - b = 2 * z + 2 * 64 - c = 2 ** b // power5 + 1 - # truncate - while c >= (1 << 128): - c //= 2 - format(c) - -for q in range(0, 308 + 1): - power5 = 5 ** q - # move the most significant bit in position - while power5 < (1 << 127): - power5 *= 2 - # *truncate* - while power5 >= (1 << 128): - power5 //= 2 - format(power5) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel deleted file mode 100644 index 57d8c34..0000000 --- a/tests/BUILD.bazel +++ /dev/null @@ -1,116 +0,0 @@ -cc_test( - name = "basictest", - srcs = ["basictest.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "example_test", - srcs = ["example_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "example_comma_test", - srcs = ["example_comma_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "fast_int", - srcs = ["fast_int.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "fixedwidthtest", - srcs = ["fixedwidthtest.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "fortran", - srcs = ["fortran.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "json_fmt", - srcs = ["json_fmt.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "long_test", - srcs = ["long_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "powersoffive_hardround", - srcs = ["powersoffive_hardround.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "rcppfastfloat_test", - srcs = ["rcppfastfloat_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "wide_char_test", - srcs = ["wide_char_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "supported_chars_test", - srcs = ["supported_chars_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) - -cc_test( - name = "string_test", - srcs = ["string_test.cpp"], - deps = [ - "//:fast_float", - "@doctest//doctest", - ], -) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index a053581..0000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,110 +0,0 @@ -# FetchContent requires cmake >=3.11 -# see https://cmake.org/cmake/help/v3.11/module/FetchContent.html -cmake_minimum_required(VERSION 3.11 FATAL_ERROR) - -include(FetchContent) - -option(SYSTEM_DOCTEST "Use system copy of doctest" OFF) -option(FASTFLOAT_SUPPLEMENTAL_TESTS "Run supplemental tests" ON) - -if (NOT SYSTEM_DOCTEST) - FetchContent_Declare(doctest - GIT_REPOSITORY https://github.com/lemire/doctest.git) -else () - find_package(doctest REQUIRED) -endif() -if (FASTFLOAT_SUPPLEMENTAL_TESTS) - FetchContent_Declare(supplemental_test_files - GIT_REPOSITORY https://github.com/fastfloat/supplemental_test_files.git - GIT_TAG origin/main) -endif() - - -# FetchContent_MakeAvailable() was only introduced in 3.14 -# https://cmake.org/cmake/help/v3.14/release/3.14.html#modules -if (NOT SYSTEM_DOCTEST) - FetchContent_MakeAvailable(doctest) -endif() - -add_library(supplemental-data INTERFACE) -if (FASTFLOAT_SUPPLEMENTAL_TESTS) - message(STATUS "Supplemental tests enabled. Retrieving test files.") - FetchContent_MakeAvailable(supplemental_test_files) - message(STATUS "Supplemental test files retrieved.") - target_compile_definitions(supplemental-data INTERFACE SUPPLEMENTAL_TEST_DATA_DIR="${supplemental_test_files_BINARY_DIR}/data") -endif() - -function(fast_float_add_cpp_test TEST_NAME) - add_executable(${TEST_NAME} ${TEST_NAME}.cpp) - if(CMAKE_CROSSCOMPILING) - set(ccemulator ${CMAKE_CROSSCOMPILING_EMULATOR}) - endif() - add_test(NAME ${TEST_NAME} - COMMAND ${ccemulator} $) - if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - target_compile_options(${TEST_NAME} PUBLIC /EHsc) - endif() - if(NOT WIN32) - target_compile_options(${TEST_NAME} PUBLIC -Werror -Wall -Wextra -Weffc++) - target_compile_options(${TEST_NAME} PUBLIC -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wsign-conversion) - endif() - target_link_libraries(${TEST_NAME} PUBLIC fast_float supplemental-data) - if (NOT SYSTEM_DOCTEST) - target_link_libraries(${TEST_NAME} PUBLIC doctest) - else () - target_link_libraries(${TEST_NAME} PUBLIC doctest::doctest) - endif() -endfunction(fast_float_add_cpp_test) - -fast_float_add_cpp_test(rcppfastfloat_test) -fast_float_add_cpp_test(wide_char_test) -fast_float_add_cpp_test(supported_chars_test) -fast_float_add_cpp_test(example_test) -fast_float_add_cpp_test(example_comma_test) -fast_float_add_cpp_test(example_integer_times_pow10) -fast_float_add_cpp_test(basictest) -option(FASTFLOAT_CONSTEXPR_TESTS "Require constexpr tests (build will fail if the compiler won't support it)" OFF) -if (FASTFLOAT_CONSTEXPR_TESTS) - target_compile_features(basictest PRIVATE cxx_std_20) - target_compile_definitions(basictest PRIVATE FASTFLOAT_CONSTEXPR_TESTS) -else() - target_compile_features(basictest PRIVATE cxx_std_17) -endif() -if (FASTFLOAT_SUPPLEMENTAL_TESTS) - target_compile_definitions(basictest PRIVATE FASTFLOAT_SUPPLEMENTAL_TESTS) -endif() -fast_float_add_cpp_test(p2497) -fast_float_add_cpp_test(long_test) -fast_float_add_cpp_test(powersoffive_hardround) -fast_float_add_cpp_test(string_test) -fast_float_add_cpp_test(fast_int) -target_compile_features(fast_int PRIVATE cxx_std_17) -fast_float_add_cpp_test(json_fmt) -fast_float_add_cpp_test(fortran) -if(CMAKE_CXX_STANDARD GREATER_EQUAL 23) - option(FASTFLOAT_FIXEDWIDTH_TESTS "Require fixed width test for C++23 (build will fail if the compiler won't support it)" ON) -else() - option(FASTFLOAT_FIXEDWIDTH_TESTS "Require fixed width test for C++23 (build will fail if the compiler won't support it)" OFF) -endif() -if (FASTFLOAT_FIXEDWIDTH_TESTS) - fast_float_add_cpp_test(fixedwidthtest) - target_compile_features(fixedwidthtest PUBLIC cxx_std_23) -endif() - -option(FASTFLOAT_EXHAUSTIVE "Exhaustive tests" OFF) - -if (FASTFLOAT_EXHAUSTIVE) - fast_float_add_cpp_test(ipv4_test) - fast_float_add_cpp_test(short_random_string) - fast_float_add_cpp_test(exhaustive32_midpoint) - fast_float_add_cpp_test(random_string) - fast_float_add_cpp_test(exhaustive32) - fast_float_add_cpp_test(exhaustive32_64) - fast_float_add_cpp_test(long_exhaustive32) - fast_float_add_cpp_test(long_exhaustive32_64) - fast_float_add_cpp_test(long_random64) - fast_float_add_cpp_test(random64) -endif(FASTFLOAT_EXHAUSTIVE) - -add_subdirectory(build_tests) -add_subdirectory(bloat_analysis) diff --git a/tests/basictest.cpp b/tests/basictest.cpp deleted file mode 100644 index dba36e8..0000000 --- a/tests/basictest.cpp +++ /dev/null @@ -1,2455 +0,0 @@ -#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include "doctest/doctest.h" - -#include "fast_float/fast_float.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if FASTFLOAT_IS_CONSTEXPR -#ifndef FASTFLOAT_CONSTEXPR_TESTS -#define FASTFLOAT_CONSTEXPR_TESTS 1 -#endif // #ifndef FASTFLOAT_CONSTEXPR_TESTS -#endif // FASTFLOAT_IS_CONSTEXPR - -#if FASTFLOAT_HAS_BIT_CAST -#include -#endif - -#ifndef SUPPLEMENTAL_TEST_DATA_DIR -#define SUPPLEMENTAL_TEST_DATA_DIR "data/" -#endif - -#ifndef __cplusplus -#error fastfloat requires a C++ compiler -#endif - -#ifndef FASTFLOAT_CPLUSPLUS -#if defined(_MSVC_LANG) && !defined(__clang__) -#define FASTFLOAT_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) -#else -#define FASTFLOAT_CPLUSPLUS __cplusplus -#endif -#endif - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) -#define FASTFLOAT_ODDPLATFORM 1 -#endif -#if defined __has_include -#if __has_include() -#else -// filesystem is not available -#define FASTFLOAT_ODDPLATFORM 1 -#endif -#else -// __has_include is not available -#define FASTFLOAT_ODDPLATFORM 1 -#endif - -template std::string iHexAndDec(T v) { - std::ostringstream ss; - ss << std::hex << "0x" << (v) << " (" << std::dec << (v) << ")"; - return ss.str(); -} - -template std::string fHexAndDec(T v) { - std::ostringstream ss; - ss << std::hexfloat << (v) << " (" << std::defaultfloat - << std::setprecision(DBL_MAX_10_EXP + 1) << (v) << ")"; - return ss.str(); -} - -char const *round_name(int d) { - switch (d) { - case FE_UPWARD: - return "FE_UPWARD"; - case FE_DOWNWARD: - return "FE_DOWNWARD"; - case FE_TOWARDZERO: - return "FE_TOWARDZERO"; - case FE_TONEAREST: - return "FE_TONEAREST"; - default: - return "UNKNOWN"; - } -} - -#define FASTFLOAT_STR(x) #x -#define SHOW_DEFINE(x) printf("%s='%s'\n", #x, FASTFLOAT_STR(x)) - -TEST_CASE("system_info") { - std::cout << "system info:" << std::endl; -#ifdef FASTFLOAT_CONSTEXPR_TESTS - SHOW_DEFINE(FASTFLOAT_CONSTEXPR_TESTS); - -#endif -#ifdef _MSC_VER - SHOW_DEFINE(_MSC_VER); -#endif -#ifdef FASTFLOAT_64BIT_LIMB - SHOW_DEFINE(FASTFLOAT_64BIT_LIMB); -#endif -#ifdef __clang__ - SHOW_DEFINE(__clang__); -#endif -#ifdef FASTFLOAT_VISUAL_STUDIO - SHOW_DEFINE(FASTFLOAT_VISUAL_STUDIO); -#endif -#ifdef FASTFLOAT_IS_BIG_ENDIAN -#if FASTFLOAT_IS_BIG_ENDIAN - printf("big endian\n"); -#else - printf("little endian\n"); -#endif -#endif -#ifdef FASTFLOAT_32BIT - SHOW_DEFINE(FASTFLOAT_32BIT); -#endif -#ifdef FASTFLOAT_64BIT - SHOW_DEFINE(FASTFLOAT_64BIT); -#endif -#ifdef FLT_EVAL_METHOD - SHOW_DEFINE(FLT_EVAL_METHOD); -#endif -#ifdef _WIN32 - SHOW_DEFINE(_WIN32); -#endif -#ifdef _WIN64 - SHOW_DEFINE(_WIN64); -#endif - std::cout << "fegetround() = " << round_name(fegetround()) << std::endl; - std::cout << std::endl; -} - -TEST_CASE("double.rounds_to_nearest") { - // - // If this function fails, we may be left in a non-standard rounding state. - // - static double volatile fmin = std::numeric_limits::min(); - fesetround(FE_UPWARD); - std::cout << "FE_UPWARD: fmin + 1.0 = " << fHexAndDec(fmin + 1.0) - << " 1.0 - fmin = " << fHexAndDec(1.0 - fmin) << std::endl; - CHECK(fegetround() == FE_UPWARD); - CHECK(fast_float::detail::rounds_to_nearest() == false); - - fesetround(FE_DOWNWARD); - std::cout << "FE_DOWNWARD: fmin + 1.0 = " << fHexAndDec(fmin + 1.0) - << " 1.0 - fmin = " << fHexAndDec(1.0 - fmin) << std::endl; - CHECK(fegetround() == FE_DOWNWARD); - CHECK(fast_float::detail::rounds_to_nearest() == false); - - fesetround(FE_TOWARDZERO); - std::cout << "FE_TOWARDZERO: fmin + 1.0 = " << fHexAndDec(fmin + 1.0) - << " 1.0 - fmin = " << fHexAndDec(1.0 - fmin) << std::endl; - CHECK(fegetround() == FE_TOWARDZERO); - CHECK(fast_float::detail::rounds_to_nearest() == false); - - fesetround(FE_TONEAREST); - std::cout << "FE_TONEAREST: fmin + 1.0 = " << fHexAndDec(fmin + 1.0) - << " 1.0 - fmin = " << fHexAndDec(1.0 - fmin) << std::endl; - CHECK(fegetround() == FE_TONEAREST); -#if (FLT_EVAL_METHOD == 1) || (FLT_EVAL_METHOD == 0) - CHECK(fast_float::detail::rounds_to_nearest() == true); -#endif -} - -TEST_CASE("double.parse_zero") { - // - // If this function fails, we may be left in a non-standard rounding state. - // - char const *zero = "0"; - uint64_t float64_parsed; - double f = 0; - ::memcpy(&float64_parsed, &f, sizeof(f)); - CHECK(float64_parsed == 0); - - fesetround(FE_UPWARD); - auto r1 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r1.ec == std::errc()); - std::cout << "FE_UPWARD parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0); - - fesetround(FE_TOWARDZERO); - auto r2 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r2.ec == std::errc()); - std::cout << "FE_TOWARDZERO parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0); - - fesetround(FE_DOWNWARD); - auto r3 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r3.ec == std::errc()); - std::cout << "FE_DOWNWARD parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0); - - fesetround(FE_TONEAREST); - auto r4 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r4.ec == std::errc()); - std::cout << "FE_TONEAREST parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0); -} - -TEST_CASE("double.parse_negative_zero") { - // - // If this function fails, we may be left in a non-standard rounding state. - // - char const *negative_zero = "-0"; - uint64_t float64_parsed; - double f = -0.; - ::memcpy(&float64_parsed, &f, sizeof(f)); - CHECK(float64_parsed == 0x8000'0000'0000'0000); - - fesetround(FE_UPWARD); - auto r1 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r1.ec == std::errc()); - std::cout << "FE_UPWARD parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0x8000'0000'0000'0000); - - fesetround(FE_TOWARDZERO); - auto r2 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r2.ec == std::errc()); - std::cout << "FE_TOWARDZERO parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0x8000'0000'0000'0000); - - fesetround(FE_DOWNWARD); - auto r3 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r3.ec == std::errc()); - std::cout << "FE_DOWNWARD parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0x8000'0000'0000'0000); - - fesetround(FE_TONEAREST); - auto r4 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r4.ec == std::errc()); - std::cout << "FE_TONEAREST parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.); - ::memcpy(&float64_parsed, &f, sizeof(f)); - std::cout << "double as uint64_t is " << iHexAndDec(float64_parsed) - << std::endl; - CHECK(float64_parsed == 0x8000'0000'0000'0000); -} - -TEST_CASE("float.rounds_to_nearest") { - // - // If this function fails, we may be left in a non-standard rounding state. - // - static float volatile fmin = std::numeric_limits::min(); - fesetround(FE_UPWARD); - std::cout << "FE_UPWARD: fmin + 1.0f = " << fHexAndDec(fmin + 1.0f) - << " 1.0f - fmin = " << fHexAndDec(1.0f - fmin) << std::endl; - CHECK(fegetround() == FE_UPWARD); - CHECK(fast_float::detail::rounds_to_nearest() == false); - - fesetround(FE_DOWNWARD); - std::cout << "FE_DOWNWARD: fmin + 1.0f = " << fHexAndDec(fmin + 1.0f) - << " 1.0f - fmin = " << fHexAndDec(1.0f - fmin) << std::endl; - CHECK(fegetround() == FE_DOWNWARD); - CHECK(fast_float::detail::rounds_to_nearest() == false); - - fesetround(FE_TOWARDZERO); - std::cout << "FE_TOWARDZERO: fmin + 1.0f = " << fHexAndDec(fmin + 1.0f) - << " 1.0f - fmin = " << fHexAndDec(1.0f - fmin) << std::endl; - CHECK(fegetround() == FE_TOWARDZERO); - CHECK(fast_float::detail::rounds_to_nearest() == false); - - fesetround(FE_TONEAREST); - std::cout << "FE_TONEAREST: fmin + 1.0f = " << fHexAndDec(fmin + 1.0f) - << " 1.0f - fmin = " << fHexAndDec(1.0f - fmin) << std::endl; - CHECK(fegetround() == FE_TONEAREST); -#if (FLT_EVAL_METHOD == 1) || (FLT_EVAL_METHOD == 0) - CHECK(fast_float::detail::rounds_to_nearest() == true); -#endif -} - -TEST_CASE("float.parse_zero") { - // - // If this function fails, we may be left in a non-standard rounding state. - // - char const *zero = "0"; - uint32_t float32_parsed; - float f = 0; - ::memcpy(&float32_parsed, &f, sizeof(f)); - CHECK(float32_parsed == 0); - - fesetround(FE_UPWARD); - auto r1 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r1.ec == std::errc()); - std::cout << "FE_UPWARD parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0); - - fesetround(FE_TOWARDZERO); - auto r2 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r2.ec == std::errc()); - std::cout << "FE_TOWARDZERO parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0); - - fesetround(FE_DOWNWARD); - auto r3 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r3.ec == std::errc()); - std::cout << "FE_DOWNWARD parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0); - - fesetround(FE_TONEAREST); - auto r4 = fast_float::from_chars(zero, zero + 1, f); - CHECK(r4.ec == std::errc()); - std::cout << "FE_TONEAREST parsed zero as " << fHexAndDec(f) << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0); -} - -TEST_CASE("float.parse_negative_zero") { - // - // If this function fails, we may be left in a non-standard rounding state. - // - char const *negative_zero = "-0"; - uint32_t float32_parsed; - float f = -0.; - ::memcpy(&float32_parsed, &f, sizeof(f)); - CHECK(float32_parsed == 0x8000'0000); - - fesetround(FE_UPWARD); - auto r1 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r1.ec == std::errc()); - std::cout << "FE_UPWARD parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0x8000'0000); - - fesetround(FE_TOWARDZERO); - auto r2 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r2.ec == std::errc()); - std::cout << "FE_TOWARDZERO parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0x8000'0000); - - fesetround(FE_DOWNWARD); - auto r3 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r3.ec == std::errc()); - std::cout << "FE_DOWNWARD parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0x8000'0000); - - fesetround(FE_TONEAREST); - auto r4 = fast_float::from_chars(negative_zero, negative_zero + 2, f); - CHECK(r4.ec == std::errc()); - std::cout << "FE_TONEAREST parsed negative zero as " << fHexAndDec(f) - << std::endl; - CHECK(f == 0.f); - ::memcpy(&float32_parsed, &f, sizeof(f)); - std::cout << "float as uint32_t is " << iHexAndDec(float32_parsed) - << std::endl; - CHECK(float32_parsed == 0x8000'0000); -} - -#if FASTFLOAT_SUPPLEMENTAL_TESTS -// C++ 17 because it is otherwise annoying to browse all files in a directory. -// We also only run these tests on little endian systems. -#if (FASTFLOAT_CPLUSPLUS >= 201703L) && (FASTFLOAT_IS_BIG_ENDIAN == 0) && \ - !defined(FASTFLOAT_ODDPLATFORM) - -#include -#include - -// return true on success -bool check_file(std::string file_name) { - std::cout << "Checking " << file_name << std::endl; - // We check all rounding directions, for each file. - std::vector directions = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, - FE_TONEAREST}; - for (int d : directions) { - std::cout << "fesetround to " << round_name(d) << std::endl; - fesetround(d); - size_t number{0}; - std::fstream newfile(file_name, std::ios::in); - if (newfile.is_open()) { - std::string str; - while (std::getline(newfile, str)) { - if (str.size() > 0) { -#ifdef __STDCPP_FLOAT16_T__ - // Read 16-bit hex - uint16_t float16{}; - auto r16 = - std::from_chars(str.data(), str.data() + str.size(), float16, 16); - if (r16.ec != std::errc()) { - std::cerr << "16-bit parsing failure: " << str << "\n"; - return false; - } -#endif - // Read 32-bit hex - uint32_t float32{}; - auto r32 = std::from_chars(str.data() + 5, str.data() + str.size(), - float32, 16); - if (r32.ec != std::errc()) { - std::cerr << "32-bit parsing failure: " << str << "\n"; - return false; - } - // Read 64-bit hex - uint64_t float64{}; - auto r64 = std::from_chars(str.data() + 14, str.data() + str.size(), - float64, 16); - if (r64.ec != std::errc()) { - std::cerr << "64-bit parsing failure: " << str << "\n"; - return false; - } - // The string to parse: - char const *number_string = str.data() + 31; - char const *end_of_string = str.data() + str.size(); -#ifdef __STDCPP_FLOAT16_T__ - // Parse as 16-bit float - std::float16_t parsed_16{}; - auto fast_float_r16 = - fast_float::from_chars(number_string, end_of_string, parsed_16); - if (fast_float_r16.ec != std::errc() && - fast_float_r16.ec != std::errc::result_out_of_range) { - std::cerr << "16-bit fast_float parsing failure: " << str << "\n"; - return false; - } -#endif - // Parse as 32-bit float - float parsed_32{}; - auto fast_float_r32 = - fast_float::from_chars(number_string, end_of_string, parsed_32); - if (fast_float_r32.ec != std::errc() && - fast_float_r32.ec != std::errc::result_out_of_range) { - std::cerr << "32-bit fast_float parsing failure: " << str << "\n"; - return false; - } - // Parse as 64-bit float - double parsed_64{}; - auto fast_float_r64 = - fast_float::from_chars(number_string, end_of_string, parsed_64); - if (fast_float_r64.ec != std::errc() && - fast_float_r32.ec != std::errc::result_out_of_range) { - std::cerr << "64-bit fast_float parsing failure: " << str << "\n"; - return false; - } - // Convert the floats to unsigned ints. -#ifdef __STDCPP_FLOAT16_T__ - uint16_t float16_parsed{}; -#endif - uint32_t float32_parsed{}; - uint64_t float64_parsed{}; -#ifdef __STDCPP_FLOAT16_T__ - ::memcpy(&float16_parsed, &parsed_16, sizeof(parsed_16)); - -#endif - ::memcpy(&float32_parsed, &parsed_32, sizeof(parsed_32)); - ::memcpy(&float64_parsed, &parsed_64, sizeof(parsed_64)); - // Compare with expected results -#ifdef __STDCPP_FLOAT16_T__ - if (float16_parsed != float16) { - std::cout << "bad 16: " << str << std::endl; - std::cout << "parsed as " << fHexAndDec(parsed_16) << std::endl; - std::cout << "as raw uint16_t, parsed = " << float16_parsed - << ", expected = " << float16 << std::endl; - std::cout << "fesetround: " << round_name(d) << std::endl; - const bool is_ulfjack = - file_name.find("ulfjack") != std::string::npos; - if (is_ulfjack) { - std::cout << "This is a known issue with ulfjack's test suite." - << std::endl; - } else { - fesetround(FE_TONEAREST); - return false; - } - } -#endif - if (float32_parsed != float32) { - std::cout << "bad 32: " << str << std::endl; - std::cout << "parsed as " << fHexAndDec(parsed_32) << std::endl; - std::cout << "as raw uint32_t, parsed = " << float32_parsed - << ", expected = " << float32 << std::endl; - std::cout << "fesetround: " << round_name(d) << std::endl; - fesetround(FE_TONEAREST); - return false; - } - if (float64_parsed != float64) { - std::cout << "bad 64: " << str << std::endl; - std::cout << "parsed as " << fHexAndDec(parsed_64) << std::endl; - std::cout << "as raw uint64_t, parsed = " << float64_parsed - << ", expected = " << float64 << std::endl; - std::cout << "fesetround: " << round_name(d) << std::endl; - fesetround(FE_TONEAREST); - return false; - } - number++; - } - } - std::cout << "checked " << std::defaultfloat << number << " values" - << std::endl; - newfile.close(); // close the file object - } else { - std::cout << "Could not read " << file_name << std::endl; - fesetround(FE_TONEAREST); - return false; - } - } - fesetround(FE_TONEAREST); - return true; -} - -TEST_CASE("supplemental") { - std::string path = SUPPLEMENTAL_TEST_DATA_DIR; - for (auto const &entry : std::filesystem::directory_iterator(path)) { - const auto file = entry.path().string(); - CAPTURE(file); - CHECK(check_file(file)); - } -} -#endif -#endif - -TEST_CASE("leading_zeroes") { - constexpr uint64_t const bit = 1; - CHECK(fast_float::leading_zeroes(bit << 0) == 63); - CHECK(fast_float::leading_zeroes(bit << 1) == 62); - CHECK(fast_float::leading_zeroes(bit << 2) == 61); - CHECK(fast_float::leading_zeroes(bit << 61) == 2); - CHECK(fast_float::leading_zeroes(bit << 62) == 1); - CHECK(fast_float::leading_zeroes(bit << 63) == 0); -} - -void test_full_multiplication(uint64_t lhs, uint64_t rhs, uint64_t expected_lo, - uint64_t expected_hi) { - fast_float::value128 v; - v = fast_float::full_multiplication(lhs, rhs); - INFO("lhs=" << iHexAndDec(lhs) << " " - << "rhs=" << iHexAndDec(rhs) - << "\n actualLo=" << iHexAndDec(v.low) << " " - << "actualHi=" << iHexAndDec(v.high) - << "\n expectedLo=" << iHexAndDec(expected_lo) << " " - << "expectedHi=" << iHexAndDec(expected_hi)); - CHECK_EQ(v.low, expected_lo); - CHECK_EQ(v.high, expected_hi); - v = fast_float::full_multiplication(rhs, lhs); - CHECK_EQ(v.low, expected_lo); - CHECK_EQ(v.high, expected_hi); -} - -TEST_CASE("full_multiplication") { - constexpr uint64_t const bit = 1; - // lhs rhs lo hi - test_full_multiplication(bit << 0, bit << 0, 1u, 0u); - test_full_multiplication(bit << 0, bit << 63, bit << 63, 0u); - test_full_multiplication(bit << 1, bit << 63, 0u, 1u); - test_full_multiplication(bit << 63, bit << 0, bit << 63, 0u); - test_full_multiplication(bit << 63, bit << 1, 0u, 1u); - test_full_multiplication(bit << 63, bit << 2, 0u, 2u); - test_full_multiplication(bit << 63, bit << 63, 0u, bit << 62); -} - -TEST_CASE("issue8") { - char const *s = - "3." - "141592653589793238462643383279502884197169399375105820974944592307816406" - "286208998628034825342117067982148086513282306647093844609550582231725359" - "408128481117450284102701938521105559644622948954930381964428810975665933" - "446128475648233786783165271201909145648566923460348610454326648213393607" - "260249141273724587006606315588174881520920962829254091715364367892590360" - "011330530548820466521384146951941511609433057270365759591953092186117381" - "932611793105118548074462379962749567351885752724891227938183011949129833" - "673362440656643086021394946395224737190702179860943702770539217176293176" - "752384674818467669405132000568127145263560827785771342757789609173637178" - "721468440901224953430146549585371050792279689258923542019956112129021960" - "864034418159813629774771309960518707211349999998372978"; - for (int i = 0; i < 16; i++) { - // Parse all but the last i chars. We should still get 3.141ish. - double d = 0.0; - auto answer = fast_float::from_chars(s, s + strlen(s) - i, d); - CHECK_MESSAGE(answer.ec == std::errc(), "i=" << i); - CHECK_MESSAGE(d == 0x1.921fb54442d18p+1, - "i=" << i << "\n" - << std::string(s, strlen(s) - size_t(i)) << "\n" - << std::hexfloat << d << "\n" - << std::defaultfloat << "\n"); - } -} - -TEST_CASE("check_behavior") { - std::string const input = "abc"; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - CHECK_MESSAGE(answer.ec != std::errc(), "expected parse failure"); - CHECK_MESSAGE( - answer.ptr == input.data(), - "If there is no pattern match, we should have ptr equals first"); -} - -TEST_CASE("decimal_point_parsing") { - double result; - fast_float::parse_options options{}; - { - std::string const input = "1,25"; - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); - CHECK_MESSAGE(answer.ptr == input.data() + 1, - "Parsing should have stopped at comma"); - CHECK_EQ(result, 1.0); - - options.decimal_point = ','; - answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); - CHECK_MESSAGE(answer.ptr == input.data() + input.size(), - "Parsing should have stopped at end"); - CHECK_EQ(result, 1.25); - } - { - std::string const input = "1.25"; - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); - CHECK_MESSAGE(answer.ptr == input.data() + 1, - "Parsing should have stopped at dot"); - CHECK_EQ(result, 1.0); - - options.decimal_point = '.'; - answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); - CHECK_MESSAGE(answer.ptr == input.data() + input.size(), - "Parsing should have stopped at end"); - CHECK_EQ(result, 1.25); - } -} - -TEST_CASE("issue19") { - std::string const input = "234532.3426362,7869234.9823,324562.645"; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - CHECK_MESSAGE(answer.ec == std::errc(), - "We want to parse up to 234532.3426362\n"); - CHECK_MESSAGE(answer.ptr == input.data() + 14, - "Parsed the number " - << result << " and stopped at the wrong character: after " - << (answer.ptr - input.data()) << " characters"); - CHECK_MESSAGE(result == 234532.3426362, "We want to parse234532.3426362\n"); - CHECK_MESSAGE(answer.ptr[0] == ',', "We want to parse up to the comma\n"); - - answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), - result); - CHECK_MESSAGE(answer.ec == std::errc(), "We want to parse 7869234.9823\n"); - CHECK_MESSAGE(answer.ptr == input.data() + 27, - "Parsed the number " << result - << " and stopped at the wrong character " - << (answer.ptr - input.data())); - CHECK_MESSAGE(answer.ptr[0] == ',', "We want to parse up to the comma\n"); - CHECK_MESSAGE(result == 7869234.9823, "We want to parse up 7869234.9823\n"); - - answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), - result); - CHECK_MESSAGE(answer.ec == std::errc(), "We want to parse 324562.645\n"); - CHECK_MESSAGE(answer.ptr == input.data() + 38, - "Parsed the number " << result - << " and stopped at the wrong character " - << (answer.ptr - input.data())); - CHECK_MESSAGE(result == 324562.645, "We want to parse up 7869234.9823\n"); -} - -TEST_CASE("issue19") { - std::string const input = "3.14e"; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - CHECK_MESSAGE(answer.ec == std::errc(), "We want to parse up to 3.14\n"); - CHECK_MESSAGE(answer.ptr == input.data() + 4, - "Parsed the number " - << result << " and stopped at the wrong character: after " - << (answer.ptr - input.data()) << " characters"); -} - -TEST_CASE("scientific_only") { - // first, we try with something that should fail... - std::string input = "3.14"; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result, - fast_float::chars_format::scientific); - CHECK_MESSAGE(answer.ec != std::errc(), - "It is not scientific! Parsed: " << result); - - input = "3.14e10"; - answer = fast_float::from_chars(input.data(), input.data() + input.size(), - result, fast_float::chars_format::scientific); - CHECK_MESSAGE(answer.ec == std::errc(), - "It is scientific! Parsed: " << result); - CHECK_MESSAGE(answer.ptr == input.data() + input.size(), - "Parsed the number " - << result << " and stopped at the wrong character: after " - << (answer.ptr - input.data()) << " characters"); -} - -TEST_CASE("test_fixed_only") { - std::string const input = "3.14e10"; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result, - fast_float::chars_format::fixed); - CHECK_MESSAGE(answer.ec == std::errc(), - "We want to parse up to 3.14; parsed: " << result); - CHECK_MESSAGE(answer.ptr == input.data() + 4, - "Parsed the number " - << result << " and stopped at the wrong character: after " - << (answer.ptr - input.data()) << " characters"); -} - -static double const testing_power_of_ten[] = { - 1e-323, 1e-322, 1e-321, 1e-320, 1e-319, 1e-318, 1e-317, 1e-316, 1e-315, - 1e-314, 1e-313, 1e-312, 1e-311, 1e-310, 1e-309, 1e-308, - - 1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299, - 1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290, - 1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, - 1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, - 1e-271, 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, - 1e-262, 1e-261, 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, - 1e-253, 1e-252, 1e-251, 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, - 1e-244, 1e-243, 1e-242, 1e-241, 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, - 1e-235, 1e-234, 1e-233, 1e-232, 1e-231, 1e-230, 1e-229, 1e-228, 1e-227, - 1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, 1e-220, 1e-219, 1e-218, - 1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, 1e-210, 1e-209, - 1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, 1e-200, - 1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, - 1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, - 1e-181, 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, - 1e-172, 1e-171, 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, - 1e-163, 1e-162, 1e-161, 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, - 1e-154, 1e-153, 1e-152, 1e-151, 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, - 1e-145, 1e-144, 1e-143, 1e-142, 1e-141, 1e-140, 1e-139, 1e-138, 1e-137, - 1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, 1e-130, 1e-129, 1e-128, - 1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, 1e-120, 1e-119, - 1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, 1e-110, - 1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, - 1e-100, 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, - 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, - 1e-82, 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, - 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, - 1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56, - 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, - 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38, - 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, - 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20, - 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, - 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, - 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, - 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, - 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, - 1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32, 1e33, 1e34, - 1e35, 1e36, 1e37, 1e38, 1e39, 1e40, 1e41, 1e42, 1e43, - 1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 1e50, 1e51, 1e52, - 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59, 1e60, 1e61, - 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69, 1e70, - 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79, - 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, - 1e89, 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, - 1e98, 1e99, 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, - 1e107, 1e108, 1e109, 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, - 1e116, 1e117, 1e118, 1e119, 1e120, 1e121, 1e122, 1e123, 1e124, - 1e125, 1e126, 1e127, 1e128, 1e129, 1e130, 1e131, 1e132, 1e133, - 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 1e140, 1e141, 1e142, - 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 1e150, 1e151, - 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 1e160, - 1e161, 1e162, 1e163, 1e164, 1e165, 1e166, 1e167, 1e168, 1e169, - 1e170, 1e171, 1e172, 1e173, 1e174, 1e175, 1e176, 1e177, 1e178, - 1e179, 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186, 1e187, - 1e188, 1e189, 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196, - 1e197, 1e198, 1e199, 1e200, 1e201, 1e202, 1e203, 1e204, 1e205, - 1e206, 1e207, 1e208, 1e209, 1e210, 1e211, 1e212, 1e213, 1e214, - 1e215, 1e216, 1e217, 1e218, 1e219, 1e220, 1e221, 1e222, 1e223, - 1e224, 1e225, 1e226, 1e227, 1e228, 1e229, 1e230, 1e231, 1e232, - 1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239, 1e240, 1e241, - 1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249, 1e250, - 1e251, 1e252, 1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259, - 1e260, 1e261, 1e262, 1e263, 1e264, 1e265, 1e266, 1e267, 1e268, - 1e269, 1e270, 1e271, 1e272, 1e273, 1e274, 1e275, 1e276, 1e277, - 1e278, 1e279, 1e280, 1e281, 1e282, 1e283, 1e284, 1e285, 1e286, - 1e287, 1e288, 1e289, 1e290, 1e291, 1e292, 1e293, 1e294, 1e295, - 1e296, 1e297, 1e298, 1e299, 1e300, 1e301, 1e302, 1e303, 1e304, - 1e305, 1e306, 1e307, 1e308}; - -TEST_CASE("powers_of_ten") { - char buf[1024]; - WARN_MESSAGE(1e-308 == std::pow(10, -308), - "On your system, the pow function is busted. Sorry about that."); - bool is_pow_correct{1e-308 == std::pow(10, -308)}; - // large negative values should be zero. - int start_point = is_pow_correct ? -1000 : -307; - for (int i = start_point; i <= 308; ++i) { - INFO("i=" << i); - size_t n = size_t(snprintf(buf, sizeof(buf), "1e%d", i)); - REQUIRE(n < sizeof(buf)); // if false, fails the test and exits - double actual; - auto result = fast_float::from_chars(buf, buf + 1000, actual); - double expected = - ((i >= -323) ? testing_power_of_ten[i + 323] : std::pow(10, i)); - auto expected_ec = - (i < -323 || i > 308) ? std::errc::result_out_of_range : std::errc(); - CHECK_MESSAGE(result.ec == expected_ec, " I could not parse " << buf); - CHECK_MESSAGE(actual == expected, - "String '" << buf << "'parsed to " << actual); - } -} - -template std::string to_string(T d) { - std::string s(64, '\0'); - auto written = std::snprintf(&s[0], s.size(), "%.*e", - std::numeric_limits::max_digits10 - 1, d); - s.resize(size_t(written)); - return s; -} - -template std::string to_long_string(T d) { - std::string s(4096, '\0'); - auto written = std::snprintf(&s[0], s.size(), "%.*e", - std::numeric_limits::max_digits10 * 10, d); - s.resize(size_t(written)); - return s; -} - -uint32_t get_mantissa(float f) { - uint32_t m; - memcpy(&m, &f, sizeof(f)); - return (m & ((uint32_t(1) << 23) - 1)); -} - -uint64_t get_mantissa(double f) { - uint64_t m; - memcpy(&m, &f, sizeof(f)); - return (m & ((uint64_t(1) << 57) - 1)); -} - -#ifdef __STDCPP_FLOAT64_T__ -uint64_t get_mantissa(std::float64_t f) { - uint64_t m; - memcpy(&m, &f, sizeof(f)); - return (m & ((uint64_t(1) << 10) - 1)); -} -#endif - -#ifdef __STDCPP_FLOAT32_T__ -uint32_t get_mantissa(std::float32_t f) { - uint32_t m; - memcpy(&m, &f, sizeof(f)); - return (m & ((uint32_t(1) << 10) - 1)); -} -#endif - -#ifdef __STDCPP_FLOAT16_T__ -uint16_t get_mantissa(std::float16_t f) { - uint16_t m; - memcpy(&m, &f, sizeof(f)); - return (m & ((uint16_t(1) << 10) - 1)); -} -#endif - -#ifdef __STDCPP_BFLOAT16_T__ -uint16_t get_mantissa(std::bfloat16_t f) { - uint16_t m; - memcpy(&m, &f, sizeof(f)); - return (m & ((uint16_t(1) << 7) - 1)); -} -#endif - -std::string append_zeros(std::string str, size_t number_of_zeros) { - std::string answer(str); - for (size_t i = 0; i < number_of_zeros; i++) { - answer += "0"; - } - return answer; -} - -namespace { - -enum class Diag { runtime, comptime }; - -} // anonymous namespace - -constexpr size_t global_string_capacity = 2048; - -template -constexpr void check_basic_test_result(stringtype str, result_type result, - T actual, T expected, - std::errc expected_ec) { - struct ComptimeDiag { - // Purposely not constexpr - static void error_not_equal() {} - }; - -#define FASTFLOAT_CHECK_EQ(...) \ - if constexpr (diag == Diag::runtime) { \ - char narrow[global_string_capacity]{}; \ - for (size_t i = 0; i < str.size(); i++) { \ - narrow[i] = char(str[i]); \ - } \ - INFO("str(char" << 8 * sizeof(typename stringtype::value_type) \ - << ")=" << narrow << "\n" \ - << " expected=" << fHexAndDec(expected) << "\n" \ - << " ..actual=" << fHexAndDec(actual) << "\n" \ - << " expected mantissa=" \ - << iHexAndDec(get_mantissa(expected)) << "\n" \ - << " ..actual mantissa=" \ - << iHexAndDec(get_mantissa(actual))); \ - CHECK_EQ(__VA_ARGS__); \ - } else { \ - if ([](auto const &lhs, auto const &rhs) { \ - return lhs != rhs; \ - }(__VA_ARGS__)) { \ - ComptimeDiag::error_not_equal(); \ - } \ - } - - auto copysign = [](double x, double y) -> double { -#if FASTFLOAT_HAS_BIT_CAST - if (fast_float::cpp20_and_in_constexpr()) { - using equiv_int = std::make_signed_t>; - auto const i = std::bit_cast(y); - if (i < 0) { - return -x; - } - return x; - } else -#endif - return std::copysign(x, y); - }; - - auto isnan = [](double x) -> bool { return x != x; }; - - FASTFLOAT_CHECK_EQ(result.ec, expected_ec); - FASTFLOAT_CHECK_EQ(result.ptr, str.data() + str.size()); - FASTFLOAT_CHECK_EQ(copysign(1, actual), copysign(1, expected)); - FASTFLOAT_CHECK_EQ(isnan(actual), isnan(expected)); - FASTFLOAT_CHECK_EQ(actual, expected); - -#undef FASTFLOAT_CHECK_EQ -} - -template -constexpr void basic_test(std::string_view str, T expected, - std::errc expected_ec = std::errc()) { - T actual{}; - auto result = - fast_float::from_chars(str.data(), str.data() + str.size(), actual); - check_basic_test_result(str, result, actual, expected, expected_ec); - - if (str.size() > global_string_capacity) { - return; - } - - // We give plenty of memory: 2048 characters. - char16_t u16[global_string_capacity]{}; - for (size_t i = 0; i < str.size(); i++) { - u16[i] = char16_t(str[i]); - } - - auto result16 = fast_float::from_chars(u16, u16 + str.size(), actual); - check_basic_test_result(std::u16string_view(u16, str.size()), result16, - actual, expected, expected_ec); - - char32_t u32[global_string_capacity]{}; - for (size_t i = 0; i < str.size(); i++) { - u32[i] = char32_t(str[i]); - } - - auto result32 = fast_float::from_chars(u32, u32 + str.size(), actual); - check_basic_test_result(std::u32string_view(u32, str.size()), result32, - actual, expected, expected_ec); -} - -template -constexpr void basic_test(std::string_view str, T expected, - fast_float::parse_options options) { - T actual{}; - auto result = fast_float::from_chars_advanced( - str.data(), str.data() + str.size(), actual, options); - check_basic_test_result(str, result, actual, expected, std::errc()); -} - -template -constexpr void basic_test(std::string_view str, T expected, - std::errc expected_ec, - fast_float::parse_options options) { - T actual{}; - auto result = fast_float::from_chars_advanced( - str.data(), str.data() + str.size(), actual, options); - check_basic_test_result(str, result, actual, expected, expected_ec); -} - -void basic_test(float val) { - { - std::string long_vals = to_long_string(val); - INFO("long vals: " << long_vals); - basic_test(long_vals, val); - } - { - std::string vals = to_string(val); - INFO("vals: " << vals); - basic_test(vals, val); - } -} - -#define verify_runtime(...) \ - do { \ - basic_test(__VA_ARGS__); \ - } while (false) - -#define verify_comptime(...) \ - do { \ - constexpr int verify_comptime_var = \ - (basic_test(__VA_ARGS__), 0); \ - (void)verify_comptime_var; \ - } while (false) - -#define verify_options_runtime(...) \ - do { \ - basic_test(__VA_ARGS__, options); \ - } while (false) - -#define verify_options_comptime(...) \ - do { \ - constexpr int verify_options_comptime_var = \ - (basic_test(__VA_ARGS__, options), 0); \ - (void)verify_options_comptime_var; \ - } while (false) - -#if defined(FASTFLOAT_CONSTEXPR_TESTS) -#if !FASTFLOAT_IS_CONSTEXPR -#error "from_chars must be constexpr for constexpr tests" -#endif - -#define verify(...) \ - do { \ - verify_runtime(__VA_ARGS__); \ - verify_comptime(__VA_ARGS__); \ - } while (false) - -#define verify_options(...) \ - do { \ - verify_options_runtime(__VA_ARGS__); \ - verify_options_comptime(__VA_ARGS__); \ - } while (false) - -#else -#define verify verify_runtime -#define verify_options verify_options_runtime -#endif - -#define verify32(val) \ - { \ - INFO(#val); \ - basic_test(val); \ - } - -TEST_CASE("double.inf") { - verify("INF", std::numeric_limits::infinity()); - verify("-INF", -std::numeric_limits::infinity()); - verify("INFINITY", std::numeric_limits::infinity()); - verify("-INFINITY", -std::numeric_limits::infinity()); - verify("infinity", std::numeric_limits::infinity()); - verify("-infinity", -std::numeric_limits::infinity()); - verify("inf", std::numeric_limits::infinity()); - verify("-inf", -std::numeric_limits::infinity()); - verify("1234456789012345678901234567890e9999999999999999999999999999", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("-2139879401095466344511101915470454744.9813888656856943E+272", - -std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("1.8e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("1.832312213213213232132132143451234453123412321321312e308", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("2e30000000000000000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("2e3000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("1.9e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - // DBL_MAX + 0.00000000000000001e308 - verify("1.79769313486231581e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - // DBL_MAX + 0.0000000000000001e308 - verify("1.7976931348623159e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - // ( (2 - 0.5*2^(−52)) * 2^1023 ) smallest number that overflows to infinity - verify("179769313486231580793728971405303415079934132710037826936173778980444" - "968292764750946649017977587207096330286416692887910946555547851940402" - "630657488671505820681908902000708383676273854845817711531764475730270" - "069855571366959622842914819860834936475292719074168444365510704342711" - "559699508093042880177904174497792", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); -} - -TEST_CASE("double.general") { - verify("0.95000000000000000000", 0.95); - verify("22250738585072012e-324", - 0x1p-1022); /* limit between normal and subnormal*/ - verify("-22250738585072012e-324", - -0x1p-1022); /* limit between normal and subnormal*/ - verify("-1e-999", -0.0, std::errc::result_out_of_range); - - // DBL_TRUE_MIN / 2 - verify("2.4703282292062327e-324", 0.0, std::errc::result_out_of_range); - - // DBL_TRUE_MIN / 2 + 0.0000000000000001e-324 - verify("2.4703282292062328e-324", 0x0.0000000000001p-1022); - - verify("0.2470328229206232720e-323", 0.0, std::errc::result_out_of_range); - verify("0.2470328229206232721e-323", 0x0.0000000000001p-1022); - - verify("-2.2222222222223e-322", -0x1.68p-1069); - verify("9007199254740993.0", 0x1p+53); - verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328); - verify_runtime(append_zeros("9007199254740993.0", 1000), 0x1p+53); - verify("10000000000000000000", 0x1.158e460913dp+63); - verify("10000000000000000000000000000001000000000000", - 0x1.cb2d6f618c879p+142); - verify("10000000000000000000000000000000000000000001", - 0x1.cb2d6f618c879p+142); - verify("1.1920928955078125e-07", 1.1920928955078125e-07); - verify("9355950000000000000." - "000000000000000000000000000000000018446744073709551616000001844674407" - "370955161618446744073709551614073709551616184467440737095516160001844" - "674407370955161660000018446744073709551616184467440737095516140737095" - "516161844674407370955161600018446744073709551616018446744073709556744" - "516161844674407370955161407370955161618446744073709551616000184467440" - "737095516160184467440737095516116160001844674407370950018446744073709" - "551616001844674407370955161600184467440737095511681644674407370955161" - "600018440737095516160184467440737095516161844674407370955161600018446" - "744075369107516016116160001844674407370950018446744073709551616001844" - "674407370955161600184467440737095516161844674407370955161600018449551" - "61618446744073709551616000184467440753691075160018446744073709", - 0x1.03ae05e8fca1cp+63); - verify("-0", -0.0); - verify( - "2." - "225073858507202124188701479202220329072405282794390378143031338374351073" - "192441946867544064325638818513821882185024380699999477330130056498841077" - "919287413419292972009704819519930679932909690427840647316820415659267286" - "329336304746701233168529834221527445172608358596545663192828352447877877" - "998943107797838336991592885945552137141811284582511455843192230798975043" - "950868594124572308917389461693683723211913736589779777232866988403563902" - "510444430354573967337065839810554204566938246584137476071559811765738776" - "267476659123871999319040063173347090030127901881752034471902500280612777" - "779167983910905785840064647159438105114891542827750411746821941339524666" - "825034313061815878293790042053923750720833666932415800027583911188541886" - "41513168478436313080237596295773983001708984375e-308", - 0x1.0000000000002p-1022); - verify("1.0000000000000006661338147750939242541790008544921875", - 1.0000000000000007); - verify("1090544144181609348835077142190", 0x1.b8779f2474dfbp+99); - verify("2.2250738585072013e-308", 2.2250738585072013e-308); - verify("-92666518056446206563E3", -92666518056446206563E3); - verify("-92666518056446206563E3", -92666518056446206563E3); - verify("-42823146028335318693e-128", -42823146028335318693e-128); - verify("90054602635948575728E72", 90054602635948575728E72); - verify( - "1." - "000000000000001885589208702234638701745660206917535153946435506630705583" - "68373221972569761144603605635692374830246134201063722058e-309", - 1.00000000000000188558920870223463870174566020691753515394643550663070558368373221972569761144603605635692374830246134201063722058e-309); - verify("0e9999999999999999999999999999", 0.0); - verify("-2402844368454405395.2", -2402844368454405395.2); - verify("2402844368454405395.2", 2402844368454405395.2); - verify( - "7.0420557077594588669468784357561207962098443483187940792729600000e+59", - 7.0420557077594588669468784357561207962098443483187940792729600000e+59); - verify( - "7.0420557077594588669468784357561207962098443483187940792729600000e+59", - 7.0420557077594588669468784357561207962098443483187940792729600000e+59); - verify( - "-1.7339253062092163730578609458683877051596800000000000000000000000e+42", - -1.7339253062092163730578609458683877051596800000000000000000000000e+42); - verify( - "-2.0972622234386619214559824785284023792871122537545728000000000000e+52", - -2.0972622234386619214559824785284023792871122537545728000000000000e+52); - verify( - "-1.0001803374372191849407179462120053338028379051879898808320000000e+57", - -1.0001803374372191849407179462120053338028379051879898808320000000e+57); - verify( - "-1.8607245283054342363818436991534856973992070520151142825984000000e+58", - -1.8607245283054342363818436991534856973992070520151142825984000000e+58); - verify( - "-1.9189205311132686907264385602245237137907390376574976000000000000e+52", - -1.9189205311132686907264385602245237137907390376574976000000000000e+52); - verify( - "-2.8184483231688951563253238886553506793085187889855201280000000000e+54", - -2.8184483231688951563253238886553506793085187889855201280000000000e+54); - verify( - "-1.7664960224650106892054063261344555646357024359107788800000000000e+53", - -1.7664960224650106892054063261344555646357024359107788800000000000e+53); - verify( - "-2.1470977154320536489471030463761883783915110400000000000000000000e+45", - -2.1470977154320536489471030463761883783915110400000000000000000000e+45); - verify( - "-4.4900312744003159009338275160799498340862630046359789166919680000e+61", - -4.4900312744003159009338275160799498340862630046359789166919680000e+61); - verify("1", 1.0); - verify("1.797693134862315700000000000000001e308", 1.7976931348623157e308); - verify("3e-324", 0x0.0000000000001p-1022); - verify("1.00000006e+09", 0x1.dcd651ep+29); - verify("4.9406564584124653e-324", 0x0.0000000000001p-1022); - verify("4.9406564584124654e-324", 0x0.0000000000001p-1022); - verify("2.2250738585072009e-308", 0x0.fffffffffffffp-1022); - verify("2.2250738585072014e-308", 0x1p-1022); - verify("0.2225073858507201136e-307", 0x0.fffffffffffffp-1022); - verify("0.2225073858507201137e-307", 0x1p-1022); - verify("1.7976931348623157e308", 0x1.fffffffffffffp+1023); - verify("1.7976931348623158e308", 0x1.fffffffffffffp+1023); - verify("1.7976931348623158079e308", std::numeric_limits::max()); - verify("1.7976931348623158080e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("4503599627370496.5", 4503599627370496.5); - verify("4503599627475352.5", 4503599627475352.5); - verify("4503599627475353.5", 4503599627475353.5); - verify("2251799813685248.25", 2251799813685248.25); - verify("1125899906842624.125", 1125899906842624.125); - verify("1125899906842901.875", 1125899906842901.875); - verify("2251799813685803.75", 2251799813685803.75); - verify("4503599627370497.5", 4503599627370497.5); - verify("45035996.273704995", 45035996.273704995); - verify("45035996.273704985", 45035996.273704985); - verify( - "0." - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000044501477170144022721148195934182639518696390927032912" - "960468522194496444440421538910330590478162701758282983178260792422137401" - "728773891892910553144148156412434867599762821265346585071045737627442980" - "259622449029037796981144446145705102663115100318287949527959668236039986" - "479250965780342141637013812613333119898765515451440315261253813266652951" - "306000184917766328660755595837392240989947807556594098101021612198814605" - "258742579179000071675999344145086087205681577915435923018910334964869420" - "614052182892431445797605163650903606514140377217442262561590244668525767" - "372446430075513332450079650686719491377688478005309963967709758965844137" - "894433796621993967316936280457084866613206797017728916080020698679408551" - "343728867675409720757232455434770912461317493580281734466552734375", - 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375); - verify( - "0." - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000022250738585072008890245868760858598876504231122409594" - "654935248025624400092282356951787758888037591552642309780950434312085877" - "387158357291821993020294379224223559819827501242041788969571311791082261" - "043971979604000454897391938079198936081525613113376149842043271751033627" - "391549782731594143828136275113838604094249464942286316695429105080201815" - "926642134996606517803095075913058719846423906068637102005108723282784678" - "843631944515866135041223479014792369585208321597621066375401613736583044" - "193603714778355306682834535634005074073040135602968046375918583163124224" - "521599262546494300836851861719422417646455137135420132217031370496583210" - "154654068035397417906022589503023501937519773030945763173210852507299305" - "089761582519159720757232455434770912461317493580281734466552734375", - 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375); - verify( - "143845666314139027352611820764223558118322784524633123116263665379036815" - "209139419693036582863468763794815794077659918279138752713535303473835713" - "411031060945569390082419354977279201654318268051974058035436546798544018" - "359870131225762454556233139701832992861319612559027418772007391481806253" - "083031653315809862498411888929828137181228878953731059903752911341543873" - "895489475212472498306724110876448834645437669901867307840475112141480493" - "722424080599312381693232622368309077056159757045779393298582616260425588" - "452913412639628220212652625338938342180672795458852559611437980126909409" - "632980505480308929973699687095125857301087740440745195384669860919821392" - "688269207855703322826525930548119852605981316446918758669325733577952202" - "040764549868426333992190522755661669812996741289128223168550466067127792" - "719829000982468018631975097866573457668378425580226970891736171946604317" - "520115884909788137047711185017157986905601606166617302905958843377601564" - "443970505037755427769614392827809345379280384625271596601673322264644238" - "289212394005244134682242972159388437821255870100435692424303005951748934" - "664657772462249891975259738209522250031112418182351225107135618176937657" - "765139002829779615620881537508915912839494571051586133448626710179749711" - "112590927250519479287088961717975870344260801614334326215999814970060659" - "779253557445756042922697427344363032381874773077131676339857211087495998" - "192373246307688452867739265415001026982223940199342748237651323138921235" - "358357356637691557265091686655361236618737895955498356671276709337290603" - "018897622016905802535497362221166650454931695827188097569714354656446980" - "679135870731887307570838334500409015197406832583817753126695417740666139" - "2229801349994695941509935655355652985723782153570084089560139142231." - "738475042362596875449154552392299548947138162081694168675340677843807613" - "129780449323363759027012972466987370921816813162658754726545121090545507" - "240267000456594786540949605260722461937870630634874991729398208026467698" - "131898691830012167897399682179601734569071423681e-733", - std::numeric_limits::infinity(), std::errc::result_out_of_range); - verify("-2240084132271013504.131248280843119943687942846658579428", - -0x1.f1660a65b00bfp+60); - - // ( (2 - 0.5*2^(−52)) * 2^1023 - 1 ) largest 309 decimal digit number - // that rounds to DBL_MAX - verify("179769313486231580793728971405303415079934132710037826936173778980444" - "968292764750946649017977587207096330286416692887910946555547851940402" - "630657488671505820681908902000708383676273854845817711531764475730270" - "069855571366959622842914819860834936475292719074168444365510704342711" - "559699508093042880177904174497791", - std::numeric_limits::max()); -} - -TEST_CASE("double.decimal_point") { - constexpr auto options = [] { - fast_float::parse_options ret{}; - ret.decimal_point = ','; - return ret; - }(); - - // infinities - verify_options("1,8e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify_options("1,832312213213213232132132143451234453123412321321312e308", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify_options("2e30000000000000000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify_options("2e3000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify_options("1,9e308", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - // finites - verify_options("-2,2222222222223e-322", -0x1.68p-1069); - verify_options("9007199254740993,0", 0x1p+53); - verify_options("860228122,6654514319E+90", 0x1.92bb20990715fp+328); - verify_options_runtime(append_zeros("9007199254740993,0", 1000), 0x1p+53); - verify_options("1,1920928955078125e-07", 1.1920928955078125e-07); - verify_options( - "9355950000000000000," - "000000000000000000000000000000000018446744073709551616000001844674407370" - "955161618446744073709551614073709551616184467440737095516160001844674407" - "370955161660000018446744073709551616184467440737095516140737095516161844" - "674407370955161600018446744073709551616018446744073709556744516161844674" - "407370955161407370955161618446744073709551616000184467440737095516160184" - "467440737095516116160001844674407370950018446744073709551616001844674407" - "370955161600184467440737095511681644674407370955161600018440737095516160" - "184467440737095516161844674407370955161600018446744075369107516016116160" - "001844674407370950018446744073709551616001844674407370955161600184467440" - "737095516161844674407370955161600018449551616184467440737095516160001844" - "67440753691075160018446744073709", - 0x1.03ae05e8fca1cp+63); - verify_options( - "2," - "225073858507202124188701479202220329072405282794390378143031338374351073" - "192441946867544064325638818513821882185024380699999477330130056498841077" - "919287413419292972009704819519930679932909690427840647316820415659267286" - "329336304746701233168529834221527445172608358596545663192828352447877877" - "998943107797838336991592885945552137141811284582511455843192230798975043" - "950868594124572308917389461693683723211913736589779777232866988403563902" - "510444430354573967337065839810554204566938246584137476071559811765738776" - "267476659123871999319040063173347090030127901881752034471902500280612777" - "779167983910905785840064647159438105114891542827750411746821941339524666" - "825034313061815878293790042053923750720833666932415800027583911188541886" - "41513168478436313080237596295773983001708984375e-308", - 0x1.0000000000002p-1022); - verify_options("1,0000000000000006661338147750939242541790008544921875", - 1.0000000000000007); - verify_options("2,2250738585072013e-308", 2.2250738585072013e-308); - verify_options( - "1," - "000000000000001885589208702234638701745660206917535153946435506630705583" - "68373221972569761144603605635692374830246134201063722058e-309", - 1.00000000000000188558920870223463870174566020691753515394643550663070558368373221972569761144603605635692374830246134201063722058e-309); - verify_options("-2402844368454405395,2", -2402844368454405395.2); - verify_options("2402844368454405395,2", 2402844368454405395.2); - verify_options( - "7,0420557077594588669468784357561207962098443483187940792729600000e+59", - 7.0420557077594588669468784357561207962098443483187940792729600000e+59); - verify_options( - "7,0420557077594588669468784357561207962098443483187940792729600000e+59", - 7.0420557077594588669468784357561207962098443483187940792729600000e+59); - verify_options( - "-1,7339253062092163730578609458683877051596800000000000000000000000e+42", - -1.7339253062092163730578609458683877051596800000000000000000000000e+42); - verify_options( - "-2,0972622234386619214559824785284023792871122537545728000000000000e+52", - -2.0972622234386619214559824785284023792871122537545728000000000000e+52); - verify_options( - "-1,0001803374372191849407179462120053338028379051879898808320000000e+57", - -1.0001803374372191849407179462120053338028379051879898808320000000e+57); - verify_options( - "-1,8607245283054342363818436991534856973992070520151142825984000000e+58", - -1.8607245283054342363818436991534856973992070520151142825984000000e+58); - verify_options( - "-1,9189205311132686907264385602245237137907390376574976000000000000e+52", - -1.9189205311132686907264385602245237137907390376574976000000000000e+52); - verify_options( - "-2,8184483231688951563253238886553506793085187889855201280000000000e+54", - -2.8184483231688951563253238886553506793085187889855201280000000000e+54); - verify_options( - "-1,7664960224650106892054063261344555646357024359107788800000000000e+53", - -1.7664960224650106892054063261344555646357024359107788800000000000e+53); - verify_options( - "-2,1470977154320536489471030463761883783915110400000000000000000000e+45", - -2.1470977154320536489471030463761883783915110400000000000000000000e+45); - verify_options( - "-4,4900312744003159009338275160799498340862630046359789166919680000e+61", - -4.4900312744003159009338275160799498340862630046359789166919680000e+61); - verify_options("1", 1.0); - verify_options("1,797693134862315700000000000000001e308", - 1.7976931348623157e308); - verify_options("3e-324", 0x0.0000000000001p-1022); - verify_options("1,00000006e+09", 0x1.dcd651ep+29); - verify_options("4,9406564584124653e-324", 0x0.0000000000001p-1022); - verify_options("4,9406564584124654e-324", 0x0.0000000000001p-1022); - verify_options("2,2250738585072009e-308", 0x0.fffffffffffffp-1022); - verify_options("2,2250738585072014e-308", 0x1p-1022); - verify_options("1,7976931348623157e308", 0x1.fffffffffffffp+1023); - verify_options("1,7976931348623158e308", 0x1.fffffffffffffp+1023); - verify_options("4503599627370496,5", 4503599627370496.5); - verify_options("4503599627475352,5", 4503599627475352.5); - verify_options("4503599627475353,5", 4503599627475353.5); - verify_options("2251799813685248,25", 2251799813685248.25); - verify_options("1125899906842624,125", 1125899906842624.125); - verify_options("1125899906842901,875", 1125899906842901.875); - verify_options("2251799813685803,75", 2251799813685803.75); - verify_options("4503599627370497,5", 4503599627370497.5); - verify_options("45035996,273704995", 45035996.273704995); - verify_options("45035996,273704985", 45035996.273704985); - verify_options( - "0," - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000044501477170144022721148195934182639518696390927032912" - "960468522194496444440421538910330590478162701758282983178260792422137401" - "728773891892910553144148156412434867599762821265346585071045737627442980" - "259622449029037796981144446145705102663115100318287949527959668236039986" - "479250965780342141637013812613333119898765515451440315261253813266652951" - "306000184917766328660755595837392240989947807556594098101021612198814605" - "258742579179000071675999344145086087205681577915435923018910334964869420" - "614052182892431445797605163650903606514140377217442262561590244668525767" - "372446430075513332450079650686719491377688478005309963967709758965844137" - "894433796621993967316936280457084866613206797017728916080020698679408551" - "343728867675409720757232455434770912461317493580281734466552734375", - 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375); - verify_options( - "0," - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000022250738585072008890245868760858598876504231122409594" - "654935248025624400092282356951787758888037591552642309780950434312085877" - "387158357291821993020294379224223559819827501242041788969571311791082261" - "043971979604000454897391938079198936081525613113376149842043271751033627" - "391549782731594143828136275113838604094249464942286316695429105080201815" - "926642134996606517803095075913058719846423906068637102005108723282784678" - "843631944515866135041223479014792369585208321597621066375401613736583044" - "193603714778355306682834535634005074073040135602968046375918583163124224" - "521599262546494300836851861719422417646455137135420132217031370496583210" - "154654068035397417906022589503023501937519773030945763173210852507299305" - "089761582519159720757232455434770912461317493580281734466552734375", - 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375); -} - -TEST_CASE("float.inf") { - verify("INF", std::numeric_limits::infinity()); - verify("-INF", -std::numeric_limits::infinity()); - verify("INFINITY", std::numeric_limits::infinity()); - verify("-INFINITY", -std::numeric_limits::infinity()); - verify("infinity", std::numeric_limits::infinity()); - verify("-infinity", -std::numeric_limits::infinity()); - verify("inf", std::numeric_limits::infinity()); - verify("-inf", -std::numeric_limits::infinity()); - verify("1234456789012345678901234567890e9999999999999999999999999999", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("2e3000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("3.5028234666e38", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - // FLT_MAX + 0.00000007e38 - verify("3.40282357e38", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - // FLT_MAX + 0.0000001e38 - verify("3.4028236e38", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - // ( (2 - 0.5*2^(-23)) * 2^127 ) smallest number that overflows to infinity - verify("340282356779733661637539395458142568448", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); -} - -TEST_CASE("float.general") { - // FLT_TRUE_MIN / 2 - verify("0.7006492e-45", 0.f, std::errc::result_out_of_range); - // FLT_TRUE_MIN / 2 + 0.0000001e-45 - verify("0.7006493e-45", 0x1p-149f); - verify("0.7006492321624085354e-45", 0.f, std::errc::result_out_of_range); - verify("0.7006492321624085355e-45", 0x1p-149f); - - // max - verify("340282346638528859811704183484516925440", 0x1.fffffep+127f); - // -max - verify("-340282346638528859811704183484516925440", -0x1.fffffep+127f); - - // ( (2 - 0.5*2^(-23)) * 2^127 - 1 ) largest 39 decimal digits number - // that rounds to FLT_MAX - verify("340282356779733661637539395458142568447", - std::numeric_limits::max()); - verify("0.3402823567797336616e39", std::numeric_limits::max()); - verify("0.3402823567797336617e39", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - verify("-1e-999", -0.0f, std::errc::result_out_of_range); - verify("1." - "175494140627517859246175898662808184331245864732796240031385942718174" - "6759860647699724722770042717456817626953125", - 0x1.2ced3p+0f); - verify("1." - "175494140627517859246175898662808184331245864732796240031385942718174" - "6759860647699724722770042717456817626953125e-38", - 0x1.fffff8p-127f); - verify("1.1754942807573642917e-38", 0x1.fffffcp-127f); - verify("1.1754942807573642918e-38", std::numeric_limits::min()); - verify_runtime( - append_zeros("1." - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 655), - 0x1.2ced3p+0f); - verify_runtime( - append_zeros("1." - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 656), - 0x1.2ced3p+0f); - verify_runtime( - append_zeros("1." - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 1000), - 0x1.2ced3p+0f); - std::string test_string; - test_string = - append_zeros("1." - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 655) + - std::string("e-38"); - verify_runtime(test_string, 0x1.fffff8p-127f); - test_string = - append_zeros("1." - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 656) + - std::string("e-38"); - verify_runtime(test_string, 0x1.fffff8p-127f); - test_string = - append_zeros("1." - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 1000) + - std::string("e-38"); - verify_runtime(test_string, 0x1.fffff8p-127f); - verify32(1.00000006e+09f); - verify32(1.4012984643e-45f); - verify32(1.1754942107e-38f); - verify32(1.1754943508e-45f); - verify("-0", -0.0f); - verify("1090544144181609348835077142190", 0x1.b877ap+99f); - verify("1.1754943508e-38", 1.1754943508e-38f); - verify("30219.0830078125", 30219.0830078125f); - verify("16252921.5", 16252921.5f); - verify("5322519.25", 5322519.25f); - verify("3900245.875", 3900245.875f); - verify("1510988.3125", 1510988.3125f); - verify("782262.28125", 782262.28125f); - verify("328381.484375", 328381.484375f); - verify("156782.0703125", 156782.0703125f); - verify("85003.24609375", 85003.24609375f); - verify("17419.6494140625", 17419.6494140625f); - verify("15498.36376953125", 15498.36376953125f); - verify("6318.580322265625", 6318.580322265625f); - verify("2525.2840576171875", 2525.2840576171875f); - verify("1370.9265747070312", 1370.9265747070312f); - verify("936.3702087402344", 936.3702087402344f); - verify("411.88682556152344", 411.88682556152344f); - verify("206.50310516357422", 206.50310516357422f); - verify("124.16878890991211", 124.16878890991211f); - verify("50.811574935913086", 50.811574935913086f); - verify("17.486443519592285", 17.486443519592285f); - verify("13.91745138168335", 13.91745138168335f); - verify("7.5464513301849365", 0x1.e2f90ep+2f); - verify("2.687217116355896", 2.687217116355896f); - verify("1.1877630352973938", 0x1.30113ep+0f); - verify("0.7622503340244293", 0.7622503340244293f); - verify("0.30531780421733856", 0x1.38a53ap-2f); - verify("0.21791061013936996", 0x1.be47eap-3f); - verify("0.09289376810193062", 0x1.7c7e2ep-4f); - verify("0.03706067614257336", 0.03706067614257336f); - verify("0.028068351559340954", 0.028068351559340954f); - verify("0.012114629615098238", 0x1.8cf8e2p-7f); - verify("0.004221370676532388", 0x1.14a6dap-8f); - verify("0.002153817447833717", 0.002153817447833717f); - verify("0.0015924838953651488", 0x1.a175cap-10f); - verify("0.0008602388261351734", 0.0008602388261351734f); - verify("0.00036393293703440577", 0x1.7d9c82p-12f); - verify("0.00013746770127909258", 0.00013746770127909258f); - verify("16407.9462890625", 16407.9462890625f); - verify("1.1754947011469036e-38", 0x1.000006p-126f); - verify("7.0064923216240854e-46", 0x1p-149f); - verify("8388614.5", 8388614.5f); - verify("0e9999999999999999999999999999", 0.f); - verify( - "4.7019774032891500318749461488889827112746622270883500860350068251e-38", - 4.7019774032891500318749461488889827112746622270883500860350068251e-38f); - verify( - "3." - "141592653589793238462643383279502884197169399375105820974944592307816406" - "2862089986280348253421170679", - 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f); - verify( - "2.3509887016445750159374730744444913556373311135441750430175034126e-38", - 2.3509887016445750159374730744444913556373311135441750430175034126e-38f); - verify("1", 1.f); - verify("7.0060e-46", 0.f, std::errc::result_out_of_range); - verify("3.4028234664e38", 0x1.fffffep+127f); - verify("3.4028234665e38", 0x1.fffffep+127f); - verify("3.4028234666e38", 0x1.fffffep+127f); - verify( - "0." - "000000000000000000000000000000000000011754943508222875079687365372222456" - "778186655567720875215087517062784172594547271728515625", - 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625); - verify( - "0." - "000000000000000000000000000000000000000000001401298464324817070923729583" - "289916131280261941876515771757068283889791082685860601486638188362121582" - "03125", - 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125f); - verify( - "0." - "000000000000000000000000000000000000023509885615147285834557659820715330" - "266457179855179808553659262368500061299303460771170648513361811637878417" - "96875", - 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875f); - verify( - "0." - "000000000000000000000000000000000000011754942106924410754870294448492873" - "488270524287458933338571745305715888704756189042655023513361811637878417" - "96875", - 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875f); -} - -TEST_CASE("float.decimal_point") { - constexpr auto options = [] { - fast_float::parse_options ret{}; - ret.decimal_point = ','; - return ret; - }(); - - // infinity - verify_options("3,5028234666e38", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - - // finites - verify_options("1," - "1754941406275178592461758986628081843312458647327962400313859" - "427181746759860647699724722770042717456817626953125", - 0x1.2ced3p+0f); - verify_options("1," - "1754941406275178592461758986628081843312458647327962400313859" - "427181746759860647699724722770042717456817626953125e-38", - 0x1.fffff8p-127f); - verify_options_runtime( - append_zeros("1," - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 655), - 0x1.2ced3p+0f); - verify_options_runtime( - append_zeros("1," - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 656), - 0x1.2ced3p+0f); - verify_options_runtime( - append_zeros("1," - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 1000), - 0x1.2ced3p+0f); - std::string test_string; - test_string = - append_zeros("1," - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 655) + - std::string("e-38"); - verify_options_runtime(test_string, 0x1.fffff8p-127f); - test_string = - append_zeros("1," - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 656) + - std::string("e-38"); - verify_options_runtime(test_string, 0x1.fffff8p-127f); - test_string = - append_zeros("1," - "17549414062751785924617589866280818433124586473279624003138" - "59427181746759860647699724722770042717456817626953125", - 1000) + - std::string("e-38"); - verify_options_runtime(test_string, 0x1.fffff8p-127f); - verify_options("1,1754943508e-38", 1.1754943508e-38f); - verify_options("30219,0830078125", 30219.0830078125f); - verify_options("1,1754947011469036e-38", 0x1.000006p-126f); - verify_options("7,0064923216240854e-46", 0x1p-149f); - verify_options("8388614,5", 8388614.5f); - verify_options("0e9999999999999999999999999999", 0.f); - verify_options( - "4,7019774032891500318749461488889827112746622270883500860350068251e-38", - 4.7019774032891500318749461488889827112746622270883500860350068251e-38f); - verify_options( - "3," - "141592653589793238462643383279502884197169399375105820974944592307816406" - "2862089986280348253421170679", - 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f); - verify_options( - "2,3509887016445750159374730744444913556373311135441750430175034126e-38", - 2.3509887016445750159374730744444913556373311135441750430175034126e-38f); - verify_options("1", 1.f); - verify_options("7,0060e-46", 0.f, std::errc::result_out_of_range); - verify_options("3,4028234664e38", 0x1.fffffep+127f); - verify_options("3,4028234665e38", 0x1.fffffep+127f); - verify_options("3,4028234666e38", 0x1.fffffep+127f); - verify_options( - "0," - "000000000000000000000000000000000000011754943508222875079687365372222456" - "778186655567720875215087517062784172594547271728515625", - 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625f); - verify_options( - "0," - "000000000000000000000000000000000000000000001401298464324817070923729583" - "289916131280261941876515771757068283889791082685860601486638188362121582" - "03125", - 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125f); - verify_options( - "0," - "000000000000000000000000000000000000023509885615147285834557659820715330" - "266457179855179808553659262368500061299303460771170648513361811637878417" - "96875", - 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875f); - verify_options( - "0," - "000000000000000000000000000000000000011754942106924410754870294448492873" - "488270524287458933338571745305715888704756189042655023513361811637878417" - "96875", - 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875f); -} - -#ifdef __STDCPP_FLOAT16_T__ -TEST_CASE("float16.inf") { - verify("INF", std::numeric_limits::infinity()); - verify("-INF", -std::numeric_limits::infinity()); - verify("INFINITY", std::numeric_limits::infinity()); - verify("-INFINITY", -std::numeric_limits::infinity()); - verify("infinity", std::numeric_limits::infinity()); - verify("-infinity", -std::numeric_limits::infinity()); - verify("inf", std::numeric_limits::infinity()); - verify("-inf", -std::numeric_limits::infinity()); - verify("1234456789012345678901234567890e9999999999999999999999999999", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("2e3000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("3.5028234666e38", std::numeric_limits::infinity(), - std::errc::result_out_of_range); -} - -TEST_CASE("float16.general") { - // max - verify("65504", 0x1.ffcp+15f16); - // -max - verify("-65504", -0x1.ffcp+15f16); - // min - verify("0.000060975551605224609375", 0x1.ff8p-15f16); - verify("6.0975551605224609375e-5", 0x1.ff8p-15f16); - // denorm_min - verify("0.000000059604644775390625", 0x1p-24f16); - verify("5.9604644775390625e-8", 0x1p-24f16); - // -min - verify("-0.000060975551605224609375", -0x1.ff8p-15f16); - verify("-6.0975551605224609375e-5", -0x1.ff8p-15f16); - // -denorm_min - verify("-0.000000059604644775390625", -0x1p-24f16); - verify("-5.9604644775390625e-8", -0x1p-24f16); - - verify("-1e-999", -0.0f16, std::errc::result_out_of_range); - verify("6.0975551605224609375", 0x1.864p+2f16); - verify_runtime(append_zeros("6.0975551605224609375", 655), 0x1.864p+2f16); - verify_runtime(append_zeros("6.0975551605224609375", 656), 0x1.864p+2f16); - verify_runtime(append_zeros("6.0975551605224609375", 1000), 0x1.864p+2f16); - verify_runtime(append_zeros("6.0975551605224609375", 655) + - std::string("e-5"), - 0x1.ff8p-15f16); - verify_runtime(append_zeros("6.0975551605224609375", 656) + - std::string("e-5"), - 0x1.ff8p-15f16); - verify_runtime(append_zeros("6.0975551605224609375", 1000) + - std::string("e-5"), - 0x1.ff8p-15f16); - verify("-0", -0.0f16); - // verify("1090544144181609348835077142190", 0x1.b877ap+99f16); - // verify("1.1754943508e-38", 1.1754943508e-38f16); - verify("30219.0830078125", 30219.0830078125f16); - verify("17419.6494140625", 17419.6494140625f16); - verify("15498.36376953125", 15498.36376953125f16); - verify("6318.580322265625", 6318.580322265625f16); - verify("2525.2840576171875", 2525.2840576171875f16); - verify("1370.9265747070312", 1370.9265747070312f16); - verify("936.3702087402344", 936.3702087402344f16); - verify("411.88682556152344", 411.88682556152344f16); - verify("206.50310516357422", 206.50310516357422f16); - verify("124.16878890991211", 124.16878890991211f16); - verify("50.811574935913086", 50.811574935913086f16); - verify("17.486443519592285", 17.486443519592285f16); - verify("13.91745138168335", 13.91745138168335f16); - verify("7.5464513301849365", 0x1.e2f90ep+2f16); - verify("2.687217116355896", 2.687217116355896f16); - verify("1.1877630352973938", 0x1.30113ep+0f16); - verify("0.7622503340244293", 0.7622503340244293f16); - verify("0.30531780421733856", 0x1.38a53ap-2f16); - verify("0.21791061013936996", 0x1.be47eap-3f16); - verify("0.09289376810193062", 0x1.7c7e2ep-4f16); - verify("0.03706067614257336", 0.03706067614257336f16); - verify("0.028068351559340954", 0.028068351559340954f16); - verify("0.012114629615098238", 0x1.8cf8e2p-7f16); - verify("0.004221370676532388", 0x1.14a6dap-8f16); - verify("0.002153817447833717", 0.002153817447833717f16); - verify("0.0015924838953651488", 0x1.a175cap-10f16); - verify("0.0008602388261351734", 0.0008602388261351734f16); - verify("0.00036393293703440577", 0x1.7d9c82p-12f16); - verify("0.00013746770127909258", 0.00013746770127909258f16); - verify("16407.9462890625", 16407.9462890625f16); - // verify("1.1754947011469036e-38", 0x1.000006p-126f16); - // verify("7.0064923216240854e-46", 0x1p-149f16); - // verify("8388614.5", 8388614.5f16); - verify("0e9999999999999999999999999999", 0.f16); - // verify( - // "4.7019774032891500318749461488889827112746622270883500860350068251e-38", - // 4.7019774032891500318749461488889827112746622270883500860350068251e-38f16); - verify( - "3." - "141592653589793238462643383279502884197169399375105820974944592307816406" - "2862089986280348253421170679", - 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f16); - // verify( - // "2.3509887016445750159374730744444913556373311135441750430175034126e-38", - // 2.3509887016445750159374730744444913556373311135441750430175034126e-38f16); - verify("1", 1.f16); - // verify("7.0060e-46", 0.f16, std::errc::result_out_of_range); - // verify("3.4028234664e38", 0x1.fffffep+127f16); - // verify("3.4028234665e38", 0x1.fffffep+127f16); - // verify("3.4028234666e38", 0x1.fffffep+127f16); - // verify( - // "0." - // "000000000000000000000000000000000000011754943508222875079687365372222456" - // "778186655567720875215087517062784172594547271728515625", - // 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625f16); - // verify( - // "0." - // "000000000000000000000000000000000000000000001401298464324817070923729583" - // "289916131280261941876515771757068283889791082685860601486638188362121582" - // "03125", - // 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125f16); - // verify( - // "0." - // "000000000000000000000000000000000000023509885615147285834557659820715330" - // "266457179855179808553659262368500061299303460771170648513361811637878417" - // "96875", - // 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875f16); - // verify( - // "0." - // "000000000000000000000000000000000000011754942106924410754870294448492873" - // "488270524287458933338571745305715888704756189042655023513361811637878417" - // "96875", - // 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875f16); -} -#endif - -#ifdef __STDCPP_BFLOAT16_T__ -TEST_CASE("bfloat16.inf") { - verify("INF", std::numeric_limits::infinity()); - verify("-INF", -std::numeric_limits::infinity()); - verify("INFINITY", std::numeric_limits::infinity()); - verify("-INFINITY", -std::numeric_limits::infinity()); - verify("infinity", std::numeric_limits::infinity()); - verify("-infinity", -std::numeric_limits::infinity()); - verify("inf", std::numeric_limits::infinity()); - verify("-inf", -std::numeric_limits::infinity()); - verify("1234456789012345678901234567890e9999999999999999999999999999", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("2e3000", std::numeric_limits::infinity(), - std::errc::result_out_of_range); - verify("3.5028234666e38", std::numeric_limits::infinity(), - std::errc::result_out_of_range); -} - -TEST_CASE("bfloat16.general") { - // max - verify("338953138925153547590470800371487866880", 0x1.fep+127bf16); - // -max - verify("-338953138925153547590470800371487866880", -0x1.fep+127bf16); - // min - verify( - "0." - "000000000000000000000000000000000000011754943508222875079687365372222456" - "778186655567720875215087517062784172594547271728515625", - 0x1p-126bf16); - verify("1." - "175494350822287507968736537222245677818665556772087521508751706278417" - "2594" - "547271728515625e-38", - 0x1p-126bf16); - // denorm_min - verify("0." - "000000000000000000000000000000000000000091835496157991211560057541970" - "4879" - "435795832466228193376178712270530013483949005603790283203125", - 0x1p-133bf16); - verify("9." - "183549615799121156005754197048794357958324662281933761787122705300134" - "8394" - "9005603790283203125e-41", - 0x1p-133bf16); - // -min - verify( - "-0." - "000000000000000000000000000000000000011754943508222875079687365372222456" - "778186655567720875215087517062784172594547271728515625", - -0x1p-126bf16); - verify( - "-1." - "175494350822287507968736537222245677818665556772087521508751706278417259" - "4547271728515625e-38", - -0x1p-126bf16); - // -denorm_min - verify("-0" - ".00000000000000000000000000000000000000009183549615799121156005754197" - "0487" - "9435795832466228193376178712270530013483949005603790283203125", - -0x1p-133bf16); - verify("-9" - ".18354961579912115600575419704879435795832466228193376178712270530013" - "4839" - "49005603790283203125e-41", - -0x1p-133bf16); - - verify("-1e-999", -0.0bf16, std::errc::result_out_of_range); - verify_runtime( - "1." - "175494350822287507968736537222245677818665556772087521508751706278417" - "2594547271728515625", - 0x1.2cp+0bf16); - verify_runtime(append_zeros("1." - "175494350822287507968736537222245677818665556772" - "0875215087517062784172594547271728515625", - 655), - 0x1.2cp+0bf16); - verify_runtime(append_zeros("1." - "175494350822287507968736537222245677818665556772" - "0875215087517062784172594547271728515625", - 656), - 0x1.2cp+0bf16); - verify_runtime(append_zeros("1." - "175494350822287507968736537222245677818665556772" - "0875215087517062784172594547271728515625", - 1000), - 0x1.2cp+0bf16); - verify_runtime(append_zeros("1." - "175494350822287507968736537222245677818665556772" - "0875215087517062784172594547271728515625", - 655) + - std::string("e-38"), - 0x1p-126bf16); - verify_runtime(append_zeros("1." - "175494350822287507968736537222245677818665556772" - "0875215087517062784172594547271728515625", - 656) + - std::string("e-38"), - 0x1p-126bf16); - verify_runtime(append_zeros("1." - "175494350822287507968736537222245677818665556772" - "0875215087517062784172594547271728515625", - 1000) + - std::string("e-38"), - 0x1p-126bf16); - verify("-0", -0.0bf16); - // verify("1090544144181609348835077142190", 0x1.b877ap+99bf16); - // verify("1.1754943508e-38", 1.1754943508e-38bf16); - verify("30219.0830078125", 30219.0830078125bf16); - verify("16252921.5", 16252921.5bf16); - verify("5322519.25", 5322519.25bf16); - verify("3900245.875", 3900245.875bf16); - verify("1510988.3125", 1510988.3125bf16); - verify("782262.28125", 782262.28125bf16); - verify("328381.484375", 328381.484375bf16); - verify("156782.0703125", 156782.0703125bf16); - verify("85003.24609375", 85003.24609375bf16); - verify("17419.6494140625", 17419.6494140625bf16); - verify("15498.36376953125", 15498.36376953125bf16); - verify("6318.580322265625", 6318.580322265625bf16); - verify("2525.2840576171875", 2525.2840576171875bf16); - verify("1370.9265747070312", 1370.9265747070312bf16); - verify("936.3702087402344", 936.3702087402344bf16); - verify("411.88682556152344", 411.88682556152344bf16); - verify("206.50310516357422", 206.50310516357422bf16); - verify("124.16878890991211", 124.16878890991211bf16); - verify("50.811574935913086", 50.811574935913086bf16); - verify("17.486443519592285", 17.486443519592285bf16); - verify("13.91745138168335", 13.91745138168335bf16); - verify("7.5464513301849365", 0x1.e2f90ep+2bf16); - verify("2.687217116355896", 2.687217116355896bf16); - verify("1.1877630352973938", 0x1.30113ep+0bf16); - verify("0.7622503340244293", 0.7622503340244293bf16); - verify("0.30531780421733856", 0x1.38a53ap-2bf16); - verify("0.21791061013936996", 0x1.be47eap-3bf16); - verify("0.09289376810193062", 0x1.7c7e2ep-4bf16); - verify("0.03706067614257336", 0.03706067614257336bf16); - verify("0.028068351559340954", 0.028068351559340954bf16); - verify("0.012114629615098238", 0x1.8cf8e2p-7bf16); - verify("0.004221370676532388", 0x1.14a6dap-8bf16); - verify("0.002153817447833717", 0.002153817447833717bf16); - verify("0.0015924838953651488", 0x1.a175cap-10bf16); - verify("0.0008602388261351734", 0.0008602388261351734bf16); - verify("0.00036393293703440577", 0x1.7d9c82p-12bf16); - verify("0.00013746770127909258", 0.00013746770127909258bf16); - verify("16407.9462890625", 16407.9462890625bf16); - // verify("1.1754947011469036e-38", 0x1.000006p-126bf16); - // verify("7.0064923216240854e-46", 0x1p-149bf16); - // verify("8388614.5", 8388614.5bf16); - verify("0e9999999999999999999999999999", 0.bf16); - // verify( - // "4.7019774032891500318749461488889827112746622270883500860350068251e-38", - // 4.7019774032891500318749461488889827112746622270883500860350068251e-38bf16); - verify( - "3." - "141592653589793238462643383279502884197169399375105820974944592307816406" - "2862089986280348253421170679", - 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679bf16); - // verify( - // "2.3509887016445750159374730744444913556373311135441750430175034126e-38", - // 2.3509887016445750159374730744444913556373311135441750430175034126e-38bf16); - verify("1", 1.bf16); - verify("7.0060e-46", 0.bf16, std::errc::result_out_of_range); - verify("3.388e+38", 0x1.fep+127bf16); - verify("3.389e+38", 0x1.fep+127bf16); - verify("3.390e+38", 0x1.fep+127bf16); - // verify( - // "0." - // "000000000000000000000000000000000000011754943508222875079687365372222456" - // "778186655567720875215087517062784172594547271728515625", - // 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625bf16); - // verify( - // "0." - // "000000000000000000000000000000000000000000001401298464324817070923729583" - // "289916131280261941876515771757068283889791082685860601486638188362121582" - // "03125", - // 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125bf16); - // verify( - // "0." - // "000000000000000000000000000000000000023509885615147285834557659820715330" - // "266457179855179808553659262368500061299303460771170648513361811637878417" - // "96875", - // 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875bf16); - // verify( - // "0." - // "000000000000000000000000000000000000011754942106924410754870294448492873" - // "488270524287458933338571745305715888704756189042655023513361811637878417" - // "96875", - // 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875bf16); -} -#endif - -template -void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent, - T actual, U expected) { - static_assert(std::is_same::value, - "expected and actual types must match"); - - INFO("m * 10^e=" << mantissa << " * 10^" << decimal_exponent - << "\n" - " expected=" - << fHexAndDec(expected) << "\n" - << " ..actual=" << fHexAndDec(actual) << "\n" - << " expected mantissa=" - << iHexAndDec(get_mantissa(expected)) << "\n" - << " ..actual mantissa=" << iHexAndDec(get_mantissa(actual)) - << "\n"); - CHECK_EQ(actual, expected); -} - -template -T calculate_integer_times_pow10_expected_result(Int mantissa, - int decimal_exponent) { - std::string constructed_string = - std::to_string(mantissa) + "e" + std::to_string(decimal_exponent); - T expected_result; - const auto result = fast_float::from_chars( - constructed_string.data(), - constructed_string.data() + constructed_string.size(), expected_result); - if (result.ec != std::errc()) - INFO("Failed to parse: " << constructed_string); - return expected_result; -} - -template -void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent, - double expected) { - static_assert(std::is_integral::value); - - // the "default" overload - const double actual = - fast_float::integer_times_pow10(mantissa, decimal_exponent); - - verify_integer_times_pow10_result(mantissa, decimal_exponent, actual, - expected); -} - -template -void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) { - static_assert(std::is_integral::value); - - const auto expected_result = - calculate_integer_times_pow10_expected_result(mantissa, - decimal_exponent); - - verify_integer_times_pow10_dflt(mantissa, decimal_exponent, expected_result); -} - -template -void verify_integer_times_pow10(Int mantissa, int decimal_exponent, - T expected) { - static_assert(std::is_floating_point::value); - static_assert(std::is_integral::value); - - // explicit specialization - const auto actual = - fast_float::integer_times_pow10(mantissa, decimal_exponent); - - verify_integer_times_pow10_result(mantissa, decimal_exponent, actual, - expected); -} - -template -void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { - static_assert(std::is_floating_point::value); - static_assert(std::is_integral::value); - - const auto expected_result = calculate_integer_times_pow10_expected_result( - mantissa, decimal_exponent); - - verify_integer_times_pow10(mantissa, decimal_exponent, expected_result); -} - -namespace all_supported_types { -template -void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { - static_assert(std::is_integral::value); - - // verify the "default" overload - verify_integer_times_pow10_dflt(mantissa, decimal_exponent); - - // verify explicit specializations - ::verify_integer_times_pow10(mantissa, decimal_exponent); - ::verify_integer_times_pow10(mantissa, decimal_exponent); -#if defined(__STDCPP_FLOAT64_T__) - ::verify_integer_times_pow10(mantissa, decimal_exponent); -#endif -#if defined(__STDCPP_FLOAT32_T__) - ::verify_integer_times_pow10(mantissa, decimal_exponent); -#endif -#if defined(__STDCPP_FLOAT16_T__) - ::verify_integer_times_pow10(mantissa, decimal_exponent); -#endif -#if defined(__STDCPP_BFLOAT16_T__) - ::verify_integer_times_pow10(mantissa, decimal_exponent); -#endif -} -} // namespace all_supported_types - -TEST_CASE("integer_times_pow10") { - /* explicitly verifying API with different types of integers */ - // double (the "default" overload) - verify_integer_times_pow10_dflt(31, -1, 3.1); - verify_integer_times_pow10_dflt(-31, -1, -3.1); - verify_integer_times_pow10_dflt(31, -1, 3.1); - verify_integer_times_pow10_dflt(31415, -4, 3.1415); - verify_integer_times_pow10_dflt(-31415, -4, -3.1415); - verify_integer_times_pow10_dflt(31415, -4, 3.1415); - verify_integer_times_pow10_dflt(314159265, -8, 3.14159265); - verify_integer_times_pow10_dflt(-314159265, -8, -3.14159265); - verify_integer_times_pow10_dflt(3141592653, -9, 3.141592653); - verify_integer_times_pow10_dflt(314159265, -8, 3.14159265); - verify_integer_times_pow10_dflt(-314159265, -8, -3.14159265); - verify_integer_times_pow10_dflt(3141592653, -9, 3.141592653); - verify_integer_times_pow10_dflt(3141592653589793238, -18, - 3.141592653589793238); - verify_integer_times_pow10_dflt(-3141592653589793238, -18, - -3.141592653589793238); - verify_integer_times_pow10_dflt(3141592653589793238, -18, - 3.141592653589793238); - verify_integer_times_pow10_dflt(3141592653589793238, -18, - 3.141592653589793238); - verify_integer_times_pow10_dflt(-3141592653589793238, -18, - -3.141592653589793238); - verify_integer_times_pow10_dflt(3141592653589793238, -18, - 3.141592653589793238); - // double (explicit specialization) - verify_integer_times_pow10(31, -1, 3.1); - verify_integer_times_pow10(-31, -1, -3.1); - verify_integer_times_pow10(31, -1, 3.1); - verify_integer_times_pow10(31415, -4, 3.1415); - verify_integer_times_pow10(-31415, -4, -3.1415); - verify_integer_times_pow10(31415, -4, 3.1415); - verify_integer_times_pow10(314159265, -8, 3.14159265); - verify_integer_times_pow10(-314159265, -8, -3.14159265); - verify_integer_times_pow10(3141592653, -9, 3.141592653); - verify_integer_times_pow10(314159265, -8, 3.14159265); - verify_integer_times_pow10(-314159265, -8, -3.14159265); - verify_integer_times_pow10(3141592653, -9, - 3.141592653); - verify_integer_times_pow10(3141592653589793238, -18, - 3.141592653589793238); - verify_integer_times_pow10(-3141592653589793238, -18, - -3.141592653589793238); - verify_integer_times_pow10(3141592653589793238, -18, - 3.141592653589793238); - verify_integer_times_pow10(3141592653589793238, -18, - 3.141592653589793238); - verify_integer_times_pow10(-3141592653589793238, -18, - -3.141592653589793238); - verify_integer_times_pow10( - 3141592653589793238, -18, 3.141592653589793238); - // float (explicit specialization) - verify_integer_times_pow10(31, -1, 3.1f); - verify_integer_times_pow10(-31, -1, -3.1f); - verify_integer_times_pow10(31, -1, 3.1f); - verify_integer_times_pow10(31415, -4, 3.1415f); - verify_integer_times_pow10(-31415, -4, -3.1415f); - verify_integer_times_pow10(31415, -4, 3.1415f); - verify_integer_times_pow10(314159265, -8, 3.14159265f); - verify_integer_times_pow10(-314159265, -8, -3.14159265f); - verify_integer_times_pow10(3141592653, -9, 3.14159265f); - verify_integer_times_pow10(314159265, -8, 3.14159265f); - verify_integer_times_pow10(-314159265, -8, -3.14159265f); - verify_integer_times_pow10(3141592653, -9, 3.14159265f); - verify_integer_times_pow10(3141592653589793238, -18, - 3.141592653589793238f); - verify_integer_times_pow10(-3141592653589793238, -18, - -3.141592653589793238f); - verify_integer_times_pow10(3141592653589793238, -18, - 3.141592653589793238f); - verify_integer_times_pow10(3141592653589793238, -18, - 3.141592653589793238f); - verify_integer_times_pow10(-3141592653589793238, -18, - -3.141592653589793238f); - verify_integer_times_pow10( - 3141592653589793238, -18, 3.141592653589793238f); - - for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) { - fesetround(mode); - INFO("fesetround(): " << std::string{round_name(mode)}); - - struct Guard { - ~Guard() { fesetround(FE_TONEAREST); } - } guard; - - namespace all = all_supported_types; - - all::verify_integer_times_pow10(0, 0); - all::verify_integer_times_pow10(1, 0); - all::verify_integer_times_pow10(0, 1); - all::verify_integer_times_pow10(1, 1); - all::verify_integer_times_pow10(-1, 0); - all::verify_integer_times_pow10(0, -1); - all::verify_integer_times_pow10(-1, -1); - all::verify_integer_times_pow10(-1, 1); - all::verify_integer_times_pow10(1, -1); - - /* denormal min */ - verify_integer_times_pow10_dflt(49406564584124654, -340, - std::numeric_limits::denorm_min()); - verify_integer_times_pow10( - 49406564584124654, -340, std::numeric_limits::denorm_min()); - verify_integer_times_pow10(14012984, -52, - std::numeric_limits::denorm_min()); - - /* normal min */ - verify_integer_times_pow10_dflt(22250738585072014, -324, - std::numeric_limits::min()); - verify_integer_times_pow10(22250738585072014, -324, - std::numeric_limits::min()); - verify_integer_times_pow10(11754944, -45, - std::numeric_limits::min()); - - /* max */ - verify_integer_times_pow10_dflt(17976931348623158, 292, - std::numeric_limits::max()); - verify_integer_times_pow10(17976931348623158, 292, - std::numeric_limits::max()); - verify_integer_times_pow10(34028235, 31, - std::numeric_limits::max()); - - /* underflow */ - // (DBL_TRUE_MIN / 2) underflows to 0 - verify_integer_times_pow10_dflt(49406564584124654 / 2, -340, 0.); - verify_integer_times_pow10(49406564584124654 / 2, -340, 0.); - // (FLT_TRUE_MIN / 2) underflows to 0 - verify_integer_times_pow10(14012984 / 2, -52, 0.f); - - /* rounding to denormal min */ - // (DBL_TRUE_MIN / 2 + 0.0000000000000001e-324) rounds to DBL_TRUE_MIN - verify_integer_times_pow10_dflt(49406564584124654 / 2 + 1, -340, - std::numeric_limits::denorm_min()); - verify_integer_times_pow10( - 49406564584124654 / 2 + 1, -340, - std::numeric_limits::denorm_min()); - // (FLT_TRUE_MIN / 2 + 0.0000001e-45) rounds to FLT_TRUE_MIN - verify_integer_times_pow10(14012984 / 2 + 1, -52, - std::numeric_limits::denorm_min()); - - /* overflow */ - // (DBL_MAX + 0.0000000000000001e308) overflows to infinity - verify_integer_times_pow10_dflt(17976931348623158 + 1, 292, - std::numeric_limits::infinity()); - verify_integer_times_pow10(17976931348623158 + 1, 292, - std::numeric_limits::infinity()); - // (DBL_MAX + 0.00000000000000001e308) overflows to infinity - verify_integer_times_pow10_dflt(179769313486231580 + 1, 291, - std::numeric_limits::infinity()); - verify_integer_times_pow10(179769313486231580 + 1, 291, - std::numeric_limits::infinity()); - // (FLT_MAX + 0.0000001e38) overflows to infinity - verify_integer_times_pow10(34028235 + 1, 31, - std::numeric_limits::infinity()); - // (FLT_MAX + 0.00000007e38) overflows to infinity - verify_integer_times_pow10(340282350 + 7, 30, - std::numeric_limits::infinity()); - - // loosely verifying correct rounding of 1 to 64 bits - // worth of significant digits - all::verify_integer_times_pow10(1, 42); - all::verify_integer_times_pow10(1, -42); - all::verify_integer_times_pow10(12, 42); - all::verify_integer_times_pow10(12, -42); - all::verify_integer_times_pow10(123, 42); - all::verify_integer_times_pow10(123, -42); - all::verify_integer_times_pow10(1234, 42); - all::verify_integer_times_pow10(1234, -42); - all::verify_integer_times_pow10(12345, 42); - all::verify_integer_times_pow10(12345, -42); - all::verify_integer_times_pow10(123456, 42); - all::verify_integer_times_pow10(123456, -42); - all::verify_integer_times_pow10(1234567, 42); - all::verify_integer_times_pow10(1234567, -42); - all::verify_integer_times_pow10(12345678, 42); - all::verify_integer_times_pow10(12345678, -42); - all::verify_integer_times_pow10(123456789, 42); - all::verify_integer_times_pow10(1234567890, 42); - all::verify_integer_times_pow10(1234567890, -42); - all::verify_integer_times_pow10(12345678901, 42); - all::verify_integer_times_pow10(12345678901, -42); - all::verify_integer_times_pow10(123456789012, 42); - all::verify_integer_times_pow10(123456789012, -42); - all::verify_integer_times_pow10(1234567890123, 42); - all::verify_integer_times_pow10(1234567890123, -42); - all::verify_integer_times_pow10(12345678901234, 42); - all::verify_integer_times_pow10(12345678901234, -42); - all::verify_integer_times_pow10(123456789012345, 42); - all::verify_integer_times_pow10(123456789012345, -42); - all::verify_integer_times_pow10(1234567890123456, 42); - all::verify_integer_times_pow10(1234567890123456, -42); - all::verify_integer_times_pow10(12345678901234567, 42); - all::verify_integer_times_pow10(12345678901234567, -42); - all::verify_integer_times_pow10(123456789012345678, 42); - all::verify_integer_times_pow10(123456789012345678, -42); - all::verify_integer_times_pow10(1234567890123456789, 42); - all::verify_integer_times_pow10(1234567890123456789, -42); - all::verify_integer_times_pow10(12345678901234567890ull, 42); - all::verify_integer_times_pow10(12345678901234567890ull, -42); - all::verify_integer_times_pow10(std::numeric_limits::max(), 42); - all::verify_integer_times_pow10(std::numeric_limits::max(), -42); - all::verify_integer_times_pow10(std::numeric_limits::max(), 42); - all::verify_integer_times_pow10(std::numeric_limits::max(), -42); - } -} \ No newline at end of file diff --git a/tests/bloat_analysis/CMakeLists.txt b/tests/bloat_analysis/CMakeLists.txt deleted file mode 100644 index 435f485..0000000 --- a/tests/bloat_analysis/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_executable(bloaty main.cpp a1.cpp a2.cpp a3.cpp a4.cpp a4.cpp a5.cpp a6.cpp a7.cpp a8.cpp a9.cpp a10.cpp) -target_link_libraries(bloaty PUBLIC fast_float) - -add_executable(bloatyref main_ref.cpp) -target_link_libraries(bloatyref PUBLIC fast_float) \ No newline at end of file diff --git a/tests/bloat_analysis/a1.cpp b/tests/bloat_analysis/a1.cpp deleted file mode 100644 index 281f1aa..0000000 --- a/tests/bloat_analysis/a1.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get1(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 1; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a10.cpp b/tests/bloat_analysis/a10.cpp deleted file mode 100644 index 0838d53..0000000 --- a/tests/bloat_analysis/a10.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get10(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 10; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a2.cpp b/tests/bloat_analysis/a2.cpp deleted file mode 100644 index 60d8274..0000000 --- a/tests/bloat_analysis/a2.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get2(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 2; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a3.cpp b/tests/bloat_analysis/a3.cpp deleted file mode 100644 index f99361b..0000000 --- a/tests/bloat_analysis/a3.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get3(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 3; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a4.cpp b/tests/bloat_analysis/a4.cpp deleted file mode 100644 index acfbc9f..0000000 --- a/tests/bloat_analysis/a4.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get4(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 4; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a5.cpp b/tests/bloat_analysis/a5.cpp deleted file mode 100644 index 67dae63..0000000 --- a/tests/bloat_analysis/a5.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get5(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 5; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a6.cpp b/tests/bloat_analysis/a6.cpp deleted file mode 100644 index b92dc10..0000000 --- a/tests/bloat_analysis/a6.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get6(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 6; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a7.cpp b/tests/bloat_analysis/a7.cpp deleted file mode 100644 index be8154a..0000000 --- a/tests/bloat_analysis/a7.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get7(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 7; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a8.cpp b/tests/bloat_analysis/a8.cpp deleted file mode 100644 index 79bffeb..0000000 --- a/tests/bloat_analysis/a8.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get8(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 8; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/a9.cpp b/tests/bloat_analysis/a9.cpp deleted file mode 100644 index 966732b..0000000 --- a/tests/bloat_analysis/a9.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "fast_float/fast_float.h" - -double get9(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 9; - } - return result_value; -} \ No newline at end of file diff --git a/tests/bloat_analysis/main.cpp b/tests/bloat_analysis/main.cpp deleted file mode 100644 index ee07ae7..0000000 --- a/tests/bloat_analysis/main.cpp +++ /dev/null @@ -1,20 +0,0 @@ - - -double get1(char const *input); -double get2(char const *input); -double get3(char const *input); -double get4(char const *input); -double get5(char const *input); -double get6(char const *input); -double get7(char const *input); -double get8(char const *input); -double get9(char const *input); -double get10(char const *input); - -int main(int arg, char **argv) { - double x = get1(argv[0]) + get2(argv[0]) + get3(argv[0]) + get4(argv[0]) + - get5(argv[0]) + get6(argv[0]) + get7(argv[0]) + get8(argv[0]) + - get9(argv[0]) + get10(argv[0]); - - return int(x); -} \ No newline at end of file diff --git a/tests/bloat_analysis/main_ref.cpp b/tests/bloat_analysis/main_ref.cpp deleted file mode 100644 index 0ac21a8..0000000 --- a/tests/bloat_analysis/main_ref.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "fast_float/fast_float.h" - -double get(char const *input) { - double result_value; - auto result = - fast_float::from_chars(input, input + strlen(input), result_value); - if (result.ec != std::errc()) { - return 10; - } - return result_value; -} - -int main(int arg, char **argv) { - double x = get(argv[0]); - return int(x); -} \ No newline at end of file diff --git a/tests/build_tests/CMakeLists.txt b/tests/build_tests/CMakeLists.txt deleted file mode 100644 index da762eb..0000000 --- a/tests/build_tests/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(issue72) \ No newline at end of file diff --git a/tests/build_tests/issue72/CMakeLists.txt b/tests/build_tests/issue72/CMakeLists.txt deleted file mode 100644 index efe39a2..0000000 --- a/tests/build_tests/issue72/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_executable(issue72 main.cpp foo.cpp) -target_link_libraries(issue72 PUBLIC fast_float) \ No newline at end of file diff --git a/tests/build_tests/issue72/foo.cpp b/tests/build_tests/issue72/foo.cpp deleted file mode 100644 index c24e0c0..0000000 --- a/tests/build_tests/issue72/foo.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "test.h" - -void foo() {} \ No newline at end of file diff --git a/tests/build_tests/issue72/main.cpp b/tests/build_tests/issue72/main.cpp deleted file mode 100644 index 68d7f8f..0000000 --- a/tests/build_tests/issue72/main.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "test.h" - -int main() { return 0; } \ No newline at end of file diff --git a/tests/build_tests/issue72/test.h b/tests/build_tests/issue72/test.h deleted file mode 100644 index 550a31b..0000000 --- a/tests/build_tests/issue72/test.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "fast_float/fast_float.h" \ No newline at end of file diff --git a/tests/example_comma_test.cpp b/tests/example_comma_test.cpp deleted file mode 100644 index 79a8e1d..0000000 --- a/tests/example_comma_test.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -#include "fast_float/fast_float.h" -#include -#include -#include - -int main() { - std::string const input = "3,1416 xyz "; - double result; - fast_float::parse_options options{fast_float::chars_format::general, ','}; - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - if ((answer.ec != std::errc()) || ((result != 3.1416))) { - std::cerr << "parsing failure\n"; - return EXIT_FAILURE; - } - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/example_integer_times_pow10.cpp b/tests/example_integer_times_pow10.cpp deleted file mode 100644 index 0205c27..0000000 --- a/tests/example_integer_times_pow10.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "fast_float/fast_float.h" - -#include - -void default_overload() { - const uint64_t W = 12345678901234567; - const int Q = 23; - const double result = fast_float::integer_times_pow10(W, Q); - std::cout.precision(17); - std::cout << W << " * 10^" << Q << " = " << result << " (" - << (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n"; -} - -void double_specialization() { - const uint64_t W = 12345678901234567; - const int Q = 23; - const double result = fast_float::integer_times_pow10(W, Q); - std::cout.precision(17); - std::cout << "double: " << W << " * 10^" << Q << " = " << result << " (" - << (result == 12345678901234567e23 ? "==" : "!=") << "expected)\n"; -} - -void float_specialization() { - const uint64_t W = 12345678; - const int Q = 23; - const float result = fast_float::integer_times_pow10(W, Q); - std::cout.precision(9); - std::cout << "float: " << W << " * 10^" << Q << " = " << result << " (" - << (result == 12345678e23f ? "==" : "!=") << "expected)\n"; -} - -int main() { - default_overload(); - double_specialization(); - float_specialization(); -} diff --git a/tests/example_test.cpp b/tests/example_test.cpp deleted file mode 100644 index cefaf29..0000000 --- a/tests/example_test.cpp +++ /dev/null @@ -1,158 +0,0 @@ - -#include "fast_float/fast_float.h" -#include -#include -#include - -bool many() { - std::string const input = "234532.3426362,7869234.9823,324562.645"; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { - return false; - } - if (result != 234532.3426362) { - return false; - } - if (answer.ptr[0] != ',') { - return false; - } - answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), - result); - if (answer.ec != std::errc()) { - return false; - } - if (result != 7869234.9823) { - return false; - } - if (answer.ptr[0] != ',') { - return false; - } - answer = fast_float::from_chars(answer.ptr + 1, input.data() + input.size(), - result); - if (answer.ec != std::errc()) { - return false; - } - if (result != 324562.645) { - return false; - } - return true; -} - -void many_loop() { - std::string const input = "234532.3426362,7869234.9823,324562.645"; - double result; - char const *pointer = input.data(); - char const *end_pointer = input.data() + input.size(); - - while (pointer < end_pointer) { - auto answer = fast_float::from_chars(pointer, end_pointer, result); - if (answer.ec != std::errc()) { - std::cerr << "error while parsing" << std::endl; - break; - } - std::cout << "parsed: " << result << std::endl; - pointer = answer.ptr; - if ((answer.ptr < end_pointer) && (*pointer == ',')) { - pointer++; - } - } -} - -#if FASTFLOAT_IS_CONSTEXPR -// consteval forces compile-time evaluation of the function in C++20. -consteval double parse(std::string_view input) { - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { - return -1.0; - } - return result; -} - -// This function should compile to a function which -// merely returns 3.1415. -constexpr double constexptest() { return parse("3.1415 input"); } -#endif - -bool small() { - double result = -1; - std::string str = "3e-1000"; - auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result); - if (r.ec != std::errc::result_out_of_range) { - return false; - } - if (r.ptr != str.data() + 7) { - return false; - } - if (result != 0) { - return false; - } - printf("small values go to zero\n"); - return true; -} - -bool large() { - double result = -1; - std::string str = "3e1000"; - auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result); - if (r.ec != std::errc::result_out_of_range) { - return false; - } - if (r.ptr != str.data() + 6) { - return false; - } - if (result != std::numeric_limits::infinity()) { - return false; - } - printf("large values go to infinity\n"); - return true; -} - -int main() { - std::string input = "3.1416 xyz "; - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - if ((answer.ec != std::errc()) || ((result != 3.1416))) { - std::cerr << "parsing failure\n"; - return EXIT_FAILURE; - } - std::cout << "parsed the number " << result << std::endl; -#ifdef __STDCPP_FLOAT16_T__ - printf("16-bit float\n"); - // Parse as 16-bit float - std::float16_t parsed_16{}; - input = "10000e-1452"; - auto fast_float_r16 = fast_float::from_chars( - input.data(), input.data() + input.size(), parsed_16); - if (fast_float_r16.ec != std::errc() && - fast_float_r16.ec != std::errc::result_out_of_range) { - std::cerr << "16-bit fast_float parsing failure for: " + input + "\n"; - return false; - } - std::cout << "parsed the 16-bit value " << float(parsed_16) << std::endl; -#endif - if (!small()) { - printf("Bug\n"); - return EXIT_FAILURE; - } - if (!large()) { - printf("Bug\n"); - return EXIT_FAILURE; - } - - if (!many()) { - printf("Bug\n"); - return EXIT_FAILURE; - } - many_loop(); -#if FASTFLOAT_IS_CONSTEXPR - if constexpr (constexptest() != 3.1415) { - return EXIT_FAILURE; - } -#endif - return EXIT_SUCCESS; -} diff --git a/tests/exhaustive32.cpp b/tests/exhaustive32.cpp deleted file mode 100644 index 5e7de2d..0000000 --- a/tests/exhaustive32.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include -#include - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 64, "%.*e", - std::numeric_limits::max_digits10 - 1, d); - return buffer + written; -} - -void allvalues() { - char buffer[64]; - for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) { - float v; - if ((w % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint32_t word = uint32_t(w); - memcpy(&v, &word, sizeof(v)); - - { - char const *string_end = to_string(v, buffer); - float result_value; - auto result = fast_float::from_chars(buffer, string_end, result_value); - // Starting with version 4.0 for fast_float, we return result_out_of_range - // if the value is either too small (too close to zero) or too large - // (effectively infinity). So std::errc::result_out_of_range is normal for - // well-formed input strings. - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cerr << "parsing error ? " << buffer << std::endl; - abort(); - } - if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - abort(); - } - } else if (copysign(1, result_value) != copysign(1, v)) { - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << v << std::endl; - abort(); - } else if (result_value != v) { - std::cerr << "no match ? " << buffer << std::endl; - std::cout << "started with " << std::hexfloat << v << std::endl; - std::cout << "got back " << std::hexfloat << result_value << std::endl; - std::cout << std::dec; - abort(); - } - } - } - std::cout << std::endl; -} - -int main() { - allvalues(); - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/exhaustive32_64.cpp b/tests/exhaustive32_64.cpp deleted file mode 100644 index c453f28..0000000 --- a/tests/exhaustive32_64.cpp +++ /dev/null @@ -1,76 +0,0 @@ - -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 64, "%.*e", - std::numeric_limits::max_digits10 - 1, d); - return buffer + written; -} - -bool basic_test_64bit(std::string vals, double val) { - double result_value; - auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(), - result_value); - if (result.ec != std::errc() && result.ec != std::errc::result_out_of_range) { - std::cerr << " I could not parse " << vals << std::endl; - return false; - } - if (std::isnan(val)) { - if (!std::isnan(result_value)) { - std::cerr << vals << std::endl; - std::cerr << "not nan" << result_value << std::endl; - return false; - } - } else if (copysign(1, result_value) != copysign(1, val)) { - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << val << std::endl; - return false; - } else if (result_value != val) { - std::cerr << vals << std::endl; - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << val << std::endl; - std::cerr << std::dec; - std::cerr << "string: " << vals << std::endl; - return false; - } - return true; -} - -void all_32bit_values() { - char buffer[64]; - for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) { - float v32; - if ((w % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint32_t word = uint32_t(w); - memcpy(&v32, &word, sizeof(v32)); - double v = v32; - - { - char const *string_end = to_string(v, buffer); - std::string s(buffer, size_t(string_end - buffer)); - if (!basic_test_64bit(s, v)) { - return; - } - } - } - std::cout << std::endl; -} - -int main() { - all_32bit_values(); - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/exhaustive32_midpoint.cpp b/tests/exhaustive32_midpoint.cpp deleted file mode 100644 index 0b97e2e..0000000 --- a/tests/exhaustive32_midpoint.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) -// Anything at all that is related to cygwin, msys and so forth will -// always use this fallback because we cannot rely on it behaving as normal -// gcc. -#include -#include - -// workaround for CYGWIN -double cygwin_strtod_l(char const *start, char **end) { - double d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} - -float cygwin_strtof_l(char const *start, char **end) { - float d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} -#endif - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 64, "%.*e", - std::numeric_limits::max_digits10 - 1, d); - return buffer + written; -} - -void strtof_from_string(char const *st, float &d) { - char *pr = (char *)st; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtof_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtof_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtof_l(st, &pr, c_locale); -#endif - if (pr == st) { - throw std::runtime_error("bug in strtod_from_string"); - } -} - -bool allvalues() { - char buffer[64]; - for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) { - float v; - if ((w % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint32_t word = uint32_t(w); - memcpy(&v, &word, sizeof(v)); - if (std::isfinite(v)) { - float nextf = std::nextafterf(v, INFINITY); - if (copysign(1, v) != copysign(1, nextf)) { - continue; - } - if (!std::isfinite(nextf)) { - continue; - } - double v1{v}; - assert(float(v1) == v); - double v2{nextf}; - assert(float(v2) == nextf); - double midv{v1 + (v2 - v1) / 2}; - float expected_midv = float(midv); - - char const *string_end = to_string(midv, buffer); - float str_answer; - strtof_from_string(buffer, str_answer); - - float result_value; - auto result = fast_float::from_chars(buffer, string_end, result_value); - // Starting with version 4.0 for fast_float, we return result_out_of_range - // if the value is either too small (too close to zero) or too large - // (effectively infinity). So std::errc::result_out_of_range is normal for - // well-formed input strings. - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cerr << "parsing error ? " << buffer << std::endl; - return false; - } - if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - std::cerr << "v " << std::hexfloat << v << std::endl; - std::cerr << "v2 " << std::hexfloat << v2 << std::endl; - std::cerr << "midv " << std::hexfloat << midv << std::endl; - std::cerr << "expected_midv " << std::hexfloat << expected_midv - << std::endl; - return false; - } - } else if (copysign(1, result_value) != copysign(1, v)) { - std::cerr << buffer << std::endl; - std::cerr << "v " << std::hexfloat << v << std::endl; - std::cerr << "v2 " << std::hexfloat << v2 << std::endl; - std::cerr << "midv " << std::hexfloat << midv << std::endl; - std::cerr << "expected_midv " << std::hexfloat << expected_midv - << std::endl; - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << v << std::endl; - return false; - } else if (result_value != str_answer) { - std::cerr << "no match ? " << buffer << std::endl; - std::cerr << "v " << std::hexfloat << v << std::endl; - std::cerr << "v2 " << std::hexfloat << v2 << std::endl; - std::cerr << "midv " << std::hexfloat << midv << std::endl; - std::cerr << "expected_midv " << std::hexfloat << expected_midv - << std::endl; - std::cout << "started with " << std::hexfloat << midv << std::endl; - std::cout << "round down to " << std::hexfloat << str_answer - << std::endl; - std::cout << "got back " << std::hexfloat << result_value << std::endl; - std::cout << std::dec; - return false; - } - } - } - std::cout << std::endl; - return true; -} - -inline void Assert(bool Assertion) { -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - if (!Assertion) { - std::cerr << "Omitting hard failure on msys/cygwin/sun systems."; - } -#else - if (!Assertion) { - throw std::runtime_error("bug"); - } -#endif -} - -int main() { -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - std::cout << "Warning: msys/cygwin or solaris detected. This particular test " - "is likely to generate false failures due to our reliance on " - "the underlying runtime library as a gold standard." - << std::endl; -#endif - Assert(allvalues()); - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/fast_int.cpp b/tests/fast_int.cpp deleted file mode 100644 index 94e76fd..0000000 --- a/tests/fast_int.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -#ifndef __cplusplus -#error fastfloat requires a C++ compiler -#endif - -// We want to enable the tests only for C++17 and above. -#ifndef FASTFLOAT_CPLUSPLUS -#if defined(_MSVC_LANG) && !defined(__clang__) -#define FASTFLOAT_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG) -#else -#define FASTFLOAT_CPLUSPLUS __cplusplus -#endif -#endif - -#if FASTFLOAT_CPLUSPLUS >= 201703L - -#include -#include -#include -#include -#include -#include "fast_float/fast_float.h" -#include - -/* -all tests conducted are to check fast_float::from_chars functionality with int -and unsigned test cases include: int basic tests - numbers only, numbers with -strings behind, decimals, negative numbers unsigned basic tests - numbers only, -numbers with strings behind, decimals int invalid tests - strings only, strings -with numbers behind, space in front of number, plus sign in front of number -unsigned invalid tests - strings only, strings with numbers behind, space in -front of number, plus/minus sign in front of number int out of range tests - -numbers exceeding int bit size for 8, 16, 32, and 64 bits unsigned out of range -tests - numbers exceeding unsigned bit size 8, 16, 32, and 64 bits int pointer -tests - points to first character that is not recognized as int unsigned pointer -tests - points to first character that is not recognized as unsigned -int/unsigned base 2 tests - numbers are converted from binary to decimal -octal tests - numbers are converted from octal to decimal -hex tests - numbers are converted from hex to decimal (Note: 0x and 0X are -considered invalid) invalid base tests - any base not within 2-36 is invalid out -of range base tests - numbers exceeding int/unsigned bit size after converted -from base (Note: only 64 bit int and unsigned are tested) within range base -tests - max/min numbers are still within int/unsigned bit size after converted -from base (Note: only 64 bit int and unsigned are tested) leading zeros tests - -ignores all zeroes in front of valid number after converted from base -*/ - -int main() { - // int basic test - std::vector const int_basic_test_expected{0, 10, -40, 1001, 9}; - std::vector const int_basic_test{"0", "10 ", "-40", - "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < int_basic_test.size(); ++i) { - auto const f = int_basic_test[i]; - int result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - if (answer.ec == std::errc::invalid_argument) { - std::cerr << "could not convert to int for input: \"" << f - << "\" because of invalid argument" << std::endl; - } else if (answer.ec == std::errc::result_out_of_range) { - std::cerr << "could not convert to int for input: \"" << f - << "\" because it's out of range" << std::endl; - } else { - std::cerr << "could not convert to int for input: \"" << f - << "\" because of an unknown error" << std::endl; - } - return EXIT_FAILURE; - } else if (result != int_basic_test_expected[i]) { - std::cerr << "result \"" << f << "\" did not match with expected int: " - << int_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned basic test - std::vector const unsigned_basic_test_expected{0, 10, 1001, 9}; - std::vector const unsigned_basic_test{ - "0", "10 ", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < unsigned_basic_test.size(); ++i) { - auto const &f = unsigned_basic_test[i]; - unsigned result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to unsigned for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != unsigned_basic_test_expected[i]) { - std::cerr << "result \"" << f - << "\" did not match with expected unsigned: " - << unsigned_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // char basic test - std::vector const char_basic_test_expected{0, 10, 40, 100, 9}; - std::vector const char_basic_test{"0", "10 ", "40", - "100 with text", "9.999"}; - - for (std::size_t i = 0; i < char_basic_test.size(); ++i) { - auto const f = char_basic_test[i]; - char result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - std::cerr << "could not convert to char for input: \"" << f - << "\" because of invalid argument" << std::endl; - return EXIT_FAILURE; - } else if (result != char_basic_test_expected[i]) { - std::cerr << "result \"" << f << "\" did not match with expected char: " - << static_cast(char_basic_test_expected[i]) << std::endl; - return EXIT_FAILURE; - } - } - - // short basic test - std::vector const short_basic_test_expected{0, 10, -40, 1001, 9}; - std::vector const short_basic_test{ - "0", "10 ", "-40", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < short_basic_test.size(); ++i) { - auto const f = short_basic_test[i]; - short result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - std::cerr << "could not convert to short for input: \"" << f - << "\" because of invalid argument" << std::endl; - return EXIT_FAILURE; - } else if (result != short_basic_test_expected[i]) { - std::cerr << "result \"" << f << "\" did not match with expected short: " - << short_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // long basic test - std::vector const long_basic_test_expected{0, 10, -40, 1001, 9}; - std::vector const long_basic_test{ - "0", "10 ", "-40", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < long_basic_test.size(); ++i) { - auto const f = long_basic_test[i]; - long result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - std::cerr << "could not convert to long for input: \"" << f - << "\" because of invalid argument" << std::endl; - return EXIT_FAILURE; - } else if (result != long_basic_test_expected[i]) { - std::cerr << "result \"" << f << "\" did not match with expected long: " - << long_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // long long basic test - std::vector const long_long_basic_test_expected{0, 10, -40, 1001, - 9}; - std::vector const long_long_basic_test{ - "0", "10 ", "-40", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < long_long_basic_test.size(); ++i) { - auto const f = long_long_basic_test[i]; - long long result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - std::cerr << "could not convert to long long for input: \"" << f - << "\" because of invalid argument" << std::endl; - return EXIT_FAILURE; - } else if (result != long_long_basic_test_expected[i]) { - std::cerr << "result \"" << f - << "\" did not match with expected long long: " - << long_long_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned char basic test - std::vector const unsigned_char_basic_test_expected{0, 10, 100, - 9}; - std::vector const unsigned_char_basic_test{ - "0", "10 ", "100 with text", "9.999"}; - - for (std::size_t i = 0; i < unsigned_char_basic_test.size(); ++i) { - auto const &f = unsigned_char_basic_test[i]; - unsigned char result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to unsigned char for input: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } else if (result != unsigned_char_basic_test_expected[i]) { - std::cerr << "result \"" << f - << "\" did not match with expected unsigned char: " - << static_cast(unsigned_char_basic_test_expected[i]) - << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned short basic test - std::vector const unsigned_short_basic_test_expected{0, 10, - 1001, 9}; - std::vector const unsigned_short_basic_test{ - "0", "10 ", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < unsigned_short_basic_test.size(); ++i) { - auto const &f = unsigned_short_basic_test[i]; - unsigned short result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to unsigned short for input: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } else if (result != unsigned_short_basic_test_expected[i]) { - std::cerr << "result \"" << f - << "\" did not match with expected unsigned short: " - << unsigned_short_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned long basic test - std::vector const unsigned_long_basic_test_expected{0, 10, - 1001, 9}; - std::vector const unsigned_long_basic_test{ - "0", "10 ", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < unsigned_long_basic_test.size(); ++i) { - auto const &f = unsigned_long_basic_test[i]; - unsigned long result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to unsigned long for input: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } else if (result != unsigned_long_basic_test_expected[i]) { - std::cerr << "result \"" << f - << "\" did not match with expected unsigned long: " - << unsigned_long_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned long long basic test - std::vector const unsigned_long_long_basic_test_expected{ - 0, 10, 1001, 9}; - std::vector const unsigned_long_long_basic_test{ - "0", "10 ", "1001 with text", "9.999"}; - - for (std::size_t i = 0; i < unsigned_long_long_basic_test.size(); ++i) { - auto const &f = unsigned_long_long_basic_test[i]; - unsigned long long result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to unsigned long long for input: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } else if (result != unsigned_long_long_basic_test_expected[i]) { - std::cerr << "result \"" << f - << "\" did not match with expected unsigned long long: " - << unsigned_long_long_basic_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // bool basic test - std::vector const bool_basic_test_expected{false, true}; - std::vector const bool_basic_test{"0", "1"}; - - for (std::size_t i = 0; i < bool_basic_test.size(); ++i) { - auto const &f = bool_basic_test[i]; - bool result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to bool for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != bool_basic_test_expected[i]) { - std::cerr << "result \"" << f << "\" did not match with expected bool: " - << (bool_basic_test_expected[i] ? "true" : "false") - << std::endl; - return EXIT_FAILURE; - } - } - - // int invalid error test - std::vector const int_invalid_argument_test{ - "text", "text with 1002", "+50", " 50"}; - - for (std::size_t i = 0; i < int_invalid_argument_test.size(); ++i) { - auto const &f = int_invalid_argument_test[i]; - int result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::invalid_argument) { - std::cerr << "expected error should be 'invalid_argument' for: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned invalid error test - std::vector const unsigned_invalid_argument_test{ - "text", "text with 1002", "+50", " 50", "-50"}; - - for (std::size_t i = 0; i < unsigned_invalid_argument_test.size(); ++i) { - auto const &f = unsigned_invalid_argument_test[i]; - unsigned result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::invalid_argument) { - std::cerr << "expected error should be 'invalid_argument' for: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int out of range error test #1 (8 bit) - std::vector const int_out_of_range_test_1{ - "2000000000000000000000", "128", "-129"}; - - for (std::size_t i = 0; i < int_out_of_range_test_1.size(); ++i) { - auto const &f = int_out_of_range_test_1[i]; - int8_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int out of range error test #2 (16 bit) - std::vector const int_out_of_range_test_2{ - "2000000000000000000000", "32768", "-32769"}; - - for (std::size_t i = 0; i < int_out_of_range_test_2.size(); ++i) { - auto const &f = int_out_of_range_test_2[i]; - int16_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int out of range error test #3 (32 bit) - std::vector const int_out_of_range_test_3{ - "2000000000000000000000", "2147483648", "-2147483649"}; - - for (std::size_t i = 0; i < int_out_of_range_test_3.size(); ++i) { - auto const &f = int_out_of_range_test_3[i]; - int32_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int out of range error test #4 (64 bit) - std::vector const int_out_of_range_test_4{ - "2000000000000000000000", "9223372036854775808", "-9223372036854775809"}; - - for (std::size_t i = 0; i < int_out_of_range_test_4.size(); ++i) { - auto const &f = int_out_of_range_test_4[i]; - int64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned out of range error test #1 (8 bit) - std::vector const unsigned_out_of_range_test_1{ - "2000000000000000000000", "256"}; - - for (std::size_t i = 0; i < unsigned_out_of_range_test_1.size(); ++i) { - auto const &f = unsigned_out_of_range_test_1[i]; - uint8_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned out of range error test #2 (16 bit) - std::vector const unsigned_out_of_range_test_2{ - "2000000000000000000000", "65536"}; - - for (std::size_t i = 0; i < unsigned_out_of_range_test_2.size(); ++i) { - auto const &f = unsigned_out_of_range_test_2[i]; - uint16_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned out of range error test #3 (32 bit) - std::vector const unsigned_out_of_range_test_3{ - "2000000000000000000000", "4294967296"}; - - for (std::size_t i = 0; i < unsigned_out_of_range_test_3.size(); ++i) { - auto const &f = unsigned_out_of_range_test_3[i]; - uint32_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned out of range error test #4 (64 bit) - std::vector const unsigned_out_of_range_test_4{ - "2000000000000000000000", "18446744073709551616"}; - - for (std::size_t i = 0; i < unsigned_out_of_range_test_4.size(); ++i) { - auto const &f = unsigned_out_of_range_test_4[i]; - uint64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int pointer test #1 (only numbers) - std::vector const int_pointer_test_1{"0", "010", "-40"}; - - for (std::size_t i = 0; i < int_pointer_test_1.size(); ++i) { - auto const &f = int_pointer_test_1[i]; - int result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to int for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (strcmp(answer.ptr, "") != 0) { - std::cerr << "ptr of result " << f - << " did not match with expected ptr: \"\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int pointer test #2 (string behind numbers) - std::string_view const int_pointer_test_2 = "1001 with text"; - - auto const &f2 = int_pointer_test_2; - int result2; - auto answer2 = - fast_float::from_chars(f2.data(), f2.data() + f2.size(), result2); - if (strcmp(answer2.ptr, " with text") != 0) { - std::cerr << "ptr of result " << f2 - << " did not match with expected ptr: \"with text\"" << std::endl; - return EXIT_FAILURE; - } - - // int pointer test #3 (string with newline behind numbers) - std::string_view const int_pointer_test_3 = "1001 with text\n"; - - auto const &f3 = int_pointer_test_3; - int result3; - auto answer3 = - fast_float::from_chars(f3.data(), f3.data() + f3.size(), result3); - if (strcmp(answer3.ptr, " with text\n") != 0) { - std::cerr << "ptr of result " << f3 - << " did not match with expected ptr: with text" << std::endl; - return EXIT_FAILURE; - } - - // int pointer test #4 (float) - std::string_view const int_pointer_test_4 = "9.999"; - - auto const &f4 = int_pointer_test_4; - int result4; - auto answer4 = - fast_float::from_chars(f4.data(), f4.data() + f4.size(), result4); - if (strcmp(answer4.ptr, ".999") != 0) { - std::cerr << "ptr of result " << f4 - << " did not match with expected ptr: .999" << std::endl; - return EXIT_FAILURE; - } - - // int pointer test #5 (invalid int) - std::string_view const int_pointer_test_5 = "+50"; - - auto const &f5 = int_pointer_test_5; - int result5; - auto answer5 = - fast_float::from_chars(f5.data(), f5.data() + f5.size(), result5); - if (strcmp(answer5.ptr, "+50") != 0) { - std::cerr << "ptr of result " << f5 - << " did not match with expected ptr: +50" << std::endl; - return EXIT_FAILURE; - } - - // unsigned pointer test #2 (string behind numbers) - std::string_view const unsigned_pointer_test_1 = "1001 with text"; - - auto const &f6 = unsigned_pointer_test_1; - unsigned result6; - auto answer6 = - fast_float::from_chars(f6.data(), f6.data() + f6.size(), result6); - if (strcmp(answer6.ptr, " with text") != 0) { - std::cerr << "ptr of result " << f6 - << " did not match with expected ptr: with text" << std::endl; - return EXIT_FAILURE; - } - - // unsigned pointer test #2 (invalid unsigned) - std::string_view const unsigned_pointer_test_2 = "-50"; - - auto const &f7 = unsigned_pointer_test_2; - unsigned result7; - auto answer7 = - fast_float::from_chars(f7.data(), f7.data() + f7.size(), result7); - if (strcmp(answer7.ptr, "-50") != 0) { - std::cerr << "ptr of result " << f7 - << " did not match with expected ptr: -50" << std::endl; - return EXIT_FAILURE; - } - - // int base 2 test - std::vector const int_base_2_test_expected{0, 1, 4, 2, -1}; - std::vector const int_base_2_test{"0", "1", "100", "010", - "-1"}; - - for (std::size_t i = 0; i < int_base_2_test.size(); ++i) { - auto const f = int_base_2_test[i]; - int result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 2); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to int for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != int_base_2_test_expected[i]) { - std::cerr << "result " << f << " did not match with expected int: " - << int_base_2_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned base 2 test - std::vector const unsigned_base_2_test_expected{0, 1, 4, 2}; - std::vector const unsigned_base_2_test{"0", "1", "100", - "010"}; - - for (std::size_t i = 0; i < unsigned_base_2_test.size(); ++i) { - auto const &f = unsigned_base_2_test[i]; - unsigned result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 2); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to unsigned for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != unsigned_base_2_test_expected[i]) { - std::cerr << "result " << f << " did not match with expected unsigned: " - << unsigned_base_2_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // int invalid error base 2 test - std::vector const int_invalid_argument_base_2_test{"2", "A", - "-2"}; - - for (std::size_t i = 0; i < int_invalid_argument_base_2_test.size(); ++i) { - auto const &f = int_invalid_argument_base_2_test[i]; - int result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 2); - if (answer.ec != std::errc::invalid_argument) { - std::cerr << "expected error should be 'invalid_argument' for: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned invalid error base 2 test - std::vector const unsigned_invalid_argument_base_2_test{ - "2", "A", "-1", "-2"}; - - for (std::size_t i = 0; i < unsigned_invalid_argument_base_2_test.size(); - ++i) { - auto const &f = unsigned_invalid_argument_base_2_test[i]; - unsigned result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 2); - if (answer.ec != std::errc::invalid_argument) { - std::cerr << "expected error should be 'invalid_argument' for: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // octal test - std::vector const base_octal_test_expected{0, 1, 7, 8, 9}; - std::vector const base_octal_test{"0", "1", "07", "010", - "0011"}; - - for (std::size_t i = 0; i < base_octal_test.size(); ++i) { - auto const &f = base_octal_test[i]; - int result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 8); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to int for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != base_octal_test_expected[i]) { - std::cerr << "result " << f << " did not match with expected int: " - << base_octal_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // hex test - std::vector const base_hex_test_expected{0, 1, 15, 31, 0, 16}; - std::vector const base_hex_test{"0", "1", "F", - "01f", "0x11", "10X11"}; - - for (std::size_t i = 0; i < base_hex_test.size(); ++i) { - auto const &f = base_hex_test[i]; - int result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 16); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to int for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != base_hex_test_expected[i]) { - std::cerr << "result " << f << " did not match with expected int: " - << base_hex_test_expected[i] << std::endl; - return EXIT_FAILURE; - } - } - - // invalid base test #1 (-1) - std::vector const invalid_base_test_1{"0", "1", "-1", "F", - "10Z"}; - - for (std::size_t i = 0; i < invalid_base_test_1.size(); ++i) { - auto const &f = invalid_base_test_1[i]; - int result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, -1); - if (answer.ec != std::errc::invalid_argument) { - std::cerr << "expected error should be 'invalid_argument' for: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // invalid base test #2 (37) - std::vector const invalid_base_test_2{"0", "1", "F", "Z", - "10Z"}; - - for (std::size_t i = 0; i < invalid_base_test_2.size(); ++i) { - auto const &f = invalid_base_test_2[i]; - int result; - auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 37); - if (answer.ec != std::errc::invalid_argument) { - std::cerr << "expected error should be 'invalid_argument' for: \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // int out of range error base test (64 bit) - std::vector const int_out_of_range_base_test{ - "1000000000000000000000000000000000000000000000000000000000000000", - "-1000000000000000000000000000000000000000000000000000000000000001", - "2021110011022210012102010021220101220222", - "-2021110011022210012102010021220101221000", - "20000000000000000000000000000000", - "-20000000000000000000000000000001", - "1104332401304422434310311213", - "-1104332401304422434310311214", - "1540241003031030222122212", - "-1540241003031030222122213", - "22341010611245052052301", - "-22341010611245052052302", - "1000000000000000000000", - "-1000000000000000000001", - "67404283172107811828", - "-67404283172107811830", - "9223372036854775808", - "-9223372036854775809", - "1728002635214590698", - "-1728002635214590699", - "41A792678515120368", - "-41A792678515120369", - "10B269549075433C38", - "-10B269549075433C39", - "4340724C6C71DC7A8", - "-4340724C6C71DC7A9", - "160E2AD3246366808", - "-160E2AD3246366809", - "8000000000000000", - "-8000000000000001", - "33D3D8307B214009", - "-33D3D8307B21400A", - "16AGH595DF825FA8", - "-16AGH595DF825FA9", - "BA643DCI0FFEEHI", - "-BA643DCI0FFEEI0", - "5CBFJIA3FH26JA8", - "-5CBFJIA3FH26JA9", - "2HEICIIIE82DH98", - "-2HEICIIIE82DH99", - "1ADAIBB21DCKFA8", - "-1ADAIBB21DCKFA9", - "I6K448CF4192C3", - "-I6K448CF4192C4", - "ACD772JNC9L0L8", - "-ACD772JNC9L0L9", - "64IE1FOCNN5G78", - "-64IE1FOCNN5G79", - "3IGOECJBMCA688", - "-3IGOECJBMCA689", - "27C48L5B37OAOQ", - "-27C48L5B37OAP0", - "1BK39F3AH3DMQ8", - "-1BK39F3AH3DMQ9", - "Q1SE8F0M04ISC", - "-Q1SE8F0M04ISD", - "HAJPPBC1FC208", - "-HAJPPBC1FC209", - "BM03I95HIA438", - "-BM03I95HIA439", - "8000000000000", - "-8000000000001", - "5HG4CK9JD4U38", - "-5HG4CK9JD4U39", - "3TDTK1V8J6TPQ", - "-3TDTK1V8J6TPR", - "2PIJMIKEXRXP8", - "-2PIJMIKEXRXP9", - "1Y2P0IJ32E8E8", - "-1Y2P0IJ32E8E9"}; - - for (std::size_t i = 0; i < int_out_of_range_base_test.size(); ++i) { - auto const &f = int_out_of_range_base_test[i]; - int64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - int(2 + (i / 2))); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned out of range error base test (64 bit) - std::vector const unsigned_out_of_range_base_test{ - "10000000000000000000000000000000000000000000000000000000000000000", - "11112220022122120101211020120210210211221", - "100000000000000000000000000000000", - "2214220303114400424121122431", - "3520522010102100444244424", - "45012021522523134134602", - "2000000000000000000000", - "145808576354216723757", - "18446744073709551616", - "335500516A429071285", - "839365134A2A240714", - "219505A9511A867B73", - "8681049ADB03DB172", - "2C1D56B648C6CD111", - "10000000000000000", - "67979G60F5428011", - "2D3FGB0B9CG4BD2G", - "141C8786H1CCAAGH", - "B53BJH07BE4DJ0G", - "5E8G4GGG7G56DIG", - "2L4LF104353J8KG", - "1DDH88H2782I516", - "L12EE5FN0JI1IG", - "C9C336O0MLB7EG", - "7B7N2PCNIOKCGG", - "4EO8HFAM6FLLMP", - "2NC6J26L66RHOG", - "1N3RSH11F098RO", - "14L9LKMO30O40G", - "ND075IB45K86G", - "G000000000000", - "B1W8P7J5Q9R6G", - "7ORP63SH4DPHI", - "5G24A25TWKWFG", - "3W5E11264SGSG"}; - int base_unsigned = 2; - for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i) { - auto const &f = unsigned_out_of_range_base_test[i]; - uint64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - base_unsigned); - if (answer.ec != std::errc::result_out_of_range) { - std::cerr << "expected error for should be 'result_out_of_range': \"" << f - << "\"" << std::endl; - return EXIT_FAILURE; - } - ++base_unsigned; - } - - // just within range base test (64 bit) - std::vector const int_within_range_base_test{ - "111111111111111111111111111111111111111111111111111111111111111", - "-1000000000000000000000000000000000000000000000000000000000000000", - "2021110011022210012102010021220101220221", - "-2021110011022210012102010021220101220222", - "13333333333333333333333333333333", - "-20000000000000000000000000000000", - "1104332401304422434310311212", - "-1104332401304422434310311213", - "1540241003031030222122211", - "-1540241003031030222122212", - "22341010611245052052300", - "-22341010611245052052301", - "777777777777777777777", - "-1000000000000000000000", - "67404283172107811827", - "-67404283172107811828", - "9223372036854775807", - "-9223372036854775808", - "1728002635214590697", - "-1728002635214590698", - "41A792678515120367", - "-41A792678515120368", - "10B269549075433C37", - "-10B269549075433C38", - "4340724C6C71DC7A7", - "-4340724C6C71DC7A8", - "160E2AD3246366807", - "-160E2AD3246366808", - "7FFFFFFFFFFFFFFF", - "-8000000000000000", - "33D3D8307B214008", - "-33D3D8307B214009", - "16AGH595DF825FA7", - "-16AGH595DF825FA8", - "BA643DCI0FFEEHH", - "-BA643DCI0FFEEHI", - "5CBFJIA3FH26JA7", - "-5CBFJIA3FH26JA8", - "2HEICIIIE82DH97", - "-2HEICIIIE82DH98", - "1ADAIBB21DCKFA7", - "-1ADAIBB21DCKFA8", - "I6K448CF4192C2", - "-I6K448CF4192C3", - "ACD772JNC9L0L7", - "-ACD772JNC9L0L8", - "64IE1FOCNN5G77", - "-64IE1FOCNN5G78", - "3IGOECJBMCA687", - "-3IGOECJBMCA688", - "27C48L5B37OAOP", - "-27C48L5B37OAOQ", - "1BK39F3AH3DMQ7", - "-1BK39F3AH3DMQ8", - "Q1SE8F0M04ISB", - "-Q1SE8F0M04ISC", - "HAJPPBC1FC207", - "-HAJPPBC1FC208", - "BM03I95HIA437", - "-BM03I95HIA438", - "7VVVVVVVVVVVV", - "-8000000000000", - "5HG4CK9JD4U37", - "-5HG4CK9JD4U38", - "3TDTK1V8J6TPP", - "-3TDTK1V8J6TPQ", - "2PIJMIKEXRXP7", - "-2PIJMIKEXRXP8", - "1Y2P0IJ32E8E7", - "-1Y2P0IJ32E8E8"}; - - for (std::size_t i = 0; i < int_within_range_base_test.size(); ++i) { - auto const &f = int_within_range_base_test[i]; - int64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - int(2 + (i / 2))); - if (answer.ec != std::errc()) { - std::cerr << "converting " << f - << " to int failed (most likely out of range)" << std::endl; - return EXIT_FAILURE; - } - } - - // unsigned within range base test (64 bit) - std::vector const unsigned_within_range_base_test{ - "1111111111111111111111111111111111111111111111111111111111111111", - "11112220022122120101211020120210210211220", - "33333333333333333333333333333333", - "2214220303114400424121122430", - "3520522010102100444244423", - "45012021522523134134601", - "1777777777777777777777", - "145808576354216723756", - "18446744073709551615", - "335500516A429071284", - "839365134A2A240713", - "219505A9511A867B72", - "8681049ADB03DB171", - "2C1D56B648C6CD110", - "FFFFFFFFFFFFFFFF", - "67979G60F5428010", - "2D3FGB0B9CG4BD2F", - "141C8786H1CCAAGG", - "B53BJH07BE4DJ0F", - "5E8G4GGG7G56DIF", - "2L4LF104353J8KF", - "1DDH88H2782I515", - "L12EE5FN0JI1IF", - "C9C336O0MLB7EF", - "7B7N2PCNIOKCGF", - "4EO8HFAM6FLLMO", - "2NC6J26L66RHOF", - "1N3RSH11F098RN", - "14L9LKMO30O40F", - "ND075IB45K86F", - "FVVVVVVVVVVVV", - "B1W8P7J5Q9R6F", - "7ORP63SH4DPHH", - "5G24A25TWKWFF", - "3W5E11264SGSF"}; - int base_unsigned2 = 2; - for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i) { - auto const &f = unsigned_within_range_base_test[i]; - uint64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - base_unsigned2); - if (answer.ec != std::errc()) { - std::cerr << "converting " << f - << " to unsigned failed (most likely out of range)" - << std::endl; - return EXIT_FAILURE; - } - ++base_unsigned2; - } - - // int leading zeros test - std::vector const int_leading_zeros_test{ - "000000000000000000000000000000000000000000000000000000000000000000000011" - "11110111", - "000000000000000000000000000000000000000000000000001101121", - "000000000000000000000000000000000000000033313", - "00000000000000000000000000000013030", - "0000000000000000000000000000004411", - "0000000000000000000000000000002650", - "0000000000000000000000000000001767", - "0000000000000000000000000000001347", - "0000000000000000000000000000001015", - "00000000000000000000843", - "00000000000000000000707", - "00000000000000000000601", - "00000000000000000000527", - "0000000000000000000047A", - "000000000000000000003F7", - "0000000000000000000038C", - "00000000000000000000327", - "000000000000000000002F8", - "000000000000000000002AF", - "00000000000000000000267", - "00000000000000000000223", - "000000000000000000001L3", - "000000000000000000001I7", - "000000000000000000001FF", - "000000000000000000001D1", - "000000000000000000001AG", - "00000000000000000000187", - "00000000000000000000160", - "0000000000000000000013P", - "0000000000000000000011N", - "00000000000000000000VN", - "00000000000000000000UP", - "00000000000000000000TT", - "00000000000000000000T0", - "00000000000000000000S7"}; - - for (std::size_t i = 0; i < int_leading_zeros_test.size(); ++i) { - auto const &f = int_leading_zeros_test[i]; - int result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - int(i + 2)); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to int for input: \"" << f << "\"" - << std::endl; - return EXIT_FAILURE; - } else if (result != 1015) { - std::cerr << "result " << f - << " did not match with expected int: " << 1015 << std::endl; - return EXIT_FAILURE; - } - } - // issue 235 - { - std::vector s = {'0'}; - s.shrink_to_fit(); - int foo; - auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), foo); - if (answer.ec != std::errc()) { - std::cerr << "could not convert to int for input: '0'" << std::endl; - return EXIT_FAILURE; - } else if (foo != 0) { - std::cerr << "expected zero: " << foo << std::endl; - return EXIT_FAILURE; - } - } - // dont parse UTF-16 code units of emojis as int if low byte is ascii digit - { - const std::u16string emojis[] = { - u"ℹ", u"ℹ️", u"☸", u"☸️", u"☹", u"☹️", u"✳", u"✳️", - u"✴", u"✴️", u"⤴", u"⤴️", u"⤵", u"⤵️", u"〰", u"〰️", - }; - bool failed = false; - auto array_size = sizeof(emojis) / sizeof(emojis[0]); - for (size_t i = 0; i < array_size; i++) { - auto e = emojis[i]; - int foo; - auto answer = fast_float::from_chars(e.data(), e.data() + e.size(), foo); - if (answer.ec == std::errc()) { - failed = true; - std::cerr << "Incorrectly parsed emoji #" << i << " as integer " << foo - << "." << std::endl; - } - } - - if (failed) { - return EXIT_FAILURE; - } - } - // dont parse UTF-32 code points of emojis as int if low byte is ascii digit - { - const std::u32string emojis[] = { - U"ℹ", - U"ℹ️", - U"☸", - U"☸️", - U"☹", - U"☹️", - U"✳", - U"✳️", - U"✴", - U"✴️", - U"⤴", - U"⤴️", - U"⤵", - U"⤵️", - U"〰", - U"〰️", - U"🈲", - U"🈳", - U"🈴", - U"🈵", - U"🈶", - U"🈷", - U"🈷️", - U"🈸", - U"🈹", - U"🌰", - U"🌱", - U"🌲", - U"🌳", - U"🌴", - U"🌵", - U"🌶", - U"🌶️", - U"🌷", - U"🌸", - U"🌹", - U"🐰", - U"🐱", - U"🐲", - U"🐳", - U"🐴", - U"🐵", - U"🐶", - U"🐷", - U"🐸", - U"🐹", - U"🔰", - U"🔱", - U"🔲", - U"🔳", - U"🔴", - U"🔵", - U"🔶", - U"🔷", - U"🔸", - U"🔹", - U"😰", - U"😱", - U"😲", - U"😳", - U"😴", - U"😵", - U"😵‍💫", - U"😶", - U"😶‍🌫", - U"😶‍🌫️", - U"😷", - U"😸", - U"😹", - U"🤰", - U"🤰🏻", - U"🤰🏼", - U"🤰🏽", - U"🤰🏾", - U"🤰🏿", - U"🤱", - U"🤱🏻", - U"🤱🏼", - U"🤱🏽", - U"🤱🏾", - U"🤱🏿", - U"🤲", - U"🤲🏻", - U"🤲🏼", - U"🤲🏽", - U"🤲🏾", - U"🤲🏿", - U"🤳", - U"🤳🏻", - U"🤳🏼", - U"🤳🏽", - U"🤳🏾", - U"🤳🏿", - U"🤴", - U"🤴🏻", - U"🤴🏼", - U"🤴🏽", - U"🤴🏾", - U"🤴🏿", - U"🤵", - U"🤵‍♀", - U"🤵‍♀️", - U"🤵‍♂", - U"🤵‍♂️", - U"🤵🏻", - U"🤵🏻‍♀", - U"🤵🏻‍♀️", - U"🤵🏻‍♂", - U"🤵🏻‍♂️", - U"🤵🏼", - U"🤵🏼‍♀", - U"🤵🏼‍♀️", - U"🤵🏼‍♂", - U"🤵🏼‍♂️", - U"🤵🏽", - U"🤵🏽‍♀", - U"🤵🏽‍♀️", - U"🤵🏽‍♂", - U"🤵🏽‍♂️", - U"🤵🏾", - U"🤵🏾‍♀", - U"🤵🏾‍♀️", - U"🤵🏾‍♂", - U"🤵🏾‍♂️", - U"🤵🏿", - U"🤵🏿‍♀", - U"🤵🏿‍♀️", - U"🤵🏿‍♂", - U"🤵🏿‍♂️", - U"🤶", - U"🤶🏻", - U"🤶🏼", - U"🤶🏽", - U"🤶🏾", - U"🤶🏿", - U"🤷", - U"🤷‍♀", - U"🤷‍♀️", - U"🤷‍♂", - U"🤷‍♂️", - U"🤷🏻", - U"🤷🏻‍♀", - U"🤷🏻‍♀️", - U"🤷🏻‍♂", - U"🤷🏻‍♂️", - U"🤷🏼", - U"🤷🏼‍♀", - U"🤷🏼‍♀️", - U"🤷🏼‍♂", - U"🤷🏼‍♂️", - U"🤷🏽", - U"🤷🏽‍♀", - U"🤷🏽‍♀️", - U"🤷🏽‍♂", - U"🤷🏽‍♂️", - U"🤷🏾", - U"🤷🏾‍♀", - U"🤷🏾‍♀️", - U"🤷🏾‍♂", - U"🤷🏾‍♂️", - U"🤷🏿", - U"🤷🏿‍♀", - U"🤷🏿‍♀️", - U"🤷🏿‍♂", - U"🤷🏿‍♂️", - U"🤸", - U"🤸‍♀", - U"🤸‍♀️", - U"🤸‍♂", - U"🤸‍♂️", - U"🤸🏻", - U"🤸🏻‍♀", - U"🤸🏻‍♀️", - U"🤸🏻‍♂", - U"🤸🏻‍♂️", - U"🤸🏼", - U"🤸🏼‍♀", - U"🤸🏼‍♀️", - U"🤸🏼‍♂", - U"🤸🏼‍♂️", - U"🤸🏽", - U"🤸🏽‍♀", - U"🤸🏽‍♀️", - U"🤸🏽‍♂", - U"🤸🏽‍♂️", - U"🤸🏾", - U"🤸🏾‍♀", - U"🤸🏾‍♀️", - U"🤸🏾‍♂", - U"🤸🏾‍♂️", - U"🤸🏿", - U"🤸🏿‍♀", - U"🤸🏿‍♀️", - U"🤸🏿‍♂", - U"🤸🏿‍♂️", - U"🤹", - U"🤹‍♀", - U"🤹‍♀️", - U"🤹‍♂", - U"🤹‍♂️", - U"🤹🏻", - U"🤹🏻‍♀", - U"🤹🏻‍♀️", - U"🤹🏻‍♂", - U"🤹🏻‍♂️", - U"🤹🏼", - U"🤹🏼‍♀", - U"🤹🏼‍♀️", - U"🤹🏼‍♂", - U"🤹🏼‍♂️", - U"🤹🏽", - U"🤹🏽‍♀", - U"🤹🏽‍♀️", - U"🤹🏽‍♂", - U"🤹🏽‍♂️", - U"🤹🏾", - U"🤹🏾‍♀", - U"🤹🏾‍♀️", - U"🤹🏾‍♂", - U"🤹🏾‍♂️", - U"🤹🏿", - U"🤹🏿‍♀", - U"🤹🏿‍♀️", - U"🤹🏿‍♂", - U"🤹🏿‍♂️", - }; - bool failed = false; - auto array_size = sizeof(emojis) / sizeof(emojis[0]); - for (size_t i = 0; i < array_size; i++) { - auto e = emojis[i]; - int foo; - auto answer = fast_float::from_chars(e.data(), e.data() + e.size(), foo); - if (answer.ec == std::errc()) { - failed = true; - std::cerr << "Incorrectly parsed emoji #" << i << " as integer " << foo - << "." << std::endl; - } - } - - if (failed) { - return EXIT_FAILURE; - } - } - - return EXIT_SUCCESS; -} -#else -#include -#include - -int main() { - std::cerr << "The test requires C++17." << std::endl; - return EXIT_SUCCESS; -} -#endif diff --git a/tests/fixedwidthtest.cpp b/tests/fixedwidthtest.cpp deleted file mode 100644 index 35c5231..0000000 --- a/tests/fixedwidthtest.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include -#include -#include -#include "fast_float/fast_float.h" -#include - -#if __cplusplus >= 202300L -#include -#endif - -int main() { - // Write some testcases for the parsing of floating point numbers in the - // float32_t type. We use the from_chars function defined in this library. -#ifdef __STDCPP_FLOAT32_T__ - std::vector const float32_test_expected{ - 123.456f, -78.9f, 0.0001f, 3.40282e+038f}; - std::vector const float32_test{"123.456", "-78.9", "0.0001", - "3.40282e+038"}; - std::cout << "runing float32 test" << std::endl; - for (std::size_t i = 0; i < float32_test.size(); ++i) { - auto const &f = float32_test[i]; - std::float32_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - std::cerr << "Failed to parse: \"" << f << "\"" << std::endl; - return EXIT_FAILURE; - } - if (result != float32_test_expected[i]) { - std::cerr << "Test failed for input: \"" << f << "\" expected " - << float32_test_expected[i] << " got " << result << std::endl; - return EXIT_FAILURE; - } - } -#else - std::cout << "No std::float32_t type available." << std::endl; -#endif - -#ifdef __STDCPP_FLOAT64_T__ - // Test cases for std::float64_t - std::vector const float64_test_expected{ - 1.23e4, -5.67e-8, 1.7976931348623157e+308, -1.7976931348623157e+308}; - std::vector const float64_test{"1.23e4", "-5.67e-8", - "1.7976931348623157e+308", - "-1.7976931348623157e+308"}; - std::cout << "runing float64 test" << std::endl; - for (std::size_t i = 0; i < float64_test.size(); ++i) { - auto const &f = float64_test[i]; - std::float64_t result; - auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result); - - if (answer.ec != std::errc()) { - std::cerr << "Failed to parse: \"" << f << "\"" << std::endl; - return EXIT_FAILURE; - } - if (result != float64_test_expected[i]) { - std::cerr << "Test failed for input: \"" << f << "\" expected " - << float64_test_expected[i] << " got " << result << std::endl; - return EXIT_FAILURE; - } - } -#else - std::cout << "No std::float64_t type available." << std::endl; -#endif - std::cout << "All tests passed successfully." << std::endl; - return EXIT_SUCCESS; - - return 0; -} \ No newline at end of file diff --git a/tests/fortran.cpp b/tests/fortran.cpp deleted file mode 100644 index 9167593..0000000 --- a/tests/fortran.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Exercise the Fortran conversion option. - */ -#include -#include -#include -#include "fast_float/fast_float.h" - -int main_readme() { - std::string const input = "1d+4"; - double result; - fast_float::parse_options options{ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}; - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - if ((answer.ec != std::errc()) || ((result != 10000))) { - std::cerr << "parsing failure\n" << result << "\n"; - return EXIT_FAILURE; - } - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; -} - -int main() { - std::vector const expected{10000, 1000, 100, 10, 1, - .1, .01, .001, .0001}; - std::vector const fmt1{"1+4", "1+3", "1+2", "1+1", "1+0", - "1-1", "1-2", "1-3", "1-4"}; - std::vector const fmt2{"1d+4", "1d+3", "1d+2", "1d+1", "1d+0", - "1d-1", "1d-2", "1d-3", "1d-4"}; - std::vector const fmt3{"+1+4", "+1+3", "+1+2", "+1+1", "+1+0", - "+1-1", "+1-2", "+1-3", "+1-4"}; - fast_float::parse_options const options{ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}; - - for (auto const &f : fmt1) { - auto d{std::distance(&fmt1[0], &f)}; - double result; - auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, options)}; - if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { - std::cerr << "parsing failure on " << f << std::endl; - return EXIT_FAILURE; - } - } - - for (auto const &f : fmt2) { - auto d{std::distance(&fmt2[0], &f)}; - double result; - auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, options)}; - if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { - std::cerr << "parsing failure on " << f << std::endl; - return EXIT_FAILURE; - } - } - - for (auto const &f : fmt3) { - auto d{std::distance(&fmt3[0], &f)}; - double result; - auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, options)}; - if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { - std::cerr << "parsing failure on " << f << std::endl; - return EXIT_FAILURE; - } - } - if (main_readme() != EXIT_SUCCESS) { - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/tests/installation_tests/find/CMakeLists.txt b/tests/installation_tests/find/CMakeLists.txt deleted file mode 100644 index 0805703..0000000 --- a/tests/installation_tests/find/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required(VERSION 3.15) - -project(test_install VERSION 0.1.0 LANGUAGES CXX) - -set(FASTFLOAT_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for fastfloat") -set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(MSVC_VERSION GREATER 1910) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -permissive-") -endif() -find_package(FastFloat REQUIRED) - - - -file(WRITE main.cpp " -#include \"fast_float/fast_float.h\" -#include - -int main() { - std::string input = \"3.1416 xyz \"; - double result; - auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result); - if (answer.ec != std::errc()) { std::cerr << \"parsing failure\\n\"; return EXIT_FAILURE; } - std::cout << \"parsed the number \" << result << std::endl; - return EXIT_SUCCESS; -}") - - - -add_executable(repro main.cpp) -target_link_libraries(repro PUBLIC FastFloat::fast_float) diff --git a/tests/installation_tests/issue72_installation/CMakeLists.txt b/tests/installation_tests/issue72_installation/CMakeLists.txt deleted file mode 100644 index e8234f9..0000000 --- a/tests/installation_tests/issue72_installation/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.15) - -project(test_simdjson_install VERSION 0.1.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -if(MSVC_VERSION GREATER 1910) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -permissive-") -endif() - -find_package(FastFloat REQUIRED) - - - -file(WRITE test.h " -#pragma once -#include \"fast_float/fast_float.h\"") - -file(WRITE main.cpp " -#include \"test.h\" -int main() { return 0; }") - -file(WRITE foo.cpp " -#include \"test.h\" -void foo() { }") -add_executable(issue72 main.cpp main.cpp) -target_link_libraries(issue72 PUBLIC FastFloat::fast_float) \ No newline at end of file diff --git a/tests/ipv4_test.cpp b/tests/ipv4_test.cpp deleted file mode 100644 index f3055dc..0000000 --- a/tests/ipv4_test.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -#include -#include -#include -#include -#include "fast_float/fast_float.h" - -char *uint8_to_chars_manual(char *ptr, uint8_t value) { - if (value == 0) { - *ptr++ = '0'; - return ptr; - } - char *start = ptr; - while (value > 0) { - *ptr++ = '0' + (value % 10); - value /= 10; - } - // Reverse the digits written so far - std::reverse(start, ptr); - return ptr; -} - -void uint32_to_ipv4_string(uint32_t ip, char *buffer) { - uint8_t octets[4] = {static_cast(ip >> 24), - static_cast(ip >> 16), - static_cast(ip >> 8), static_cast(ip)}; - - char *ptr = buffer; - - for (int i = 0; i < 4; ++i) { - ptr = uint8_to_chars_manual(ptr, octets[i]); - - if (i < 3) { - *ptr++ = '.'; - } - } - *ptr = '\0'; -} - -fastfloat_really_inline uint32_t ipv4_string_to_uint32(const char *str, - const char *end) { - uint32_t ip = 0; - const char *current = str; - - for (int i = 0; i < 4; ++i) { - uint8_t value; - auto r = fast_float::from_chars(current, end, value); - if (r.ec != std::errc()) { - throw std::invalid_argument("Invalid IP address format"); - } - current = r.ptr; - ip = (ip << 8) | value; - - if (i < 3) { - if (current == end || *current++ != '.') { - throw std::invalid_argument("Invalid IP address format"); - } - } - } - return ip; -} - -bool test_all_ipv4_conversions() { - std::cout << "Testing all IPv4 conversions... 0, 1000, 2000, 3000, 4000, " - "5000, 6000, 7000, 8000, 9000, ..." - << std::endl; - char buffer[16]; - for (uint64_t ip = 0; ip <= 0xFFFFFFFF; ip += 1000) { - if (ip % 10000000 == 0) { - std::cout << "." << std::flush; - } - uint32_to_ipv4_string(static_cast(ip), buffer); - const char *end = buffer + strlen(buffer); - uint32_t parsed_ip = ipv4_string_to_uint32(buffer, end); - if (parsed_ip != ip) { - std::cerr << "Mismatch: original " << ip << ", parsed " << parsed_ip - << std::endl; - return false; - } - } - std::cout << std::endl; - return true; -} - -int main() { - if (test_all_ipv4_conversions()) { - std::cout << "All IPv4 conversions passed!" << std::endl; - return EXIT_SUCCESS; - } else { - std::cerr << "IPv4 conversion test failed!" << std::endl; - return EXIT_FAILURE; - } -} \ No newline at end of file diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp deleted file mode 100644 index 1ba0d5a..0000000 --- a/tests/json_fmt.cpp +++ /dev/null @@ -1,170 +0,0 @@ - -#include -#include -#include -#include "fast_float/fast_float.h" - -int main_readme() { - std::string const input = "+.1"; // not valid - double result; - fast_float::parse_options options{ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - if (answer.ec == std::errc()) { - std::cerr << "should have failed\n"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -int main_readme2() { - std::string const input = "inf"; // not valid in JSON - double result; - fast_float::parse_options options{ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - if (answer.ec == std::errc()) { - std::cerr << "should have failed\n"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -int main_readme3() { - std::string const input = - "inf"; // not valid in JSON but we allow it with json_or_infnan - double result; - fast_float::parse_options options{ - fast_float::chars_format::json_or_infnan | - fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); - if (answer.ec != std::errc() || (!std::isinf(result))) { - std::cerr << "should have parsed infinity\n"; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -struct ExpectedResult { - double value; - std::string junk_chars; -}; - -struct AcceptedValue { - std::string input; - ExpectedResult expected; -}; - -struct RejectReason { - fast_float::parse_error error; - intptr_t location_offset; -}; - -struct RejectedValue { - std::string input; - RejectReason reason; -}; - -int main() { - std::vector const accept{ - {"-0.2", {-0.2, ""}}, - {"0.02", {0.02, ""}}, - {"0.002", {0.002, ""}}, - {"1e+0000", {1., ""}}, - {"0e-2", {0., ""}}, - {"1e", {1., "e"}}, - {"1e+", {1., "e+"}}, - {"inf", {std::numeric_limits::infinity(), ""}}}; - std::vector const reject{ - {"-.2", {fast_float::parse_error::missing_integer_after_sign, 1}}, - {"00.02", {fast_float::parse_error::leading_zeros_in_integer_part, 0}}, - {"0.e+1", {fast_float::parse_error::no_digits_in_fractional_part, 2}}, - {"00.e+1", {fast_float::parse_error::leading_zeros_in_integer_part, 0}}, - {".25", {fast_float::parse_error::no_digits_in_integer_part, 0}}, - // The following cases already start as invalid JSON, so they are - // handled as trailing junk and the error is for not having digits in the - // empty string before the invalid token. - {"+0.25", {fast_float::parse_error::no_digits_in_integer_part, 0}}, - {"inf", {fast_float::parse_error::no_digits_in_integer_part, 0}}, - {"nan(snan)", {fast_float::parse_error::no_digits_in_integer_part, 0}}}; - - for (std::size_t i = 0; i < accept.size(); ++i) { - auto const &s = accept[i].input; - auto const &expected = accept[i].expected; - double result; - auto answer = - fast_float::from_chars(s.data(), s.data() + s.size(), result, - fast_float::chars_format::json_or_infnan); - if (answer.ec != std::errc()) { - std::cerr << "json fmt rejected valid json " << s << std::endl; - return EXIT_FAILURE; - } - if (result != expected.value) { - std::cerr << "json fmt gave wrong result " << s << " (expected " - << expected.value << " got " << result << ")" << std::endl; - return EXIT_FAILURE; - } - if (std::string(answer.ptr) != expected.junk_chars) { - std::cerr << "json fmt has wrong trailing characters " << s - << " (expected " << expected.junk_chars << " got " << answer.ptr - << ")" << std::endl; - return EXIT_FAILURE; - } - } - - for (std::size_t i = 0; i < reject.size(); ++i) { - auto const &s = reject[i].input; - double result; - auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, - fast_float::chars_format::json); - if (answer.ec == std::errc()) { - std::cerr << "json fmt accepted invalid json " << s << std::endl; - return EXIT_FAILURE; - } - } - - for (std::size_t i = 0; i < reject.size(); ++i) { - auto const &f = reject[i].input; - auto const &expected_reason = reject[i].reason; - auto answer = fast_float::parse_number_string( - f.data(), f.data() + f.size(), - fast_float::parse_options( - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus)); // should be ignored - if (answer.valid) { - std::cerr << "json parse accepted invalid json " << f << std::endl; - return EXIT_FAILURE; - } - if (answer.error != expected_reason.error) { - std::cerr << "json parse failure had invalid error reason " << f - << std::endl; - return EXIT_FAILURE; - } - intptr_t error_location = answer.lastmatch - f.data(); - if (error_location != expected_reason.location_offset) { - std::cerr << "json parse failure had invalid error location " << f - << " (expected " << expected_reason.location_offset << " got " - << error_location << ")" << std::endl; - return EXIT_FAILURE; - } - } - - if (main_readme() != EXIT_SUCCESS) { - return EXIT_FAILURE; - } - if (main_readme2() != EXIT_SUCCESS) { - return EXIT_FAILURE; - } -#ifndef __FAST_MATH__ - if (main_readme3() != EXIT_SUCCESS) { - return EXIT_FAILURE; - } -#endif - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/tests/long_exhaustive32.cpp b/tests/long_exhaustive32.cpp deleted file mode 100644 index ef7d5be..0000000 --- a/tests/long_exhaustive32.cpp +++ /dev/null @@ -1,68 +0,0 @@ - -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 128, "%.*e", 64, d); - return buffer + written; -} - -void allvalues() { - char buffer[128]; - for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) { - float v; - if ((w % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint32_t word = uint32_t(w); - memcpy(&v, &word, sizeof(v)); - - { - char const *string_end = to_string(v, buffer); - float result_value; - auto result = fast_float::from_chars(buffer, string_end, result_value); - // Starting with version 4.0 for fast_float, we return result_out_of_range - // if the value is either too small (too close to zero) or too large - // (effectively infinity). So std::errc::result_out_of_range is normal for - // well-formed input strings. - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cerr << "parsing error ? " << buffer << std::endl; - abort(); - } - if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - abort(); - } - } else if (copysign(1, result_value) != copysign(1, v)) { - std::cerr << buffer << std::endl; - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << v << std::endl; - abort(); - } else if (result_value != v) { - std::cerr << "no match ? " << buffer << " got " << result_value - << " expected " << v << std::endl; - std::cout << "started with " << std::hexfloat << v << std::endl; - std::cout << "got back " << std::hexfloat << result_value << std::endl; - std::cout << std::dec; - abort(); - } - } - } - std::cout << std::endl; -} - -int main() { - allvalues(); - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/long_exhaustive32_64.cpp b/tests/long_exhaustive32_64.cpp deleted file mode 100644 index 8409588..0000000 --- a/tests/long_exhaustive32_64.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 128, "%.*e", 64, d); - return buffer + written; -} - -void all_32bit_values() { - char buffer[128]; - for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) { - float v32; - if ((w % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint32_t word = uint32_t(w); - memcpy(&v32, &word, sizeof(v32)); - double v = v32; - - { - char const *string_end = to_string(v, buffer); - double result_value; - auto result = fast_float::from_chars(buffer, string_end, result_value); - // Starting with version 4.0 for fast_float, we return result_out_of_range - // if the value is either too small (too close to zero) or too large - // (effectively infinity). So std::errc::result_out_of_range is normal for - // well-formed input strings. - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cerr << "parsing error ? " << buffer << std::endl; - abort(); - } - if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - abort(); - } - } else if (copysign(1, result_value) != copysign(1, v)) { - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << v << std::endl; - abort(); - } else if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - abort(); - } - } else if (result_value != v) { - std::cerr << "no match ? " << buffer << std::endl; - std::cout << "started with " << std::hexfloat << v << std::endl; - std::cout << "got back " << std::hexfloat << result_value << std::endl; - std::cout << std::dec; - abort(); - } - } - } - std::cout << std::endl; -} - -int main() { - all_32bit_values(); - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/long_random64.cpp b/tests/long_random64.cpp deleted file mode 100644 index 8616416..0000000 --- a/tests/long_random64.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 128, "%.*e", 64, d); - return buffer + written; -} - -static fast_float::value128 g_lehmer64_state; - -/** - * D. H. Lehmer, Mathematical methods in large-scale computing units. - * Proceedings of a Second Symposium on Large Scale Digital Calculating - * Machinery; - * Annals of the Computation Laboratory, Harvard Univ. 26 (1951), pp. 141-146. - * - * P L'Ecuyer, Tables of linear congruential generators of different sizes and - * good lattice structure. Mathematics of Computation of the American - * Mathematical - * Society 68.225 (1999): 249-260. - */ - -static inline void lehmer64_seed(uint64_t seed) { - g_lehmer64_state.high = 0; - g_lehmer64_state.low = seed; -} - -static inline uint64_t lehmer64() { - fast_float::value128 v = fast_float::full_multiplication( - g_lehmer64_state.low, UINT64_C(0xda942042e4dd58b5)); - v.high += g_lehmer64_state.high * UINT64_C(0xda942042e4dd58b5); - g_lehmer64_state = v; - return v.high; -} - -size_t errors; - -void random_values(size_t N) { - char buffer[128]; - lehmer64_seed(N); - for (size_t t = 0; t < N; t++) { - if ((t % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint64_t word = lehmer64(); - double v; - memcpy(&v, &word, sizeof(v)); - { - char const *string_end = to_string(v, buffer); - double result_value; - auto result = fast_float::from_chars(buffer, string_end, result_value); - // Starting with version 4.0 for fast_float, we return result_out_of_range - // if the value is either too small (too close to zero) or too large - // (effectively infinity). So std::errc::result_out_of_range is normal for - // well-formed input strings. - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cerr << "parsing error ? " << buffer << std::endl; - errors++; - if (errors > 10) { - abort(); - } - continue; - } - if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - errors++; - if (errors > 10) { - abort(); - } - } - } else if (copysign(1, result_value) != copysign(1, v)) { - std::cerr << buffer << std::endl; - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << v << std::endl; - abort(); - } else if (result_value != v) { - std::cerr << "no match ? '" << buffer << "'" << std::endl; - std::cout << "started with " << std::hexfloat << v << std::endl; - std::cout << "got back " << std::hexfloat << result_value << std::endl; - std::cout << std::dec; - errors++; - if (errors > 10) { - abort(); - } - } - } - } - std::cout << std::endl; -} - -int main() { - errors = 0; - size_t N = - size_t(1) << (sizeof(size_t) * 4); // shift: 32 for 64bit, 16 for 32bit - random_values(N); - if (errors == 0) { - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; - } - std::cerr << std::endl; - std::cerr << "errors were encountered" << std::endl; - return EXIT_FAILURE; -} diff --git a/tests/long_test.cpp b/tests/long_test.cpp deleted file mode 100644 index feab4d0..0000000 --- a/tests/long_test.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include - -inline void Assert(bool Assertion) { - if (!Assertion) { - throw std::runtime_error("bug"); - } -} - -template bool test() { - std::string input = "0.156250000000000000000000000000000000000000 " - "3.14159265358979323846264338327950288419716939937510 " - "2.71828182845904523536028747135266249775724709369995"; - std::vector answers = {T(0.15625), T(3.141592653589793), - T(2.718281828459045)}; - char const *begin = input.data(); - char const *end = input.data() + input.size(); - for (size_t i = 0; i < answers.size(); i++) { - T result_value = 0; - while ((begin < end) && (std::isspace(*begin))) { - begin++; - } - auto result = fast_float::from_chars(begin, end, result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - printf("parsing %.*s\n", int(end - begin), begin); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result_value != answers[i]) { - printf("parsing %.*s\n", int(end - begin), begin); - std::cerr << " Mismatch " << std::endl; - std::cerr << " Expected " << answers[i] << std::endl; - std::cerr << " Got " << result_value << std::endl; - - return false; - } - begin = result.ptr; - } - if (begin != end) { - std::cerr << " bad ending " << std::endl; - return false; - } - return true; -} - -int main() { - - std::cout << "32 bits checks" << std::endl; - Assert(test()); - - std::cout << "64 bits checks" << std::endl; - Assert(test()); - - std::cout << "All ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/p2497.cpp b/tests/p2497.cpp deleted file mode 100644 index fec5133..0000000 --- a/tests/p2497.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include - -int main() { - std::string input = "3.1416 xyz "; - double result; - if (auto answer = fast_float::from_chars( - input.data(), input.data() + input.size(), result)) { - std::cout << "parsed the number " << result << std::endl; - return EXIT_SUCCESS; - } - std::cerr << "failed to parse " << result << std::endl; - return EXIT_FAILURE; -} \ No newline at end of file diff --git a/tests/powersoffive_hardround.cpp b/tests/powersoffive_hardround.cpp deleted file mode 100644 index 5e2ec96..0000000 --- a/tests/powersoffive_hardround.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) -// Anything at all that is related to cygwin, msys and so forth will -// always use this fallback because we cannot rely on it behaving as normal -// gcc. -#include - -// workaround for CYGWIN -double cygwin_strtod_l(char const *start, char **end) { - double d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} - -float cygwin_strtof_l(char const *start, char **end) { - float d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} -#endif - -std::pair strtod_from_string(char const *st) { - double d; - char *pr; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtod_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtod_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtod_l(st, &pr, c_locale); -#endif - if (st == pr) { - std::cerr << "strtod_l could not parse '" << st << std::endl; - return std::make_pair(0, false); - } - return std::make_pair(d, true); -} - -std::pair strtof_from_string(char *st) { - float d; - char *pr; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtof_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtof_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtof_l(st, &pr, c_locale); -#endif - if (st == pr) { - std::cerr << "strtof_l could not parse '" << st << std::endl; - return std::make_pair(0.0f, false); - } - return std::make_pair(d, true); -} - -bool tester() { - std::random_device rd; - std::mt19937 gen(rd()); - for (int q = 18; q <= 27; q++) { - std::cout << "q = " << -q << std::endl; - uint64_t power5 = 1; - for (int k = 0; k < q; k++) { - power5 *= 5; - } - uint64_t low_threshold = 0x20000000000000 / power5 + 1; - uint64_t threshold = 0xFFFFFFFFFFFFFFFF / power5; - std::uniform_int_distribution dis(low_threshold, threshold); - for (size_t i = 0; i < 10000; i++) { - uint64_t mantissa = dis(gen) * power5; - std::stringstream ss; - ss << mantissa; - ss << "e"; - ss << -q; - std::string to_be_parsed = ss.str(); - std::pair expected_double = - strtod_from_string(to_be_parsed.c_str()); - double result_value; - auto result = fast_float::from_chars( - to_be_parsed.data(), to_be_parsed.data() + to_be_parsed.size(), - result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cout << to_be_parsed << std::endl; - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result_value != expected_double.first) { - std::cout << to_be_parsed << std::endl; - std::cerr << std::hexfloat << result_value << std::endl; - std::cerr << std::hexfloat << expected_double.first << std::endl; - std::cerr << " Mismatch " << std::endl; - return false; - } - } - } - return true; -} - -int main() { - if (tester()) { - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; - } - std::cerr << std::endl; - std::cerr << "errors were encountered" << std::endl; - return EXIT_FAILURE; -} diff --git a/tests/random64.cpp b/tests/random64.cpp deleted file mode 100644 index d02735c..0000000 --- a/tests/random64.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include -#include - -template char *to_string(T d, char *buffer) { - auto written = std::snprintf(buffer, 64, "%.*e", - std::numeric_limits::max_digits10 - 1, d); - return buffer + written; -} - -static fast_float::value128 g_lehmer64_state; - -/** - * D. H. Lehmer, Mathematical methods in large-scale computing units. - * Proceedings of a Second Symposium on Large Scale Digital Calculating - * Machinery; - * Annals of the Computation Laboratory, Harvard Univ. 26 (1951), pp. 141-146. - * - * P L'Ecuyer, Tables of linear congruential generators of different sizes and - * good lattice structure. Mathematics of Computation of the American - * Mathematical - * Society 68.225 (1999): 249-260. - */ - -static inline void lehmer64_seed(uint64_t seed) { - g_lehmer64_state.high = 0; - g_lehmer64_state.low = seed; -} - -static inline uint64_t lehmer64() { - fast_float::value128 v = fast_float::full_multiplication( - g_lehmer64_state.low, UINT64_C(0xda942042e4dd58b5)); - v.high += g_lehmer64_state.high * UINT64_C(0xda942042e4dd58b5); - g_lehmer64_state = v; - return v.high; -} - -size_t errors; - -void random_values(size_t N) { - char buffer[64]; - lehmer64_seed(N); - for (size_t t = 0; t < N; t++) { - if ((t % 1048576) == 0) { - std::cout << "."; - std::cout.flush(); - } - uint64_t word = lehmer64(); - double v; - memcpy(&v, &word, sizeof(v)); - // if (!std::isnormal(v)) - { - char const *string_end = to_string(v, buffer); - double result_value; - auto result = fast_float::from_chars(buffer, string_end, result_value); - // Starting with version 4.0 for fast_float, we return result_out_of_range - // if the value is either too small (too close to zero) or too large - // (effectively infinity). So std::errc::result_out_of_range is normal for - // well-formed input strings. - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - std::cerr << "parsing error ? " << buffer << std::endl; - errors++; - if (errors > 10) { - abort(); - } - continue; - } - if (std::isnan(v)) { - if (!std::isnan(result_value)) { - std::cerr << "not nan" << buffer << std::endl; - errors++; - if (errors > 10) { - abort(); - } - } - } else if (copysign(1, result_value) != copysign(1, v)) { - std::cerr << buffer << std::endl; - std::cerr << "I got " << std::hexfloat << result_value - << " but I was expecting " << v << std::endl; - abort(); - } else if (result_value != v) { - std::cerr << "no match ? " << buffer << std::endl; - std::cout << "started with " << std::hexfloat << v << std::endl; - std::cout << "got back " << std::hexfloat << result_value << std::endl; - std::cout << std::dec; - errors++; - if (errors > 10) { - abort(); - } - } - } - } - std::cout << std::endl; -} - -int main() { - errors = 0; - size_t N = - size_t(1) << (sizeof(size_t) * 4); // shift: 32 for 64bit, 16 for 32bit - random_values(N); - if (errors == 0) { - std::cout << std::endl; - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; - } - std::cerr << std::endl; - std::cerr << "errors were encountered" << std::endl; - return EXIT_FAILURE; -} diff --git a/tests/random_string.cpp b/tests/random_string.cpp deleted file mode 100644 index 940cd7a..0000000 --- a/tests/random_string.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) -// Anything at all that is related to cygwin, msys and so forth will -// always use this fallback because we cannot rely on it behaving as normal -// gcc. -#include -#include - -// workaround for CYGWIN -double cygwin_strtod_l(char const *start, char **end) { - double d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} - -float cygwin_strtof_l(char const *start, char **end) { - float d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} -#endif - -class RandomEngine { -public: - RandomEngine() = delete; - RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; - - uint64_t next() { - // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h - // Inspired from - // https://github.com/lemire/testingRNG/blob/master/source/wyhash.h - wyhash64_x_ += UINT64_C(0x60bee2bee120fc15); - fast_float::value128 tmp = fast_float::full_multiplication( - wyhash64_x_, UINT64_C(0xa3b195354a39b70d)); - uint64_t m1 = (tmp.high) ^ tmp.low; - tmp = fast_float::full_multiplication(m1, UINT64_C(0x1b03738712fad5c9)); - uint64_t m2 = (tmp.high) ^ tmp.low; - return m2; - } - - bool next_bool() { return (next() & 1) == 1; } - - int next_int() { return static_cast(next()); } - - char next_char() { return static_cast(next()); } - - double next_double() { return static_cast(next()); } - - int next_ranged_int(int min, int max) { // min and max are included - // Adapted from - // https://lemire.me/blog/2019/06/06/nearly-divisionless-random-integer-generation-on-various-systems/ - /* if (min == max) { - return min; - }*/ - uint64_t s = uint64_t(max - min + 1); - uint64_t x = next(); - fast_float::value128 m = fast_float::full_multiplication(x, s); - uint64_t l = m.low; - if (l < s) { - uint64_t t = -s % s; - while (l < t) { - x = next(); - m = fast_float::full_multiplication(x, s); - l = m.low; - } - } - return int(m.high) + min; - } - - int next_digit() { return next_ranged_int(0, 9); } - -private: - uint64_t wyhash64_x_; -}; - -size_t build_random_string(RandomEngine &rand, char *buffer) { - size_t pos{0}; - if (rand.next_bool()) { - buffer[pos++] = '-'; - } - int number_of_digits = rand.next_ranged_int(1, 100); - if (number_of_digits == 100) { - // With low probability, we want to allow very long strings just to stress - // the system. - number_of_digits = rand.next_ranged_int(1, 2000); - } - int location_of_decimal_separator = rand.next_ranged_int(1, number_of_digits); - for (size_t i = 0; i < size_t(number_of_digits); i++) { - if (i == size_t(location_of_decimal_separator)) { - buffer[pos++] = '.'; - } - buffer[pos] = char(rand.next_digit() + '0'); - // We can have a leading zero only if location_of_decimal_separator = 1. - while (i == 0 && 1 != size_t(location_of_decimal_separator) && - buffer[pos] == '0') { - buffer[pos] = char(rand.next_digit() + '0'); - } - pos++; - } - if (rand.next_bool()) { - if (rand.next_bool()) { - buffer[pos++] = 'e'; - } else { - buffer[pos++] = 'E'; - } - if (rand.next_bool()) { - buffer[pos++] = '-'; - } else { - if (rand.next_bool()) { - buffer[pos++] = '+'; - } - } - number_of_digits = rand.next_ranged_int(1, 3); - for (size_t i = 0; i < size_t(number_of_digits); i++) { - buffer[pos++] = char(rand.next_digit() + '0'); - } - } - buffer[pos] = '\0'; // null termination - return pos; -} - -std::pair strtod_from_string(char *st) { - double d; - char *pr; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtod_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtod_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtod_l(st, &pr, c_locale); -#endif - if (st == pr) { - std::cerr << "strtod_l could not parse '" << st << std::endl; - return std::make_pair(0, false); - } - return std::make_pair(d, true); -} - -std::pair strtof_from_string(char *st) { - float d; - char *pr; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtof_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtof_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtof_l(st, &pr, c_locale); -#endif - if (st == pr) { - std::cerr << "strtof_l could not parse '" << st << std::endl; - return std::make_pair(0.0f, false); - } - return std::make_pair(d, true); -} - -/** - * We generate random strings and we try to parse them with both strtod/strtof, - * and we verify that we get the same answer with with fast_float::from_chars. - */ -bool tester(uint64_t seed, size_t volume) { - char buffer[4096]; // large buffer (can't overflow) - RandomEngine rand(seed); - for (size_t i = 0; i < volume; i++) { - if ((i % 100000) == 0) { - std::cout << "."; - std::cout.flush(); - } - size_t length = build_random_string(rand, buffer); - std::pair expected_double = strtod_from_string(buffer); - if (expected_double.second) { - double result_value; - auto result = - fast_float::from_chars(buffer, buffer + length, result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result.ptr != buffer + length) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " Did not get to the end " << std::endl; - return false; - } - if (result_value != expected_double.first) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << std::hexfloat << result_value << std::endl; - std::cerr << std::hexfloat << expected_double.first << std::endl; - std::cerr << " Mismatch " << std::endl; - return false; - } - } - std::pair expected_float = strtof_from_string(buffer); - if (expected_float.second) { - float result_value; - auto result = - fast_float::from_chars(buffer, buffer + length, result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result.ptr != buffer + length) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " Did not get to the end " << std::endl; - return false; - } - if (result_value != expected_float.first) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << std::hexfloat << result_value << std::endl; - std::cerr << std::hexfloat << expected_float.first << std::endl; - std::cerr << " Mismatch " << std::endl; - return false; - } - } - } - return true; -} - -int main() { - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - std::cout << "Warning: msys/cygwin or solaris detected." << std::endl; - return EXIT_SUCCESS; -#else - if (tester(1234344, 100000000)) { - std::cout << "All tests ok." << std::endl; - return EXIT_SUCCESS; - } - std::cout << "Failure." << std::endl; - return EXIT_FAILURE; - -#endif -} diff --git a/tests/rcppfastfloat_test.cpp b/tests/rcppfastfloat_test.cpp deleted file mode 100644 index 0c939ca..0000000 --- a/tests/rcppfastfloat_test.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/** - * See https://github.com/eddelbuettel/rcppfastfloat/issues/4 - */ - -#include "fast_float/fast_float.h" -#include -#include -#include - -struct test_data { - std::string input; - bool expected_success; - double expected_result; -}; - -bool eddelbuettel() { - std::vector const test_datas = { - {"infinity", true, std::numeric_limits::infinity()}, - {" \r\n\t\f\v3.16227766016838 \r\n\t\f\v", true, 3.16227766016838}, - {" \r\n\t\f\v3 \r\n\t\f\v", true, 3.0}, - {" 1970-01-01", false, 0.0}, - {"-NaN", true, std::numeric_limits::quiet_NaN()}, - {"-inf", true, -std::numeric_limits::infinity()}, - {" \r\n\t\f\v2.82842712474619 \r\n\t\f\v", true, 2.82842712474619}, - {"nan", true, std::numeric_limits::quiet_NaN()}, - {" \r\n\t\f\v2.44948974278318 \r\n\t\f\v", true, 2.44948974278318}, - {"Inf", true, std::numeric_limits::infinity()}, - {" \r\n\t\f\v2 \r\n\t\f\v", true, 2.0}, - {"-infinity", true, -std::numeric_limits::infinity()}, - {" \r\n\t\f\v0 \r\n\t\f\v", true, 0.0}, - {" \r\n\t\f\v1.73205080756888 \r\n\t\f\v", true, 1.73205080756888}, - {" \r\n\t\f\v1 \r\n\t\f\v", true, 1.0}, - {" \r\n\t\f\v1.4142135623731 \r\n\t\f\v", true, 1.4142135623731}, - {" \r\n\t\f\v2.23606797749979 \r\n\t\f\v", true, 2.23606797749979}, - {"1970-01-02 ", false, 0.0}, - {" \r\n\t\f\v2.64575131106459 \r\n\t\f\v", true, 2.64575131106459}, - {"inf", true, std::numeric_limits::infinity()}, - {"-nan", true, std::numeric_limits::quiet_NaN()}, - {"NaN", true, std::numeric_limits::quiet_NaN()}, - {"", false, 0.0}, - {"-Inf", true, -std::numeric_limits::infinity()}, - {"+2.2", true, 2.2}, - {"1d+4", false, 0.0}, - {"1d-1", false, 0.0}, - {"0.", true, 0.0}, - {"-.1", true, -0.1}, - {"+.1", true, 0.1}, - {"1e+1", true, 10.0}, - {"+1e1", true, 10.0}, - {"-+0", false, 0.0}, - {"-+inf", false, 0.0}, - {"-+nan", false, 0.0}, - }; - for (size_t i = 0; i < test_datas.size(); i++) { - auto const &input = test_datas[i].input; - auto const expected_success = test_datas[i].expected_success; - auto const expected_result = test_datas[i].expected_result; - double result; - // answer contains a error code and a pointer to the end of the - // parsed region (on success). - auto const answer = fast_float::from_chars( - input.data(), input.data() + input.size(), result, - fast_float::chars_format::general | - fast_float::chars_format::allow_leading_plus | - fast_float::chars_format::skip_white_space); - if (answer.ec != std::errc()) { - std::cout << "could not parse" << std::endl; - if (expected_success) { - return false; - } - continue; - } - bool non_space_trailing_content = false; - if (answer.ptr != input.data() + input.size()) { - // check that there is no content left - for (char const *leftover = answer.ptr; - leftover != input.data() + input.size(); leftover++) { - if (!fast_float::is_space(*leftover)) { - non_space_trailing_content = true; - break; - } - } - } - if (non_space_trailing_content) { - std::cout << "found trailing content " << std::endl; - if (!expected_success) { - continue; - } else { - return false; - } - } - std::cout << "parsed " << result << std::endl; - if (!expected_success) { - return false; - } - if (result != expected_result && - !(std::isnan(result) && std::isnan(expected_result))) { - std::cout << "results do not match. Expected " << expected_result - << std::endl; - return false; - } - } - return true; -} - -int main() { - if (!eddelbuettel()) { - printf("Bug.\n"); - return EXIT_FAILURE; - } - printf("All ok.\n"); - return EXIT_SUCCESS; -} diff --git a/tests/short_random_string.cpp b/tests/short_random_string.cpp deleted file mode 100644 index 9008bf3..0000000 --- a/tests/short_random_string.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) -// Anything at all that is related to cygwin, msys and so forth will -// always use this fallback because we cannot rely on it behaving as normal -// gcc. -#include -#include - -// workaround for CYGWIN -double cygwin_strtod_l(char const *start, char **end) { - double d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} - -float cygwin_strtof_l(char const *start, char **end) { - float d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} -#endif - -class RandomEngine { -public: - RandomEngine() = delete; - RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; - - uint64_t next() { - // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h - // Inspired from - // https://github.com/lemire/testingRNG/blob/master/source/wyhash.h - wyhash64_x_ += UINT64_C(0x60bee2bee120fc15); - fast_float::value128 tmp = fast_float::full_multiplication( - wyhash64_x_, UINT64_C(0xa3b195354a39b70d)); - uint64_t m1 = (tmp.high) ^ tmp.low; - tmp = fast_float::full_multiplication(m1, UINT64_C(0x1b03738712fad5c9)); - uint64_t m2 = (tmp.high) ^ tmp.low; - return m2; - } - - bool next_bool() { return (next() & 1) == 1; } - - int next_int() { return static_cast(next()); } - - char next_char() { return static_cast(next()); } - - double next_double() { return static_cast(next()); } - - int next_ranged_int(int min, int max) { // min and max are included - // Adapted from - // https://lemire.me/blog/2019/06/06/nearly-divisionless-random-integer-generation-on-various-systems/ - /* if (min == max) { - return min; - }*/ - uint64_t s = uint64_t(max - min + 1); - uint64_t x = next(); - fast_float::value128 m = fast_float::full_multiplication(x, s); - uint64_t l = m.low; - if (l < s) { - uint64_t t = -s % s; - while (l < t) { - x = next(); - m = fast_float::full_multiplication(x, s); - l = m.low; - } - } - return int(m.high) + min; - } - - int next_digit() { return next_ranged_int(0, 9); } - -private: - uint64_t wyhash64_x_; -}; - -size_t build_random_string(RandomEngine &rand, char *buffer) { - size_t pos{0}; - if (rand.next_bool()) { - buffer[pos++] = '-'; - } - int number_of_digits = rand.next_ranged_int(1, 19); - int location_of_decimal_separator = rand.next_ranged_int(1, number_of_digits); - for (size_t i = 0; i < size_t(number_of_digits); i++) { - if (i == size_t(location_of_decimal_separator)) { - buffer[pos++] = '.'; - } - buffer[pos] = char(rand.next_digit() + '0'); - // We can have a leading zero only if location_of_decimal_separator = 1. - while (i == 0 && 1 != size_t(location_of_decimal_separator) && - buffer[pos] == '0') { - buffer[pos] = char(rand.next_digit() + '0'); - } - pos++; - } - if (rand.next_bool()) { - if (rand.next_bool()) { - buffer[pos++] = 'e'; - } else { - buffer[pos++] = 'E'; - } - if (rand.next_bool()) { - buffer[pos++] = '-'; - } else { - if (rand.next_bool()) { - buffer[pos++] = '+'; - } - } - number_of_digits = rand.next_ranged_int(1, 3); - for (size_t i = 0; i < size_t(number_of_digits); i++) { - buffer[pos++] = char(rand.next_digit() + '0'); - } - } - buffer[pos] = '\0'; // null termination - return pos; -} - -std::pair strtod_from_string(char *st) { - double d; - char *pr; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtod_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtod_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtod_l(st, &pr, c_locale); -#endif - if (st == pr) { - std::cerr << "strtod_l could not parse '" << st << std::endl; - return std::make_pair(0, false); - } - return std::make_pair(d, true); -} - -std::pair strtof_from_string(char *st) { - float d; - char *pr; -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtof_l(st, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtof_l(st, &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtof_l(st, &pr, c_locale); -#endif - if (st == pr) { - std::cerr << "strtof_l could not parse '" << st << std::endl; - return std::make_pair(0.0f, false); - } - return std::make_pair(d, true); -} - -/** - * We generate random strings and we try to parse them with both strtod/strtof, - * and we verify that we get the same answer with with fast_float::from_chars. - */ -bool tester(uint64_t seed, size_t volume) { - char buffer[4096]; // large buffer (can't overflow) - RandomEngine rand(seed); - for (size_t i = 0; i < volume; i++) { - if ((i % 1000000) == 0) { - std::cout << "."; - std::cout.flush(); - } - size_t length = build_random_string(rand, buffer); - std::pair expected_double = strtod_from_string(buffer); - if (expected_double.second) { - double result_value; - auto result = - fast_float::from_chars(buffer, buffer + length, result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result.ptr != buffer + length) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " Did not get to the end " << std::endl; - return false; - } - if (result_value != expected_double.first) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << std::hexfloat << result_value << std::endl; - std::cerr << std::hexfloat << expected_double.first << std::endl; - std::cerr << " Mismatch " << std::endl; - return false; - } - } - std::pair expected_float = strtof_from_string(buffer); - if (expected_float.second) { - float result_value; - auto result = - fast_float::from_chars(buffer, buffer + length, result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result.ptr != buffer + length) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << " Did not get to the end " << std::endl; - return false; - } - if (result_value != expected_float.first) { - printf("parsing %.*s\n", int(length), buffer); - std::cerr << std::hexfloat << result_value << std::endl; - std::cerr << std::hexfloat << expected_float.first << std::endl; - std::cerr << " Mismatch " << std::endl; - return false; - } - } - } - return true; -} - -int main() { -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - std::cout << "Warning: msys/cygwin detected. This particular test is likely " - "to generate false failures due to our reliance on the " - "underlying runtime library." - << std::endl; - return EXIT_SUCCESS; -#else - if (tester(1234344, 100000000)) { - std::cout << "All tests ok." << std::endl; - return EXIT_SUCCESS; - } - return EXIT_FAILURE; - -#endif -} diff --git a/tests/string_test.cpp b/tests/string_test.cpp deleted file mode 100644 index 69d2a31..0000000 --- a/tests/string_test.cpp +++ /dev/null @@ -1,1134 +0,0 @@ -#include "fast_float/fast_float.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) -// Anything at all that is related to cygwin, msys and so forth will -// always use this fallback because we cannot rely on it behaving as normal -// gcc. -#include -#include - -// workaround for CYGWIN -double cygwin_strtod_l(char const *start, char **end) { - double d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} - -float cygwin_strtof_l(char const *start, char **end) { - float d; - std::stringstream ss; - ss.imbue(std::locale::classic()); - ss << start; - ss >> d; - if (ss.fail()) { - *end = nullptr; - } - if (ss.eof()) { - ss.clear(); - } - auto nread = ss.tellg(); - *end = const_cast(start) + nread; - return d; -} -#endif - -inline void Assert(bool Assertion) { -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - if (!Assertion) { - std::cerr << "Omitting hard failure on msys/cygwin/sun systems."; - } -#else - if (!Assertion) { - throw std::runtime_error("bug"); - } -#endif -} - -template std::string to_string(T d) { - std::string s(64, '\0'); - auto written = std::snprintf(&s[0], s.size(), "%.*e", - std::numeric_limits::max_digits10 - 1, d); - s.resize(size_t(written)); - return s; -} - -template bool test() { - std::string input = - "0.1 1e1000 100000 3.14159265359 -1e-500 001 1e01 1e0000001 -inf"; - std::vector answers = {T(0.1), - std::numeric_limits::infinity(), - 100000, - T(3.14159265359), - -0.0, - 1, - 10, - 10, - -std::numeric_limits::infinity()}; - std::vector expected_ec = {std::errc(), - std::errc::result_out_of_range, - std::errc(), - std::errc(), - std::errc::result_out_of_range, - std::errc(), - std::errc(), - std::errc(), - std::errc()}; - char const *begin = input.data(); - char const *end = input.data() + input.size(); - for (size_t i = 0; i < answers.size(); i++) { - T result_value = 0; - while ((begin < end) && (std::isspace(*begin))) { - begin++; - } - auto result = fast_float::from_chars(begin, end, result_value); - if (result.ec != expected_ec[i]) { - printf("parsing %.*s\n", int(end - begin), begin); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result_value != answers[i]) { - printf("parsing %.*s\n", int(end - begin), begin); - std::cerr << " Mismatch " << std::endl; - return false; - } - begin = result.ptr; - } - if (begin != end) { - std::cerr << " bad ending " << std::endl; - return false; - } - return true; -} - -template void strtod_from_string(std::string const &st, T &d); - -template <> void strtod_from_string(std::string const &st, double &d) { - char *pr = (char *)st.c_str(); -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtod_l(pr, &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtod_l(st.c_str(), &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtod_l(st.c_str(), &pr, c_locale); -#endif - if (pr == st.c_str()) { - throw std::runtime_error("bug in strtod_from_string"); - } -} - -template <> void strtod_from_string(std::string const &st, float &d) { - char *pr = (char *)st.c_str(); -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - d = cygwin_strtof_l(st.c_str(), &pr); -#elif defined(_WIN32) - static _locale_t c_locale = _create_locale(LC_ALL, "C"); - d = _strtof_l(st.c_str(), &pr, c_locale); -#else - static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL); - d = strtof_l(st.c_str(), &pr, c_locale); -#endif - if (pr == st.c_str()) { - throw std::runtime_error("bug in strtod_from_string"); - } -} - -template bool partow_test() { - // credit: - // https://github.com/ArashPartow/strtk/blob/master/strtk_tokenizer_cmp.cpp#L568 - // MIT license - std::string const strint_list[] = { - "9007199254740993", - "9007199254740994", - "9007199254740995", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "917049", - "4931205", - "6768064", - "6884243", - "5647132", - "7371203", - "-8629878", - "4941840", - "4543268", - "1075600", - "290", - "823", - "111", - "715", - "-866", - "367", - "666", - "-706", - "850", - "-161", - "9922547", - "6960207", - "1883152", - "2300759", - "-279294", - "4187292", - "3699841", - "8386395", - "-1441129", - "-887892", - "-635422", - "9742573", - "2326186", - "-5903851", - "5648486", - "3057647", - "2980079", - "2957468", - "7929158", - "1925615", - "879", - "130", - "292", - "705", - "817", - "446", - "576", - "750", - "523", - "-527", - "4365041", - "5624958", - "8990205", - "2652177", - "3993588", - "-298316", - "2901599", - "3887387", - "-5202979", - "1196268", - "5968501", - "7619928", - "3565643", - "1885272", - "-749485", - "2961381", - "2982579", - "2387454", - "4250081", - "5958205", - "00000", - "00001", - "00002", - "00003", - "00004", - "00005", - "00006", - "00007", - "00008", - "00009", - "4907034", - "2592882", - "3269234", - "549815", - "6256292", - "9721039", - "-595225", - "5587491", - "4596297", - "-3885009", - "673", - "-899", - "174", - "354", - "870", - "147", - "898", - "-510", - "369", - "859", - "6518423", - "5149762", - "8834164", - "-8085586", - "3233120", - "8166948", - "4172345", - "6735549", - "-934295", - "9481935", - "-430406", - "6932717", - "4087292", - "4047263", - "3236400", - "-3863050", - "4312079", - "6956261", - "5689446", - "3871332", - "535", - "691", - "326", - "-409", - "704", - "-568", - "301", - "951", - "121", - "384", - "4969414", - "9378599", - "7971781", - "5380630", - "5001363", - "1715827", - "6044615", - "9118925", - "9956168", - "-8865496", - "5962464", - "7408980", - "6646513", - "-634564", - "4188330", - "9805948", - "5625691", - "7641113", - "-4212929", - "7802447", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "2174248", - "7449361", - "9896659", - "-25961", - "1706598", - "2412368", - "-4617035", - "6314554", - "2225957", - "7521434", - "-9530566", - "3914164", - "2394759", - "7157744", - "9919392", - "6406949", - "-744004", - "9899789", - "8380325", - "-1416284", - "3402833", - "2150043", - "5191009", - "8979538", - "9565778", - "3750211", - "7304823", - "2829359", - "6544236", - "-615740", - "363", - "-627", - "129", - "656", - "135", - "113", - "381", - "646", - "198", - "38", - "8060564", - "-176752", - "1184717", - "-666343", - "-1273292", - "-485827", - "6241066", - "6579411", - "8093119", - "7481306", - "-4924485", - "7467889", - "9813178", - "7927100", - "3614859", - "7293354", - "9232973", - "4323115", - "1133911", - "9511638", - "4443188", - "2289448", - "5639726", - "9073898", - "8540394", - "5389992", - "1397726", - "-589230", - "1017086", - "1852330", - "-840", - "267", - "201", - "533", - "-675", - "494", - "315", - "706", - "-920", - "784", - "9097353", - "6002251", - "-308780", - "-3830169", - "4340467", - "2235284", - "3314444", - "1085967", - "4152107", - "5431117", - "-0000", - "-0001", - "-0002", - "-0003", - "-0004", - "-0005", - "-0006", - "-0007", - "-0008", - "-0009", - "-444999", - "2136400", - "6925907", - "6990614", - "3588271", - "8422028", - "-4034772", - "5804039", - "-6740545", - "9381873", - "-924923", - "1652367", - "2302616", - "6776663", - "2567821", - "-248935", - "2587688", - "7076742", - "-6461467", - "1562896", - "-768116", - "2338768", - "9887307", - "9992184", - "2045182", - "2797589", - "9784597", - "9696554", - "5113329", - "1067216", - "-76247763", - "58169007", - "29408062", - "85342511", - "42092201", - "-95817703", - "-1912517", - "-26275135", - "54656606", - "-58188878", - "473", - "74", - "374", - "-64", - "266", - "715", - "937", - "-249", - "249", - "780", - "3907360", - "-23063423", - "59062754", - "83711047", - "-95221044", - "34894840", - "-38562139", - "-82018330", - "14226223", - "-10799717", - "8529722", - "88961903", - "25608618", - "-39988247", - "33228241", - "38598533", - "21161480", - "-33723784", - "8873948", - "96505557", - "-47385048", - "-79413272", - "-85904404", - "87791158", - "49194195", - "13051222", - "57773302", - "31904423", - "3142966", - "27846156", - "7420011", - "-72376922", - "-68873971", - "23765361", - "4040725", - "-22359806", - "85777219", - "10099223", - "-90364256", - "-40158172", - "-7948696", - "-64344821", - "34404238", - "84037448", - "-85084788", - "-42078409", - "-56550310", - "96898389", - "-595829", - "-73166703", - "-0", - "-1", - "-2", - "-3", - "-4", - "-5", - "-6", - "-7", - "-8", - "-9", - "2147483647", - "31", - "2147483610", - "33", - "2147483573", - "37", - "2147483536", - "-82838342", - "64441808", - "43641062", - "-64419642", - "-44421934", - "75232413", - "-75773725", - "-89139509", - "12812089", - "-97633526", - "36090916", - "-57706234", - "17804655", - "4189936", - "-4100124", - "38803710", - "-39735126", - "-62397437", - "75801648", - "51302332", - "73433906", - "13015224", - "-12624818", - "91360377", - "11576319", - "-54467535", - "8892431", - "36319780", - "38832042", - "50172572", - "-317", - "109", - "-888", - "302", - "-463", - "716", - "916", - "665", - "826", - "513", - "42423473", - "41078812", - "40445652", - "-76722281", - "95092224", - "12075234", - "-4045888", - "-74396490", - "-57304222", - "-21726885", - "92038121", - "-31899682", - "21589254", - "-30260046", - "56000244", - "69686659", - "93327838", - "96882881", - "-91419389", - "77529147", - "43288506", - "1192435", - "-74095920", - "76756590", - "-31184683", - "-35716724", - "9451980", - "-63168350", - "62864002", - "26283194", - "37188395", - "29151634", - "99343471", - "-69450330", - "-55680090", - "-64957599", - "47577948", - "47107924", - "2490477", - "48633003", - "-82740809", - "-24122215", - "67301713", - "-63649610", - "75499016", - "82746620", - "17052193", - "4602244", - "-32721165", - "20837836", - "674", - "467", - "706", - "889", - "172", - "282", - "-795", - "188", - "87", - "153", - "64501793", - "53146328", - "5152287", - "-9674493", - "68105580", - "57245637", - "39740229", - "-74071854", - "86777268", - "86484437", - "-86962508", - "12644427", - "-62944073", - "59539680", - "43340539", - "30661534", - "20143968", - "-68183731", - "-48250926", - "42669063", - "000", - "001", - "002", - "003", - "004", - "005", - "006", - "007", - "008", - "009", - "2147483499", - "71", - "2147483462", - "73", - "2147483425", - "77", - "2147483388", - "87736852", - "-4444906", - "-48094147", - "54774735", - "54571890", - "-22473078", - "95053418", - "393654", - "-33229960", - "32276798", - "-48361110", - "44295939", - "-79813406", - "11630865", - "38544571", - "70972830", - "-9821748", - "-60965384", - "-13096675", - "-24569041", - "708", - "-467", - "-794", - "610", - "929", - "766", - "152", - "482", - "397", - "-191", - "97233152", - "51028396", - "-13796948", - "95437272", - "71352512", - "-83233730", - "-68517318", - "61832742", - "-42667174", - "-18002395", - "-92239407", - "12701336", - "-63830875", - "41514172", - "-5726049", - "18668677", - "69555144", - "-13737009", - "-22626233", - "-55078143", - "00", - "11", - "22", - "33", - "44", - "-00", - "-11", - "-22", - "-33", - "-44", - "000", - "111", - "222", - "333", - "444", - "-000", - "-111", - "-222", - "-333", - "-444", - "0000", - "1111", - "2222", - "3333", - "4444", - "-0000", - "-1111", - "-2222", - "-3333", - "-4444", - "00000", - "11111", - "22222", - "33333", - "44444", - "-00000", - "-11111", - "-22222", - "-33333", - "-44444", - "000000", - "111111", - "222222", - "333333", - "444444", - "-000000", - "-111111", - "-222222", - "-333333", - "-444444", - "0000000", - "1111111", - "2222222", - "3333333", - "4444444", - "-0000000", - "-1111111", - "-2222222", - "-3333333", - "-4444444", - "00000000", - "11111111", - "22222222", - "33333333", - "44444444", - "-00000000", - "-11111111", - "-22222222", - "-33333333", - "-44444444", - "000000000", - "111111111", - "222222222", - "333333333", - "444444444", - "-000000000", - "-111111111", - "-222222222", - "-333333333", - "-444444444", - "2147483351", - "51", - "2147483314", - "53", - "-2147483648", - "57", - "-2147483611", - "55", - "66", - "77", - "88", - "99", - "-55", - "-66", - "-77", - "-88", - "-99", - "555", - "666", - "777", - "888", - "999", - "-555", - "-666", - "-777", - "-888", - "-999", - "5555", - "6666", - "7777", - "8888", - "9999", - "-5555", - "-6666", - "-7777", - "-8888", - "-9999", - "55555", - "66666", - "77777", - "88888", - "99999", - "-55555", - "-66666", - "-77777", - "-88888", - "-99999", - "555555", - "666666", - "777777", - "888888", - "999999", - "-555555", - "-666666", - "-777777", - "-888888", - "-999999", - "5555555", - "6666666", - "7777777", - "8888888", - "9999999", - "-5555555", - "-6666666", - "-7777777", - "-8888888", - "-9999999", - "55555555", - "66666666", - "77777777", - "88888888", - "99999999", - "-55555555", - "-66666666", - "-77777777", - "-88888888", - "-99999999", - "555555555", - "666666666", - "777777777", - "888888888", - "999999999", - "-555555555", - "-666666666", - "-777777777", - "-888888888", - "-999999999", - "-2147483574", - "91", - "-2147483537", - "93", - "-2147483500", - "97", - "-2147483463", - "0000000011", - "0000000022", - "0000000033", - "0000000044", - "-000000011", - "-000000022", - "-000000033", - "-000000044", - "-000000088", - "0000000111", - "0000000222", - "0000000333", - "0000000444", - "-000000111", - "-000000222", - "-000000333", - "-000000444", - "-000000888", - "0000001111", - "0000002222", - "0000003333", - "0000004444", - "-000001111", - "-000002222", - "-000003333", - "-000004444", - "-000008888", - "0000011111", - "0000022222", - "0000033333", - "0000044444", - "-000011111", - "-000022222", - "-000033333", - "-000044444", - "-000088888", - "0000111111", - "0000222222", - "0000333333", - "0000444444", - "-000111111", - "-000222222", - "-000333333", - "-000444444", - "-000888888", - "0001111111", - "0002222222", - "0003333333", - "0004444444", - "-001111111", - "-002222222", - "-003333333", - "-004444444", - "-008888888", - "0011111111", - "0022222222", - "0033333333", - "0044444444", - "-011111111", - "-022222222", - "-033333333", - "-044444444", - "-088888888", - "0111111111", - "0222222222", - "0333333333", - "0444444444", - "-111111111", - "-222222222", - "-333333333", - "-444444444", - "-888888888", - "0000000055", - "0000000066", - "0000000077", - "0000000088", - "0000000099", - "-000000055", - "-000000066", - "-000000077", - "-000000099", - "0000000555", - "0000000666", - "0000000777", - "0000000888", - "0000000999", - "-000000555", - "-000000666", - "-000000777", - "-000000999", - "0000005555", - "0000006666", - "0000007777", - "0000008888", - "0000009999", - "-000005555", - "-000006666", - "-000007777", - "-000009999", - "0000055555", - "0000066666", - "0000077777", - "0000088888", - "0000099999", - "-000055555", - "-000066666", - "-000077777", - "-000099999", - "0000555555", - "0000666666", - "0000777777", - "0000888888", - "0000999999", - "-000555555", - "-000666666", - "-000777777", - "-000999999", - "0005555555", - "0006666666", - "0007777777", - "0008888888", - "0009999999", - "-005555555", - "-006666666", - "-007777777", - "-009999999", - "0055555555", - "0066666666", - "0077777777", - "0088888888", - "0099999999", - "-055555555", - "-066666666", - "-077777777", - "-099999999", - "0555555555", - "0666666666", - "0777777777", - "0888888888", - "0999999999", - "-555555555", - "-666666666", - "-777777777", - "-999999999", - "-2147483426", - "101", - "-2147483389", - "103", - "-2147483352", - "105", - "-2147483315", - "0000001234567890", - "0000001234567890", - "-0000001234567890", - "000001234567890", - "000001234567890", - "-000001234567890", - "00001234567890", - "00001234567890", - "-00001234567890", - "0001234567890", - "0001234567890", - "-0001234567890", - "001234567890", - "001234567890", - "-001234567890", - "01234567890", - "01234567890", - "-01234567890", - "1234567890", - "1234567890", - "-1234567890", - }; - for (std::string const &st : strint_list) { - T expected_value; - strtod_from_string(st, expected_value); - T result_value; - auto result = - fast_float::from_chars(st.data(), st.data() + st.size(), result_value); - if (result.ec != std::errc() && - result.ec != std::errc::result_out_of_range) { - printf("parsing %.*s\n", int(st.size()), st.data()); - std::cerr << " I could not parse " << std::endl; - return false; - } - if (result.ptr != st.data() + st.size()) { - printf("parsing %.*s\n", int(st.size()), st.data()); - std::cerr << " Did not get to the end " << std::endl; - return false; - } - if (result_value != expected_value) { - printf("parsing %.*s\n", int(st.size()), st.data()); - std::cerr << "expected value : " << to_string(expected_value) - << std::endl; - std::cerr << "result value : " << to_string(result_value) << std::endl; - std::cerr << " Mismatch " << std::endl; - return false; - } - } - return true; -} - -int main() { -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ - defined(sun) || defined(__sun) - std::cout << "Warning: msys/cygwin or solaris detected." << std::endl; -#endif - std::cout << "32 bits checks" << std::endl; - Assert(partow_test()); - Assert(test()); - - std::cout << "64 bits checks" << std::endl; - Assert(partow_test()); - Assert(test()); - - std::cout << "All ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/supported_chars_test.cpp b/tests/supported_chars_test.cpp deleted file mode 100644 index 3660f81..0000000 --- a/tests/supported_chars_test.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "fast_float/fast_float.h" -#include -#include -#include - -template bool test(std::string s, double expected) { - std::basic_string input(s.begin(), s.end()); - double result; - auto answer = - fast_float::from_chars(input.data(), input.data() + input.size(), result); - if (answer.ec != std::errc()) { - std::cerr << "parsing of \"" << s << "\" should succeed\n"; - return false; - } - if (result != expected && !(std::isnan(result) && std::isnan(expected))) { - std::cerr << "parsing of \"" << s << "\" succeeded, expected " << expected - << " got " << result << "\n"; - return false; - } - return true; -} - -int main() { - if (!test("4.2", 4.2)) { - std::cout << "test failure for char" << std::endl; - return EXIT_FAILURE; - } - - if (!test("4.2", 4.2)) { - std::cout << "test failure for wchar_t" << std::endl; - return EXIT_FAILURE; - } - -#ifdef __cpp_char8_t - if (!test("4.2", 4.2)) { - std::cout << "test failure for char8_t" << std::endl; - return EXIT_FAILURE; - } -#endif - - if (!test("4.2", 4.2)) { - std::cout << "test failure for char16_t" << std::endl; - return EXIT_FAILURE; - } - - if (!test("4.2", 4.2)) { - std::cout << "test failure for char32_t" << std::endl; - return EXIT_FAILURE; - } - - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; -} diff --git a/tests/wide_char_test.cpp b/tests/wide_char_test.cpp deleted file mode 100644 index 3b6ccd6..0000000 --- a/tests/wide_char_test.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "fast_float/fast_float.h" -#include -#include -#include - -bool tester(std::string s, double expected, - fast_float::chars_format fmt = fast_float::chars_format::general) { - std::wstring input(s.begin(), s.end()); - double result; - auto answer = fast_float::from_chars( - input.data(), input.data() + input.size(), result, fmt); - if (answer.ec != std::errc()) { - std::cerr << "parsing of \"" << s << "\" should succeed\n"; - return false; - } - if (result != expected && !(std::isnan(result) && std::isnan(expected))) { - std::cerr << "parsing of \"" << s << "\" succeeded, expected " << expected - << " got " << result << "\n"; - return false; - } - input[0] += 256; - answer = fast_float::from_chars(input.data(), input.data() + input.size(), - result, fmt); - if (answer.ec == std::errc()) { - std::cerr << "parsing of altered \"" << s << "\" should fail\n"; - return false; - } - return true; -} - -bool test_minus() { return tester("-42", -42); } - -bool test_plus() { - return tester("+42", 42, - fast_float::chars_format::general | - fast_float::chars_format::allow_leading_plus); -} - -bool test_space() { - return tester(" 42", 42, - fast_float::chars_format::general | - fast_float::chars_format::skip_white_space); -} - -bool test_nan() { - return tester("nan", std::numeric_limits::quiet_NaN()); -} - -int main() { - if (test_minus() && test_plus() && test_space() && test_nan()) { - std::cout << "all ok" << std::endl; - return EXIT_SUCCESS; - } - - std::cout << "test failure" << std::endl; - return EXIT_FAILURE; -}