diff options
author | thegeorg <[email protected]> | 2025-05-07 11:09:12 +0300 |
---|---|---|
committer | thegeorg <[email protected]> | 2025-05-07 11:25:22 +0300 |
commit | 4c98f14a2491da2bc1a9d40fed1d1682c7ec5dd6 (patch) | |
tree | 8142081775c27c8780fa0282a0273ee268e13b98 | |
parent | 40b86c68b431bb65d67bba51ef9159066a833b68 (diff) |
Update contrib/restricted/boost/locale to 1.88.0
commit_hash:87b595328ea79c6ba38cb973580804486ca4a3ff
143 files changed, 19028 insertions, 839 deletions
diff --git a/contrib/restricted/boost/charconv/.yandex_meta/__init__.py b/contrib/restricted/boost/charconv/.yandex_meta/__init__.py new file mode 100644 index 00000000000..9cd73a5e8d1 --- /dev/null +++ b/contrib/restricted/boost/charconv/.yandex_meta/__init__.py @@ -0,0 +1,20 @@ +from devtools.yamaker import boost +from devtools.yamaker.project import NixSourceProject + + +def post_install(self): + self.yamakes["."] = boost.make_library(self) + + +boost_charconv = NixSourceProject( + nixattr="boost_charconv", + arcdir=boost.make_arcdir("charconv"), + owners=["g:cpp-contrib", "g:taxi-common"], + copy_sources=[ + "include/boost/", + ], + disable_includes=[ + "stdfloat", + ], + post_install=post_install, +) diff --git a/contrib/restricted/boost/charconv/.yandex_meta/default.nix b/contrib/restricted/boost/charconv/.yandex_meta/default.nix new file mode 100644 index 00000000000..84c6fec242e --- /dev/null +++ b/contrib/restricted/boost/charconv/.yandex_meta/default.nix @@ -0,0 +1,13 @@ +self: super: with self; { + boost_charconv = stdenv.mkDerivation rec { + pname = "boost_charconv"; + version = "1.88.0"; + + src = fetchFromGitHub { + owner = "boostorg"; + repo = "charconv"; + rev = "boost-${version}"; + hash = "sha256-/BT/McmmdetjDtaqwOKvmid6MthUqfzwfv1V/FXjqP8="; + }; + }; +} diff --git a/contrib/restricted/boost/charconv/.yandex_meta/devtools.copyrights.report b/contrib/restricted/boost/charconv/.yandex_meta/devtools.copyrights.report new file mode 100644 index 00000000000..902429a44dc --- /dev/null +++ b/contrib/restricted/boost/charconv/.yandex_meta/devtools.copyrights.report @@ -0,0 +1,196 @@ +# File format ($ symbol means the beginning of a line): +# +# $ # this message +# $ # ======================= +# $ # comments (all commentaries should starts with some number of spaces and # symbol) +# $ IGNORE_FILES {file1.ext1} {file2.ext2} - (optional) ignore listed files when generating license macro and credits +# $ RENAME {original license id} TO {new license id} # user comments - (optional) use {new license id} instead {original license id} in ya.make files +# $ # user comments +# $ +# ${action} {license id} {license text hash} +# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make +# ${all_file_action} filename +# $ # user commentaries (many lines) +# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify) +# ${action} {license spdx} {license text hash} +# $BELONGS ./ya/make/file/relative/path/3/ya.make +# ${all_file_action} filename +# $ # user commentaries +# $ generated description +# $ ... +# +# You can modify action, all_file_action and add commentaries +# Available actions: +# keep - keep license in contrib and use in credits +# skip - skip license +# remove - remove all files with this license +# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file +# +# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory) +# We suppose that that files can contain some license info +# Available all file actions: +# FILE_IGNORE - ignore file (do nothing) +# FILE_INCLUDE - include all file data into licenses text file +# ======================= + +KEEP COPYRIGHT_SERVICE_LABEL 0e29c20336773b79c29d48a3387695cf +BELONGS ya.make + License text: + // Copyright 2022 Peter Dimov + // Copyright 2023 Matt Borland + // Copyright 2023 Junekey Jeon + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/to_chars.hpp [1:5] + +KEEP COPYRIGHT_SERVICE_LABEL 175f8970b1267cb559b66251e237f95e +BELONGS ya.make + License text: + // Copyright 2020-2023 Junekey Jeon + // Copyright 2022 Peter Dimov + // Copyright 2023 Matt Borland + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/detail/to_chars_integer_impl.hpp [1:5] + +KEEP COPYRIGHT_SERVICE_LABEL 5bea22e8da8464acc8d9ab38156e45ce +BELONGS ya.make + License text: + // Copyright 2024 Matt Borland + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/detail/buffer_sizing.hpp [1:3] + include/boost/charconv/detail/fallback_routines.hpp [1:3] + +KEEP COPYRIGHT_SERVICE_LABEL 6629d20784d6175b2277b7f2294eb136 +BELONGS ya.make + License text: + // Copyright 2020-2023 Daniel Lemire + // Copyright 2023 Matt Borland + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/detail/compute_float64.hpp [1:4] + include/boost/charconv/detail/emulated128.hpp [1:4] + include/boost/charconv/detail/fast_float/ascii_number.hpp [1:4] + include/boost/charconv/detail/fast_float/bigint.hpp [1:4] + include/boost/charconv/detail/fast_float/constexpr_feature_detect.hpp [1:4] + include/boost/charconv/detail/fast_float/decimal_to_binary.hpp [1:4] + include/boost/charconv/detail/fast_float/digit_comparison.hpp [1:4] + include/boost/charconv/detail/fast_float/fast_float.hpp [1:4] + include/boost/charconv/detail/fast_float/fast_table.hpp [1:4] + include/boost/charconv/detail/fast_float/float_common.hpp [1:4] + include/boost/charconv/detail/fast_float/parse_number.hpp [1:4] + include/boost/charconv/detail/significand_tables.hpp [1:4] + +KEEP COPYRIGHT_SERVICE_LABEL 9ffe57ee27b8ed11f13a2ad92594afe9 +BELONGS ya.make + License text: + // Copyright 2018 - 2023 Ulf Adams + // Copyright 2023 Matt Borland + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/detail/ryu/generic_128.hpp [1:4] + include/boost/charconv/detail/ryu/ryu_generic_128.hpp [1:4] + +KEEP COPYRIGHT_SERVICE_LABEL df56a08a51f11ebc1571263ab013bc25 +BELONGS ya.make + License text: + // Copyright 2022 Peter Dimov + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv.hpp [4:6] + include/boost/charconv/config.hpp [4:7] + include/boost/charconv/detail/to_chars_integer_impl.hpp [1:5] + include/boost/charconv/from_chars.hpp [1:4] + include/boost/charconv/to_chars.hpp [1:5] + +KEEP COPYRIGHT_SERVICE_LABEL ed2a55914865861705ece89451296d32 +BELONGS ya.make + License text: + // Copyright 2020-2022 Junekey Jeon + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox.hpp [1:1] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [1:1] + include/boost/charconv/detail/dragonbox/floff.hpp [1:1] + +KEEP COPYRIGHT_SERVICE_LABEL fdba0502771598acb9f3611d2cd4bb09 +BELONGS ya.make + License text: + // Copyright 2023 Matt Borland + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/charconv/chars_format.hpp [1:3] + include/boost/charconv/config.hpp [4:7] + include/boost/charconv/detail/apply_sign.hpp [1:3] + include/boost/charconv/detail/bit_layouts.hpp [1:3] + include/boost/charconv/detail/compute_float32.hpp [1:3] + include/boost/charconv/detail/compute_float64.hpp [1:4] + include/boost/charconv/detail/compute_float80.hpp [1:3] + include/boost/charconv/detail/config.hpp [1:3] + include/boost/charconv/detail/dragonbox/dragonbox.hpp [18:20] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [20:22] + include/boost/charconv/detail/dragonbox/floff.hpp [20:22] + include/boost/charconv/detail/emulated128.hpp [1:4] + include/boost/charconv/detail/fast_float/ascii_number.hpp [1:4] + include/boost/charconv/detail/fast_float/bigint.hpp [1:4] + include/boost/charconv/detail/fast_float/constexpr_feature_detect.hpp [1:4] + include/boost/charconv/detail/fast_float/decimal_to_binary.hpp [1:4] + include/boost/charconv/detail/fast_float/digit_comparison.hpp [1:4] + include/boost/charconv/detail/fast_float/fast_float.hpp [1:4] + include/boost/charconv/detail/fast_float/fast_table.hpp [1:4] + include/boost/charconv/detail/fast_float/float_common.hpp [1:4] + include/boost/charconv/detail/fast_float/parse_number.hpp [1:4] + include/boost/charconv/detail/from_chars_integer_impl.hpp [1:3] + include/boost/charconv/detail/from_chars_result.hpp [1:3] + include/boost/charconv/detail/integer_search_trees.hpp [1:3] + include/boost/charconv/detail/issignaling.hpp [1:3] + include/boost/charconv/detail/memcpy.hpp [1:3] + include/boost/charconv/detail/parser.hpp [1:3] + include/boost/charconv/detail/ryu/generic_128.hpp [1:4] + include/boost/charconv/detail/ryu/ryu_generic_128.hpp [1:4] + include/boost/charconv/detail/significand_tables.hpp [1:4] + include/boost/charconv/detail/to_chars_integer_impl.hpp [1:5] + include/boost/charconv/detail/to_chars_result.hpp [1:3] + include/boost/charconv/detail/type_traits.hpp [1:3] + include/boost/charconv/from_chars.hpp [1:4] + include/boost/charconv/limits.hpp [1:3] + include/boost/charconv/to_chars.hpp [1:5] diff --git a/contrib/restricted/boost/charconv/.yandex_meta/devtools.licenses.report b/contrib/restricted/boost/charconv/.yandex_meta/devtools.licenses.report new file mode 100644 index 00000000000..3430b38ab29 --- /dev/null +++ b/contrib/restricted/boost/charconv/.yandex_meta/devtools.licenses.report @@ -0,0 +1,216 @@ +# File format ($ symbol means the beginning of a line): +# +# $ # this message +# $ # ======================= +# $ # comments (all commentaries should starts with some number of spaces and # symbol) +# $ IGNORE_FILES {file1.ext1} {file2.ext2} - (optional) ignore listed files when generating license macro and credits +# $ RENAME {original license id} TO {new license id} # user comments - (optional) use {new license id} instead {original license id} in ya.make files +# $ # user comments +# $ +# ${action} {license id} {license text hash} +# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make +# ${all_file_action} filename +# $ # user commentaries (many lines) +# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify) +# ${action} {license spdx} {license text hash} +# $BELONGS ./ya/make/file/relative/path/3/ya.make +# ${all_file_action} filename +# $ # user commentaries +# $ generated description +# $ ... +# +# You can modify action, all_file_action and add commentaries +# Available actions: +# keep - keep license in contrib and use in credits +# skip - skip license +# remove - remove all files with this license +# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file +# +# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory) +# We suppose that that files can contain some license info +# Available all file actions: +# FILE_IGNORE - ignore file (do nothing) +# FILE_INCLUDE - include all file data into licenses text file +# ======================= + +KEEP Apache-2.0 2c3bc3726a0ef68dea2a008702f96131 +BELONGS ya.make + License text: + // (See accompanying file LICENSE-Apache or copy at + Scancode info: + Original SPDX id: Apache-2.0 + Score : 90.00 + Match type : TAG + Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox.hpp [6:6] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [6:6] + include/boost/charconv/detail/dragonbox/floff.hpp [6:6] + +KEEP BSL-1.0 2c7a3fa82e66676005cd4ee2608fd7d2 +BELONGS ya.make + Note: matched license text is too long. Read it in the source files. + Scancode info: + Original SPDX id: BSL-1.0 + Score : 100.00 + Match type : TEXT + Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 + Files with this license: + LICENSE [1:23] + +KEEP BSL-1.0 67d785c23d7b32d9a77d1123e74d8da2 +BELONGS ya.make + License text: + // the Boost Software License, Version 1.0. + // (See accompanying file LICENSE-Boost or copy at + // https://www.boost.org/LICENSE_1_0.txt) + Scancode info: + Original SPDX id: BSL-1.0 + Score : 72.00 + Match type : NOTICE + Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox.hpp [10:12] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [10:12] + include/boost/charconv/detail/dragonbox/floff.hpp [10:12] + +SKIP LicenseRef-scancode-warranty-disclaimer 92f6bc64e50f9371e66428f437beef7d +BELONGS ya.make + # Not a license, but a warranty disclaimer + Note: matched license text is too long. Read it in the source files. + Scancode info: + Original SPDX id: LicenseRef-scancode-warranty-disclaimer + Score : 61.70 + Match type : TEXT + Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/warranty-disclaimer.LICENSE + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox.hpp [14:20] + +KEEP Apache-2.0 WITH LLVM-exception c6d514740e772226c6397fc13f9c7395 +BELONGS ya.make + License text: + // the Apache License v2.0 with LLVM Exceptions. + Scancode info: + Original SPDX id: Apache-2.0 + Score : 100.00 + Match type : NOTICE + Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox.hpp [4:4] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [4:4] + include/boost/charconv/detail/dragonbox/floff.hpp [4:4] + Scancode info: + Original SPDX id: LLVM-exception + Score : 100.00 + Match type : NOTICE + Links : http://llvm.org/foundation/relicensing/LICENSE.txt, https://spdx.org/licenses/LLVM-exception + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox.hpp [4:4] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [4:4] + include/boost/charconv/detail/dragonbox/floff.hpp [4:4] + +KEEP BSL-1.0 c9e6118e07afed16d6f26c06b5f29fe8 +BELONGS ya.make + License text: + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: BSL-1.0 + Score : 100.00 + Match type : REFERENCE + Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 + Files with this license: + include/boost/charconv/detail/apply_sign.hpp [3:3] + include/boost/charconv/detail/bit_layouts.hpp [3:3] + include/boost/charconv/detail/compute_float64.hpp [4:4] + include/boost/charconv/detail/config.hpp [3:3] + include/boost/charconv/detail/dragonbox/dragonbox.hpp [20:20] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [22:22] + include/boost/charconv/detail/dragonbox/floff.hpp [22:22] + include/boost/charconv/detail/fallback_routines.hpp [3:3] + include/boost/charconv/detail/from_chars_result.hpp [3:3] + include/boost/charconv/detail/ryu/generic_128.hpp [4:4] + include/boost/charconv/detail/ryu/ryu_generic_128.hpp [4:4] + include/boost/charconv/detail/to_chars_result.hpp [3:3] + include/boost/charconv/from_chars.hpp [4:4] + include/boost/charconv/to_chars.hpp [5:5] + +SKIP LicenseRef-scancode-warranty-disclaimer d89f6d713ddca845d1eef6a38b0cf573 +BELONGS ya.make + # Not a license, but a warranty disclaimer + Note: matched license text is too long. Read it in the source files. + Scancode info: + Original SPDX id: LicenseRef-scancode-warranty-disclaimer + Score : 61.70 + Match type : TEXT + Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/warranty-disclaimer.LICENSE + Files with this license: + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [14:22] + include/boost/charconv/detail/dragonbox/floff.hpp [14:22] + +KEEP BSL-1.0 e03c043ca7052925e34194f3fe2631e4 +BELONGS ya.make + License text: + // Distributed under the Boost Software License, Version 1.0. + Scancode info: + Original SPDX id: BSL-1.0 + Score : 100.00 + Match type : NOTICE + Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 + Files with this license: + include/boost/charconv/detail/apply_sign.hpp [2:2] + include/boost/charconv/detail/bit_layouts.hpp [2:2] + include/boost/charconv/detail/compute_float64.hpp [3:3] + include/boost/charconv/detail/config.hpp [2:2] + include/boost/charconv/detail/dragonbox/dragonbox.hpp [19:19] + include/boost/charconv/detail/dragonbox/dragonbox_common.hpp [21:21] + include/boost/charconv/detail/dragonbox/floff.hpp [21:21] + include/boost/charconv/detail/fallback_routines.hpp [2:2] + include/boost/charconv/detail/from_chars_result.hpp [2:2] + include/boost/charconv/detail/ryu/generic_128.hpp [3:3] + include/boost/charconv/detail/ryu/ryu_generic_128.hpp [3:3] + include/boost/charconv/detail/to_chars_result.hpp [2:2] + include/boost/charconv/from_chars.hpp [3:3] + include/boost/charconv/to_chars.hpp [4:4] + +KEEP BSL-1.0 AND BSL-1.0 e9df2954141aa96551bf39192c39d2fe +BELONGS ya.make + License text: + // Distributed under the Boost Software License, Version 1.0. + // https://www.boost.org/LICENSE_1_0.txt + Scancode info: + Original SPDX id: BSL-1.0 + Score : 94.44 + Match type : NOTICE + Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 + Files with this license: + include/boost/charconv.hpp [5:6] + include/boost/charconv/chars_format.hpp [2:3] + include/boost/charconv/detail/buffer_sizing.hpp [2:3] + include/boost/charconv/detail/compute_float32.hpp [2:3] + include/boost/charconv/detail/compute_float80.hpp [2:3] + include/boost/charconv/detail/emulated128.hpp [3:4] + include/boost/charconv/detail/fast_float/ascii_number.hpp [3:4] + include/boost/charconv/detail/fast_float/bigint.hpp [3:4] + include/boost/charconv/detail/fast_float/constexpr_feature_detect.hpp [3:4] + include/boost/charconv/detail/fast_float/decimal_to_binary.hpp [3:4] + include/boost/charconv/detail/fast_float/digit_comparison.hpp [3:4] + include/boost/charconv/detail/fast_float/fast_float.hpp [3:4] + include/boost/charconv/detail/fast_float/fast_table.hpp [3:4] + include/boost/charconv/detail/fast_float/float_common.hpp [3:4] + include/boost/charconv/detail/fast_float/parse_number.hpp [3:4] + include/boost/charconv/detail/from_chars_integer_impl.hpp [2:3] + include/boost/charconv/detail/integer_search_trees.hpp [2:3] + include/boost/charconv/detail/issignaling.hpp [2:3] + include/boost/charconv/detail/memcpy.hpp [2:3] + include/boost/charconv/detail/parser.hpp [2:3] + include/boost/charconv/detail/significand_tables.hpp [3:4] + include/boost/charconv/detail/to_chars_integer_impl.hpp [4:5] + include/boost/charconv/detail/type_traits.hpp [2:3] + include/boost/charconv/limits.hpp [2:3] + Scancode info: + Original SPDX id: BSL-1.0 + Score : 88.89 + Match type : NOTICE + Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 + Files with this license: + include/boost/charconv/config.hpp [6:7] diff --git a/contrib/restricted/boost/charconv/.yandex_meta/licenses.list.txt b/contrib/restricted/boost/charconv/.yandex_meta/licenses.list.txt new file mode 100644 index 00000000000..57dd425c46e --- /dev/null +++ b/contrib/restricted/boost/charconv/.yandex_meta/licenses.list.txt @@ -0,0 +1,102 @@ +====================Apache-2.0==================== +// (See accompanying file LICENSE-Apache or copy at + + +====================Apache-2.0 WITH LLVM-exception==================== +// the Apache License v2.0 with LLVM Exceptions. + + +====================BSL-1.0==================== +// Distributed under the Boost Software License, Version 1.0. + + +====================BSL-1.0==================== +// https://www.boost.org/LICENSE_1_0.txt + + +====================BSL-1.0==================== +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) + + +====================BSL-1.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. + +====================BSL-1.0 AND BSL-1.0==================== +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2018 - 2023 Ulf Adams +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2020-2022 Junekey Jeon + + +====================COPYRIGHT==================== +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2020-2023 Junekey Jeon +// Copyright 2022 Peter Dimov +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2022 Peter Dimov +// Copyright 2023 Matt Borland +// Copyright 2023 Junekey Jeon +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + + +====================COPYRIGHT==================== +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt diff --git a/contrib/restricted/boost/charconv/LICENSE b/contrib/restricted/boost/charconv/LICENSE new file mode 100644 index 00000000000..36b7cd93cdf --- /dev/null +++ b/contrib/restricted/boost/charconv/LICENSE @@ -0,0 +1,23 @@ +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. diff --git a/contrib/restricted/boost/charconv/README.md b/contrib/restricted/boost/charconv/README.md new file mode 100644 index 00000000000..ce70657a205 --- /dev/null +++ b/contrib/restricted/boost/charconv/README.md @@ -0,0 +1,148 @@ +# CharConv +This library is a C++11 compatible implementation of `<charconv>`. The full documentation can be found here: https://www.boost.org/doc/libs/master/libs/charconv/doc/html/charconv.html + +# Build Status + +| | Master | Develop | +|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Github Actions | [](https://github.com/boostorg/charconv/actions/workflows/ci.yml) | [](https://github.com/boostorg/charconv/actions/workflows/ci.yml) | +| Drone | [](https://drone.cpp.al/boostorg/charconv) | [](https://drone.cpp.al/boostorg/charconv) | +| Codecov | [](https://codecov.io/gh/boostorg/charconv/branch/master) | [](https://codecov.io/gh/boostorg/charconv/branch/develop) | +| Fuzzing | [](https://github.com/boostorg/charconv/actions/workflows/fuzz.yml) | [](https://github.com/boostorg/charconv/actions/workflows/fuzz.yml)| + +# How to build the library + +## B2 + +```` +git clone https://github.com/boostorg/boost +cd boost +git submodule update --init +cd .. +./bootstrap +./b2 cxxstd=11 +```` + +This sets up a complete boost development and allows the tests to be run. To install the development environment run: + +```` +sudo ./b2 install cxxstd=11 +```` + +# Synopsis + +Charconv is a collection of parsing functions that are locale-independent, non-allocating, and non-throwing. + +```` +namespace boost { namespace charconv { + +enum class chars_format : unsigned +{ + scientific = 1 << 0, + fixed = 1 << 1, + hex = 1 << 2, + general = fixed | scientific +}; + +struct from_chars_result +{ + const char* ptr; + std::errc ec; + + friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept + friend constexpr bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept + constexpr explicit operator bool() const noexcept +} + +template <typename Integral> +BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integral& value, int base = 10) noexcept; + +BOOST_CXX14_CONSTEXPR from_chars_result from_chars<bool>(const char* first, const char* last, bool& value, int base) = delete; + +template <typename Real> +from_chars_result from_chars(const char* first, const char* last, Real& value, chars_format fmt = chars_format::general) noexcept; + +template <typename Real> +from_chars_result from_chars_erange(const char* first, const char* last, Real& value, chars_format fmt = chars_format::general) noexcept; + +struct to_chars_result +{ + char* ptr; + std::errc ec; + + friend constexpr bool operator==(const to_chars_result& lhs, const to_chars_result& rhs) noexcept; + friend constexpr bool operator!=(const to_chars_result& lhs, const to_chars_result& rhs) noexcept; + constexpr explicit operator bool() const noexcept +}; + +template <typename Integral> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, Integral value, int base = 10) noexcept; + +template <typename Integral> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars<bool>(char* first, char* last, Integral value, int base) noexcept = delete; + +template <typename Real> +to_chars_result to_chars(char* first, char* last, Real value, chars_format fmt = chars_format::general, int precision) noexcept; + +}} // Namespace boost::charconv +```` + +## Notes +- `BOOST_CXX14_CONSTEXPR` is defined as `constexpr` when compiling with C++14 or newer. + +- `BOOST_CHARCONV_CONSTEXPR` is defined as `constexpr` when compiling with C++14 or newer, and the compiler has `__builtin_is_constant_evaluated` + +- For explanation of `from_chars_erange` see docs under heading: _Usage notes for from_chars for floating point types_ + +# Examples + +## `from_chars` + +```` +const char* buffer = "42"; +int v = 0; +from_chars_result r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); +assert(r.ec == std::errc()); +assert(r); // Equivalent to the above +assert(v == 42); + +const char* buffer = "1.2345" +double v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); +assert(r.ec == std::errc()); +assert(v == 1.2345); + +const char* buffer = "2a"; +unsigned v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v, 16); +assert(r); // from_chars_result has operator bool() +assert(v == 42); + +const char* buffer = "1.3a2bp-10"; +double v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v, boost::charconv::chars_format::hex); +assert(r); +assert(v == 8.0427e-18); +```` +## `to_chars` + +```` +char buffer[64] {}; +int v = 42; +to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), v); +assert(r.ec == std::errc()); +assert(!strcmp(buffer, "42")); // strcmp returns 0 on match + +char buffer[64] {}; +double v = 1e300; +to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), v); +assert(r.ec == std::errc()); +assert(!strcmp(buffer, "1e+300")); + +char buffer[64] {}; +int v = 42; +to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), v, 16); +assert(r); // to_chars_result has operator bool() +assert(!strcmp(buffer, "2a")); // strcmp returns 0 on match + +```` diff --git a/contrib/restricted/boost/charconv/include/boost/charconv.hpp b/contrib/restricted/boost/charconv/include/boost/charconv.hpp new file mode 100644 index 00000000000..975390bea45 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv.hpp @@ -0,0 +1,12 @@ +#ifndef BOOST_CHARCONV_HPP_INCLUDED +#define BOOST_CHARCONV_HPP_INCLUDED + +// Copyright 2022 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include <boost/charconv/from_chars.hpp> +#include <boost/charconv/to_chars.hpp> +#include <boost/charconv/limits.hpp> + +#endif // #ifndef BOOST_CHARCONV_HPP_INCLUDED diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/chars_format.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/chars_format.hpp new file mode 100644 index 00000000000..0542372bffd --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/chars_format.hpp @@ -0,0 +1,22 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_CHARS_FORMAT_HPP +#define BOOST_CHARCONV_CHARS_FORMAT_HPP + +namespace boost { namespace charconv { + +// Floating-point format for primitive numerical conversion +// chars_format is a bitmask type (16.3.3.3.3) +enum class chars_format : unsigned +{ + scientific = 1 << 0, + fixed = 1 << 1, + hex = 1 << 2, + general = fixed | scientific +}; + +}} // Namespaces + +#endif // BOOST_CHARCONV_CHARS_FORMAT_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/config.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/config.hpp new file mode 100644 index 00000000000..0d94ccd4a70 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/config.hpp @@ -0,0 +1,39 @@ +#ifndef BOOST_CHARCONV_CONFIG_HPP_INCLUDED +#define BOOST_CHARCONV_CONFIG_HPP_INCLUDED + +// Copyright 2022 Peter Dimov +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include <boost/config.hpp> +#include <climits> + +// This header implements separate compilation features as described in +// http://www.boost.org/more/separate_compilation.html + +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHARCONV_DYN_LINK) +# if defined(BOOST_CHARCONV_SOURCE) +# define BOOST_CHARCONV_DECL BOOST_SYMBOL_EXPORT +# else +# define BOOST_CHARCONV_DECL BOOST_SYMBOL_IMPORT +# endif +#else +# define BOOST_CHARCONV_DECL +#endif + +// Autolink + +#if !defined(BOOST_CHARCONV_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_CHARCONV_NO_LIB) + +#define BOOST_LIB_NAME boost_charconv + +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHARCONV_DYN_LINK) +# define BOOST_DYN_LINK +#endif + +#include <boost/config/auto_link.hpp> + +#endif + +#endif // BOOST_CHARCONV_CONFIG_HPP_INCLUDED diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/apply_sign.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/apply_sign.hpp new file mode 100644 index 00000000000..ef6db714376 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/apply_sign.hpp @@ -0,0 +1,50 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_APPLY_SIGN_HPP +#define BOOST_CHARCONV_DETAIL_APPLY_SIGN_HPP + +#include <boost/config.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/detail/type_traits.hpp> +#include <type_traits> + +// We are purposefully converting values here +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4146) +#elif defined(__GNUC__) && __GNUC__ >= 5 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +#elif defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wconversion" +#endif + +namespace boost { namespace charconv { namespace detail { + +template <typename Integer, typename Unsigned_Integer = detail::make_unsigned_t<Integer>, + typename std::enable_if<detail::is_signed<Integer>::value, bool>::type = true> +constexpr Unsigned_Integer apply_sign(Integer val) noexcept +{ + return -(static_cast<Unsigned_Integer>(val)); +} + +template <typename Unsigned_Integer, typename std::enable_if<!detail::is_signed<Unsigned_Integer>::value, bool>::type = true> +constexpr Unsigned_Integer apply_sign(Unsigned_Integer val) noexcept +{ + return val; +} + +}}} // Namespaces + +#ifdef BOOST_MSVC +# pragma warning(pop) +#elif defined(__GNUC__) && __GNUC__ >= 5 +# pragma GCC diagnostic pop +#elif defined(__clang__) +# pragma clang diagnostic pop +#endif + +#endif // BOOST_CHARCONV_DETAIL_APPLY_SIGN_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/bit_layouts.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/bit_layouts.hpp new file mode 100644 index 00000000000..c163ce06ad2 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/bit_layouts.hpp @@ -0,0 +1,160 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_BIT_LAYOUTS_HPP +#define BOOST_CHARCONV_DETAIL_BIT_LAYOUTS_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <cstdint> +#include <cfloat> + +// Layouts of floating point types as specified by IEEE 754 +// See page 23 of IEEE 754-2008 + +namespace boost { namespace charconv { namespace detail { + +struct ieee754_binary16 +{ + static constexpr int significand_bits = 10; + static constexpr int exponent_bits = 5; + static constexpr int min_exponent = -14; + static constexpr int max_exponent = 15; + static constexpr int exponent_bias = -15; + static constexpr int decimal_digits = 5; +}; + +struct brainfloat16 +{ + static constexpr int significand_bits = 7; + static constexpr int exponent_bits = 8; + static constexpr int min_exponent = -126; + static constexpr int max_exponent = 127; + static constexpr int exponent_bias = -127; + static constexpr int decimal_digits = 4; +}; + +struct ieee754_binary32 +{ + static constexpr int significand_bits = 23; + static constexpr int exponent_bits = 8; + static constexpr int min_exponent = -126; + static constexpr int max_exponent = 127; + static constexpr int exponent_bias = -127; + static constexpr int decimal_digits = 9; +}; + +struct ieee754_binary64 +{ + static constexpr int significand_bits = 52; + static constexpr int exponent_bits = 11; + static constexpr int min_exponent = -1022; + static constexpr int max_exponent = 1023; + static constexpr int exponent_bias = -1023; + static constexpr int decimal_digits = 17; +}; + +// 80 bit long double (e.g. x86-64) +#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +struct IEEEl2bits +{ +#if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE + std::uint64_t mantissa_l : 64; + std::uint32_t exponent : 15; + std::uint32_t sign : 1; + std::uint64_t pad : 48; +#else // Big endian + std::uint64_t pad : 48; + std::uint32_t sign : 1; + std::uint32_t exponent : 15; + std::uint64_t mantissa_h : 64; +#endif +}; + +struct ieee754_binary80 +{ + static constexpr int significand_bits = 64; // Fraction is 63 and 1 integer bit + static constexpr int exponent_bits = 15; + static constexpr int min_exponent = -16382; + static constexpr int max_exponent = 16383; + static constexpr int exponent_bias = -16383; + static constexpr int decimal_digits = 18; +}; + +#define BOOST_CHARCONV_LDBL_BITS 80 + +// 128 bit long double (e.g. s390x, ppcle64) +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 + +struct IEEEl2bits +{ +#if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE + std::uint64_t mantissa_l : 64; + std::uint64_t mantissa_h : 48; + std::uint32_t exponent : 15; + std::uint32_t sign : 1; +#else // Big endian + std::uint32_t sign : 1; + std::uint32_t exponent : 15; + std::uint64_t mantissa_h : 48; + std::uint64_t mantissa_l : 64; +#endif +}; + +#define BOOST_CHARCONV_LDBL_BITS 128 + +// 64 bit long double (double == long double on ARM) +#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 + +struct IEEEl2bits +{ +#if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE + std::uint32_t mantissa_l : 32; + std::uint32_t mantissa_h : 20; + std::uint32_t exponent : 11; + std::uint32_t sign : 1; +#else // Big endian + std::uint32_t sign : 1; + std::uint32_t exponent : 11; + std::uint32_t mantissa_h : 20; + std::uint32_t mantissa_l : 32; +#endif +}; + +#define BOOST_CHARCONV_LDBL_BITS 64 + +#else // Unsupported long double representation +# define BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +# define BOOST_CHARCONV_LDBL_BITS -1 +#endif + +struct IEEEbinary128 +{ +#if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE + std::uint64_t mantissa_l : 64; + std::uint64_t mantissa_h : 48; + std::uint32_t exponent : 15; + std::uint32_t sign : 1; +#else // Big endian + std::uint32_t sign : 1; + std::uint32_t exponent : 15; + std::uint64_t mantissa_h : 48; + std::uint64_t mantissa_l : 64; +#endif +}; + +struct ieee754_binary128 +{ + static constexpr int significand_bits = 112; + static constexpr int exponent_bits = 15; + static constexpr int min_exponent = -16382; + static constexpr int max_exponent = 16383; + static constexpr int exponent_bias = 16383; + static constexpr int decimal_digits = 33; +}; + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_BIT_LAYOUTS_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/buffer_sizing.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/buffer_sizing.hpp new file mode 100644 index 00000000000..3115ee39e5f --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/buffer_sizing.hpp @@ -0,0 +1,72 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_BUFFER_SIZING_HPP +#define BOOST_CHARCONV_DETAIL_BUFFER_SIZING_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/integer_search_trees.hpp> +#include <type_traits> + +namespace boost { +namespace charconv { +namespace detail { + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127) // Conditional expression for BOOST_IF_CONSTEXPR will be constant in not C++17 +#endif + +template <typename Real> +inline int get_real_precision(int precision = -1) noexcept +{ + // If the user did not specify a precision than we use the maximum representable amount + // and remove trailing zeros at the end + + int real_precision; + BOOST_IF_CONSTEXPR (!std::is_same<Real, long double>::value + #ifdef BOOST_CHARCONV_HAS_QUADMATH + && !std::is_same<Real, __float128>::value + #endif + ) + { + real_precision = precision == -1 ? std::numeric_limits<Real>::max_digits10 : precision; + } + else + { + #ifdef BOOST_CHARCONV_HAS_QUADMATH + BOOST_CHARCONV_IF_CONSTEXPR (std::is_same<Real, __float128>::value) + { + real_precision = 33; + } + else + #endif + { + #if BOOST_CHARCONV_LDBL_BITS == 128 + real_precision = 33; + #else + real_precision = 18; + #endif + } + } + + return real_precision; +} + +template <typename Int> +inline int total_buffer_length(int real_precision, Int exp, bool signed_value) +{ + // Sign + integer part + '.' + precision of fraction part + e+/e- or p+/p- + exponent digits + return static_cast<int>(signed_value) + 1 + real_precision + 2 + num_digits(exp); +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +} //namespace detail +} //namespace charconv +} //namespace boost + +#endif //BOOST_CHARCONV_DETAIL_BUFFER_SIZING_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float32.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float32.hpp new file mode 100644 index 00000000000..85ece7f8c3a --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float32.hpp @@ -0,0 +1,55 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT32_HPP +#define BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT32_HPP + +#include <boost/charconv/detail/compute_float64.hpp> +#include <limits> +#include <cstdint> +#include <cmath> + +namespace boost { namespace charconv { namespace detail { + +inline float compute_float32(std::int64_t power, std::uint64_t i, bool negative, bool& success) noexcept +{ + const double d = compute_float64(power, i, negative, success); + float return_val; + + if (success) + { + // Some compilers (e.g. Intel) will optimize std::isinf to always false depending on compiler flags + // + // From Intel(R) oneAPI DPC++/C++ Compiler 2023.0.0 (2023.0.0.20221201) + // warning: comparison with infinity always evaluates to false in fast floating point modes [-Wtautological-constant-compare] + // if (std::isinf(return_val)) + if (d > static_cast<double>((std::numeric_limits<float>::max)()) || + d < static_cast<double>((std::numeric_limits<float>::lowest)())) + { + return_val = negative ? -HUGE_VALF : HUGE_VALF; + success = false; + } + else + { + return_val = static_cast<float>(d); + } + } + else + { + if (power > 38) + { + return_val = negative ? -HUGE_VALF : HUGE_VALF; + } + else + { + return_val = negative ? -0.0F : 0.0F; + } + } + + return return_val; +} + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT32_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float64.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float64.hpp new file mode 100644 index 00000000000..3cb83537fa9 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float64.hpp @@ -0,0 +1,201 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP +#define BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/significand_tables.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/core/bit.hpp> +#include <cstdint> +#include <cfloat> +#include <cstring> +#include <cmath> + +namespace boost { namespace charconv { namespace detail { + +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 +}; + +// Attempts to compute i * 10^(power) exactly; and if "negative" is true, negate the result. +// +// This function will only work in some cases, when it does not work, success is +// set to false. This should work *most of the time* (like 99% of the time). +// We assume that power is in the [-325, 308] interval. +inline double compute_float64(std::int64_t power, std::uint64_t i, bool negative, bool& success) noexcept +{ + static constexpr auto smallest_power = -325; + static constexpr auto largest_power = 308; + + // We start with a fast path + // It was described in Clinger WD. + // How to read floating point numbers accurately. + // ACM SIGPLAN Notices. 1990 +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + if (0 <= power && power <= 22 && i <= UINT64_C(9007199254740991)) +#else + if (-22 <= power && power <= 22 && i <= UINT64_C(9007199254740991)) +#endif + { + // The general idea is as follows. + // If 0 <= s < 2^53 and if 10^0 <= p <= 10^22 then + // 1) Both s and p can be represented exactly as 64-bit floating-point + // values + // (binary64). + // 2) Because s and p can be represented exactly as floating-point values, + // then s * p + // and s / p will produce correctly rounded values. + + auto d = static_cast<double>(i); + + if (power < 0) + { + d = d / powers_of_ten[-power]; + } + else + { + d = d * powers_of_ten[power]; + } + + if (negative) + { + d = -d; + } + + success = true; + return d; + } + + // When 22 < power && power < 22 + 16, we could + // hope for another, secondary fast path. It was + // described by David M. Gay in "Correctly rounded + // binary-decimal and decimal-binary conversions." (1990) + // If you need to compute i * 10^(22 + x) for x < 16, + // first compute i * 10^x, if you know that result is exact + // (e.g., when i * 10^x < 2^53), + // then you can still proceed and do (i * 10^x) * 10^22. + // Is this worth your time? + // You need 22 < power *and* power < 22 + 16 *and* (i * 10^(x-22) < 2^53) + // for this second fast path to work. + // If you have 22 < power *and* power < 22 + 16, and then you + // optimistically compute "i * 10^(x-22)", there is still a chance that you + // have wasted your time if i * 10^(x-22) >= 2^53. It makes the use cases of + // this optimization maybe less common than we would like. Source: + // http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + // also used in RapidJSON: https://rapidjson.org/strtod_8h_source.html + + if (i == 0 || power < smallest_power) + { + return negative ? -0.0 : 0.0; + } + else if (power > largest_power) + { + return negative ? -HUGE_VAL : HUGE_VAL; + } + + const std::uint64_t factor_significand = significands_table::significand_64[power - smallest_power]; + const std::int64_t exponent = (((152170 + 65536) * power) >> 16) + 1024 + 63; + int leading_zeros = boost::core::countl_zero(i); + i <<= static_cast<std::uint64_t>(leading_zeros); + + uint128 product = umul128(i, factor_significand); + std::uint64_t low = product.low; + std::uint64_t high = product.high; + + // We know that upper has at most one leading zero because + // both i and factor_mantissa have a leading one. This means + // that the result is at least as large as ((1<<63)*(1<<63))/(1<<64). + // + // As long as the first 9 bits of "upper" are not "1", then we + // know that we have an exact computed value for the leading + // 55 bits because any imprecision would play out as a +1, in the worst case. + // Having 55 bits is necessary because we need 53 bits for the mantissa, + // but we have to have one rounding bit and, we can waste a bit if the most + // significant bit of the product is zero. + // + // We expect this next branch to be rarely taken (say 1% of the time). + // When (upper & 0x1FF) == 0x1FF, it can be common for + // lower + i < lower to be true (proba. much higher than 1%). + if (BOOST_UNLIKELY((high & 0x1FF) == 0x1FF) && (low + i < low)) + { + const std::uint64_t factor_significand_low = significands_table::significand_128[power - smallest_power]; + product = umul128(i, factor_significand_low); + //const std::uint64_t product_low = product.low; + const std::uint64_t product_middle2 = product.high; + const std::uint64_t product_middle1 = low; + std::uint64_t product_high = high; + const std::uint64_t product_middle = product_middle1 + product_middle2; + + if (product_middle < product_middle1) + { + product_high++; + } + + // Commented out because possibly unneeded + // See: https://arxiv.org/pdf/2212.06644.pdf + /* + // we want to check whether mantissa *i + i would affect our result + // This does happen, e.g. with 7.3177701707893310e+15 + if (((product_middle + 1 == 0) && ((product_high & 0x1FF) == 0x1FF) && (product_low + i < product_low))) + { + success = false; + return 0; + } + */ + + low = product_middle; + high = product_high; + } + + // The final significand should be 53 bits with a leading 1 + // We shift it so that it occupies 54 bits with a leading 1 + const std::uint64_t upper_bit = high >> 63; + std::uint64_t significand = high >> (upper_bit + 9); + leading_zeros += static_cast<int>(1 ^ upper_bit); + + // If we have lots of trailing zeros we may fall between two values + if (BOOST_UNLIKELY((low == 0) && ((high & 0x1FF) == 0) && ((significand & 3) == 1))) + { + // if significand & 1 == 1 we might need to round up + success = false; + return 0; + } + + significand += significand & 1; + significand >>= 1; + + // Here the significand < (1<<53), unless there is an overflow + if (significand >= (UINT64_C(1) << 53)) + { + significand = (UINT64_C(1) << 52); + leading_zeros--; + } + + significand &= ~(UINT64_C(1) << 52); + const auto real_exponent = static_cast<std::uint64_t>(exponent - leading_zeros); + + // We have to check that real_exponent is in range, otherwise fail + if (BOOST_UNLIKELY((real_exponent < 1) || (real_exponent > 2046))) + { + success = false; + return 0; + } + + significand |= real_exponent << 52; + significand |= ((static_cast<std::uint64_t>(negative) << 63)); + + double d; + std::memcpy(&d, &significand, sizeof(d)); + + success = true; + return d; +} + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT64_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float80.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float80.hpp new file mode 100644 index 00000000000..ad1e51486ab --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/compute_float80.hpp @@ -0,0 +1,114 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT80_HPP +#define BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT80_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <system_error> +#include <type_traits> +#include <limits> +#include <cstdint> +#include <cmath> +#include <climits> +#include <cfloat> + +#ifdef BOOST_CHARCONV_DEBUG_FLOAT128 +#include <iostream> +#include <iomanip> +#include <boost/charconv/detail/to_chars_integer_impl.hpp> +#endif + +namespace boost { namespace charconv { namespace detail { + +#if BOOST_CHARCONV_LDBL_BITS > 64 + +static constexpr long double powers_of_ten_ld[] = { + 1e0L, 1e1L, 1e2L, 1e3L, 1e4L, 1e5L, 1e6L, + 1e7L, 1e8L, 1e9L, 1e10L, 1e11L, 1e12L, 1e13L, + 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L, 1e20L, + 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L, + 1e28L, 1e29L, 1e30L, 1e31L, 1e32L, 1e33L, 1e34L, + 1e35L, 1e36L, 1e37L, 1e38L, 1e39L, 1e40L, 1e41L, + 1e42L, 1e43L, 1e44L, 1e45L, 1e46L, 1e47L, 1e48L, + 1e49L, 1e50L, 1e51L, 1e52L, 1e53L, 1e54L, 1e55L +}; + +template <typename ResultType, typename Unsigned_Integer, typename ArrayPtr> +inline ResultType fast_path(std::int64_t q, Unsigned_Integer w, bool negative, ArrayPtr table) noexcept +{ + // The general idea is as follows. + // if 0 <= s <= 2^64 and if 10^0 <= p <= 10^27 + // Both s and p can be represented exactly + // because of this s*p and s/p will produce + // correctly rounded values + + auto ld = static_cast<ResultType>(w); + + if (q < 0) + { + ld /= table[-q]; + } + else + { + ld *= table[q]; + } + + if (negative) + { + ld = -ld; + } + + return ld; +} + +template <typename ResultType, typename Unsigned_Integer> +inline ResultType compute_float80(std::int64_t q, Unsigned_Integer w, bool negative, std::errc& success) noexcept +{ + // GLIBC uses 2^-16444 but MPFR uses 2^-16445 as the smallest subnormal value for 80 bit + // 39 is the max number of digits in an uint128_t + static constexpr auto smallest_power = -4951 - 39; + static constexpr auto largest_power = 4932; + + // We start with a fast path + // It is an extension of what was described in Clinger WD. + // How to read floating point numbers accurately. + // ACM SIGPLAN Notices. 1990 + // https://dl.acm.org/doi/pdf/10.1145/93542.93557 + static constexpr auto clinger_max_exp = BOOST_CHARCONV_LDBL_BITS == 80 ? 27 : 48; // NOLINT : Only changes by platform + static constexpr auto clinger_min_exp = BOOST_CHARCONV_LDBL_BITS == 80 ? -34 : -55; // NOLINT + + if (clinger_min_exp <= q && q <= clinger_max_exp && w <= static_cast<Unsigned_Integer>(1) << 113) + { + success = std::errc(); + return fast_path<ResultType>(q, w, negative, powers_of_ten_ld); + } + + if (w == 0) + { + success = std::errc(); + return negative ? -0.0L : 0.0L; + } + else if (q > largest_power) + { + success = std::errc::result_out_of_range; + return negative ? -HUGE_VALL : HUGE_VALL; + } + else if (q < smallest_power) + { + success = std::errc::result_out_of_range; + return negative ? -0.0L : 0.0L; + } + + success = std::errc::not_supported; + return 0; +} + +#endif // BOOST_CHARCONV_LDBL_BITS > 64 + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT80_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/config.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/config.hpp new file mode 100644 index 00000000000..602f8c75d61 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/config.hpp @@ -0,0 +1,191 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_CONFIG_HPP +#define BOOST_CHARCONV_DETAIL_CONFIG_HPP + +#include <boost/config.hpp> +#include <type_traits> +#include <cfloat> + +#include <boost/assert.hpp> +#define BOOST_CHARCONV_ASSERT(expr) BOOST_ASSERT(expr) +#define BOOST_CHARCONV_ASSERT_MSG(expr, msg) BOOST_ASSERT_MSG(expr, msg) + +#ifdef BOOST_CHARCONV_DEBUG +# define BOOST_CHARCONV_DEBUG_ASSERT(expr) BOOST_CHARCONV_ASSERT(expr) +#else +# define BOOST_CHARCONV_DEBUG_ASSERT(expr) +#endif + +// Use 128-bit integers and suppress warnings for using extensions +#if defined(BOOST_HAS_INT128) +# define BOOST_CHARCONV_HAS_INT128 +# define BOOST_CHARCONV_INT128_MAX static_cast<boost::int128_type>((static_cast<boost::uint128_type>(1) << 127) - 1) +# define BOOST_CHARCONV_INT128_MIN (-BOOST_CHARCONV_INT128_MAX - 1) +# define BOOST_CHARCONV_UINT128_MAX (2 * static_cast<boost::uint128_type>(BOOST_CHARCONV_INT128_MAX) + 1) +#endif + +#ifndef BOOST_NO_CXX14_CONSTEXPR +# define BOOST_CHARCONV_CXX14_CONSTEXPR BOOST_CXX14_CONSTEXPR +# define BOOST_CHARCONV_CXX14_CONSTEXPR_NO_INLINE BOOST_CXX14_CONSTEXPR +#else +# define BOOST_CHARCONV_CXX14_CONSTEXPR inline +# define BOOST_CHARCONV_CXX14_CONSTEXPR_NO_INLINE +#endif + +#if defined(__GNUC__) && __GNUC__ == 5 +# define BOOST_CHARCONV_GCC5_CONSTEXPR inline +#else +# define BOOST_CHARCONV_GCC5_CONSTEXPR BOOST_CHARCONV_CXX14_CONSTEXPR +#endif + +// C++17 allowed for constexpr lambdas +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201603L +# define BOOST_CHARCONV_CXX17_CONSTEXPR constexpr +#else +# define BOOST_CHARCONV_CXX17_CONSTEXPR inline +#endif + +// Determine endianness +#if defined(_WIN32) + +#define BOOST_CHARCONV_ENDIAN_BIG_BYTE 0 +#define BOOST_CHARCONV_ENDIAN_LITTLE_BYTE 1 + +#elif defined(__BYTE_ORDER__) + +#define BOOST_CHARCONV_ENDIAN_BIG_BYTE (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define BOOST_CHARCONV_ENDIAN_LITTLE_BYTE (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + +#else + +#error Could not determine endian type. Please file an issue at https://github.com/cppalliance/charconv with your architecture + +#endif // Determine endianness + +// Inclue intrinsics if available +#if defined(BOOST_MSVC) +# include <intrin.h> +# if defined(_WIN64) +# define BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS +# else +# define BOOST_CHARCONV_HAS_MSVC_32BIT_INTRINSICS +# endif +#endif + +static_assert((BOOST_CHARCONV_ENDIAN_BIG_BYTE || BOOST_CHARCONV_ENDIAN_LITTLE_BYTE) && + !(BOOST_CHARCONV_ENDIAN_BIG_BYTE && BOOST_CHARCONV_ENDIAN_LITTLE_BYTE), +"Inconsistent endianness detected. Please file an issue at https://github.com/cppalliance/charconv with your architecture"); + +// Suppress additional buffer overrun check. +// I have no idea why MSVC thinks some functions here are vulnerable to the buffer overrun +// attacks. No, they aren't. +#if defined(__GNUC__) || defined(__clang__) + #define BOOST_CHARCONV_SAFEBUFFERS +#elif defined(_MSC_VER) + #define BOOST_CHARCONV_SAFEBUFFERS __declspec(safebuffers) +#else + #define BOOST_CHARCONV_SAFEBUFFERS +#endif + +#if defined(__has_builtin) + #define BOOST_CHARCONV_HAS_BUILTIN(x) __has_builtin(x) +#else + #define BOOST_CHARCONV_HAS_BUILTIN(x) false +#endif + +// Workaround for errors in MSVC 14.3 with gotos in if constexpr blocks +#if defined(BOOST_MSVC) && (BOOST_MSVC == 1933 || BOOST_MSVC == 1934) +# define BOOST_CHARCONV_IF_CONSTEXPR if +#else +# define BOOST_CHARCONV_IF_CONSTEXPR BOOST_IF_CONSTEXPR +#endif + +// Clang < 4 return type deduction does not work with the policy implementation +#ifndef BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +# if (defined(__clang__) && __clang_major__ < 4) || (defined(_MSC_VER) && _MSC_VER == 1900) +# define BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION +# endif +#elif defined(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION) +# define BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif + +// Is constant evaluated detection +#ifdef __cpp_lib_is_constant_evaluated +# define BOOST_CHARCONV_HAS_IS_CONSTANT_EVALUATED +#endif + +#ifdef __has_builtin +# if __has_builtin(__builtin_is_constant_evaluated) && !defined(BOOST_NO_CXX14_CONSTEXPR) +# define BOOST_CHARCONV_HAS_BUILTIN_IS_CONSTANT_EVALUATED +# endif +#endif + +// +// MSVC also supports __builtin_is_constant_evaluated if it's recent enough: +// +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 192528326) +# define BOOST_CHARCONV_HAS_BUILTIN_IS_CONSTANT_EVALUATED +#endif + +// +// As does GCC-9: +// +#if !defined(BOOST_NO_CXX14_CONSTEXPR) && defined(__GNUC__) && (__GNUC__ >= 9) && !defined(BOOST_CHARCONV_HAS_BUILTIN_IS_CONSTANT_EVALUATED) +# define BOOST_CHARCONV_HAS_BUILTIN_IS_CONSTANT_EVALUATED +#endif + +#if defined(BOOST_CHARCONV_HAS_IS_CONSTANT_EVALUATED) && !defined(BOOST_NO_CXX14_CONSTEXPR) +# define BOOST_CHARCONV_IS_CONSTANT_EVALUATED(x) std::is_constant_evaluated() +#elif defined(BOOST_CHARCONV_HAS_BUILTIN_IS_CONSTANT_EVALUATED) +# define BOOST_CHARCONV_IS_CONSTANT_EVALUATED(x) __builtin_is_constant_evaluated() +#elif !defined(BOOST_NO_CXX14_CONSTEXPR) && defined(__GNUC__) && (__GNUC__ >= 6) +# define BOOST_CHARCONV_IS_CONSTANT_EVALUATED(x) __builtin_constant_p(x) +# define BOOST_CHARCONV_USING_BUILTIN_CONSTANT_P +#else +# define BOOST_CHARCONV_IS_CONSTANT_EVALUATED(x) false +# define BOOST_CHARCONV_NO_CONSTEXPR_DETECTION +#endif + +#ifdef BOOST_MSVC +# define BOOST_CHARCONV_ASSUME(expr) __assume(expr) +#elif defined(__clang__) +# define BOOST_CHARCONV_ASSUME(expr) __builtin_assume(expr) +#elif defined(__GNUC__) +# define BOOST_CHARCONV_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +#elif defined(__has_cpp_attribute) +# if __has_cpp_attribute(assume) +# define BOOST_CHARCONV_ASSUME(expr) [[assume(expr)]] +# else +# define BOOST_CHARCONV_ASSUME(expr) +# endif +#else +# define BOOST_CHARCONV_ASSUME(expr) +#endif + +// Detection for C++23 fixed width floating point types +// All of these types are optional so check for each of them individually +#if (defined(_MSVC_LANG) && _MSVC_LANG > 202002L) || __cplusplus > 202002L +# if __has_include(<stdfloat>) +# error #include <stdfloat> +# endif +#endif +#ifdef __STDCPP_FLOAT16_T__ +# define BOOST_CHARCONV_HAS_FLOAT16 +#endif +#ifdef __STDCPP_FLOAT32_T__ +# define BOOST_CHARCONV_HAS_FLOAT32 +#endif +#ifdef __STDCPP_FLOAT64_T__ +# define BOOST_CHARCONV_HAS_FLOAT64 +#endif +#ifdef __STDCPP_FLOAT128_T__ +# define BOOST_CHARCONV_HAS_STDFLOAT128 +#endif +#ifdef __STDCPP_BFLOAT16_T__ +# define BOOST_CHARCONV_HAS_BRAINFLOAT16 +#endif + +#endif // BOOST_CHARCONV_DETAIL_CONFIG_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/dragonbox.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/dragonbox.hpp new file mode 100644 index 00000000000..f2d3449acdf --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/dragonbox.hpp @@ -0,0 +1,2752 @@ +// Copyright 2020-2022 Junekey Jeon +// +// The contents of this file may be used under the terms of +// the Apache License v2.0 with LLVM Exceptions. +// +// (See accompanying file LICENSE-Apache or copy at +// https://llvm.org/foundation/relicensing/LICENSE.txt) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +// +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_DRAGONBOX_HPP +#define BOOST_CHARCONV_DETAIL_DRAGONBOX_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/dragonbox/dragonbox_common.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/detail/buffer_sizing.hpp> +#include <boost/charconv/detail/to_chars_result.hpp> +#include <boost/charconv/chars_format.hpp> +#include <boost/core/bit.hpp> +#include <type_traits> +#include <limits> +#include <cstdint> +#include <cstring> + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127) // Conditional expression is constant (e.g. BOOST_IF_CONSTEXPR statements) +# pragma warning(disable: 4307) // Integral constant overflow (Only MSVC-14.1 issued this warning) +#endif + +namespace boost { namespace charconv { namespace detail { + +// A floating-point traits class defines ways to interpret a bit pattern of given size as an +// encoding of floating-point number. This is a default implementation of such a traits class, +// supporting ways to interpret 32-bits into a binary32-encoded floating-point number and to +// interpret 64-bits into a binary64-encoded floating-point number. Users might specialize this +// class to change the default behavior for certain types. + +template <typename T> +struct dragonbox_float_traits +{ + // I don't know if there is a truly reliable way of detecting + // IEEE-754 binary32/binary64 formats; I just did my best here. + static_assert(std::numeric_limits<T>::is_iec559 && std::numeric_limits<T>::radix == 2 && + (physical_bits<T>::value == 32 || physical_bits<T>::value == 64), + "default_ieee754_traits only works for 32-bits or 64-bits types " + "supporting binary32 or binary64 formats!"); + + // The type that is being viewed. + using type = T; + + // Refers to the format specification class. + using format = typename std::conditional<physical_bits<T>::value == 32, ieee754_binary32, ieee754_binary64>::type; + + // Defines an unsigned integer type that is large enough to carry a variable of type T. + // Most of the operations will be done on this integer type. + using carrier_uint = + typename std::conditional<physical_bits<T>::value == 32, std::uint32_t, std::uint64_t>::type; + + static_assert(sizeof(carrier_uint) == sizeof(T), "Type T must have a unsigned type with the same number of bits"); + + // Number of bits in the above unsigned integer type. + static constexpr int carrier_bits = static_cast<int>(physical_bits<carrier_uint>::value); + + // Convert from carrier_uint into the original type. + // Depending on the floating-point encoding format, this operation might not be possible for + // some specific bit patterns. However, the contract is that u always denotes a + // valid bit pattern, so this function must be assumed to be noexcept. + static T carrier_to_float(carrier_uint u) noexcept + { + T x; + std::memcpy(&x, &u, sizeof(carrier_uint)); + return x; + } + + // Same as above. + static carrier_uint float_to_carrier(T x) noexcept + { + carrier_uint u; + std::memcpy(&u, &x, sizeof(carrier_uint)); + return u; + } + + // Extract exponent bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. This function does not do bias adjustment. + static constexpr unsigned extract_exponent_bits(carrier_uint u) noexcept + { + return static_cast<unsigned>(u >> format::significand_bits) & ((static_cast<unsigned int>(1) << format::exponent_bits) - 1); + } + + // Extract significand bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. The result does not contain the implicit bit. + static constexpr carrier_uint extract_significand_bits(carrier_uint u) noexcept + { + return carrier_uint(u & carrier_uint((carrier_uint(1) << format::significand_bits) - 1)); + } + + // Remove the exponent bits and extract significand bits together with the sign bit. + static constexpr carrier_uint remove_exponent_bits(carrier_uint u, unsigned int exponent_bits) noexcept + { + return u ^ (carrier_uint(exponent_bits) << format::significand_bits); + } + + // Shift the obtained signed significand bits to the left by 1 to remove the sign bit. + static constexpr carrier_uint remove_sign_bit_and_shift(carrier_uint u) noexcept { + return carrier_uint(carrier_uint(u) << 1); + } + + // The actual value of exponent is obtained by adding this value to the extracted exponent + // bits. + static constexpr int exponent_bias = 1 - (1 << (carrier_bits - format::significand_bits - 2)); + + // Obtain the actual value of the binary exponent from the extracted exponent bits. + static constexpr int binary_exponent(unsigned exponent_bits) noexcept + { + return static_cast<int>(exponent_bits == 0 ? format::min_exponent : int(exponent_bits) + format::exponent_bias); + } + + // Obtain the actual value of the binary exponent from the extracted significand bits and + // exponent bits. + static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept + { + return exponent_bits == 0 ? significand_bits : significand_bits | (carrier_uint(1) << format::significand_bits); + } + + /* Various boolean observer functions */ + + static constexpr bool is_nonzero(carrier_uint u) noexcept + { + return (u << 1) != 0; + } + + static constexpr bool is_positive(carrier_uint u) noexcept + { + return u < (carrier_uint(1) << (format::significand_bits + format::exponent_bits)); + } + + static constexpr bool is_negative(carrier_uint u) noexcept + { + return !is_positive(u); + } + + static constexpr bool is_finite(unsigned exponent_bits) noexcept + { + return exponent_bits != ((1u << format::exponent_bits) - 1); + } + + static constexpr bool has_all_zero_significand_bits(carrier_uint u) noexcept + { + return (u << 1) == 0; + } + + static constexpr bool has_even_significand_bits(carrier_uint u) noexcept + { + return u % 2 == 0; + } +}; + +// Convenient wrappers for floating-point traits classes. +// In order to reduce the argument passing overhead, these classes should be as simple as +// possible (e.g., no inheritance, no private non-static data member, etc.; this is an +// unfortunate fact about common ABI convention). + +template <typename T, typename Traits = dragonbox_float_traits<T>> +struct dragonbox_float_bits; + +template <typename T, typename Traits = dragonbox_float_traits<T>> +struct dragonbox_signed_significand_bits; + +template <typename T, typename Traits> +struct dragonbox_float_bits +{ + using type = T; + using traits_type = Traits; + using carrier_uint = typename traits_type::carrier_uint; + + carrier_uint u; + + dragonbox_float_bits() = default; + constexpr explicit dragonbox_float_bits(carrier_uint bit_pattern) noexcept : u{bit_pattern} {} + constexpr explicit dragonbox_float_bits(T float_value) noexcept + : u{traits_type::float_to_carrier(float_value)} {} + + T to_float() const noexcept + { + return traits_type::carrier_to_float(u); + } + + // Extract exponent bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. This function does not do bias adjustment. + constexpr unsigned int extract_exponent_bits() const noexcept + { + return traits_type::extract_exponent_bits(u); + } + + // Extract significand bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. The result does not contain the implicit bit. + constexpr carrier_uint extract_significand_bits() const noexcept + { + return traits_type::extract_significand_bits(u); + } + + // Remove the exponent bits and extract significand bits together with the sign bit. + constexpr auto remove_exponent_bits(unsigned int exponent_bits) const noexcept -> dragonbox_signed_significand_bits<type, traits_type> + { + return dragonbox_signed_significand_bits<type, traits_type>(traits_type::remove_exponent_bits(u, exponent_bits)); + } + + // Obtain the actual value of the binary exponent from the extracted exponent bits. + static constexpr int binary_exponent(unsigned exponent_bits) noexcept + { + return traits_type::binary_exponent(exponent_bits); + } + + constexpr int binary_exponent() const noexcept + { + return binary_exponent(extract_exponent_bits()); + } + + // Obtain the actual value of the binary exponent from the extracted significand bits and + // exponent bits. + static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept + { + return traits_type::binary_significand(significand_bits, exponent_bits); + } + + constexpr carrier_uint binary_significand() const noexcept + { + return binary_significand(extract_significand_bits(), extract_exponent_bits()); + } + + constexpr bool is_nonzero() const noexcept + { + return traits_type::is_nonzero(u); + } + + constexpr bool is_positive() const noexcept + { + return traits_type::is_positive(u); + } + + constexpr bool is_negative() const noexcept + { + return traits_type::is_negative(u); + } + + constexpr bool is_finite(unsigned exponent_bits) const noexcept + { + return traits_type::is_finite(exponent_bits); + } + + constexpr bool is_finite() const noexcept + { + return traits_type::is_finite(extract_exponent_bits()); + } + + constexpr bool has_even_significand_bits() const noexcept + { + return traits_type::has_even_significand_bits(u); + } +}; + +template <typename T, typename Traits> +struct dragonbox_signed_significand_bits +{ + using type = T; + using traits_type = Traits; + using carrier_uint = typename traits_type::carrier_uint; + + carrier_uint u; + + dragonbox_signed_significand_bits() = default; + constexpr explicit dragonbox_signed_significand_bits(carrier_uint bit_pattern) noexcept + : u{bit_pattern} {} + + // Shift the obtained signed significand bits to the left by 1 to remove the sign bit. + constexpr carrier_uint remove_sign_bit_and_shift() const noexcept + { + return traits_type::remove_sign_bit_and_shift(u); + } + + constexpr bool is_positive() const noexcept + { + return traits_type::is_positive(u); + } + + constexpr bool is_negative() const noexcept + { + return traits_type::is_negative(u); + } + + constexpr bool has_all_zero_significand_bits() const noexcept + { + return traits_type::has_all_zero_significand_bits(u); + } + + constexpr bool has_even_significand_bits() const noexcept + { + return traits_type::has_even_significand_bits(u); + } +}; + + //////////////////////////////////////////////////////////////////////////////////////// + // Utilities for fast divisibility tests. + //////////////////////////////////////////////////////////////////////////////////////// + + namespace div { + // Replace n by floor(n / 10^N). + // Returns true if and only if n is divisible by 10^N. + // Precondition: n <= 10^(N+1) + // !!It takes an in-out parameter!! + template <int N> + struct divide_by_pow10_info; + + template <> + struct divide_by_pow10_info<1> + { + static constexpr std::uint32_t magic_number = 6554; + static constexpr int shift_amount = 16; + }; + + template <> + struct divide_by_pow10_info<2> + { + static constexpr std::uint32_t magic_number = 656; + static constexpr int shift_amount = 16; + }; + + template <int N> + BOOST_CXX14_CONSTEXPR bool check_divisibility_and_divide_by_pow10(std::uint32_t& n) noexcept + { + // Make sure the computation for max_n does not overflow. + // static_assert(N + 1 <= log::floor_log10_pow2(31)); + BOOST_CHARCONV_ASSERT(n <= compute_power(UINT32_C(10), N + 1)); + + using info = divide_by_pow10_info<N>; + n *= info::magic_number; + + constexpr auto mask = std::uint32_t(std::uint32_t(1) << info::shift_amount) - 1; + bool result = ((n & mask) < info::magic_number); + + n >>= info::shift_amount; + return result; + } + + // Compute floor(n / 10^N) for small n and N. + // Precondition: n <= 10^(N+1) + template <int N> + BOOST_CXX14_CONSTEXPR std::uint32_t small_division_by_pow10(std::uint32_t n) noexcept + { + // Make sure the computation for max_n does not overflow. + // static_assert(N + 1 <= log::floor_log10_pow2(31)); + BOOST_CHARCONV_ASSERT(n <= compute_power(UINT32_C(10), N + 1)); + + return (n * divide_by_pow10_info<N>::magic_number) >> divide_by_pow10_info<N>::shift_amount; + } + + // Compute floor(n / 10^N) for small N. + // Precondition: n <= n_max + template <unsigned N, typename UInt, UInt n_max> + BOOST_CXX14_CONSTEXPR UInt divide_by_pow10(UInt n) noexcept + { + + // Specialize for 32-bit division by 100. + // Compiler is supposed to generate the identical code for just writing + // "n / 100", but for some reason MSVC generates an inefficient code + // (mul + mov for no apparent reason, instead of single imul), + // so we does this manually. + BOOST_IF_CONSTEXPR (std::is_same<UInt, std::uint32_t>::value && N == 2) + { + return static_cast<UInt>(umul64(static_cast<std::uint32_t>(n), UINT32_C(1374389535)) >> 37); + } + // Specialize for 64-bit division by 1000. + // Ensure that the correctness condition is met. + else BOOST_IF_CONSTEXPR (std::is_same<UInt, std::uint64_t>::value && N == 3 && n_max <= UINT64_C(15534100272597517998)) + { + return static_cast<UInt>(umul128_upper64(n, UINT64_C(2361183241434822607)) >> 7); + } + else + { + BOOST_CXX14_CONSTEXPR auto divisor = compute_power(static_cast<UInt>(10), N); + return n / divisor; + } + } + + #ifdef BOOST_MSVC + # pragma warning(push) + # pragma warning(disable: 4100) // MSVC 14.0 does not have BOOST_ATTRIBUTE_UNUSED so we disable the warning + #endif + + template <typename UInt> + BOOST_CXX14_CONSTEXPR UInt divide_by_pow10(unsigned N, BOOST_ATTRIBUTE_UNUSED UInt n_max, UInt n) noexcept + { + BOOST_IF_CONSTEXPR (std::is_same<UInt, std::uint32_t>::value && N == 2) + { + return static_cast<UInt>(umul64(static_cast<std::uint32_t>(n), static_cast<std::uint32_t>(1374389535)) >> UINT32_C(37)); + } + // Specialize for 64-bit division by 1000. + // Ensure that the correctness condition is met. + else BOOST_IF_CONSTEXPR (std::is_same<UInt, std::uint64_t>::value && N == 3 && n_max <= UINT64_C(15534100272597517998)) + { + return static_cast<UInt>(umul128_upper64(n, UINT64_C(2361183241434822607)) >> 7); + } + else + { + auto divisor = compute_power(static_cast<UInt>(10), N); + return n / divisor; + } + } + + #ifdef BOOST_MSVC + # pragma warning(pop) + #endif + } + +//////////////////////////////////////////////////////////////////////////////////////// +// Return types for the main interface function. +//////////////////////////////////////////////////////////////////////////////////////// + +template <typename UInt, bool is_signed, bool trailing_zero_flag> +struct decimal_fp; + +template <typename UInt> +struct decimal_fp<UInt, false, false> +{ + using carrier_uint = UInt; + + carrier_uint significand; + int exponent; +}; + +template <typename UInt> +struct decimal_fp<UInt, true, false> +{ + using carrier_uint = UInt; + + carrier_uint significand; + int exponent; + bool is_negative; +}; + +template <typename UInt> +struct decimal_fp<UInt, false, true> +{ + using carrier_uint = UInt; + + carrier_uint significand; + int exponent; + bool may_have_trailing_zeros; +}; + +template <typename UInt> +struct decimal_fp<UInt, true, true> +{ + using carrier_uint = UInt; + + carrier_uint significand; + int exponent; + bool is_negative; + bool may_have_trailing_zeros; +}; + +template <typename UInt> +using unsigned_decimal_fp = decimal_fp<UInt, false, false>; + +template <typename UInt> +using signed_decimal_fp = decimal_fp<UInt, true, false>; + +//////////////////////////////////////////////////////////////////////////////////////// +// Computed cache entries. +//////////////////////////////////////////////////////////////////////////////////////// + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) +template <bool b> +struct cache_holder_ieee754_binary32_impl +#else +struct cache_holder_ieee754_binary32 +#endif +{ + using cache_entry_type = std::uint64_t; + static constexpr int cache_bits = 64; + static constexpr int min_k = -31; + static constexpr int max_k = 46; + static constexpr cache_entry_type cache[] = { + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, 0xfd87b5f28300ca0e, + 0x9e74d1b791e07e49, 0xc612062576589ddb, 0xf79687aed3eec552, 0x9abe14cd44753b53, + 0xc16d9a0095928a28, 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, 0xe69594bec44de15c, + 0x901d7cf73ab0acda, 0xb424dc35095cd810, 0xe12e13424bb40e14, 0x8cbccc096f5088cc, + 0xafebff0bcb24aaff, 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, 0xd1b71758e219652c, + 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, 0xcccccccccccccccd, 0x8000000000000000, + 0xa000000000000000, 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, 0xbebc200000000000, + 0xee6b280000000000, 0x9502f90000000000, 0xba43b74000000000, 0xe8d4a51000000000, + 0x9184e72a00000000, 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, 0xad78ebc5ac620000, + 0xd8d726b7177a8000, 0x878678326eac9000, 0xa968163f0a57b400, 0xd3c21bcecceda100, + 0x84595161401484a0, 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985, + 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, 0x9dc5ada82b70b59e, + 0xc5371912364ce306, 0xf684df56c3e01bc7, 0x9a130b963a6c115d, 0xc097ce7bc90715b4, + 0xf0bdc21abb48db21, 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, + 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, 0x8f7e32ce7bea5c70, + 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <bool b> constexpr int cache_holder_ieee754_binary32_impl<b>::cache_bits; +template <bool b> constexpr int cache_holder_ieee754_binary32_impl<b>::min_k; +template <bool b> constexpr int cache_holder_ieee754_binary32_impl<b>::max_k; +template <bool b> constexpr typename cache_holder_ieee754_binary32_impl<b>::cache_entry_type cache_holder_ieee754_binary32_impl<b>::cache[]; + +#endif + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) +using cache_holder_ieee754_binary32 = cache_holder_ieee754_binary32_impl<true>; +#endif + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) +template <bool b> +struct cache_holder_ieee754_binary64_impl +#else +struct cache_holder_ieee754_binary64 +#endif +{ + using cache_entry_type = uint128; + static constexpr int cache_bits = 128; + static constexpr int min_k = -292; + static constexpr int max_k = 326; + static constexpr cache_entry_type cache[] = { + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, {0x9faacf3df73609b1, 0x77b191618c54e9ad}, + {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, + {0x9becce62836ac577, 0x4ee367f9430aec33}, {0xc2e801fb244576d5, 0x229c41f793cda740}, + {0xf3a20279ed56d48a, 0x6b43527578c11110}, {0x9845418c345644d6, 0x830a13896b78aaaa}, + {0xbe5691ef416bd60c, 0x23cc986bc656d554}, {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, + {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, + {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, {0x91376c36d99995be, 0x23100809b9c21fa2}, + {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, + {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, + {0xdd95317f31c7fa1d, 0x40405643d711d584}, {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, + {0xad1c8eab5ee43b66, 0xda3243650005eed0}, {0xd863b256369d4a40, 0x90bed43e40076a83}, + {0x873e4f75e2224e68, 0x5a7744a6e804a292}, {0xa90de3535aaae202, 0x711515d0a205cb37}, + {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, {0x8412d9991ed58091, 0xe858790afe9486c3}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, + {0xc987434744ac874e, 0xa327ffb266b56221}, {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, + {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, + {0xf6019da07f549b2b, 0x7e2a53a146606a49}, {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, + {0xc0314325637a1939, 0xfa911155fefb5309}, {0xf03d93eebc589f88, 0x793555ab7eba27cb}, + {0x96267c7535b763b5, 0x4bc1558b2f3458df}, {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, + {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, {0x92a1958a7675175f, 0x0bfacd89ec191eca}, + {0xb749faed14125d36, 0xcef980ec671f667c}, {0xe51c79a85916f484, 0x82b7e12780e7401b}, + {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, + {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, + {0xaecc49914078536d, 0x58fae9f773886e19}, {0xda7f5bf590966848, 0xaf39a475506a899f}, + {0x888f99797a5e012d, 0x6d8406c952429604}, {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, + {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, {0xd0601d8efc57b08b, 0xf13b94daf124da27}, + {0x823c12795db6ce57, 0x76c53d08d6b70859}, {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, + {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, + {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, + {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, + {0xc21094364dfb5636, 0x985915fc12f542e5}, {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, + {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, {0xbd8430bd08277231, 0x50c6ff782a838354}, + {0xece53cec4a314ebd, 0xa4f8bf5635246429}, {0x940f4613ae5ed136, 0x871b7795e136be9a}, + {0xb913179899f68584, 0x28e2557b59846e40}, {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, + {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, {0xb4bca50b065abe63, 0x0fed077a756b53aa}, + {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, + {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, + {0x89e42caaf9491b60, 0xf41686c49db57245}, {0xac5d37d5b79b6239, 0x311c2875c522ced6}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, {0xd267caa862a12d66, 0xd072df63c324fd7c}, + {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, {0xa46116538d0deb78, 0x52d9be85f074e609}, + {0xcd795be870516656, 0x67902e276c921f8c}, {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, + {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, + {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, + {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, + {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, + {0xef340a98172aace4, 0x86fb897116c87c35}, {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, + {0xbae0a846d2195712, 0x8974836059cca10a}, {0xe998d258869facd7, 0x2bd1a438703fc94c}, + {0x91ff83775423cc06, 0x7b6306a34627ddd0}, {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, + {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, {0x8e938662882af53e, 0x547eb47b7282ee9d}, + {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, + {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, + {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, {0xd47487cc8470652b, 0x7647c32000696720}, + {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, {0xa5fb0a17c777cf09, 0xf468107100525891}, + {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, {0x81ac1fe293d599bf, 0xc6f14cd848405531}, + {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, + {0xfd442e4688bd304a, 0x908f4a166d1da664}, {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, + {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, {0xf7549530e188c128, 0xd12bee59e68ef47d}, + {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, + {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, + {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, {0xebdf661791d60f56, 0x111b495b3464ad22}, + {0x936b9fcebb25c995, 0xcab10dd900beec35}, {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, + {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, + {0xb3f4e093db73a093, 0x59ed216765690f57}, {0xe0f218b8d25088b8, 0x306869c13ec3532d}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, {0x894bc396ce5da772, 0x6b8bba8c328eb784}, + {0xab9eb47c81f5114f, 0x066ea92f3f326565}, {0xd686619ba27255a2, 0xc80a537b0efefebe}, + {0x8613fd0145877585, 0xbd06742ce95f5f37}, {0xa798fc4196e952e7, 0x2c48113823b73705}, + {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, {0x82ef85133de648c4, 0x9a984d73dbe722fc}, + {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, {0xcc963fee10b7d1b3, 0x318df905079926a9}, + {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, + {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, + {0x9c1661a651213e2d, 0x06bea10ca65c084f}, {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, + {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, + {0xbe89523386091465, 0xf6bbb397f1135824}, {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, + {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, {0xba121a4650e4ddeb, 0x92f34d62616ce414}, + {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, + {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, + {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, + {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, + {0x87625f056c7c4a8b, 0x11471cd764ad4973}, {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, + {0xd389b47879823479, 0x4aff1d108d4ec2c4}, {0x843610cb4bf160cb, 0xcedf722a585139bb}, + {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, {0xce947a3da6a9273e, 0x733d226229feea33}, + {0x811ccc668829b887, 0x0806357d5a3f5260}, {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, + {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, + {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, {0xc5029163f384a931, 0x0a9e795e65d4df12}, + {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, + {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, + {0x964e858c91ba2655, 0x3a6a07f8d510f870}, {0xbbe226efb628afea, 0x890489f70a55368c}, + {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, {0xb32df8e9f3546564, 0x47939822dc96abfa}, + {0xdff9772470297ebd, 0x59787e2b93bc56f8}, {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, + {0xaefae51477a06b03, 0xede622920b6b23f2}, {0xdab99e59958885c4, 0xe95fab368e45ecee}, + {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, + {0xd59944a37c0752a2, 0x4be76d3346f04960}, {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, + {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, + {0x825ecc24c873782f, 0x8ed400668c0c28c9}, {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, + {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, + {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, + {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, + {0xc24452da229b021b, 0xfbe85badce996169}, {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, + {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, + {0xed246723473e3813, 0x290123e9aab23b69}, {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, + {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, + {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, {0x8d590723948a535f, 0x579c487e5a38ad0f}, + {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, {0xdcdb1b2798182244, 0xf8e431456cf88e66}, + {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, + {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, + {0xa87fea27a539e9a5, 0x3f2398d747b36225}, {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, + {0x83a3eeeef9153e89, 0x1953cf68300424ad}, {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, + {0xcdb02555653131b6, 0x3792f412cb06794e}, {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, + {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, {0xc8de047564d20a8b, 0xf245825a5a445276}, + {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, {0x9ced737bb6c4183d, 0x55464dd69685606c}, + {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, {0xf53304714d9265df, 0xd53dd99f4b3066a9}, + {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, {0xbf8fdb78849a5f96, 0xde98520472bdd034}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xbb127c53b17ec159, 0x5560c018580d5d53}, {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, + {0x9226712162ab070d, 0xcab3961304ca70e9}, {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, + {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, + {0xb267ed1940f1c61c, 0x55f038b237591ed4}, {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, + {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, + {0xd9c7dced53c72255, 0x96e7bd358c904a22}, {0x881cea14545c7575, 0x7e50d64177da2e55}, + {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, + {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, + {0xcfb11ead453994ba, 0x67de18eda5814af3}, {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, + {0xa2425ff75e14fc31, 0xa1258379a94d028e}, {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, + {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, {0x9e74d1b791e07e48, 0x775ea264cf55347e}, + {0xc612062576589dda, 0x95364afe032a819e}, {0xf79687aed3eec551, 0x3a83ddbd83f52205}, + {0x9abe14cd44753b52, 0xc4926a9672793543}, {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, + {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, + {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, {0xb877aa3236a4b449, 0x09befeb9fad487c3}, + {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, + {0xb424dc35095cd80f, 0x538484c19ef38c95}, {0xe12e13424bb40e13, 0x2865a5f206b06fba}, + {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, {0xafebff0bcb24aafe, 0xf78f69a51539d749}, + {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, {0x89705f4136b4a597, 0x31680a88f8953031}, + {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, + {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, + {0xd1b71758e219652b, 0xd3c36113404ea4a9}, {0x83126e978d4fdf3b, 0x645a1cac083126ea}, + {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, {0xcccccccccccccccc, 0xcccccccccccccccd}, + {0x8000000000000000, 0x0000000000000000}, {0xa000000000000000, 0x0000000000000000}, + {0xc800000000000000, 0x0000000000000000}, {0xfa00000000000000, 0x0000000000000000}, + {0x9c40000000000000, 0x0000000000000000}, {0xc350000000000000, 0x0000000000000000}, + {0xf424000000000000, 0x0000000000000000}, {0x9896800000000000, 0x0000000000000000}, + {0xbebc200000000000, 0x0000000000000000}, {0xee6b280000000000, 0x0000000000000000}, + {0x9502f90000000000, 0x0000000000000000}, {0xba43b74000000000, 0x0000000000000000}, + {0xe8d4a51000000000, 0x0000000000000000}, {0x9184e72a00000000, 0x0000000000000000}, + {0xb5e620f480000000, 0x0000000000000000}, {0xe35fa931a0000000, 0x0000000000000000}, + {0x8e1bc9bf04000000, 0x0000000000000000}, {0xb1a2bc2ec5000000, 0x0000000000000000}, + {0xde0b6b3a76400000, 0x0000000000000000}, {0x8ac7230489e80000, 0x0000000000000000}, + {0xad78ebc5ac620000, 0x0000000000000000}, {0xd8d726b7177a8000, 0x0000000000000000}, + {0x878678326eac9000, 0x0000000000000000}, {0xa968163f0a57b400, 0x0000000000000000}, + {0xd3c21bcecceda100, 0x0000000000000000}, {0x84595161401484a0, 0x0000000000000000}, + {0xa56fa5b99019a5c8, 0x0000000000000000}, {0xcecb8f27f4200f3a, 0x0000000000000000}, + {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, 0xbff8f10e7a8921a5}, {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, {0xc5a05277621be293, 0xc7098b7305241886}, + {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}}; +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <bool b> constexpr int cache_holder_ieee754_binary64_impl<b>::cache_bits; +template <bool b> constexpr int cache_holder_ieee754_binary64_impl<b>::min_k; +template <bool b> constexpr int cache_holder_ieee754_binary64_impl<b>::max_k; +template <bool b> constexpr typename cache_holder_ieee754_binary64_impl<b>::cache_entry_type cache_holder_ieee754_binary64_impl<b>::cache[]; + +#endif + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) +using cache_holder_ieee754_binary64 = cache_holder_ieee754_binary64_impl<true>; +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Policies. +//////////////////////////////////////////////////////////////////////////////////////// + +// Forward declare the implementation class. +template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>> +struct impl; + +namespace policy_impl { +// Sign policies. +namespace sign { + struct base {}; + + struct ignore : base + { + using sign_policy = ignore; + static constexpr bool return_has_sign = false; + + template <typename SignedSignificandBits, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void handle_sign(SignedSignificandBits, ReturnType&) noexcept {} + }; + + struct return_sign : base + { + using sign_policy = return_sign; + static constexpr bool return_has_sign = true; + + template <typename SignedSignificandBits, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void handle_sign(SignedSignificandBits s, ReturnType& r) noexcept + { + r.is_negative = s.is_negative(); + } + }; +} + +// Trailing zero policies. +namespace trailing_zero { + struct base {}; + + struct ignore : base + { + using trailing_zero_policy = ignore; + static constexpr bool report_trailing_zeros = false; + + template <typename Impl, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void on_trailing_zeros(ReturnType&) noexcept {} + + template <typename Impl, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void no_trailing_zeros(ReturnType&) noexcept {} + }; + + struct remove : base + { + using trailing_zero_policy = remove; + static constexpr bool report_trailing_zeros = false; + + template <typename Impl, typename ReturnType> + BOOST_FORCEINLINE static void on_trailing_zeros(ReturnType& r) noexcept + { + r.exponent += Impl::remove_trailing_zeros(r.significand); + } + + template <typename Impl, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void no_trailing_zeros(ReturnType&) noexcept {} + }; + + struct report : base + { + using trailing_zero_policy = report; + static constexpr bool report_trailing_zeros = true; + + template <typename Impl, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void on_trailing_zeros(ReturnType& r) noexcept + { + r.may_have_trailing_zeros = true; + } + + template <typename Impl, typename ReturnType> + static BOOST_CXX14_CONSTEXPR void no_trailing_zeros(ReturnType& r) noexcept + { + r.may_have_trailing_zeros = false; + } + }; +} + +// Decimal-to-binary rounding mode policies. +namespace decimal_to_binary_rounding { + struct base {}; + + enum class tag_t + { + to_nearest, + left_closed_directed, + right_closed_directed + }; + + namespace interval_type { + struct symmetric_boundary + { + static constexpr bool is_symmetric = true; + bool is_closed; + constexpr bool include_left_endpoint() const noexcept { return is_closed; } + constexpr bool include_right_endpoint() const noexcept { return is_closed; } + }; + + struct asymmetric_boundary + { + static constexpr bool is_symmetric = false; + bool is_left_closed; + constexpr bool include_left_endpoint() const noexcept { return is_left_closed; } + constexpr bool include_right_endpoint() const noexcept { return !is_left_closed; } + }; + + struct closed + { + static constexpr bool is_symmetric = true; + static constexpr bool include_left_endpoint() noexcept { return true; } + static constexpr bool include_right_endpoint() noexcept { return true; } + }; + + struct open + { + static constexpr bool is_symmetric = true; + static constexpr bool include_left_endpoint() noexcept { return false; } + static constexpr bool include_right_endpoint() noexcept { return false; } + }; + + struct left_closed_right_open + { + static constexpr bool is_symmetric = false; + static constexpr bool include_left_endpoint() noexcept { return true; } + static constexpr bool include_right_endpoint() noexcept { return false; } + }; + + struct right_closed_left_open + { + static constexpr bool is_symmetric = false; + static constexpr bool include_left_endpoint() noexcept { return false; } + static constexpr bool include_right_endpoint() noexcept { return true; } + }; + } + + template <typename T> + struct return_type : return_type<decltype(&T::operator())> + {}; + + struct nearest_to_even : base + { + using decimal_to_binary_rounding_policy = nearest_to_even; + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::symmetric_boundary; + using shorter_interval_type = interval_type::closed; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func f) noexcept + { + return f(nearest_to_even{}); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept + { + return f(s.has_even_significand_bits()); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + }; + + struct nearest_to_odd : base + { + using decimal_to_binary_rounding_policy = nearest_to_odd; + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::symmetric_boundary; + using shorter_interval_type = interval_type::open; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(nearest_to_odd{}); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept + { + return f(!s.has_even_significand_bits()); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + }; + + struct nearest_toward_plus_infinity : base + { + using decimal_to_binary_rounding_policy = nearest_toward_plus_infinity; + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::asymmetric_boundary; + using shorter_interval_type = interval_type::asymmetric_boundary; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(nearest_toward_plus_infinity{}); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept + { + return f(!s.is_negative()); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits s, Func&& f) noexcept + { + return f(!s.is_negative()); + } + }; + + struct nearest_toward_minus_infinity : base + { + using decimal_to_binary_rounding_policy = nearest_toward_minus_infinity; + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::asymmetric_boundary; + using shorter_interval_type = interval_type::asymmetric_boundary; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(nearest_toward_minus_infinity{}); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits s, Func&& f) noexcept + { + return f(s.is_negative()); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits s, Func&& f) noexcept + { + return f(s.is_negative()); + } + }; + + struct nearest_toward_zero : base + { + using decimal_to_binary_rounding_policy = nearest_toward_zero; + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::right_closed_left_open; + using shorter_interval_type = interval_type::right_closed_left_open; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(nearest_toward_zero{}); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + }; + + struct nearest_away_from_zero : base + { + using decimal_to_binary_rounding_policy = nearest_away_from_zero; + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::left_closed_right_open; + using shorter_interval_type = interval_type::left_closed_right_open; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(nearest_away_from_zero{}); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + }; + + struct nearest_always_closed + { + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::closed; + using shorter_interval_type = interval_type::closed; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + }; + + struct nearest_always_open + { + static constexpr auto tag = tag_t::to_nearest; + using normal_interval_type = interval_type::open; + using shorter_interval_type = interval_type::open; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_normal_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static constexpr ReturnType + invoke_shorter_interval_case(SignedSignificandBits, Func&& f) noexcept + { + return f(); + } + }; + + struct nearest_to_even_static_boundary : base + { + using decimal_to_binary_rounding_policy = nearest_to_even_static_boundary; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits s, Func&& f) noexcept + { + if (s.has_even_significand_bits()) + { + return f(nearest_always_closed{}); + } + else + { + return f(nearest_always_open{}); + } + } + }; + + struct nearest_to_odd_static_boundary : base + { + using decimal_to_binary_rounding_policy = nearest_to_odd_static_boundary; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits s, Func&& f) noexcept + { + if (s.has_even_significand_bits()) + { + return f(nearest_always_open{}); + } + else + { + return f(nearest_always_closed{}); + } + } + }; + struct nearest_toward_plus_infinity_static_boundary : base + { + using decimal_to_binary_rounding_policy = nearest_toward_plus_infinity_static_boundary; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits s, Func&& f) noexcept + { + if (s.is_negative()) + { + return f(nearest_toward_zero{}); + } + else + { + return f(nearest_away_from_zero{}); + } + } + }; + + struct nearest_toward_minus_infinity_static_boundary : base + { + using decimal_to_binary_rounding_policy = nearest_toward_minus_infinity_static_boundary; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits s, Func&& f) noexcept + { + if (s.is_negative()) + { + return f(nearest_away_from_zero{}); + } + else + { + return f(nearest_toward_zero{}); + } + } + }; + + struct left_closed_directed + { + static constexpr auto tag = tag_t::left_closed_directed; + }; + struct right_closed_directed + { + static constexpr auto tag = tag_t::right_closed_directed; + }; + + struct toward_plus_infinity : base + { + using decimal_to_binary_rounding_policy = toward_plus_infinity; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits s, Func&& f) noexcept + { + if (s.is_negative()) + { + return f(left_closed_directed{}); + } + else + { + return f(right_closed_directed{}); + } + } + }; + + struct toward_minus_infinity : base + { + using decimal_to_binary_rounding_policy = toward_minus_infinity; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits s, Func&& f) noexcept + { + if (s.is_negative()) + { + return f(right_closed_directed{}); + } + else + { + return f(left_closed_directed{}); + } + } + }; + + struct toward_zero : base + { + using decimal_to_binary_rounding_policy = toward_zero; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(left_closed_directed{}); + } + }; + + struct away_from_zero : base + { + using decimal_to_binary_rounding_policy = away_from_zero; + + template <typename ReturnType, typename SignedSignificandBits, typename Func> + BOOST_FORCEINLINE static ReturnType delegate(SignedSignificandBits, Func&& f) noexcept + { + return f(right_closed_directed{}); + } + }; +} + +// Binary-to-decimal rounding policies. +// (Always assumes nearest rounding modes.) +namespace binary_to_decimal_rounding { + struct base {}; + + enum class tag_t + { + do_not_care, + to_even, + to_odd, + away_from_zero, + toward_zero + }; + + struct do_not_care : base + { + using binary_to_decimal_rounding_policy = do_not_care; + static constexpr auto tag = tag_t::do_not_care; + + template <typename ReturnType> + static constexpr bool prefer_round_down(ReturnType const&) noexcept + { + return false; + } + }; + + struct to_even : base + { + using binary_to_decimal_rounding_policy = to_even; + static constexpr auto tag = tag_t::to_even; + + template <typename ReturnType> + static constexpr bool prefer_round_down(ReturnType const& r) noexcept + { + return r.significand % 2 != 0; + } + }; + + struct to_odd : base + { + using binary_to_decimal_rounding_policy = to_odd; + static constexpr auto tag = tag_t::to_odd; + + template <typename ReturnType> + static constexpr bool prefer_round_down(ReturnType const& r) noexcept + { + return r.significand % 2 == 0; + } + }; + + struct away_from_zero : base + { + using binary_to_decimal_rounding_policy = away_from_zero; + static constexpr auto tag = tag_t::away_from_zero; + + template <typename ReturnType> + static constexpr bool prefer_round_down(ReturnType const&) noexcept + { + return false; + } + }; + + struct toward_zero : base + { + using binary_to_decimal_rounding_policy = toward_zero; + static constexpr auto tag = tag_t::toward_zero; + + template <typename ReturnType> + static constexpr bool prefer_round_down(ReturnType const&) noexcept + { + return true; + } + }; +} + +// Cache policies. +namespace cache { + struct base {}; + + struct full : base + { + using cache_policy = full; + + template <typename FloatFormat, typename cache_format = typename std::conditional<std::is_same<FloatFormat, ieee754_binary32>::value, + cache_holder_ieee754_binary32, + cache_holder_ieee754_binary64>::type> + static constexpr typename cache_format::cache_entry_type get_cache(int k) noexcept + { + return cache_format::cache[std::size_t(k - cache_format::min_k)]; + } + }; +} +} + +namespace policy { +namespace sign { + BOOST_INLINE_VARIABLE constexpr auto ignore = detail::policy_impl::sign::ignore{}; + BOOST_INLINE_VARIABLE constexpr auto return_sign = detail::policy_impl::sign::return_sign{}; +} + +namespace trailing_zero { + BOOST_INLINE_VARIABLE constexpr auto ignore = detail::policy_impl::trailing_zero::ignore{}; + BOOST_INLINE_VARIABLE constexpr auto remove = detail::policy_impl::trailing_zero::remove{}; + BOOST_INLINE_VARIABLE constexpr auto report = detail::policy_impl::trailing_zero::report{}; +} + +namespace decimal_to_binary_rounding { + BOOST_INLINE_VARIABLE constexpr auto nearest_to_even = + detail::policy_impl::decimal_to_binary_rounding::nearest_to_even{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_to_odd = + detail::policy_impl::decimal_to_binary_rounding::nearest_to_odd{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_toward_plus_infinity = + detail::policy_impl::decimal_to_binary_rounding::nearest_toward_plus_infinity{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_toward_minus_infinity = + detail::policy_impl::decimal_to_binary_rounding::nearest_toward_minus_infinity{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_toward_zero = + detail::policy_impl::decimal_to_binary_rounding::nearest_toward_zero{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_away_from_zero = + detail::policy_impl::decimal_to_binary_rounding::nearest_away_from_zero{}; + + BOOST_INLINE_VARIABLE constexpr auto nearest_to_even_static_boundary = + detail::policy_impl::decimal_to_binary_rounding::nearest_to_even_static_boundary{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_to_odd_static_boundary = + detail::policy_impl::decimal_to_binary_rounding::nearest_to_odd_static_boundary{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_toward_plus_infinity_static_boundary = + detail::policy_impl::decimal_to_binary_rounding:: + nearest_toward_plus_infinity_static_boundary{}; + BOOST_INLINE_VARIABLE constexpr auto nearest_toward_minus_infinity_static_boundary = + detail::policy_impl::decimal_to_binary_rounding:: + nearest_toward_minus_infinity_static_boundary{}; + + BOOST_INLINE_VARIABLE constexpr auto toward_plus_infinity = + detail::policy_impl::decimal_to_binary_rounding::toward_plus_infinity{}; + BOOST_INLINE_VARIABLE constexpr auto toward_minus_infinity = + detail::policy_impl::decimal_to_binary_rounding::toward_minus_infinity{}; + BOOST_INLINE_VARIABLE constexpr auto toward_zero = + detail::policy_impl::decimal_to_binary_rounding::toward_zero{}; + BOOST_INLINE_VARIABLE constexpr auto away_from_zero = + detail::policy_impl::decimal_to_binary_rounding::away_from_zero{}; +} + +namespace binary_to_decimal_rounding { + BOOST_INLINE_VARIABLE constexpr auto do_not_care = + detail::policy_impl::binary_to_decimal_rounding::do_not_care{}; + BOOST_INLINE_VARIABLE constexpr auto to_even = + detail::policy_impl::binary_to_decimal_rounding::to_even{}; + BOOST_INLINE_VARIABLE constexpr auto to_odd = + detail::policy_impl::binary_to_decimal_rounding::to_odd{}; + BOOST_INLINE_VARIABLE constexpr auto away_from_zero = + detail::policy_impl::binary_to_decimal_rounding::away_from_zero{}; + BOOST_INLINE_VARIABLE constexpr auto toward_zero = + detail::policy_impl::binary_to_decimal_rounding::toward_zero{}; +} + +namespace cache { + BOOST_INLINE_VARIABLE constexpr auto full = detail::policy_impl::cache::full{}; +} +} // Namespace Policy + +//////////////////////////////////////////////////////////////////////////////////////// +// The main algorithm. +//////////////////////////////////////////////////////////////////////////////////////// + +template <typename Float, typename FloatTraits> +struct impl : private FloatTraits, private FloatTraits::format +{ + using format = typename FloatTraits::format; + using carrier_uint = typename FloatTraits::carrier_uint; + + using FloatTraits::carrier_bits; + using format::significand_bits; + using format::min_exponent; + using format::max_exponent; + using format::exponent_bias; + using format::decimal_digits; + + static constexpr int kappa = std::is_same<format, ieee754_binary32>::value ? 1 : 2; + static_assert(kappa >= 1, "Kappa must be >= 1"); + // static_assert(carrier_bits >= significand_bits + 2 + log::floor_log2_pow10(kappa + 1)); + + static constexpr int min_k_a = -log::floor_log10_pow2_minus_log10_4_over_3(int(max_exponent - significand_bits)); + static constexpr int min_k_b = -log::floor_log10_pow2(int(max_exponent - significand_bits)) + kappa; + static constexpr int min_k = min_k_a < min_k_b ? min_k_a : min_k_b; + // static_assert(min_k >= cache_holder<format>::min_k, "Min k is not in the cache"); + + static constexpr int max_k_a = -log::floor_log10_pow2_minus_log10_4_over_3(int(min_exponent - significand_bits /*+ 1*/)); + static constexpr int max_k_b = -log::floor_log10_pow2(int(min_exponent - significand_bits)) + kappa; + static constexpr int max_k = max_k_a > max_k_b ? max_k_a : max_k_b; + + using cache_format = typename std::conditional<std::is_same<format, ieee754_binary32>::value, + cache_holder_ieee754_binary32, + cache_holder_ieee754_binary64>::type; + using cache_entry_type = typename cache_format::cache_entry_type; + static constexpr auto cache_bits = cache_format::cache_bits; + + static constexpr int case_shorter_interval_left_endpoint_lower_threshold = 2; + static BOOST_CXX14_CONSTEXPR const int case_shorter_interval_left_endpoint_upper_threshold = 3; + //2 + log::floor_log2(compute_power(10, count_factors<5>((carrier_uint(1) << (significand_bits + 2)) - 1) + 1) / 3); + + static constexpr int case_shorter_interval_right_endpoint_lower_threshold = 0; + static BOOST_CXX14_CONSTEXPR const int case_shorter_interval_right_endpoint_upper_threshold = 3; + //2 + log::floor_log2(compute_power(10, count_factors<5>((carrier_uint(1) << (significand_bits + 1)) + 1) + 1) / 3); + + static constexpr int shorter_interval_tie_lower_threshold = + -log::floor_log5_pow2_minus_log5_3(significand_bits + 4) - 2 - significand_bits; + static constexpr int shorter_interval_tie_upper_threshold = + -log::floor_log5_pow2(significand_bits + 2) - 2 - significand_bits; + + struct compute_mul_result + { + carrier_uint result; + bool is_integer; + }; + + struct compute_mul_parity_result + { + bool parity; + bool is_integer; + }; + + //// The main algorithm assumes the input is a normal/subnormal finite number + + #if defined(__GNUC__) && (__GNUC__ < 5) && !defined(__clang__) + # pragma GCC diagnostic push + # pragma GCC diagnostic ignored "-Wmissing-field-initializers" + #endif + + template <typename ReturnType, typename IntervalType, typename TrailingZeroPolicy, + typename BinaryToDecimalRoundingPolicy, typename CachePolicy, typename... AdditionalArgs> + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_nearest_normal(carrier_uint const two_fc, const int exponent, + AdditionalArgs... additional_args) noexcept + { + ////////////////////////////////////////////////////////////////////// + // Step 1: Schubfach multiplier calculation + ////////////////////////////////////////////////////////////////////// + + ReturnType ret_value = {}; + IntervalType interval_type{additional_args...}; + + // Compute k and beta. + const int minus_k = log::floor_log10_pow2(exponent) - kappa; + const auto cache = CachePolicy::template get_cache<format>(-minus_k); + const int beta = exponent + log::floor_log2_pow10(-minus_k); + + // Compute zi and deltai. + // 10^kappa <= deltai < 10^(kappa + 1) + const auto deltai = compute_delta(cache, beta); + // For the case of binary32, the result of integer check is not correct for + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, + // and they are the unique counterexamples. However, since 29711844 is even, + // this does not cause any problem for the endpoints calculations; it can only + // cause a problem when we need to perform integer check for the center. + // Fortunately, with these inputs, that branch is never executed, so we are fine. + //const auto [zi, is_z_integer] = compute_mul((two_fc | 1) << beta, cache); + const auto z_res = compute_mul((two_fc | 1) << beta, cache); + const auto zi = z_res.result; + const auto is_z_integer = z_res.is_integer; + + ////////////////////////////////////////////////////////////////////// + // Step 2: Try larger divisor; remove trailing zeros if necessary + ////////////////////////////////////////////////////////////////////// + + BOOST_CXX14_CONSTEXPR auto big_divisor = compute_power(std::uint32_t(10), kappa + 1); + BOOST_CXX14_CONSTEXPR auto small_divisor = compute_power(std::uint32_t(10), kappa); + + // Using an upper bound on zi, we might be able to optimize the division + // better than the compiler; we are computing zi / big_divisor here. + #ifdef BOOST_NO_CXX14_CONSTEXPR + ret_value.significand = div::divide_by_pow10<carrier_uint>(kappa + 1, (carrier_uint(1) << (significand_bits + 1)) * big_divisor - 1, zi); + #else + ret_value.significand = div::divide_by_pow10<kappa + 1, carrier_uint, (carrier_uint(1) << (significand_bits + 1)) * big_divisor - 1>(zi); + #endif + + auto r = std::uint32_t(zi - big_divisor * ret_value.significand); + + if (r < deltai) + { + // Exclude the right endpoint if necessary. + if (r == 0 && (is_z_integer & !interval_type.include_right_endpoint())) + { + BOOST_IF_CONSTEXPR (BinaryToDecimalRoundingPolicy::tag == policy_impl::binary_to_decimal_rounding::tag_t::do_not_care) + { + ret_value.significand *= 10; + ret_value.exponent = minus_k + kappa; + --ret_value.significand; + TrailingZeroPolicy::template no_trailing_zeros<impl>(ret_value); + + return ret_value; + } + else + { + --ret_value.significand; + r = big_divisor; + + goto small_divisor_case_label; + } + } + } + else if (r > deltai) + { + goto small_divisor_case_label; + } + else + { + // r == deltai; compare fractional parts. + // const auto [xi_parity, x_is_integer] = + // compute_mul_parity(two_fc - 1, cache, beta); + const auto x_res = compute_mul_parity(two_fc - 1, cache, beta); + const auto xi_parity = x_res.parity; + const auto x_is_integer = x_res.is_integer; + + if (!(xi_parity | (x_is_integer & interval_type.include_left_endpoint()))) + { + goto small_divisor_case_label; + } + } + ret_value.exponent = minus_k + kappa + 1; + + // We may need to remove trailing zeros. + TrailingZeroPolicy::template on_trailing_zeros<impl>(ret_value); + return ret_value; + + + ////////////////////////////////////////////////////////////////////// + // Step 3: Find the significand with the smaller divisor + ////////////////////////////////////////////////////////////////////// + + small_divisor_case_label: + TrailingZeroPolicy::template no_trailing_zeros<impl>(ret_value); + ret_value.significand *= 10; + ret_value.exponent = minus_k + kappa; + + BOOST_IF_CONSTEXPR (BinaryToDecimalRoundingPolicy::tag == policy_impl::binary_to_decimal_rounding::tag_t::do_not_care) + { + // Normally, we want to compute + // ret_value.significand += r / small_divisor + // and return, but we need to take care of the case that the resulting + // value is exactly the right endpoint, while that is not included in the + // interval. + if (!interval_type.include_right_endpoint()) + { + // Is r divisible by 10^kappa? + if (is_z_integer && div::check_divisibility_and_divide_by_pow10<kappa>(r)) + { + // This should be in the interval. + ret_value.significand += r - 1; + } + else + { + ret_value.significand += r; + } + } + else + { + ret_value.significand += div::small_division_by_pow10<kappa>(r); + } + } + else + { + auto dist = r - (deltai / 2) + (small_divisor / 2); + const bool approx_y_parity = ((dist ^ (small_divisor / 2)) & 1) != 0; + + // Is dist divisible by 10^kappa? + const bool divisible_by_small_divisor = div::check_divisibility_and_divide_by_pow10<kappa>(dist); + + // Add dist / 10^kappa to the significand. + ret_value.significand += dist; + + if (divisible_by_small_divisor) + { + // Check z^(f) >= epsilon^(f). + // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). + // Since there are only 2 possibilities, we only need to care about the + // parity. Also, zi and r should have the same parity since the divisor is + // an even number. + //const auto [yi_parity, is_y_integer] = + // compute_mul_parity(two_fc, cache, beta); + const auto y_res = compute_mul_parity(two_fc, cache, beta); + const auto yi_parity = y_res.parity; + const auto is_y_integer = y_res.is_integer; + + if (yi_parity != approx_y_parity) + { + --ret_value.significand; + } + else + { + // If z^(f) >= epsilon^(f), we might have a tie + // when z^(f) == epsilon^(f), or equivalently, when y is an integer. + // For tie-to-up case, we can just choose the upper one. + if (BinaryToDecimalRoundingPolicy::prefer_round_down(ret_value) & is_y_integer) + { + --ret_value.significand; + } + } + } + } + + return ret_value; + } + + template <typename ReturnType, typename IntervalType, typename TrailingZeroPolicy, + typename BinaryToDecimalRoundingPolicy, typename CachePolicy, typename... AdditionalArgs> + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_nearest_shorter(const int exponent, AdditionalArgs... additional_args) noexcept + { + ReturnType ret_value = {}; + IntervalType interval_type{additional_args...}; + + // Compute k and beta. + const int minus_k = log::floor_log10_pow2_minus_log10_4_over_3(exponent); + const int beta = exponent + log::floor_log2_pow10(-minus_k); + + // Compute xi and zi. + const auto cache = CachePolicy::template get_cache<format>(-minus_k); + + auto xi = compute_left_endpoint_for_shorter_interval_case(cache, beta); + auto zi = compute_right_endpoint_for_shorter_interval_case(cache, beta); + + // If we don't accept the right endpoint and + // if the right endpoint is an integer, decrease it. + if (!interval_type.include_right_endpoint() && is_right_endpoint_integer_shorter_interval(exponent)) + { + --zi; + } + // If we don't accept the left endpoint or + // if the left endpoint is not an integer, increase it. + if (!interval_type.include_left_endpoint() || !is_left_endpoint_integer_shorter_interval(exponent)) + { + ++xi; + } + + // Try bigger divisor. + ret_value.significand = zi / 10; + + // If succeed, remove trailing zeros if necessary and return. + if (ret_value.significand * 10 >= xi) + { + ret_value.exponent = minus_k + 1; + TrailingZeroPolicy::template on_trailing_zeros<impl>(ret_value); + return ret_value; + } + + // Otherwise, compute the round-up of y. + TrailingZeroPolicy::template no_trailing_zeros<impl>(ret_value); + ret_value.significand = compute_round_up_for_shorter_interval_case(cache, beta); + ret_value.exponent = minus_k; + + // When tie occurs, choose one of them according to the rule. + if (BinaryToDecimalRoundingPolicy::prefer_round_down(ret_value) && + exponent >= shorter_interval_tie_lower_threshold && + exponent <= shorter_interval_tie_upper_threshold) + { + --ret_value.significand; + } + else if (ret_value.significand < xi) + { + ++ret_value.significand; + } + + return ret_value; + } + + #if defined(__GNUC__) && (__GNUC__ < 5) && !defined(__clang__) + # pragma GCC diagnostic pop + #endif + + template <class ReturnType, class TrailingZeroPolicy, class CachePolicy> + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_left_closed_directed(carrier_uint const two_fc, int exponent) noexcept + { + ////////////////////////////////////////////////////////////////////// + // Step 1: Schubfach multiplier calculation + ////////////////////////////////////////////////////////////////////// + + ReturnType ret_value; + + // Compute k and beta. + const int minus_k = log::floor_log10_pow2(exponent) - kappa; + const auto cache = CachePolicy::template get_cache<format>(-minus_k); + const int beta = exponent + log::floor_log2_pow10(-minus_k); + + // Compute xi and deltai. + // 10^kappa <= deltai < 10^(kappa + 1) + const auto deltai = compute_delta(cache, beta); + //auto [xi, is_x_integer] = compute_mul(two_fc << beta, cache); + const auto x_res = compute_mul(two_fc << beta, cache); + auto xi = x_res.result; + auto is_x_integer = x_res.is_integer; + + // Deal with the unique exceptional cases + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17 + // for binary32. + BOOST_IF_CONSTEXPR (std::is_same<format, ieee754_binary32>::value) + { + if (exponent <= -80) + { + is_x_integer = false; + } + } + + if (!is_x_integer) + { + ++xi; + } + + ////////////////////////////////////////////////////////////////////// + // Step 2: Try larger divisor; remove trailing zeros if necessary + ////////////////////////////////////////////////////////////////////// + + BOOST_CXX14_CONSTEXPR auto big_divisor = compute_power(std::uint32_t(10), kappa + 1); + + // Using an upper bound on xi, we might be able to optimize the division + // better than the compiler; we are computing xi / big_divisor here. + + #ifdef BOOST_NO_CXX14_CONSTEXPR + ret_value.significand = div::divide_by_pow10<carrier_uint>(kappa + 1, (carrier_uint(1) << (significand_bits + 1)) * big_divisor - 1, xi); + #else + ret_value.significand = div::divide_by_pow10<kappa + 1, carrier_uint, (carrier_uint(1) << (significand_bits + 1)) * big_divisor - 1>(xi); + #endif + + auto r = std::uint32_t(xi - big_divisor * ret_value.significand); + + if (r != 0) + { + ++ret_value.significand; + r = big_divisor - r; + } + + if (r > deltai) + { + goto small_divisor_case_label; + } + else if (r == deltai) + { + // Compare the fractional parts. + // This branch is never taken for the exceptional cases + // 2f_c = 29711482, e = -81 + // (6.1442649164096937243516663440523473127541365101933479309082... * 10^-18) + // and 2f_c = 29711482, e = -80 + // (1.2288529832819387448703332688104694625508273020386695861816... * 10^-17). + //const auto [zi_parity, is_z_integer] = + // compute_mul_parity(two_fc + 2, cache, beta); + const auto z_res = compute_mul_parity(two_fc + 2, cache, beta); + if (z_res.parity || z_res.is_integer) + { + goto small_divisor_case_label; + } + } + + // The ceiling is inside, so we are done. + ret_value.exponent = minus_k + kappa + 1; + TrailingZeroPolicy::template on_trailing_zeros<impl>(ret_value); + return ret_value; + + + ////////////////////////////////////////////////////////////////////// + // Step 3: Find the significand with the smaller divisor + ////////////////////////////////////////////////////////////////////// + + small_divisor_case_label: + ret_value.significand *= 10; + ret_value.significand -= div::small_division_by_pow10<kappa>(r); + ret_value.exponent = minus_k + kappa; + TrailingZeroPolicy::template no_trailing_zeros<impl>(ret_value); + return ret_value; + } + + template <typename ReturnType, typename TrailingZeroPolicy, typename CachePolicy> + BOOST_CHARCONV_SAFEBUFFERS static ReturnType compute_right_closed_directed(carrier_uint const two_fc, const int exponent, bool shorter_interval) noexcept + { + ////////////////////////////////////////////////////////////////////// + // Step 1: Schubfach multiplier calculation + ////////////////////////////////////////////////////////////////////// + + ReturnType ret_value; + + // Compute k and beta. + const int minus_k = log::floor_log10_pow2(exponent - (shorter_interval ? 1 : 0)) - kappa; + const auto cache = CachePolicy::template get_cache<format>(-minus_k); + const int beta = exponent + log::floor_log2_pow10(-minus_k); + + // Compute zi and deltai. + // 10^kappa <= deltai < 10^(kappa + 1) + const auto deltai = shorter_interval ? compute_delta(cache, beta - 1) : compute_delta(cache, beta); + carrier_uint const zi = compute_mul(two_fc << beta, cache).result; + + + ////////////////////////////////////////////////////////////////////// + // Step 2: Try larger divisor; remove trailing zeros if necessary + ////////////////////////////////////////////////////////////////////// + + BOOST_CXX14_CONSTEXPR auto big_divisor = compute_power(std::uint32_t(10), kappa + 1); + + // Using an upper bound on zi, we might be able to optimize the division better than + // the compiler; we are computing zi / big_divisor here. + #ifdef BOOST_NO_CXX14_CONSTEXPR + ret_value.significand = div::divide_by_pow10<carrier_uint>(kappa + 1, (carrier_uint(1) << (significand_bits + 1)) * big_divisor - 1, zi); + #else + ret_value.significand = div::divide_by_pow10<kappa + 1, carrier_uint, (carrier_uint(1) << (significand_bits + 1)) * big_divisor - 1>(zi); + #endif + + const auto r = std::uint32_t(zi - big_divisor * ret_value.significand); + + if (r > deltai) + { + goto small_divisor_case_label; + } + else if (r == deltai) + { + // Compare the fractional parts. + if (!compute_mul_parity(two_fc - (shorter_interval ? 1 : 2), cache, beta).parity) + { + goto small_divisor_case_label; + } + } + + // The floor is inside, so we are done. + ret_value.exponent = minus_k + kappa + 1; + TrailingZeroPolicy::template on_trailing_zeros<impl>(ret_value); + return ret_value; + + + ////////////////////////////////////////////////////////////////////// + // Step 3: Find the significand with the small divisor + ////////////////////////////////////////////////////////////////////// + + small_divisor_case_label: + ret_value.significand *= 10; + ret_value.significand += div::small_division_by_pow10<kappa>(r); + ret_value.exponent = minus_k + kappa; + TrailingZeroPolicy::template no_trailing_zeros<impl>(ret_value); + + return ret_value; + } + + // Remove trailing zeros from n and return the number of zeros removed. + BOOST_FORCEINLINE static int remove_trailing_zeros(carrier_uint& n) noexcept + { + if (n == 0) + { + return 0; + } + + BOOST_IF_CONSTEXPR (std::is_same<format, ieee754_binary32>::value) + { + constexpr auto mod_inv_5 = UINT32_C(0xcccccccd); + constexpr auto mod_inv_25 = mod_inv_5 * mod_inv_5; + + int s = 0; + while (true) + { + auto q = boost::core::rotr(n * mod_inv_25, 2); + if (q <= (std::numeric_limits<std::uint32_t>::max)() / 100) + { + n = q; + s += 2; + } + else + { + break; + } + } + auto q = boost::core::rotr(n * mod_inv_5, 1); + if (q <= (std::numeric_limits<std::uint32_t>::max)() / 10) + { + n = q; + s |= 1; + } + + return s; + } + else + { + // Static assertion does not work unless if constexpr is supported + // static_assert(std::is_same<format, ieee754_binary64>::value, "Must be a double type"); + + // Divide by 10^8 and reduce to 32-bits if divisible. + // Since ret_value.significand <= (2^53 * 1000 - 1) / 1000 < 10^16, + // n is at most of 16 digits. + + // This magic number is ceil(2^90 / 10^8). + constexpr auto magic_number = UINT64_C(12379400392853802749); + auto nm = umul128(n, magic_number); + + // Is n is divisible by 10^8? + if ((nm.high & ((std::uint64_t(1) << (90 - 64)) - 1)) == 0 && + nm.low < magic_number) { + // If yes, work with the quotient. + auto n32 = static_cast<std::uint32_t>(nm.high >> (90 - 64)); + + constexpr auto mod_inv_5 = UINT32_C(0xcccccccd); + constexpr auto mod_inv_25 = mod_inv_5 * mod_inv_5; + + int s = 8; + while (true) + { + auto q = boost::core::rotr(n32 * mod_inv_25, 2); + if (q <= (std::numeric_limits<std::uint32_t>::max)() / 100) + { + n32 = q; + s += 2; + } + else + { + break; + } + } + + auto q = boost::core::rotr(n32 * mod_inv_5, 1); + if (q <= (std::numeric_limits<std::uint32_t>::max)() / 10) + { + n32 = q; + s |= 1; + } + + n = n32; + return s; + } + + // If n is not divisible by 10^8, work with n itself. + constexpr auto mod_inv_5 = UINT64_C(0xcccccccccccccccd); + constexpr auto mod_inv_25 = mod_inv_5 * mod_inv_5; + + int s = 0; + while (true) + { + auto q = static_cast<carrier_uint>(boost::core::rotr(n * mod_inv_25, 2)); + if (q <= (std::numeric_limits<std::uint64_t>::max)() / 100) + { + n = q; + s += 2; + } + else + { + break; + } + } + + auto q = static_cast<carrier_uint>(boost::core::rotr(n * mod_inv_5, 1)); + if (q <= (std::numeric_limits<std::uint64_t>::max)() / 10) + { + n = q; + s |= 1; + } + + return s; + } + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary32>::value, bool>::type = true> + static compute_mul_result compute_mul(carrier_uint u, cache_entry_type const& cache) noexcept + { + auto r = umul96_upper64(u, cache); + return {carrier_uint(r >> 32), carrier_uint(r) == 0}; + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary64>::value, bool>::type = true> + static compute_mul_result compute_mul(carrier_uint u, cache_entry_type const& cache) noexcept + { + auto r = umul192_upper128(u, cache); + return {r.high, r.low == 0}; + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary32>::value, bool>::type = true> + static constexpr std::uint32_t compute_delta(cache_entry_type const& cache, + int beta) noexcept + { + return std::uint32_t(cache >> (cache_bits - 1 - beta)); + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary64>::value, bool>::type = true> + static constexpr std::uint32_t compute_delta(cache_entry_type const& cache, + int beta) noexcept + { + return std::uint32_t(cache.high >> (carrier_bits - 1 - beta)); + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary32>::value, bool>::type = true> + static compute_mul_parity_result compute_mul_parity(carrier_uint two_f, + cache_entry_type const& cache, + int beta) noexcept + { + auto r = umul96_lower64(two_f, cache); + return {((r >> (64 - beta)) & 1) != 0, std::uint32_t(r >> (32 - beta)) == 0}; + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary64>::value, bool>::type = true> + static compute_mul_parity_result compute_mul_parity(carrier_uint two_f, + cache_entry_type const& cache, + int beta) noexcept + { + auto r = umul192_lower128(two_f, cache); + return {((r.high >> (64 - beta)) & 1) != 0, ((r.high << beta) | (r.low >> (64 - beta))) == 0}; + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary32>::value, bool>::type = true> + static constexpr carrier_uint compute_left_endpoint_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept + { + return carrier_uint((cache - (cache >> (significand_bits + 2))) >> (cache_bits - significand_bits - 1 - beta)); + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary64>::value, bool>::type = true> + static constexpr carrier_uint compute_left_endpoint_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept + { + return (cache.high - (cache.high >> (significand_bits + 2))) >> (carrier_bits - significand_bits - 1 - beta); + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary32>::value, bool>::type = true> + static constexpr carrier_uint compute_right_endpoint_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept + { + return carrier_uint((cache + (cache >> (significand_bits + 1))) >> (cache_bits - significand_bits - 1 - beta)); + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary64>::value, bool>::type = true> + static constexpr carrier_uint compute_right_endpoint_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept + { + return (cache.high + (cache.high >> (significand_bits + 1))) >> (carrier_bits - significand_bits - 1 - beta); + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary32>::value, bool>::type = true> + static constexpr carrier_uint compute_round_up_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept + { + return (carrier_uint(cache >> (cache_bits - significand_bits - 2 - beta)) + 1) / 2; + } + + template <typename local_format = format, typename std::enable_if<std::is_same<local_format, ieee754_binary64>::value, bool>::type = true> + static constexpr carrier_uint compute_round_up_for_shorter_interval_case(cache_entry_type const& cache, int beta) noexcept + { + return ((cache.high >> (carrier_bits - significand_bits - 2 - beta)) + 1) / 2; + } + + static constexpr bool is_right_endpoint_integer_shorter_interval(int exponent) noexcept + { + return exponent >= case_shorter_interval_right_endpoint_lower_threshold && + exponent <= case_shorter_interval_right_endpoint_upper_threshold; + } + + static constexpr bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept + { + return exponent >= case_shorter_interval_left_endpoint_lower_threshold && + exponent <= case_shorter_interval_left_endpoint_upper_threshold; + } +}; + + +//////////////////////////////////////////////////////////////////////////////////////// +// Policy holder. +//////////////////////////////////////////////////////////////////////////////////////// + +namespace policy_impl { + // The library will specify a list of accepted kinds of policies and their defaults, and + // the user will pass a list of policies. The aim of helper classes/functions here is to + // do the following: + // 1. Check if the policy parameters given by the user are all valid; that means, + // each of them should be of the kinds specified by the library. + // If that's not the case, then the compilation fails. + // 2. Check if multiple policy parameters for the same kind is specified by the user. + // If that's the case, then the compilation fails. + // 3. Build a class deriving from all policies the user have given, and also from + // the default policies if the user did not specify one for some kinds. + // A policy belongs to a certain kind if it is deriving from a base class. + + // For a given kind, find a policy belonging to that kind. + // Check if there are more than one such policies. + enum class policy_found_info + { + not_found, + unique, + repeated + }; + + template <typename Policy, policy_found_info info> + struct found_policy_pair + { + using policy = Policy; + static constexpr auto found_info = info; + }; + + template <typename Base, typename DefaultPolicy> + struct base_default_pair + { + using base = Base; + + template <class FoundPolicyInfo> + static constexpr FoundPolicyInfo get_policy_impl(FoundPolicyInfo) + { + return {}; + } + + template <typename FoundPolicyInfo, typename FirstPolicy, typename... RemainingPolicies, + typename std::enable_if<std::is_base_of<Base, FirstPolicy>::value && (FoundPolicyInfo::found_info == policy_found_info::not_found), bool>::type = true> + static constexpr auto get_policy_impl(FoundPolicyInfo, FirstPolicy, RemainingPolicies... remainings) noexcept -> found_policy_pair<FirstPolicy, policy_found_info::unique> + { + return get_policy_impl(found_policy_pair<FirstPolicy, policy_found_info::unique>{}, remainings...); + } + + template <typename FoundPolicyInfo, typename FirstPolicy, typename... RemainingPolicies, + typename std::enable_if<std::is_base_of<Base, FirstPolicy>::value && !(FoundPolicyInfo::found_info == policy_found_info::not_found), bool>::type = true> + static constexpr auto get_policy_impl(FoundPolicyInfo, FirstPolicy, RemainingPolicies... remainings) noexcept -> found_policy_pair<FirstPolicy, policy_found_info::repeated> + { + return get_policy_impl(found_policy_pair<FirstPolicy, policy_found_info::repeated>{}, remainings...); + } + + template <typename FoundPolicyInfo, typename FirstPolicy, typename... RemainingPolicies, + typename std::enable_if<!std::is_base_of<Base, FirstPolicy>::value, bool>::type = true> + static constexpr auto get_policy_impl(FoundPolicyInfo, FirstPolicy, RemainingPolicies... remainings) noexcept -> found_policy_pair<FirstPolicy, FoundPolicyInfo::found_info> + { + return get_policy_impl(FoundPolicyInfo{}, remainings...); + } + + template <typename... Policies> + static constexpr auto get_policy(Policies... policies) -> found_policy_pair<DefaultPolicy, policy_found_info::not_found> + { + return get_policy_impl(found_policy_pair<DefaultPolicy, policy_found_info::not_found>{}, policies...); + } + }; + + template <typename... BaseDefaultPairs> + struct base_default_pair_list {}; + + // Check if a given policy belongs to one of the kinds specified by the library. + template <typename Policy> + constexpr bool check_policy_validity(Policy, base_default_pair_list<>) + { + return false; + } + + template <typename Policy, typename FirstBaseDefaultPair, typename... RemainingBaseDefaultPairs> + constexpr bool check_policy_validity(Policy, base_default_pair_list<FirstBaseDefaultPair, RemainingBaseDefaultPairs...>) + { + return std::is_base_of<typename FirstBaseDefaultPair::base, Policy>::value || + check_policy_validity(Policy{}, base_default_pair_list<RemainingBaseDefaultPairs...>{}); + } + + template <typename BaseDefaultPairList> + constexpr bool check_policy_list_validity(BaseDefaultPairList) + { + return true; + } + + template <typename BaseDefaultPairList, typename FirstPolicy, typename... RemainingPolicies> + constexpr bool check_policy_list_validity(BaseDefaultPairList, FirstPolicy, RemainingPolicies... remaining_policies) + { + return check_policy_validity(FirstPolicy{}, BaseDefaultPairList{}) && + check_policy_list_validity(BaseDefaultPairList{}, remaining_policies...); + } + + // Build policy_holder. + template <bool repeated_, typename... FoundPolicyPairs> + struct found_policy_pair_list + { + static constexpr bool repeated = repeated_; + }; + + template <typename... Policies> + struct policy_holder : Policies... {}; + + #ifndef BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION + + template <bool repeated, typename... FoundPolicyPairs, typename... Policies> + constexpr auto make_policy_holder_impl(base_default_pair_list<>, found_policy_pair_list<repeated, FoundPolicyPairs...>, Policies...) + -> found_policy_pair_list<repeated, FoundPolicyPairs...> + { + return found_policy_pair_list<repeated, FoundPolicyPairs...>{}; + } + + template <typename FirstBaseDefaultPair, typename... RemainingBaseDefaultPairs, bool repeated, + typename... FoundPolicyPairs, typename... Policies> + constexpr auto make_policy_holder_impl(base_default_pair_list<FirstBaseDefaultPair, RemainingBaseDefaultPairs...>, + found_policy_pair_list<repeated, FoundPolicyPairs...>, Policies... policies) + { + using new_found_policy_pair = decltype(FirstBaseDefaultPair::get_policy(policies...)); + + return make_policy_holder_impl(base_default_pair_list<RemainingBaseDefaultPairs...>{}, + found_policy_pair_list < repeated || new_found_policy_pair::found_info == policy_found_info::repeated, + new_found_policy_pair, FoundPolicyPairs... > {}, policies...); + } + + template <bool repeated, typename... RawPolicies> + constexpr auto convert_to_policy_holder(found_policy_pair_list<repeated>, RawPolicies...) -> policy_holder<RawPolicies...> + { + return policy_holder<RawPolicies...>{}; + } + + template <bool repeated, typename FirstFoundPolicyPair, typename... RemainingFoundPolicyPairs, typename... RawPolicies> + constexpr auto convert_to_policy_holder(found_policy_pair_list<repeated, FirstFoundPolicyPair, RemainingFoundPolicyPairs...>, + RawPolicies... policies) + { + return convert_to_policy_holder(found_policy_pair_list<repeated, RemainingFoundPolicyPairs...>{}, typename FirstFoundPolicyPair::policy{}, policies...); + } + + template <typename BaseDefaultPairList, typename... Policies> + constexpr auto make_policy_holder(BaseDefaultPairList, Policies... policies) + { + static_assert(check_policy_list_validity(BaseDefaultPairList{}, Policies{}...), + "jkj::dragonbox: an invalid policy is specified"); + + using policy_pair_list = decltype(make_policy_holder_impl( + BaseDefaultPairList{}, found_policy_pair_list<false>{}, policies...)); + + static_assert(!policy_pair_list::repeated, + "jkj::dragonbox: each policy should be specified at most once"); + + return convert_to_policy_holder(policy_pair_list{}); + } + #endif +} +//////////////////////////////////////////////////////////////////////////////////////// +// The interface function. +//////////////////////////////////////////////////////////////////////////////////////// + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4100) // Unreferenced formal parameter (interval_type_provider) +# pragma warning(disable: 4189) // Local variable is initializaed but unused (tag) +#endif + +template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>, typename... Policies> +BOOST_FORCEINLINE BOOST_CHARCONV_SAFEBUFFERS auto +to_decimal(dragonbox_signed_significand_bits<Float, FloatTraits> dragonbox_signed_significand_bits, + unsigned int exponent_bits, BOOST_ATTRIBUTE_UNUSED Policies... policies) noexcept + #ifdef BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION + -> decimal_fp<typename FloatTraits::carrier_uint, true, false> + #endif +{ + // Build policy holder type. + using namespace policy_impl; + + #ifdef BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION + // For C++11 we hardcode the policy holder + using policy_holder = policy_holder<decimal_to_binary_rounding::nearest_to_even, binary_to_decimal_rounding::to_even, cache::full, sign::return_sign, trailing_zero::remove>; + + #else + + using policy_holder = decltype(make_policy_holder( + base_default_pair_list<base_default_pair<sign::base, sign::return_sign>, + base_default_pair<trailing_zero::base, trailing_zero::remove>, + base_default_pair<decimal_to_binary_rounding::base, + decimal_to_binary_rounding::nearest_to_even>, + base_default_pair<binary_to_decimal_rounding::base, + binary_to_decimal_rounding::to_even>, + base_default_pair<cache::base, cache::full>>{}, + policies...)); + + #endif + + using return_type = decimal_fp<typename FloatTraits::carrier_uint, policy_holder::return_has_sign, policy_holder::report_trailing_zeros>; + + return_type ret = policy_holder::template delegate<return_type>(dragonbox_signed_significand_bits, + [exponent_bits, dragonbox_signed_significand_bits](policy_impl::decimal_to_binary_rounding::nearest_to_even interval_type_provider) { + using format = typename FloatTraits::format; + constexpr auto tag = decltype(interval_type_provider)::tag; + + auto two_fc = dragonbox_signed_significand_bits.remove_sign_bit_and_shift(); + auto exponent = int(exponent_bits); + + BOOST_IF_CONSTEXPR (tag == decimal_to_binary_rounding::tag_t::to_nearest) { // NOLINT: if constexpr not always false + // Is the input a normal number? + if (exponent != 0) { + exponent += format::exponent_bias - format::significand_bits; + + // Shorter interval case; proceed like Schubfach. + // One might think this condition is wrong, since when exponent_bits == 1 + // and two_fc == 0, the interval is actually regular. However, it turns out + // that this seemingly wrong condition is actually fine, because the end + // result is anyway the same. + // + // [binary32] + // (fc-1/2) * 2^e = 1.175'494'28... * 10^-38 + // (fc-1/4) * 2^e = 1.175'494'31... * 10^-38 + // fc * 2^e = 1.175'494'35... * 10^-38 + // (fc+1/2) * 2^e = 1.175'494'42... * 10^-38 + // + // Hence, shorter_interval_case will return 1.175'494'4 * 10^-38. + // 1.175'494'3 * 10^-38 is also a correct shortest representation that will + // be rejected if we assume shorter interval, but 1.175'494'4 * 10^-38 is + // closer to the true value so it doesn't matter. + // + // [binary64] + // (fc-1/2) * 2^e = 2.225'073'858'507'201'13... * 10^-308 + // (fc-1/4) * 2^e = 2.225'073'858'507'201'25... * 10^-308 + // fc * 2^e = 2.225'073'858'507'201'38... * 10^-308 + // (fc+1/2) * 2^e = 2.225'073'858'507'201'63... * 10^-308 + // + // Hence, shorter_interval_case will return 2.225'073'858'507'201'4 * + // 10^-308. This is indeed of the shortest length, and it is the unique one + // closest to the true value among valid representations of the same length. + static_assert(std::is_same<format, ieee754_binary32>::value || + std::is_same<format, ieee754_binary64>::value, "Format must be IEEE754 binary 32 or 64"); + + if (two_fc == 0) { + return decltype(interval_type_provider)::template invoke_shorter_interval_case<return_type>( + dragonbox_signed_significand_bits, [exponent]() { + return detail::impl<Float, FloatTraits>:: + template compute_nearest_shorter< + return_type, + typename decltype(interval_type_provider):: + shorter_interval_type, + typename policy_holder::trailing_zero_policy, + typename policy_holder:: + binary_to_decimal_rounding_policy, + typename policy_holder::cache_policy>( + exponent); + }); + } + + two_fc |= (decltype(two_fc)(1) << (format::significand_bits + 1)); + } + // Is the input a subnormal number? + else { + exponent = format::min_exponent - format::significand_bits; + } + + return decltype(interval_type_provider)::template invoke_normal_interval_case<return_type>( + dragonbox_signed_significand_bits, [two_fc, exponent](bool additional_args) { + return detail::impl<Float, FloatTraits>:: + template compute_nearest_normal< + return_type, + typename decltype(interval_type_provider)::normal_interval_type, + typename policy_holder::trailing_zero_policy, + typename policy_holder::binary_to_decimal_rounding_policy, + typename policy_holder::cache_policy>(two_fc, exponent, additional_args); + }); + } + else BOOST_IF_CONSTEXPR (tag == decimal_to_binary_rounding::tag_t::left_closed_directed) // NOLINT: if constexpr not always false + { + // Is the input a normal number? + if (exponent != 0) { + exponent += format::exponent_bias - format::significand_bits; + two_fc |= (decltype(two_fc)(1) << (format::significand_bits + 1)); + } + // Is the input a subnormal number? + else { + exponent = format::min_exponent - format::significand_bits; + } + + return detail::impl<Float>::template compute_left_closed_directed< + return_type, typename policy_holder::trailing_zero_policy, + typename policy_holder::cache_policy>(two_fc, exponent); + } + else + { + // Assertion does not work unless if constexpr is defined + // static_assert(tag == decimal_to_binary_rounding::tag_t::right_closed_directed, "Tag should be right_closed_direction"); + + bool shorter_interval = false; + + // Is the input a normal number? + if (exponent != 0) { + if (two_fc == 0 && exponent != 1) { + shorter_interval = true; + } + exponent += format::exponent_bias - format::significand_bits; + two_fc |= (decltype(two_fc)(1) << (format::significand_bits + 1)); + } + // Is the input a subnormal number? + else { + exponent = format::min_exponent - format::significand_bits; + } + + return detail::impl<Float>::template compute_right_closed_directed< + return_type, typename policy_holder::trailing_zero_policy, + typename policy_holder::cache_policy>(two_fc, exponent, shorter_interval); + } + }); + + policy_holder::handle_sign(dragonbox_signed_significand_bits, ret); + return ret; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>, typename... Policies> +BOOST_FORCEINLINE BOOST_CHARCONV_SAFEBUFFERS auto to_decimal(Float x, Policies... policies) noexcept + #ifdef BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION + -> decimal_fp<typename FloatTraits::carrier_uint, true, false> + #endif +{ + const auto br = dragonbox_float_bits<Float, FloatTraits>(x); + const auto exponent_bits = br.extract_exponent_bits(); + const auto s = br.remove_exponent_bits(exponent_bits); + + return to_decimal<Float, FloatTraits>(s, exponent_bits, policies...); +} + +namespace to_chars_detail { + template <class Float, class FloatTraits> + extern to_chars_result dragon_box_print_chars(typename FloatTraits::carrier_uint significand, int exponent, char* first, char* last, chars_format fmt) noexcept; + + // Avoid needless ABI overhead incurred by tag dispatch. + template <class PolicyHolder, class Float, class FloatTraits> + to_chars_result to_chars_n_impl(dragonbox_float_bits<Float, FloatTraits> br, char* first, char* last, chars_format fmt) noexcept + { + const auto exponent_bits = br.extract_exponent_bits(); + const auto s = br.remove_exponent_bits(exponent_bits); + + auto buffer = first; + const auto buffer_size = last - first; + + if (br.is_finite(exponent_bits)) + { + if (s.is_negative()) + { + *buffer = '-'; + ++buffer; + } + if (br.is_nonzero()) + { + auto result = to_decimal<Float, FloatTraits>( + s, exponent_bits, policy::sign::ignore, policy::trailing_zero::ignore, + typename PolicyHolder::decimal_to_binary_rounding_policy{}, + typename PolicyHolder::binary_to_decimal_rounding_policy{}, + typename PolicyHolder::cache_policy{}); + return to_chars_detail::dragon_box_print_chars<Float, FloatTraits>(result.significand, result.exponent, buffer, last, fmt); + } + else + { + if (fmt != chars_format::scientific) + { + std::memcpy(buffer, "0", 1); // NOLINT: Specifically not null-terminated + return {buffer + 1, std::errc()}; + } + + if (buffer_size >= 5) + { + std::memcpy(buffer, "0e+00", 5); // NOLINT: Specifically not null-terminated + return {buffer + 5, std::errc()}; + } + else + { + return {last, std::errc::value_too_large}; + } + } + } + else + { + bool is_negative = false; + if (s.is_negative()) + { + *buffer = '-'; + ++buffer; + is_negative = true; + } + + if (s.has_all_zero_significand_bits()) + { + if (buffer_size >= 3 + static_cast<std::ptrdiff_t>(is_negative)) + { + std::memcpy(buffer, "inf", 3); // NOLINT: Specifically not null-terminated + return {buffer + 3, std::errc()}; + } + else + { + return {last, std::errc::value_too_large}; + } + } + else + { + // Doubles: + // qNaN = 2251799813685248 + // sNaN = 1125899906842624 + // + // Floats: + // qNaN = 4194304 + // sNaN = 2097152 + // + // use 1 for qNaN and 0 for sNaN + int nan_type; + BOOST_IF_CONSTEXPR (std::is_same<typename FloatTraits::format, ieee754_binary32>::value) + { + if (br.extract_significand_bits() == UINT32_C(4194304)) + { + nan_type = 1; + } + else + { + nan_type = 0; + } + } + else + { + if (br.extract_significand_bits() == UINT64_C(2251799813685248)) + { + nan_type = 1; + } + else + { + nan_type = 0; + } + } + + if (nan_type == 1) + { + if (!s.is_negative()) + { + if (buffer_size >= 3 + static_cast<std::ptrdiff_t>(is_negative)) + { + std::memcpy(buffer, "nan", 3); // NOLINT: Specifically not null-terminated + return {buffer + 3, std::errc()}; + } + else + { + return {last, std::errc::value_too_large}; + } + } + else + { + if (buffer_size >= 8 + static_cast<std::ptrdiff_t>(is_negative)) + { + std::memcpy(buffer, "nan(ind)", 8); // NOLINT: Specifically not null-terminated + return {buffer + 8, std::errc()}; + } + else + { + return {last, std::errc::value_too_large}; + } + } + } + else + { + if (buffer_size >= 9 + static_cast<std::ptrdiff_t>(is_negative)) + { + std::memcpy(buffer, "nan(snan)", 9); // NOLINT: Specifically not null-terminated + return {buffer + 9, std::errc()}; + } + else + { + return {last, std::errc::value_too_large}; + } + } + } + } + } +} + +// Returns the next-to-end position +template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>, typename... Policies> +to_chars_result to_chars_n(Float x, char* first, char* last, chars_format fmt, BOOST_ATTRIBUTE_UNUSED Policies... policies) noexcept +{ + using namespace policy_impl; + + #ifdef BOOST_CHARCONV_NO_CXX14_RETURN_TYPE_DEDUCTION + // For C++11 we hardcode the policy holder + using policy_holder = policy_holder<decimal_to_binary_rounding::nearest_to_even, binary_to_decimal_rounding::to_even, cache::full, sign::return_sign, trailing_zero::remove>; + + #else + + using policy_holder = decltype(make_policy_holder( + base_default_pair_list<base_default_pair<sign::base, sign::return_sign>, + base_default_pair<trailing_zero::base, trailing_zero::remove>, + base_default_pair<decimal_to_binary_rounding::base, + decimal_to_binary_rounding::nearest_to_even>, + base_default_pair<binary_to_decimal_rounding::base, + binary_to_decimal_rounding::to_even>, + base_default_pair<cache::base, cache::full>>{}, + policies...)); + + #endif + + return to_chars_detail::to_chars_n_impl<policy_holder>(dragonbox_float_bits<Float, FloatTraits>(x), first, last, fmt); +} + +// Null-terminate and bypass the return value of fp_to_chars_n +template <typename Float, typename FloatTraits = dragonbox_float_traits<Float>, typename... Policies> +to_chars_result dragonbox_to_chars(Float x, char* first, char* last, chars_format fmt, Policies... policies) noexcept +{ + return to_chars_n<Float, FloatTraits>(x, first, last, fmt, policies...); +} + +}}} // Namespaces + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // BOOST_CHARCONV_DETAIL_DRAGONBOX_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/dragonbox_common.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/dragonbox_common.hpp new file mode 100644 index 00000000000..0bee7d091fa --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/dragonbox_common.hpp @@ -0,0 +1,829 @@ +// Copyright 2020-2022 Junekey Jeon +// +// The contents of this file may be used under the terms of +// the Apache License v2.0 with LLVM Exceptions. +// +// (See accompanying file LICENSE-Apache or copy at +// https://llvm.org/foundation/relicensing/LICENSE.txt) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +// +// Some parts are copied from Dragonbox project. +// +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_DRAGONBOX_COMMON_HPP +#define BOOST_CHARCONV_DETAIL_DRAGONBOX_COMMON_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/chars_format.hpp> +#include <boost/core/bit.hpp> +#include <type_traits> +#include <limits> +#include <cstdint> +#include <cstring> +#include <cstddef> +#include <climits> + +namespace boost { namespace charconv { namespace detail { + +template <typename T> +struct physical_bits +{ + static constexpr std::size_t value = sizeof(T) * CHAR_BIT; +}; + +template <typename T> +struct value_bits +{ + static constexpr std::size_t value = std::numeric_limits<typename std::enable_if<std::is_unsigned<T>::value, T>::type>::digits; +}; + +#ifdef BOOST_NO_CXX17_INLINE_VARIABLES + +template <typename T> constexpr std::size_t physical_bits<T>::value; +template <typename T> constexpr std::size_t value_bits<T>::value; + +#endif + +// A floating-point traits class defines ways to interpret a bit pattern of given size as an +// encoding of floating-point number. This is a default implementation of such a traits class, +// supporting ways to interpret 32-bits into a binary32-encoded floating-point number and to +// interpret 64-bits into a binary64-encoded floating-point number. Users might specialize this +// class to change the default behavior for certain types. +template <typename T> +struct default_float_traits +{ + // I don't know if there is a truly reliable way of detecting + // IEEE-754 binary32/binary64 formats; I just did my best here. + static_assert(std::numeric_limits<T>::is_iec559 && std::numeric_limits<T>::radix == 2 && + (detail::physical_bits<T>::value == 32 || detail::physical_bits<T>::value == 64), + "default_ieee754_traits only works for 32-bits or 64-bits types " + "supporting binary32 or binary64 formats!"); + + // The type that is being viewed. + using type = T; + + // Refers to the format specification class. + using format = + typename std::conditional<detail::physical_bits<T>::value == 32, detail::ieee754_binary32, detail::ieee754_binary64>::type; + + // Defines an unsignedeger type that is large enough to carry a variable of type T. + // Most of the operations will be done on this integer type. + using carrier_uint = typename std::conditional<detail::physical_bits<T>::value == 32, std::uint32_t, std::uint64_t>::type; + + static_assert(sizeof(carrier_uint) == sizeof(T), "carrier_uint must be T"); + + // Number of bits in the above unsignedeger type. + static constexpr int carrier_bits = static_cast<int>(detail::physical_bits<carrier_uint>::value); + + // Convert from carrier_uint into the original type. + // Depending on the floating-point encoding format, this operation might not be possible for + // some specific bit patterns. However, the contract is that u always denotes a + // valid bit pattern, so this function must be assumed to be noexcept. + static T carrier_to_float(carrier_uint u) noexcept + { + T x; + std::memcpy(&x, &u, sizeof(carrier_uint)); + return x; + } + + // Same as above. + static carrier_uint float_to_carrier(T x) noexcept + { + carrier_uint u; + std::memcpy(&u, &x, sizeof(carrier_uint)); + return u; + } + + // Extract exponent bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. This function does not do bias adjustment. + static constexpr unsigned extract_exponent_bits(carrier_uint u) noexcept + { + return static_cast<unsigned>(u >> format::exponent_bits) & static_cast<unsigned>((1U << format::exponent_bits) - 1); + } + + // Extract significand bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. The result does not contain the implicit bit. + static constexpr carrier_uint extract_significand_bits(carrier_uint u) noexcept + { + return static_cast<carrier_uint>(u & static_cast<carrier_uint>((static_cast<carrier_uint>(1) << format::significand_bits) - 1)); + } + + // Remove the exponent bits and extract significand bits together with the sign bit. + static constexpr carrier_uint remove_exponent_bits(carrier_uint u, unsigned exponent_bits) noexcept + { + return u ^ (static_cast<carrier_uint>(exponent_bits) << format::significand_bits); + } + + // Shift the obtained signed significand bits to the left by 1 to remove the sign bit. + static constexpr carrier_uint remove_sign_bit_and_shift(carrier_uint u) noexcept + { + return static_cast<carrier_uint>(static_cast<carrier_uint>(u) << 1); + } + + // The actual value of exponent is obtained by adding this value to the extracted exponent bits + static constexpr int exponent_bias = 1 - (1 << (carrier_bits - format::significand_bits - 2)); + + // Obtain the actual value of the binary exponent from the extracted exponent bits. + static constexpr int binary_exponent(unsigned exponent_bits) noexcept + { + return exponent_bits == 0 ? format::min_exponent : static_cast<int>(exponent_bits) + format::exponent_bias; + } + + // Obtain the actual value of the binary exponent from the extracted significand bits and + // exponent bits. + static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept + { + return exponent_bits == 0 ? significand_bits : (significand_bits | (static_cast<carrier_uint>(1) << format::significand_bits)); + } + + + // Various boolean observer functions + + static constexpr bool is_nonzero(carrier_uint u) noexcept { return (u << 1) != 0; } + + static constexpr bool is_positive(carrier_uint u) noexcept + { + return u < static_cast<carrier_uint>(1) << (format::significand_bits + format::exponent_bits); + } + + static constexpr bool is_negative(carrier_uint u) noexcept { return !is_positive(u); } + + static constexpr bool is_finite(unsigned exponent_bits) noexcept + { + //constexpr unsigned exponent_bits_all_set = (1u << format::exponent_bits) - 1; + return exponent_bits != (1u << format::exponent_bits) - 1; + } + + static constexpr bool has_all_zero_significand_bits(carrier_uint u) noexcept + { + return (u << 1) == 0; + } + + static constexpr bool has_even_significand_bits(carrier_uint u) noexcept + { + return u % 2 == 0; + } +}; + +// Convenient wrappers for floating-point traits classes. +// In order to reduce the argument passing overhead, these classes should be as simple as +// possible (e.g., no inheritance, no private non-static data member, etc.; this is an +// unfortunate fact about common ABI convention). + +template <typename T, typename Traits = default_float_traits<T>> +struct float_bits; + +template <typename T, typename Traits = default_float_traits<T>> +struct signed_significand_bits; + +template <typename T, typename Traits> +struct float_bits +{ + using type = T; + using traits_type = Traits; + using carrier_uint = typename traits_type::carrier_uint; + + carrier_uint u; + + float_bits() = default; + constexpr explicit float_bits(carrier_uint bit_pattern) noexcept : u{bit_pattern} {} + constexpr explicit float_bits(T float_value) noexcept : u{traits_type::float_to_carrier(float_value)} {} + + constexpr T to_float() const noexcept { return traits_type::carrier_to_float(u); } + + // Extract exponent bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. This function does not do bias adjustment. + constexpr unsigned extract_exponent_bits() const noexcept + { + return traits_type::extract_exponent_bits(u); + } + + // Extract significand bits from a bit pattern. + // The result must be aligned to the LSB so that there is no additional zero paddings + // on the right. The result does not contain the implicit bit. + constexpr carrier_uint extract_significand_bits() const noexcept + { + return traits_type::extract_significand_bits(u); + } + + // Remove the exponent bits and extract significand bits together with the sign bit. + constexpr signed_significand_bits<type, traits_type> remove_exponent_bits(unsigned exponent_bits) const noexcept + { + return signed_significand_bits<type, traits_type>(traits_type::remove_exponent_bits(u, exponent_bits)); + } + + // Obtain the actual value of the binary exponent from the extracted exponent bits. + static constexpr int binary_exponent(unsigned exponent_bits) noexcept + { + return traits_type::binary_exponent(exponent_bits); + } + + constexpr int binary_exponent() const noexcept + { + return binary_exponent(extract_exponent_bits()); + } + + // Obtain the actual value of the binary exponent from the extracted significand bits and + // exponent bits. + static constexpr carrier_uint binary_significand(carrier_uint significand_bits, unsigned exponent_bits) noexcept + { + return traits_type::binary_significand(significand_bits, exponent_bits); + } + + constexpr carrier_uint binary_significand() const noexcept + { + return binary_significand(extract_significand_bits(), extract_exponent_bits()); + } + + constexpr bool is_nonzero() const noexcept { return traits_type::is_nonzero(u); } + + constexpr bool is_positive() const noexcept { return traits_type::is_positive(u); } + + constexpr bool is_negative() const noexcept { return traits_type::is_negative(u); } + + constexpr bool is_finite(unsigned exponent_bits) const noexcept { return traits_type::is_finite(exponent_bits); } + + constexpr bool is_finite() const noexcept { return traits_type::is_finite(extract_exponent_bits()); } + + constexpr bool has_even_significand_bits() const noexcept { return traits_type::has_even_significand_bits(u); } +}; + +template <typename T, typename Traits> +struct signed_significand_bits +{ + using type = T; + using traits_type = Traits; + using carrier_uint = typename traits_type::carrier_uint; + + carrier_uint u; + + signed_significand_bits() = default; + constexpr explicit signed_significand_bits(carrier_uint bit_pattern) noexcept + : u{bit_pattern} {} + + // Shift the obtained signed significand bits to the left by 1 to remove the sign bit. + constexpr carrier_uint remove_sign_bit_and_shift() const noexcept + { + return traits_type::remove_sign_bit_and_shift(u); + } + + constexpr bool is_positive() const noexcept { return traits_type::is_positive(u); } + + constexpr bool is_negative() const noexcept { return traits_type::is_negative(u); } + + constexpr bool has_all_zero_significand_bits() const noexcept + { + return traits_type::has_all_zero_significand_bits(u); + } + + constexpr bool has_even_significand_bits() const noexcept + { + return traits_type::has_even_significand_bits(u); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////// +// Some simple utilities for constexpr computation. +//////////////////////////////////////////////////////////////////////////////////////// + +template <class Int, class Int2> +BOOST_CHARCONV_CXX14_CONSTEXPR Int compute_power(Int a, Int2 exp) noexcept +{ + BOOST_CHARCONV_ASSERT(exp >= 0); + + Int res = 1; + while (exp > 0) + { + if (exp % 2 != 0) + { + res *= a; + } + + a *= a; + exp >>= 1; + } + return res; +} + +static constexpr std::uint64_t power_of_10[] = { + UINT64_C(1), UINT64_C(10), UINT64_C(100), UINT64_C(1000), UINT64_C(10000), + UINT64_C(100000), UINT64_C(1000000), UINT64_C(10000000), UINT64_C(100000000), + UINT64_C(1000000000), UINT64_C(10000000000), UINT64_C(100000000000), UINT64_C(1000000000000), + UINT64_C(10000000000000), UINT64_C(100000000000000), UINT64_C(1000000000000000), + UINT64_C(10000000000000000), UINT64_C(100000000000000000), UINT64_C(1000000000000000000), + UINT64_C(10000000000000000000) +}; + +static_assert(sizeof(power_of_10) == 20 * sizeof(std::uint64_t), "There should be the first 20 powers of 10"); + + +template <unsigned a, typename UInt> +BOOST_CHARCONV_CXX14_CONSTEXPR int count_factors(UInt n) noexcept +{ + int c = 0; + + while (n % a == 0) + { + n /= a; + ++c; + } + return c; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Utilities for fast/constexpr log computation. +//////////////////////////////////////////////////////////////////////////////////////// + +namespace log { +static_assert((-1 >> 1) == -1, "right-shift for signed integers must be arithmetic"); + +// Compute floor(e * c - s). +enum class multiply : std::uint32_t {}; +enum class subtract : std::uint32_t {}; +enum class shift : std::size_t {}; +enum class min_exponent : std::int32_t {}; +enum class max_exponent : std::int32_t {}; + +template <multiply m, subtract f, shift k, min_exponent e_min, max_exponent e_max> +constexpr int compute(int e) noexcept +{ + return static_cast<int>((std::int32_t(e) * std::int32_t(m) - std::int32_t(f)) >> std::size_t(k)); +} + +// For constexpr computation. +// Returns -1 when n = 0. +template <class UInt> +BOOST_CHARCONV_CXX14_CONSTEXPR int floor_log2(UInt n) noexcept +{ + int count = -1; + while (n != 0) + { + ++count; + n >>= 1; + } + + return count; +} + +static constexpr int floor_log10_pow2_min_exponent = -2620; + +static constexpr int floor_log10_pow2_max_exponent = 2620; + +constexpr int floor_log10_pow2(int e) noexcept +{ + using namespace log; + return compute<multiply(315653), subtract(0), shift(20), + min_exponent(floor_log10_pow2_min_exponent), + max_exponent(floor_log10_pow2_max_exponent)>(e); +} + +static constexpr int floor_log2_pow10_min_exponent = -1233; + +static constexpr int floor_log2_pow10_max_exponent = 1233; + +constexpr int floor_log2_pow10(int e) noexcept +{ + using namespace log; + return compute<multiply(1741647), subtract(0), shift(19), + min_exponent(floor_log2_pow10_min_exponent), + max_exponent(floor_log2_pow10_max_exponent)>(e); +} + +static constexpr int floor_log10_pow2_minus_log10_4_over_3_min_exponent = -2985; + +static constexpr int floor_log10_pow2_minus_log10_4_over_3_max_exponent = 2936; + +constexpr int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept +{ + using namespace log; + return compute<multiply(631305), subtract(261663), shift(21), + min_exponent(floor_log10_pow2_minus_log10_4_over_3_min_exponent), + max_exponent(floor_log10_pow2_minus_log10_4_over_3_max_exponent)>(e); +} + +static constexpr int floor_log5_pow2_min_exponent = -1831; + +static constexpr int floor_log5_pow2_max_exponent = 1831; + +constexpr int floor_log5_pow2(int e) noexcept +{ + using namespace log; + return compute<multiply(225799), subtract(0), shift(19), + min_exponent(floor_log5_pow2_min_exponent), + max_exponent(floor_log5_pow2_max_exponent)>(e); +} + +static constexpr int floor_log5_pow2_minus_log5_3_min_exponent = -3543; + +static constexpr int floor_log5_pow2_minus_log5_3_max_exponent = 2427; + +constexpr int floor_log5_pow2_minus_log5_3(int e) noexcept +{ + using namespace log; + return compute<multiply(451597), subtract(715764), shift(20), + min_exponent(floor_log5_pow2_minus_log5_3_min_exponent), + max_exponent(floor_log5_pow2_minus_log5_3_max_exponent)>(e); +} +} // Namespace log + +template <bool b> +struct main_cache_holder_impl +{ + using cache_entry_type = boost::charconv::detail::uint128; + static constexpr int cache_bits = 128; + static constexpr int min_k = -292; + static constexpr int max_k = 326; + static constexpr cache_entry_type cache[] = { + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, {0x9faacf3df73609b1, 0x77b191618c54e9ad}, + {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, + {0x9becce62836ac577, 0x4ee367f9430aec33}, {0xc2e801fb244576d5, 0x229c41f793cda740}, + {0xf3a20279ed56d48a, 0x6b43527578c11110}, {0x9845418c345644d6, 0x830a13896b78aaaa}, + {0xbe5691ef416bd60c, 0x23cc986bc656d554}, {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, + {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, + {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, {0x91376c36d99995be, 0x23100809b9c21fa2}, + {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, + {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, + {0xdd95317f31c7fa1d, 0x40405643d711d584}, {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, + {0xad1c8eab5ee43b66, 0xda3243650005eed0}, {0xd863b256369d4a40, 0x90bed43e40076a83}, + {0x873e4f75e2224e68, 0x5a7744a6e804a292}, {0xa90de3535aaae202, 0x711515d0a205cb37}, + {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, {0x8412d9991ed58091, 0xe858790afe9486c3}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, + {0xc987434744ac874e, 0xa327ffb266b56221}, {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, + {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, + {0xf6019da07f549b2b, 0x7e2a53a146606a49}, {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, + {0xc0314325637a1939, 0xfa911155fefb5309}, {0xf03d93eebc589f88, 0x793555ab7eba27cb}, + {0x96267c7535b763b5, 0x4bc1558b2f3458df}, {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, + {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, {0x92a1958a7675175f, 0x0bfacd89ec191eca}, + {0xb749faed14125d36, 0xcef980ec671f667c}, {0xe51c79a85916f484, 0x82b7e12780e7401b}, + {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, + {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, + {0xaecc49914078536d, 0x58fae9f773886e19}, {0xda7f5bf590966848, 0xaf39a475506a899f}, + {0x888f99797a5e012d, 0x6d8406c952429604}, {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, + {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, {0xd0601d8efc57b08b, 0xf13b94daf124da27}, + {0x823c12795db6ce57, 0x76c53d08d6b70859}, {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, + {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, + {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, + {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, + {0xc21094364dfb5636, 0x985915fc12f542e5}, {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, + {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, {0xbd8430bd08277231, 0x50c6ff782a838354}, + {0xece53cec4a314ebd, 0xa4f8bf5635246429}, {0x940f4613ae5ed136, 0x871b7795e136be9a}, + {0xb913179899f68584, 0x28e2557b59846e40}, {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, + {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, {0xb4bca50b065abe63, 0x0fed077a756b53aa}, + {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, + {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, + {0x89e42caaf9491b60, 0xf41686c49db57245}, {0xac5d37d5b79b6239, 0x311c2875c522ced6}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, {0xd267caa862a12d66, 0xd072df63c324fd7c}, + {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, {0xa46116538d0deb78, 0x52d9be85f074e609}, + {0xcd795be870516656, 0x67902e276c921f8c}, {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, + {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, + {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, + {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, + {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, + {0xef340a98172aace4, 0x86fb897116c87c35}, {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, + {0xbae0a846d2195712, 0x8974836059cca10a}, {0xe998d258869facd7, 0x2bd1a438703fc94c}, + {0x91ff83775423cc06, 0x7b6306a34627ddd0}, {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, + {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, {0x8e938662882af53e, 0x547eb47b7282ee9d}, + {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, + {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, + {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, {0xd47487cc8470652b, 0x7647c32000696720}, + {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, {0xa5fb0a17c777cf09, 0xf468107100525891}, + {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, {0x81ac1fe293d599bf, 0xc6f14cd848405531}, + {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, + {0xfd442e4688bd304a, 0x908f4a166d1da664}, {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, + {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, {0xf7549530e188c128, 0xd12bee59e68ef47d}, + {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, + {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, + {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, {0xebdf661791d60f56, 0x111b495b3464ad22}, + {0x936b9fcebb25c995, 0xcab10dd900beec35}, {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, + {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, + {0xb3f4e093db73a093, 0x59ed216765690f57}, {0xe0f218b8d25088b8, 0x306869c13ec3532d}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, {0x894bc396ce5da772, 0x6b8bba8c328eb784}, + {0xab9eb47c81f5114f, 0x066ea92f3f326565}, {0xd686619ba27255a2, 0xc80a537b0efefebe}, + {0x8613fd0145877585, 0xbd06742ce95f5f37}, {0xa798fc4196e952e7, 0x2c48113823b73705}, + {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, {0x82ef85133de648c4, 0x9a984d73dbe722fc}, + {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, {0xcc963fee10b7d1b3, 0x318df905079926a9}, + {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, + {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, + {0x9c1661a651213e2d, 0x06bea10ca65c084f}, {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, + {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, + {0xbe89523386091465, 0xf6bbb397f1135824}, {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, + {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, {0xba121a4650e4ddeb, 0x92f34d62616ce414}, + {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, + {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, + {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, + {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, + {0x87625f056c7c4a8b, 0x11471cd764ad4973}, {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, + {0xd389b47879823479, 0x4aff1d108d4ec2c4}, {0x843610cb4bf160cb, 0xcedf722a585139bb}, + {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, {0xce947a3da6a9273e, 0x733d226229feea33}, + {0x811ccc668829b887, 0x0806357d5a3f5260}, {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, + {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, + {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, {0xc5029163f384a931, 0x0a9e795e65d4df12}, + {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, + {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, + {0x964e858c91ba2655, 0x3a6a07f8d510f870}, {0xbbe226efb628afea, 0x890489f70a55368c}, + {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, {0xb32df8e9f3546564, 0x47939822dc96abfa}, + {0xdff9772470297ebd, 0x59787e2b93bc56f8}, {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, + {0xaefae51477a06b03, 0xede622920b6b23f2}, {0xdab99e59958885c4, 0xe95fab368e45ecee}, + {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, + {0xd59944a37c0752a2, 0x4be76d3346f04960}, {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, + {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, + {0x825ecc24c873782f, 0x8ed400668c0c28c9}, {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, + {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, + {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, + {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, + {0xc24452da229b021b, 0xfbe85badce996169}, {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, + {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, + {0xed246723473e3813, 0x290123e9aab23b69}, {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, + {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, + {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, {0x8d590723948a535f, 0x579c487e5a38ad0f}, + {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, {0xdcdb1b2798182244, 0xf8e431456cf88e66}, + {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, + {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, + {0xa87fea27a539e9a5, 0x3f2398d747b36225}, {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, + {0x83a3eeeef9153e89, 0x1953cf68300424ad}, {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, + {0xcdb02555653131b6, 0x3792f412cb06794e}, {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, + {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, {0xc8de047564d20a8b, 0xf245825a5a445276}, + {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, {0x9ced737bb6c4183d, 0x55464dd69685606c}, + {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, {0xf53304714d9265df, 0xd53dd99f4b3066a9}, + {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, {0xbf8fdb78849a5f96, 0xde98520472bdd034}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xbb127c53b17ec159, 0x5560c018580d5d53}, {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, + {0x9226712162ab070d, 0xcab3961304ca70e9}, {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, + {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, + {0xb267ed1940f1c61c, 0x55f038b237591ed4}, {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, + {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, + {0xd9c7dced53c72255, 0x96e7bd358c904a22}, {0x881cea14545c7575, 0x7e50d64177da2e55}, + {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, + {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, + {0xcfb11ead453994ba, 0x67de18eda5814af3}, {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, + {0xa2425ff75e14fc31, 0xa1258379a94d028e}, {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, + {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, {0x9e74d1b791e07e48, 0x775ea264cf55347e}, + {0xc612062576589dda, 0x95364afe032a819e}, {0xf79687aed3eec551, 0x3a83ddbd83f52205}, + {0x9abe14cd44753b52, 0xc4926a9672793543}, {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, + {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, + {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, {0xb877aa3236a4b449, 0x09befeb9fad487c3}, + {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, + {0xb424dc35095cd80f, 0x538484c19ef38c95}, {0xe12e13424bb40e13, 0x2865a5f206b06fba}, + {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, {0xafebff0bcb24aafe, 0xf78f69a51539d749}, + {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, {0x89705f4136b4a597, 0x31680a88f8953031}, + {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, + {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, + {0xd1b71758e219652b, 0xd3c36113404ea4a9}, {0x83126e978d4fdf3b, 0x645a1cac083126ea}, + {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, {0xcccccccccccccccc, 0xcccccccccccccccd}, + {0x8000000000000000, 0x0000000000000000}, {0xa000000000000000, 0x0000000000000000}, + {0xc800000000000000, 0x0000000000000000}, {0xfa00000000000000, 0x0000000000000000}, + {0x9c40000000000000, 0x0000000000000000}, {0xc350000000000000, 0x0000000000000000}, + {0xf424000000000000, 0x0000000000000000}, {0x9896800000000000, 0x0000000000000000}, + {0xbebc200000000000, 0x0000000000000000}, {0xee6b280000000000, 0x0000000000000000}, + {0x9502f90000000000, 0x0000000000000000}, {0xba43b74000000000, 0x0000000000000000}, + {0xe8d4a51000000000, 0x0000000000000000}, {0x9184e72a00000000, 0x0000000000000000}, + {0xb5e620f480000000, 0x0000000000000000}, {0xe35fa931a0000000, 0x0000000000000000}, + {0x8e1bc9bf04000000, 0x0000000000000000}, {0xb1a2bc2ec5000000, 0x0000000000000000}, + {0xde0b6b3a76400000, 0x0000000000000000}, {0x8ac7230489e80000, 0x0000000000000000}, + {0xad78ebc5ac620000, 0x0000000000000000}, {0xd8d726b7177a8000, 0x0000000000000000}, + {0x878678326eac9000, 0x0000000000000000}, {0xa968163f0a57b400, 0x0000000000000000}, + {0xd3c21bcecceda100, 0x0000000000000000}, {0x84595161401484a0, 0x0000000000000000}, + {0xa56fa5b99019a5c8, 0x0000000000000000}, {0xcecb8f27f4200f3a, 0x0000000000000000}, + {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, 0xbff8f10e7a8921a5}, {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, {0xc5a05277621be293, 0xc7098b7305241886}, + {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}}; +}; + +#if (defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900)) || \ + (defined(__clang_major__) && __clang_major__ == 5) + +template <bool b> constexpr int main_cache_holder_impl<b>::cache_bits; +template <bool b> constexpr int main_cache_holder_impl<b>::min_k; +template <bool b> constexpr int main_cache_holder_impl<b>::max_k; +template <bool b> constexpr typename main_cache_holder_impl<b>::cache_entry_type main_cache_holder_impl<b>::cache[]; + +#endif + +using main_cache_holder = main_cache_holder_impl<true>; + +// Compressed cache for double +struct compressed_cache_detail +{ + static constexpr int compression_ratio = 27; + static constexpr std::size_t compressed_table_size = (main_cache_holder::max_k - main_cache_holder::min_k + compression_ratio) / + compression_ratio; + + struct cache_holder_t + { + static constexpr uint128 table[] = { + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, + {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, + {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, + {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, + {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, + {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0x9c40000000000000, 0x0000000000000000}, + {0xfc6f7c4045812296, 0x4d00000000000000}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, + {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, + {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, + {0xeeea5d5004981478, 0x1858ccfce06cac75}, + }; + + static_assert(sizeof(table) == compressed_table_size * sizeof(uint128), "Table should have 23 elements"); + }; + + struct pow5_holder_t + { + static constexpr std::uint64_t table[] = { + 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, + 6103515625, 30517578125, 152587890625, 762939453125, 3814697265625, 19073486328125, 95367431640625, + 476837158203125, 2384185791015625, 11920928955078125, 59604644775390625, 298023223876953125, 1490116119384765625 + }; + + static_assert(sizeof(table) == compression_ratio * sizeof(std::uint64_t), "Table should have 27 elements"); + }; +}; + +}}} + +#endif // BOOST_CHARCONV_DETAIL_DRAGONBOX_COMMON_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/floff.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/floff.hpp new file mode 100644 index 00000000000..32d138b3739 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/dragonbox/floff.hpp @@ -0,0 +1,4044 @@ +// Copyright 2020-2022 Junekey Jeon +// +// The contents of this file may be used under the terms of +// the Apache License v2.0 with LLVM Exceptions. +// +// (See accompanying file LICENSE-Apache or copy at +// https://llvm.org/foundation/relicensing/LICENSE.txt) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. +// +// Some parts are copied from Dragonbox project. +// +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_FLOFF +#define BOOST_CHARCONV_DETAIL_FLOFF + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/detail/dragonbox/dragonbox_common.hpp> +#include <boost/charconv/detail/to_chars_result.hpp> +#include <boost/charconv/chars_format.hpp> +#include <boost/core/bit.hpp> +#include <type_traits> +#include <limits> +#include <cstdint> +#include <cstring> +#include <cstddef> +#include <climits> + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127) // Extensive use of BOOST_IF_CONSTEXPR emits warnings under C++11 and 14 +# pragma warning(disable: 4554) // parentheses are used be warning is still emitted +#endif + +namespace boost { namespace charconv { namespace detail { + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // use of BOOST_IF_CONSTEXPR can result in unreachable code if max_blocks is 3 + // Other older compilers will emit warnings if the unreachable code is wrapped + // in an else block (e.g. no return statment) +#endif + +template <std::size_t max_blocks> +struct fixed_point_calculator +{ + static_assert(1 < max_blocks, "Max blocks must be greater than 1"); + + // Multiply multiplier to the fractional blocks and take the resulting integer part. + // The fractional blocks are updated. + template <typename MultiplierType> + BOOST_FORCEINLINE static MultiplierType generate(MultiplierType multiplier, + std::uint64_t* blocks_ptr, + std::size_t number_of_blocks) noexcept + { + BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks); + + BOOST_IF_CONSTEXPR (max_blocks == 3) + { + uint128 mul_result; + std::uint64_t carry = 0; + + switch (number_of_blocks) + { + case 3: + mul_result = umul128(blocks_ptr[2], multiplier); + blocks_ptr[2] = mul_result.low; + carry = mul_result.high; + BOOST_FALLTHROUGH; + + case 2: + mul_result = umul128(blocks_ptr[1], multiplier); + mul_result += carry; + blocks_ptr[1] = mul_result.low; + carry = mul_result.high; + BOOST_FALLTHROUGH; + + case 1: + mul_result = umul128(blocks_ptr[0], multiplier); + mul_result += carry; + blocks_ptr[0] = mul_result.low; + return mul_result.high; + + default: + BOOST_UNREACHABLE_RETURN(carry); // NOLINT : Macro for unreachable can expand to be empty + } + } + + auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], multiplier); + blocks_ptr[number_of_blocks - 1] = mul_result.low; + auto carry = mul_result.high; + for (std::size_t i = 1; i < number_of_blocks; ++i) + { + mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], multiplier); + mul_result += carry; + blocks_ptr[number_of_blocks - i - 1] = mul_result.low; + carry = mul_result.high; + } + + return MultiplierType(carry); + } + + // Multiply multiplier to the fractional blocks and discard the resulting integer part. + // The fractional blocks are updated. + template <typename MultiplierType> + BOOST_FORCEINLINE static void discard_upper(MultiplierType multiplier, + std::uint64_t* blocks_ptr, + std::size_t number_of_blocks) noexcept + { + BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks); + + blocks_ptr[0] *= multiplier; + if (number_of_blocks > 1) + { + BOOST_IF_CONSTEXPR (max_blocks == 3) + { + uint128 mul_result; + std::uint64_t carry = 0; + + if (number_of_blocks > 2) + { + mul_result = umul128(multiplier, blocks_ptr[2]); + blocks_ptr[2] = mul_result.low; + carry = mul_result.high; + } + + mul_result = umul128(multiplier, blocks_ptr[1]); + mul_result += carry; + blocks_ptr[1] = mul_result.low; + blocks_ptr[0] += mul_result.high; + } + else + { + auto mul_result = umul128(multiplier, blocks_ptr[number_of_blocks - 1]); + blocks_ptr[number_of_blocks - 1] = mul_result.low; + auto carry = mul_result.high; + + for (std::size_t i = 2; i < number_of_blocks; ++i) + { + mul_result = umul128(multiplier, blocks_ptr[number_of_blocks - i]); + mul_result += carry; + blocks_ptr[number_of_blocks - i] = mul_result.low; + carry = mul_result.high; + } + + blocks_ptr[0] += carry; + } + } + } + + // Multiply multiplier to the fractional blocks and take the resulting integer part. + // Don't care about what happens to the fractional blocks. + template <typename MultiplierType> + BOOST_FORCEINLINE static MultiplierType + generate_and_discard_lower(MultiplierType multiplier, std::uint64_t* blocks_ptr, + std::size_t number_of_blocks) noexcept + { + BOOST_CHARCONV_ASSERT(0 < number_of_blocks && number_of_blocks <= max_blocks); + + BOOST_IF_CONSTEXPR (max_blocks == 3) + { + uint128 mul_result; + std::uint64_t carry = 0; + + switch (number_of_blocks) + { + case 3: + mul_result = umul128(blocks_ptr[2], static_cast<std::uint64_t>(multiplier)); + carry = mul_result.high; + BOOST_FALLTHROUGH; + + case 2: + mul_result = umul128(blocks_ptr[1], static_cast<std::uint64_t>(multiplier)); + mul_result += carry; + carry = mul_result.high; + BOOST_FALLTHROUGH; + + case 1: + mul_result = umul128(blocks_ptr[0], static_cast<std::uint64_t>(multiplier)); + mul_result += carry; + return static_cast<MultiplierType>(mul_result.high); + + default: + BOOST_UNREACHABLE_RETURN(carry); // NOLINT + } + } + + auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], static_cast<std::uint64_t>(multiplier)); + auto carry = mul_result.high; + for (std::size_t i = 1; i < number_of_blocks; ++i) + { + mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], static_cast<std::uint64_t>(multiplier)); + mul_result += carry; + carry = mul_result.high; + } + + return static_cast<MultiplierType>(carry); + } +}; + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template <bool b> +struct additional_static_data_holder_impl +{ + static constexpr char radix_100_table[] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', // + '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', // + '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', // + '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', // + '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', // + '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', // + '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', // + '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', // + '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', // + '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', // + '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', // + '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', // + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', // + '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', // + '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', // + '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', // + '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', // + '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', // + '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', // + '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' // + }; + + static constexpr std::uint32_t fractional_part_rounding_thresholds32[] = { + UINT32_C(2576980378), UINT32_C(2190433321), UINT32_C(2151778616), UINT32_C(2147913145), + UINT32_C(2147526598), UINT32_C(2147487943), UINT32_C(2147484078), UINT32_C(2147483691) + }; + + static constexpr std::uint64_t fractional_part_rounding_thresholds64[] = { + UINT64_C(11068046444225730970), UINT64_C(9407839477591871325), UINT64_C(9241818780928485360), + UINT64_C(9225216711262146764), UINT64_C(9223556504295512904), UINT64_C(9223390483598849518), + UINT64_C(9223373881529183179), UINT64_C(9223372221322216546), UINT64_C(9223372055301519882), + UINT64_C(9223372038699450216), UINT64_C(9223372037039243249), UINT64_C(9223372036873222553), + UINT64_C(9223372036856620483), UINT64_C(9223372036854960276), UINT64_C(9223372036854794255), + UINT64_C(9223372036854777653), UINT64_C(9223372036854775993), UINT64_C(9223372036854775827) + }; +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <bool b> constexpr char additional_static_data_holder_impl<b>::radix_100_table[]; +template <bool b> constexpr std::uint32_t additional_static_data_holder_impl<b>::fractional_part_rounding_thresholds32[]; +template <bool b> constexpr std::uint64_t additional_static_data_holder_impl<b>::fractional_part_rounding_thresholds64[]; + +#endif + +using additional_static_data_holder = additional_static_data_holder_impl<true>; + +struct compute_mul_result +{ + std::uint64_t result; + bool is_integer; +}; + +// Load the necessary bits into blocks_ptr and then return the number of cache blocks +// loaded. The most significant block is loaded into blocks_ptr[0]. +template <typename ExtendedCache, bool zero_out, + typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type, + typename std::enable_if<(ExtendedCache::constant_block_count), bool>::type = true> +inline std::uint8_t cache_block_count_helper(CacheBlockType*, int, int, std::uint32_t) noexcept +{ + return static_cast<std::uint8_t>(ExtendedCache::max_cache_blocks); +} + +template <typename ExtendedCache, bool zero_out, + typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type, + typename std::enable_if<!(ExtendedCache::constant_block_count), bool>::type = true> +inline std::uint8_t cache_block_count_helper(CacheBlockType*, int e, int, std::uint32_t multiplier_index) noexcept +{ + const auto mul_info = ExtendedCache::multiplier_index_info_table[multiplier_index]; + + const auto cache_block_count_index = + mul_info.cache_block_count_index_offset + + static_cast<std::uint32_t>(e - ExtendedCache::e_min) / ExtendedCache::collapse_factor - + ExtendedCache::cache_block_count_offset_base; + + BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks < 3) + { + // 1-bit packing. + return static_cast<std::uint8_t>( + (ExtendedCache::cache_block_counts[cache_block_count_index / + 8] >> + (cache_block_count_index % 8)) & + 0x1) + + 1; + } + else BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks < 4) + { + // 2-bit packing. + return static_cast<std::uint8_t>( + (ExtendedCache::cache_block_counts[cache_block_count_index / 4] >> + (2 * (cache_block_count_index % 4))) & + 0x3); + } + else + { + // 4-bit packing. + return std::uint8_t( + (ExtendedCache::cache_block_counts[cache_block_count_index / 2] >> + (4 * (cache_block_count_index % 2))) & + 0xf); + } +} + +template <typename ExtendedCache, bool zero_out, + typename CacheBlockType = typename std::decay<decltype(ExtendedCache::cache[0])>::type> +BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, int e, int k, + std::uint32_t multiplier_index) noexcept +{ + BOOST_IF_CONSTEXPR (zero_out) + { + std::memset(blocks_ptr, 0, sizeof(CacheBlockType) * ExtendedCache::max_cache_blocks); + } + + const auto mul_info = ExtendedCache::multiplier_index_info_table[multiplier_index]; + + std::uint32_t number_of_leading_zero_blocks; + std::uint32_t first_cache_block_index; + std::uint32_t bit_offset; + std::uint32_t excessive_bits_to_left; + std::uint32_t excessive_bits_to_right; + std::uint8_t cache_block_count = cache_block_count_helper<ExtendedCache, zero_out, CacheBlockType>(blocks_ptr, e, k, multiplier_index); + + // The request window starting/ending positions. + auto start_bit_index = static_cast<int>(mul_info.cache_bit_index_offset) + e - ExtendedCache::cache_bit_index_offset_base; + auto end_bit_index = start_bit_index + cache_block_count * static_cast<int>(ExtendedCache::cache_bits_unit); + + // The source window starting/ending positions. + const auto src_start_bit_index = static_cast<int>(mul_info.first_cache_bit_index); + const auto src_end_bit_index = static_cast<int>(ExtendedCache::multiplier_index_info_table[multiplier_index + 1].first_cache_bit_index); + + // If the request window goes further than the left boundary of the source window, + if (start_bit_index < src_start_bit_index) + { + number_of_leading_zero_blocks = + static_cast<std::uint32_t>(src_start_bit_index - start_bit_index) / + static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); + excessive_bits_to_left = static_cast<std::uint32_t>(src_start_bit_index - start_bit_index) % + static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); + + BOOST_IF_CONSTEXPR (!zero_out) + { + std::memset(blocks_ptr, 0, number_of_leading_zero_blocks * sizeof(CacheBlockType)); + } + + start_bit_index += static_cast<int>(number_of_leading_zero_blocks * ExtendedCache::cache_bits_unit); + + const auto src_start_block_index = + static_cast<int>(static_cast<std::uint32_t>(src_start_bit_index) / + static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit)); + + const auto src_start_block_bit_index = + src_start_block_index * static_cast<int>(ExtendedCache::cache_bits_unit); + + first_cache_block_index = static_cast<std::uint32_t>(src_start_block_index); + + if (start_bit_index < src_start_block_bit_index) + { + auto shift_amount = src_start_block_bit_index - start_bit_index; + BOOST_CHARCONV_ASSERT(shift_amount >= 0 && shift_amount < static_cast<int>(ExtendedCache::cache_bits_unit)); + + blocks_ptr[number_of_leading_zero_blocks] = + ((ExtendedCache::cache[src_start_block_index] >> shift_amount) & + (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) >> + excessive_bits_to_left)); + + ++number_of_leading_zero_blocks; + bit_offset = static_cast<std::uint32_t>(static_cast<int>(ExtendedCache::cache_bits_unit) - shift_amount); + excessive_bits_to_left = 0; + } + else + { + bit_offset = static_cast<std::uint32_t>(start_bit_index - src_start_block_bit_index); + } + } + else + { + number_of_leading_zero_blocks = 0; + first_cache_block_index = + static_cast<std::uint32_t>(start_bit_index) / static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); + bit_offset = + static_cast<std::uint32_t>(start_bit_index) % static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); + excessive_bits_to_left = 0; + } + + // If the request window goes further than the right boundary of the source window, + if (end_bit_index > src_end_bit_index) + { + const std::uint8_t number_of_trailing_zero_blocks = + static_cast<std::uint8_t>(end_bit_index - src_end_bit_index) / ExtendedCache::cache_bits_unit; + excessive_bits_to_right = static_cast<std::uint32_t>(end_bit_index - src_end_bit_index) % + static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit); + + cache_block_count -= number_of_trailing_zero_blocks; + } + else + { + excessive_bits_to_right = 0; + } + + // Load blocks. + const auto number_of_blocks_to_load = cache_block_count - number_of_leading_zero_blocks; + auto* const dst_ptr = blocks_ptr + number_of_leading_zero_blocks; + if (bit_offset == 0) + { + BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks == 3) + { + switch (number_of_blocks_to_load) + { + case 3: + std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, 3 * sizeof(CacheBlockType)); + break; + case 2: + std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, 2 * sizeof(CacheBlockType)); + break; + case 1: + std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, 1 * sizeof(CacheBlockType)); + break; + case 0: + break; + default: + BOOST_UNREACHABLE_RETURN(dst_ptr); // NOLINT + } + } + else + { + std::memcpy(dst_ptr, ExtendedCache::cache + first_cache_block_index, number_of_blocks_to_load * sizeof(CacheBlockType)); + } + } + else + { + BOOST_IF_CONSTEXPR (ExtendedCache::max_cache_blocks == 3) + { + switch (number_of_blocks_to_load) + { + case 3: + *(dst_ptr + 2) = + (ExtendedCache::cache[first_cache_block_index + 2] << bit_offset) | + (ExtendedCache::cache[first_cache_block_index + 3] >> + (ExtendedCache::cache_bits_unit - bit_offset)); + BOOST_FALLTHROUGH; + case 2: + *(dst_ptr + 1) = + (ExtendedCache::cache[first_cache_block_index + 1] << bit_offset) | + (ExtendedCache::cache[first_cache_block_index + 2] >> + (ExtendedCache::cache_bits_unit - bit_offset)); + BOOST_FALLTHROUGH; + case 1: + *dst_ptr = (ExtendedCache::cache[first_cache_block_index] << bit_offset) | + (ExtendedCache::cache[first_cache_block_index + 1] >> + (ExtendedCache::cache_bits_unit - bit_offset)); + case 0: + break; + default: + BOOST_UNREACHABLE_RETURN(dst_ptr); // NOLINT + } + } + else + { + for (std::uint8_t i = 0; i < number_of_blocks_to_load; ++i) + { + *(dst_ptr + i) = + (ExtendedCache::cache[first_cache_block_index + i] << bit_offset) | + (ExtendedCache::cache[first_cache_block_index + i + 1] >> + (ExtendedCache::cache_bits_unit - bit_offset)); + } + } + } + + // Remove possible flooding bits from adjacent entries. + *dst_ptr &= (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) >> excessive_bits_to_left); + + blocks_ptr[cache_block_count - 1] &= (CacheBlockType(CacheBlockType(0) - CacheBlockType(1)) << excessive_bits_to_right); + + // To compute ceil(2^Q * x / D), we need to check if + // 2^Q * x / D = 2^(Q + e + k - eta - 1) * 5^(k - eta) is an integer or not. + if (k < ExtendedCache::segment_length || + e + k + static_cast<int>(cache_block_count * ExtendedCache::cache_bits_unit) - + static_cast<int>(excessive_bits_to_right) < + ExtendedCache::segment_length + 1) { + blocks_ptr[cache_block_count - 1] += (CacheBlockType(1) << excessive_bits_to_right); + BOOST_CHARCONV_ASSERT(blocks_ptr[cache_block_count - 1] != 0); + } + + return cache_block_count; +} + +template <bool constant_block_count, std::uint8_t max_cache_blocks> +struct cache_block_count_t; + +template <std::uint8_t max_cache_blocks> +struct cache_block_count_t<false, max_cache_blocks> +{ + std::uint8_t value; + + operator std::uint8_t() const noexcept { return value; } // NOLINT : implicit conversions are ok for block count + cache_block_count_t& operator=(std::uint8_t new_value) noexcept + { + value = new_value; + return *this; + } +}; + +template <std::uint8_t max_cache_blocks> +struct cache_block_count_t<true, max_cache_blocks> +{ + static constexpr std::uint8_t value = max_cache_blocks; + operator std::uint8_t() const noexcept { return value; } // NOLINT : implicit conversions are ok for block count + cache_block_count_t& operator=(std::uint8_t) noexcept + { + // Don't do anything. + return *this; + } +}; + +template <unsigned n> +struct uconst +{ + constexpr uconst() {}; // NOLINT : Clang 3.x does not support = default + static constexpr unsigned value = n; +}; + +BOOST_INLINE_VARIABLE constexpr uconst<0> uconst0; +BOOST_INLINE_VARIABLE constexpr uconst<1> uconst1; +BOOST_INLINE_VARIABLE constexpr uconst<6> uconst6; +BOOST_INLINE_VARIABLE constexpr uconst<9> uconst9; +BOOST_INLINE_VARIABLE constexpr uconst<14> uconst14; +BOOST_INLINE_VARIABLE constexpr uconst<16> uconst16; + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wsign-conversion" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-conversion" +#elif defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4365 4267) +#endif + +template <unsigned digits, bool dummy = (digits <= 9)> +struct uint_with_known_number_of_digits; + +template <unsigned digits_> +struct uint_with_known_number_of_digits<digits_, true> +{ + static constexpr auto digits = digits_; + std::uint32_t value; +}; + +template <unsigned digits_> +struct uint_with_known_number_of_digits<digits_, false> +{ + static constexpr auto digits = digits_; + std::uint64_t value; +}; + +template <typename HasFurtherDigits, typename... Args, typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> +static BOOST_FORCEINLINE bool check_rounding_condition_inside_subsegment( + std::uint32_t current_digits, std::uint32_t fractional_part, + int remaining_digits_in_the_current_subsegment, HasFurtherDigits has_further_digits, + Args...) noexcept +{ + if (fractional_part >= additional_static_data_holder::fractional_part_rounding_thresholds32[remaining_digits_in_the_current_subsegment - 1]) + { + return true; + } + + return ((fractional_part >> 31) & ((current_digits & 1) | has_further_digits)) != 0; +} + +template <typename HasFurtherDigits, typename... Args, + typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> +static BOOST_FORCEINLINE bool check_rounding_condition_inside_subsegment( + std::uint32_t current_digits, std::uint32_t fractional_part, + int remaining_digits_in_the_current_subsegment, HasFurtherDigits has_further_digits, + Args... args) noexcept +{ + if (fractional_part >= additional_static_data_holder::fractional_part_rounding_thresholds32[remaining_digits_in_the_current_subsegment - 1]) + { + return true; + } + + return fractional_part >= 0x80000000 && ((current_digits & 1) != 0 || has_further_digits(args...)); +} + +template <typename HasFurtherDigits, typename... Args, + typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> +static BOOST_FORCEINLINE bool check_rounding_condition_with_next_bit(std::uint32_t current_digits, bool next_bit, + HasFurtherDigits has_further_digits, Args...) noexcept +{ + if (!next_bit) + { + return false; + } + + return ((current_digits & 1) | has_further_digits) != 0; +} + +template <typename HasFurtherDigits, typename... Args, + typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> +static BOOST_FORCEINLINE bool check_rounding_condition_with_next_bit(std::uint32_t current_digits, bool next_bit, + HasFurtherDigits has_further_digits, Args... args) noexcept +{ + if (!next_bit) + { + return false; + } + + return (current_digits & 1) != 0 || has_further_digits(args...); +} + +template <typename UintWithKnownDigits, typename HasFurtherDigits, typename... Args, + typename std::enable_if<std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> +static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_next_subsegment( + std::uint32_t current_digits, UintWithKnownDigits next_subsegment, + HasFurtherDigits has_further_digits, Args...) noexcept +{ + if (next_subsegment.value > power_of_10[decltype(next_subsegment)::digits] / 2) + { + return true; + } + + return next_subsegment.value == power_of_10[decltype(next_subsegment)::digits] / 2 && + ((current_digits & 1) | has_further_digits) != 0; +} + +template <typename UintWithKnownDigits, typename HasFurtherDigits, typename... Args, + typename std::enable_if<!std::is_same<HasFurtherDigits, bool>::value, bool>::type = true> +static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_next_subsegment( + std::uint32_t current_digits, UintWithKnownDigits next_subsegment, + HasFurtherDigits has_further_digits, Args... args) noexcept +{ + if (next_subsegment.value > power_of_10[decltype(next_subsegment)::digits] / 2) + { + return true; + } + + return next_subsegment.value == power_of_10[decltype(next_subsegment)::digits] / 2 && + ((current_digits & 1) != 0 || has_further_digits(args...)); +} + +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4307) // MSVC 14.1 emits warnings for uint64_t constants +#endif + +namespace has_further_digits_impl { +template <int k_right_threshold, int additional_neg_exp_of_2> +bool no_neg_k_can_be_integer(int k, int exp2_base) noexcept +{ + return k < k_right_threshold || exp2_base + k < additional_neg_exp_of_2; +} + +template <int k_left_threshold, int k_right_threshold, int additional_neg_exp_of_2, int min_neg_exp_of_5, typename SignificandType> +bool only_one_neg_k_can_be_integer(int k, int exp2_base, SignificandType significand) noexcept +{ + // Supposed to be k - additional_neg_exp_of_5_v < -min_neg_exp_of_5 || ... + if (k < k_left_threshold || exp2_base + k < additional_neg_exp_of_2) + { + return true; + } + // Supposed to be k - additional_neg_exp_of_5_v >= 0. + if (k >= k_right_threshold) + { + return false; + } + + BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = compute_power(UINT64_C(0xcccccccccccccccd), static_cast<unsigned>(min_neg_exp_of_5)); + BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = UINT64_C(0xffffffffffffffff) / compute_power(UINT64_C(5), static_cast<unsigned>(min_neg_exp_of_5)); + + return (significand * mod_inv) > max_quot; +} + +template <int k_left_threshold, int k_middle_threshold, int k_right_threshold, + int additional_neg_exp_of_2, int min_neg_exp_of_5, int segment_length, + typename SignificandType> +bool only_two_neg_k_can_be_integer(int k, int exp2_base, + SignificandType significand) noexcept { + // Supposed to be k - additional_neg_exp_of_5_v < -min_neg_exp_of_5 - segment_length + // || ... + if (k < k_left_threshold || exp2_base + k < additional_neg_exp_of_2) { + return true; + } + // Supposed to be k - additional_neg_exp_of_5_v >= 0. + if (k >= k_right_threshold) { + return false; + } + + if (k >= k_middle_threshold) { + BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = + compute_power(UINT64_C(0xcccccccccccccccd), static_cast<unsigned>(min_neg_exp_of_5)); + BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = + UINT64_C(0xffffffffffffffff) / + compute_power(UINT64_C(5), static_cast<unsigned>(min_neg_exp_of_5)); + + return (significand * mod_inv) > max_quot; + } + else { + BOOST_CXX14_CONSTEXPR std::uint64_t mod_inv = compute_power( + UINT64_C(0xcccccccccccccccd), static_cast<unsigned>(min_neg_exp_of_5 + segment_length)); + BOOST_CXX14_CONSTEXPR std::uint64_t max_quot = + UINT64_C(0xffffffffffffffff) / + compute_power(UINT64_C(5), + static_cast<unsigned>(min_neg_exp_of_5 + segment_length)); + + return (significand * mod_inv) > max_quot; + } +} +} // Namespace has_further_digits_impl + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +inline void print_1_digit(std::uint32_t n, char* buffer) noexcept +{ + *buffer = char('0' + n); +} + +inline void print_2_digits(std::uint32_t n, char* buffer) noexcept +{ + std::memcpy(buffer, additional_static_data_holder::radix_100_table + n * 2, 2); +} + +inline void print_6_digits(std::uint32_t n, char* buffer) noexcept +{ + // 429497 = ceil(2^32/10^4) + auto prod = (n * UINT64_C(429497)) + 1; + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + + for (int i = 0; i < 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 2 + i * 2); + } +} + +inline void print_7_digits(std::uint32_t n, char* buffer) noexcept +{ + // 17592187 = ceil(2^(32+12)/10^6) + auto prod = ((n * UINT64_C(17592187)) >> 12) + 1; + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + + for (int i = 0; i < 3; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 1 + i * 2); + } +} + +inline void print_8_digits(std::uint32_t n, char* buffer) noexcept +{ + // 140737489 = ceil(2^(32+15)/10^6) + auto prod = ((n * UINT64_C(140737489)) >> 15) + 1; + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + + for (int i = 0; i < 3; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 2 + i * 2); + } +} + +inline void print_9_digits(std::uint32_t n, char* buffer) noexcept +{ + // 1441151881 = ceil(2^(32+25)/10^8) + auto prod = ((n * UINT64_C(1441151881)) >> 25) + 1; + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + + for (int i = 0; i < 4; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer + 1 + i * 2); + } +} + +struct main_cache_full +{ + template <typename FloatFormat> + static constexpr typename main_cache_holder::cache_entry_type get_cache(int k) noexcept + { + return main_cache_holder::cache[std::size_t(k - main_cache_holder::min_k)]; + } +}; + +struct main_cache_compressed +{ + template <typename FloatFormat> + static BOOST_CHARCONV_CXX14_CONSTEXPR typename main_cache_holder::cache_entry_type get_cache(int k) noexcept + { + BOOST_CHARCONV_ASSERT(k >= main_cache_holder::min_k && k <= main_cache_holder::max_k); + + BOOST_IF_CONSTEXPR (std::is_same<FloatFormat, ieee754_binary64>::value) + { + // Compute the base index. + const auto cache_index = + static_cast<int>(static_cast<std::uint32_t>(k - main_cache_holder::min_k) / + compressed_cache_detail::compression_ratio); + + const auto kb = cache_index * compressed_cache_detail::compression_ratio + + main_cache_holder::min_k; + + const auto offset = k - kb; + + // Get the base cache. + const auto base_cache = compressed_cache_detail::cache_holder_t::table[cache_index]; + + if (offset == 0) + { + return base_cache; + } + else + { + + // Compute the required amount of bit-shift. + const auto alpha = log::floor_log2_pow10(kb + offset) - log::floor_log2_pow10(kb) - offset; + BOOST_CHARCONV_ASSERT(alpha > 0 && alpha < 64); + + // Try to recover the real cache. + const auto pow5 = compressed_cache_detail::pow5_holder_t::table[offset]; + auto recovered_cache = umul128(base_cache.high, pow5); + const auto middle_low = umul128(base_cache.low, pow5); + + recovered_cache += middle_low.high; + + const auto high_to_middle = recovered_cache.high << (64 - alpha); + const auto middle_to_low = recovered_cache.low << (64 - alpha); + + recovered_cache = uint128{(recovered_cache.low >> alpha) | high_to_middle, ((middle_low.low >> alpha) | middle_to_low)}; + + BOOST_CHARCONV_ASSERT(recovered_cache.low + 1 != 0); + recovered_cache = uint128(recovered_cache.high, recovered_cache.low + 1); + + return recovered_cache; + } + } + else + { + // Just use the full cache for anything other than binary64 + return main_cache_holder::cache[std::size_t(k - main_cache_holder::min_k)]; + } + } +}; + +template <bool b> +struct extended_cache_long_impl +{ + static constexpr std::size_t max_cache_blocks = 3; + static constexpr std::size_t cache_bits_unit = 64; + static constexpr int segment_length = 22; + static constexpr bool constant_block_count = true; + static constexpr int e_min = -1074; + static constexpr int k_min = -272; + static constexpr int cache_bit_index_offset_base = 977; + static constexpr std::uint64_t cache[] = { + 0xa37fce126597973c, 0xe50ff107bab528a0, 0x8f1ba3f17395a391, 0xd56bdc876cdb4648, + 0x6ca000bdd9e33bd4, 0x23cf34bbf983f78b, 0x8737d87296e93f5d, 0xa2824ba6d9df301d, + 0x8ce3eccf7cfb42ab, 0xe5ecdc0b78109f00, 0xa620c9995c9c5c3a, 0xa0f79c97ac210943, + 0x64dfb5636985915f, 0xc12f542e4c7ea6ee, 0x34de81232784ea17, 0xd0cbde7fac4643f2, + 0x5d9400de8fef7552, 0x81214f68696d9af2, 0xb7d0e0a2ccaccf20, 0x5c4ed9243f16193d, + 0xf71838486e60b926, 0x48892047ec1a8bf4, 0x14ff2faa9c32befa, 0x666fbaa24ddbb8e9, + 0x436682c807652a58, 0xed98ddaee19068c7, 0x63badd624dd9b095, 0x72dbb637d5b77493, + 0xd01998fb8d9e8861, 0xacb39418dce017b9, 0x8db8f2f13eed81cf, 0xfd699fbb7d0a737a, + 0x011cd67160923d91, 0x9a66fd7732c14d98, 0x235857d065a52d18, 0x895288951dab0d8e, + 0x59041cb66e4f0e68, 0x5e7c68240249e750, 0x8881a2a6ab00987b, 0x5fc8c32c863aaeac, + 0x3bafbe662a7f81a8, 0xd47692705ae76b64, 0xeb1cc7d99143fb53, 0xcf8be24f7b0fc499, + 0x6a276e8f0fbf33eb, 0x63b2d61966fa7243, 0x0970327d2cc58011, 0x43ff09410ec24aae, + 0x0bdb6f345ea1851d, 0x409c37132c5836ff, 0xf3150f74a6190324, 0x5c358d6c07453d23, + 0x7207012ad7846ba7, 0x61ad5d0772604733, 0x19a20a6e21c2018d, 0x5f568fd497ef18b2, + 0xeda5815eed00749f, 0x029531461bc483d8, 0xb8789d7784875911, 0x6fc40572236f2ba5, + 0x9c2a50a76ace3168, 0xbf4815c2bea56741, 0xf84e8f2fe9b211f5, 0x689033182d2ea7ed, + 0x5bcb3a3230a68f47, 0xa848403d116805ef, 0xfaeaa73623b79604, 0x31d76828d2181b64, + 0x7c4eabddc7dd634b, 0xc2b13231eeff6fda, 0x8094743db32bf251, 0x2df07391bde052d2, + 0xffd9bdbf321ad8ae, 0x06b2c6d1cf6cf742, 0xf32a54ce1598fe8f, 0x1cc2e3082d28897e, + 0x0485f2e46b488584, 0xe3f6965b145a49cb, 0x406eaa1217aefe69, 0x0777373638de456b, + 0xcde91853b592212b, 0x3faf7b46d7f79c18, 0x558d83afb7127381, 0x5f490259c7957aeb, + 0x76e6540e246d73cc, 0x5098a935a866dc75, 0xc50d9c29002d9e73, 0xcc8f8252faac0b7f, + 0xb759afb688f8251d, 0x6a2934d3036c85d3, 0x570eb3ce4c86407f, 0x036f2b68794754af, + 0x57661a5d6993fe2c, 0x6d07b7fabe546a80, 0x38efe4029259743c, 0x548f417ebaa61c6c, + 0xb0c31fa64a3fcc9e, 0x7dab825964fb7100, 0xd0c92ae8207d6f22, 0xf1e38a8a9c541144, + 0x2139951c68d0385b, 0x9d9e22c42f139287, 0x4fea4d670876b800, 0x35f293a9a62252d4, + 0x4b606b26f1922c5c, 0x8e5660b37505cb11, 0x868138391855da81, 0x6e95f6c9b45c7aa2, + 0x425ff75e14fc31a1, 0x258379a94d028d18, 0xdf2ccd1fe00a03b6, 0x398471c1ff970f83, + 0x8c36b2214a3db8e7, 0x431dd42c3fe7f4fb, 0xb09bcf0fffb5b849, 0xc47dd13da60fb5a1, + 0x8fdad56516fe9d75, 0xc317e1025a7e1c63, 0x9ddcb98cbb384fda, 0x80adccda993bf70e, + 0x667f1622e4052ae4, 0xa41598d58f777363, 0x704b93d675808501, 0xaf046d3fd448aaf3, + 0x1dc4611873bf3f70, 0x834acdae9f0f4f53, 0x4f5d60585a5f1c1a, 0x3ced1b4be0d415c1, + 0x5d57f4de8ec12376, 0x51c0e7e72f799542, 0x46f7604940e6a510, 0x1a546a0f9345ed75, + 0x0df4097cab773ca2, 0x72b122774e4029e6, 0xae4a55b99aebd424, 0x04163a291bad2fa3, + 0x86ad58be322a49aa, 0x98f051614696e839, 0x64d08f241fc4ec58, 0xae41f23dca90dd5d, + 0x68bbd62f5af3107a, 0x7025f39ef241c56c, 0xd2e7c72fa9be33ac, 0x0aece66fd3e29a7d, + 0xd91241cebf3bd47c, 0x3ed7bfdee19ba2f6, 0x4bdf483194c7444e, 0xc99d83c931e8ab87, + 0x1732f416dbf7381f, 0x2ac88e244de13b96, 0x2cab688bd86c8bf8, 0x9f209787bb47d6b8, + 0x4c0678c5dbd23a49, 0xa0612c3c5ce15e55, 0x4dccc6ca29b3e9df, 0x0dc079c918022212, + 0x26be55a64c249495, 0x4da2c9789dd268b0, 0xe975528c76435158, 0xa6cb8a4d2356f9cf, + 0xdcafd2279c77d987, 0xaa9aff7904228690, 0xfb44d2f05d0842fb, 0x118fc9c217a1d2b2, + 0x04b3d9686f55b572, 0xbd9cb3625ef1cfc3, 0x2eba0e25e938e6c3, 0x1f48eaf234ad3a21, + 0xf2dc02fad2890f79, 0xace340325d4a7f9b, 0xe9e051f540b239dc, 0x221091f05abb8687, + 0x7e08deb014db8afe, 0x4711e1e9d9a094cc, 0x0b2d79bd90a9ef61, 0xb93d19bd45b82515, + 0x45e9e31d63c1afe1, 0x2c5f0a596005c216, 0xe687cc2331b14a12, 0x51963a2412b6f60c, + 0x91aeb77c8fe68eaa, 0xd6e18e8cc6841d68, 0x9391085cc2c933d9, 0x6e184be07e68df49, + 0x4fe4e52edb0dce60, 0x6cda31e8617f0ca2, 0xf8b9374fda7e7c95, 0x8032c603725e774d, + 0x222b6aa27e007612, 0xf7b7f47cf096afad, 0xe6a9fbafee77e77a, 0x3776ee406e63fbaa, + 0xde147932fcf78be6, 0x2ab9e031ffaa071e, 0x2169ad0e8a9b1256, 0xe33358135938b76a, + 0xcaec07e7a5373835, 0xef2863090a97c3ec, 0x6ccfb95f69c3adcc, 0x173e00da427cee4b, + 0x20f4ed58fcfb3040, 0x16f6fb326a60c32c, 0x2968fa04270ed545, 0x70673adfac0eabc4, + 0x6ff3c9364ff4e873, 0xde09ed35f13325d3, 0x2396e863b18c500f, 0xe22d253cc031e3ff, + 0x756d97a61247798d, 0xc9fc8d937e43c880, 0x0759ba59c08e14c7, 0xcd7aad86a4a45810, + 0x9f91c21c571dbe84, 0xd52d936f44abe8a3, 0xd5b48c100959d9d0, 0xb6cc856b3adc93b6, + 0x7aea8f8e067d2c8d, 0x04bc177f7b4287a6, 0xe3fcda36fa3b3342, 0xeaeb442e15d45095, + 0x2f4dd1ca5e89b18b, 0x602368385bb19cb1, 0x4bdfc434d3028181, 0x0b5a92cb80ac8150, + 0xb95953a97b1578ab, 0x46e6a18b01781b92, 0xdfd31585f38d7433, 0x0b1084b96009370b, + 0x9a81808e52462ba3, 0xff83368ace4af235, 0xb4e5d8a647e05e95, 0xf848cfc90df4b231, + 0x9919c68cf3576038, 0x1e89dad8a6790435, 0x7ac9361379139511, 0x7b5f9b6b937a7760, + 0x6e42e395fde0c1f7, 0x430cef1679799f8f, 0x0ad21cc1b4828074, 0x8982577d0ea42349, + 0xb1aca6185a7d0d0d, 0x4085c6db106c3d74, 0xba6f7a86e728a418, 0x0325a28758a974d2, + 0x57ea317f731817ed, 0xbd1e8e00b215a6eb, 0xb39f323742948e87, 0x9f9b0f873784cef4, + 0xa8c83d26585c5377, 0x837ba337bfcf893c, 0x0a7eeca62a23b805, 0xba4925a9e7f7346f, + 0xa574eebb90c8da6d, 0x5db7ff0e8d0b8d2d, 0x1562834c52c048d8, 0x0b2e577a853bcafc, + 0xdecef97a3524ff97, 0xeec053c8fd537066, 0xeaf2b1df83d600e4, 0x5be8b9ab7717eccf, + 0x05905b91ecbba038, 0xabacba5b373029ed, 0x22fb2283c0ee1267, 0x9c32b2ec3634c580, + 0x5186c586b6e5611c, 0x71eb0de5e91bb0a0, 0x89e969b42975ef08, 0x2ba0958bc44e322f, + 0x626d033cb828ba7d, 0xe5fbb65c7776509d, 0xb1403ae51ae9bc82, 0x5d773f0d9753a966, + 0x4a06feadd4ec8585, 0xda58a710fccd7b76, 0x6061ba4cd3d80d59, 0xf4824f5cfa2ba71c, + 0xfce622bba0ece756, 0x7d9c738486bc6842, 0x5f629d33c99db969, 0x855ff7c9b79362e6, + 0x892188a87c7de231, 0x85fea7caf30e2b5e, 0xbefeb221543782c5, 0x769ca33d280842f6, + 0x3974ebaf71353e52, 0xed0577283980f0cb, 0x7c37d689ab6b0662, 0x5037aeffcd3db52d, + 0x11bb0a5f64fbdcb5, 0xf5fd5aa5f2b7e974, 0xe1aa07ba7074367b, 0x4b5c14aa1c6a0d28, + 0xe9fc8c9c36f73953, 0x2609ad2cd0f99b76, 0x8d4f1d6bb589844f, 0xde09f066714fa909, + 0xe004c5d7adad3747, 0xd5ac81a94dfdefe3, 0xfd3e0083658a13c2, 0xf5512f25dd6e39a7, + 0xeb7204042ffa181d, 0x046d9254242d06e3, 0x91a5ca94f8706fab, 0xf5c58cc57af63c98, + 0x04e7ff1e23474908, 0xe4a9bec5c5818324, 0x1edfb105cc3084dd, 0x82431ec76e72a87a, + 0xe0b215be32c51083, 0x0d9942e3b5245098, 0xa49f1aad5723fd7e, 0xad45edba25a4bde8, + 0x241f0adc0cd56771, 0xf09bf2de59df3274, 0x090db856bbc020f2, 0x6aa4efb2d2ecb9bb, + 0xc6be4224ba04c233, 0x557a1760bde90850, 0x23090117938cb921, 0xcbec34da23f3e9c2, + 0xdfe2d55daad85c54, 0xa7932be700067f48, 0xfb7874535e2d76a4, 0x5161ba088056e74f, + 0xc275a8435be6cdb2, 0x05fcb771cab5aa15, 0x7f18a4382c9565a8, 0x4244c2cb833d6710, + 0x884e2b7a4a3db4d0, 0x08ded459d3edf2c2, 0x1616df531fee90cd, 0x9531c65800a97aaa, + 0x881ba77ab7e5d63a, 0x606d27428df4edd3, 0x294063ed78e305c7, 0x7de2b12f8a8cceb5, + 0xe6b01cc54a494437, 0x0cdecbe5ac90907c, 0xb88496c657d3e644, 0xf3eecf996f9c6b13, + 0x24aad7949edcde03, 0x304ca88ebfeaa534, 0x7b68a7bd3ef1916b, 0x3cc307a784d9060c, + 0x5dca03f19b213efd, 0xa380539c235f80c3, 0xf39756fc01d75bd7, 0x39ac6c7281739adb, + 0x4b606dc4aa036fda, 0x97126cd02a23b97c, 0x98c1e6906230aead, 0xe12d0f696a6bbc36, + 0x657a202bb6a89a33, 0x6421a07bda47e13d, 0x8d9d21b3c6b1dbee, 0x1f110f3744f13e0d, + 0x04d86fccb6e77ee8, 0x8c92852d9c9c14b3, 0x56be3cef19b19446, 0x57ceef0e2ebcbcf7, + 0x230a9328be0144bf, 0x3c1949b98a92aebc, 0x7ed2db80a62003f2, 0x84e609d13c7594f4, + 0xf8e81b9a9f35b4e8, 0xc2982fde1a087e4b, 0x84b0713cb3b18147, 0x3582530578d1ff08, + 0x0e5b6538cd61fce4, 0x46867abf4b6e72bc, 0x4fe9652832325e89, 0x7d141d065654745f, + 0x9bd5c0479188a53d, 0x4ccd47925108c00b, 0xfd3f6c8d961d47e3, 0x9c5c18a96093d2ad, + 0xa7d91bf008a358c3, 0x3ea3e5629f977d55, 0x80f0fed6a5f06003, 0x21f390e377ee4d68, + 0x73ed055ec082526b, 0x28482600c10f6ce2, 0x2bff1aaf94c11fe9, 0xde29cb7a943801b8, + 0x045b0493dd35af0e, 0xaeae25ff7a431c16, 0x78c9d3348f5364b7, 0xf973d1af84bc2476, + 0x4d2303e11baf18f3, 0xacebdb3fe5efbc7b, 0xd274a5cf5be50678, 0x2d60c40fdf53ac67, + 0x109592b606139855, 0x612f472a9c09925f, 0x701a035ccd4e7ab0, 0xac881f0db121a709, + 0xe1ed47438368366d, 0xde2faff8eeb2810a, 0x8eb2188044342ef9, 0x0e3c1aa7b6851548, + 0x7ce94a6ba4fd843f, 0x0da503676ee5ebb2, 0xf3bc7bb2cb8669e8, 0xd4b9e44de392fe64, + 0x81e470ebf207fdea, 0xdd53b09d49a0e5b5, 0xf78e23167a350d5a, 0x706470fc2d84423b, + 0x816ee82b19a29476, 0x35a9d218ba7cd4a1, 0xf590f12fb09b3fe3, 0x5e574140b302f8b7, + 0x6cb237a2021f77c3, 0x30a29037231a861e, 0xff4bb07af553a606, 0x831412ee2690d92c, + 0xf6d2d725ef14ff67, 0x2f79f810928a40ff, 0x2857d91ea9b04f71, 0xd063066f0ed78f3c, + 0xbf4b8dbc8a34017d, 0x6230f319f8b1f9c4, 0x061b0e25d8899834, 0x4071de32ef7ff0bf, + 0xbc546a0793fcfcd3, 0xd5881f5d968cf898, 0x0e21c0674cdda190, 0x0000000000000000}; + + struct multiplier_index_info + { + std::uint16_t first_cache_bit_index; + std::uint16_t cache_bit_index_offset; + }; + + static constexpr multiplier_index_info multiplier_index_info_table[] = { + {0, 0}, {171, 244}, {419, 565}, {740, 959}, {1135, 1427}, + {1604, 1969}, {2141, 2579}, {2750, 3261}, {3434, 4019}, {4191, 4849}, + {5019, 5750}, {5924, 6728}, {6904, 7781}, {7922, 8872}, {8993, 10016}, + {9026, 10122}, {9110, 10279}, {9245, 10487}, {9431, 10746}, {9668, 11056}, + {9956, 11418}, {10296, 11831}, {10687, 12295}, {11129, 12810}, {11622, 13376}, + {12166, 13993}, {12761, 14661}, {13407, 15380}, {14104, 16150}, {14852, 16902}, + {15582, 17627}, {16285, 18332}, {16968, 19019}, {17633, 19683}, {18275, 20326}, + {18896, 20947}, {19495, 21546}, {20072, 22122}, {20626, 22669}, {21151, 23202}, + {21662, 23713}, {22151, 24202}, {22618, 24669}, {23063, 25114}, {23486, 25535}, + {23885, 25936}, {24264, 26313}, {24619, 26670}, {24954, 27004}, {25266, 27316}, + {25556, 27603}, {25821, 27870}, {26066, 28117}, {26291, 28340}, {26492, 28543}, + {26673, 28723}, {26831, 28881}, {26967, 29018}, {27082, 29133}, {27175, 29225}, + {27245, 29296}, {27294, 29344}, {27320, 29370}, {27324, 0}}; +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <bool b> constexpr std::size_t extended_cache_long_impl<b>::max_cache_blocks; +template <bool b> constexpr std::size_t extended_cache_long_impl<b>::cache_bits_unit; +template <bool b> constexpr int extended_cache_long_impl<b>::segment_length; +template <bool b> constexpr bool extended_cache_long_impl<b>::constant_block_count; +template <bool b> constexpr int extended_cache_long_impl<b>::e_min; +template <bool b> constexpr int extended_cache_long_impl<b>::k_min; +template <bool b> constexpr int extended_cache_long_impl<b>::cache_bit_index_offset_base; +template <bool b> constexpr std::uint64_t extended_cache_long_impl<b>::cache[]; +template <bool b> constexpr typename extended_cache_long_impl<b>::multiplier_index_info extended_cache_long_impl<b>::multiplier_index_info_table[]; + +#endif + +using extended_cache_long = extended_cache_long_impl<true>; + +struct extended_cache_compact +{ + static constexpr std::size_t max_cache_blocks = 6; + static constexpr std::size_t cache_bits_unit = 64; + static constexpr int segment_length = 80; + static constexpr bool constant_block_count = false; + static constexpr int collapse_factor = 64; + static constexpr int e_min = -1074; + static constexpr int k_min = -211; + static constexpr int cache_bit_index_offset_base = 967; + static constexpr int cache_block_count_offset_base = 27; + + static constexpr std::uint64_t cache[] = { + 0x9faacf3df73609b1, 0x77b191618c54e9ac, 0xcbc0fe19cae9528c, 0x8164d034592c3d4e, + 0x04c42d46c9d7a229, 0x7ee39007a5bc8cc3, 0x5469cf7bb8b25e57, 0x2effce010198cb81, + 0x642eb5bc0d8169e0, 0x91356aed1f5cd514, 0xe1c8f30156868b8c, 0xd1201a2b857f5cc5, + 0x15c07ee55715eff8, 0x8530360cd386f94f, 0xeb706c10ea02c329, 0x3cb22680f921f59e, + 0x3231912d5bf60e61, 0x0e1fff697ed6c695, 0xa8bed97c2f3b63fc, 0xda96e93c07538a6d, + 0xc1c4e34ccd6fdbc5, 0x85c09fd1d0f79834, 0x485f3a5d03622bba, 0xe640b09cca5b9d50, + 0x19a80913a40927a9, 0x4d82d751a5cf886d, 0x325c9cd793b9977b, 0x4896c18501fb9e0c, + 0xa9993bfdf3ea7275, 0xcb7d257a3ee7c9d8, 0xcbf8fdb78849a5f9, 0x6de98520472bdd03, + 0x36efd14b69b311de, 0x694fa387dcf3e78f, 0xdccfbfc61d1662ef, 0xbe3a4d4104fb75a2, + 0x289ccaebae5c6d2d, 0x436915952987fa63, 0x830446728505ab75, 0x3ad8772923e4e0c0, + 0xca946600436f3894, 0x0faae7895e3885f0, 0xadf6b773b1ebf8e0, 0x52473dd5e8218647, + 0x5e6b5121ca3b747c, 0x217399923cd80bc0, 0x0a56ced144bb2f9f, 0xb856e82eea863c1f, + 0x5cdae42f9562104d, 0x3fa421962c8c4241, 0x63451ff73769a3d2, 0xb0895649e11affd6, + 0xe5dd7be415e5d3ef, 0x282a242e818f1668, 0xc8a86da5faf0b5cc, 0xf5176ecc7cbb19db, + 0x2a9a282e49b4da0e, 0x59e22f9ed2cb3a4b, 0xc010afa26505a7e7, 0xee47b3ab83a99c3e, + 0xc7eafae5fa385ec2, 0x3ec747e06293a148, 0x4b8a8260baf424a7, 0x63079a1ac7709a4e, + 0x7fd0cd567aa4a0fa, 0x6909d0e0cfc6ce8d, 0xe0c965770d1491dd, 0xa6d4449e3a3e13ea, + 0x73e06d2253c6b584, 0x9f95a4b69679998d, 0x0cc8cc76a8234060, 0xd3da311bb4fc0aae, + 0x670614382f45f33c, 0x21f68425f4189fbf, 0x557ce28d58d9a8bd, 0x1f16d908907d0a0e, + 0x929415f993b9a2c2, 0x95e0878748988052, 0xc4a104701f794a31, 0xe7d2d2b0c3c31b19, + 0x1e6a68d5574b3d9d, 0x5727ec70c7681154, 0xe4b2adae8ac5259e, 0x1cefff5ed639205f, + 0xf9410ba5daeb3af5, 0x21b0ad30acb4b8d2, 0xd324604028bf6fac, 0x349a5d2dc4bdc6e0, + 0xc77223714aff22d9, 0x5b18ce4aabb5b369, 0xb8a6d609b15ecab7, 0x2111dbce86023643, + 0x2a5717a571b96b6c, 0x8039783af28427bf, 0x5bbadd6a1a3fb931, 0xe8564a7a3e3ff2dc, + 0xd0868939e541158e, 0xc57d0b8a8af06dde, 0xf1706d329def96c1, 0xbe74f435713bb7d5, + 0x8dcdaef5bfb0242c, 0x73b5a1c8c8ec33c7, 0x4ab726d9dac95550, 0x210cf3b3ddfa00ae, + 0x559d5e65eefbfa04, 0xe5d1f67c5f9de0ec, 0x6ad4699ea2d0efd6, 0x9590c0f05024f29a, + 0x917d5715e6e20913, 0xb13124a40bffe5ba, 0x5248ce22e40406e5, 0xb844b16596551ded, + 0xad4c4c5140496c58, 0x458562ae335689b6, 0x269441e13a195ad3, 0x7a5e32a8baf53ea8, + 0x6d1469edb474b5f6, 0xe87b554829f6ee5b, 0xbf824a42bae3bdef, 0xed12ec6937744feb, + 0x2ca544e624e048f9, 0x1bab8d5ee0c61285, 0x8863eaef018d32d9, 0x98f37ac46669f7ea, + 0xa9a0573cb5501b2b, 0xf25c3a8e08a5694d, 0x42355a8000000000, 0x0000000000000000}; + + struct multiplier_index_info + { + std::uint16_t first_cache_bit_index; + std::uint16_t cache_bit_index_offset; + std::uint16_t cache_block_count_index_offset; + }; + + static constexpr multiplier_index_info multiplier_index_info_table[] = { + {0, 0, 0}, {377, 643, 9}, {1020, 1551, 22}, {1924, 2721, 39}, + {3046, 4109, 60}, {3114, 4443, 70}, {3368, 4962, 84}, {3807, 5667, 98}, + {4432, 6473, 111}, {5158, 7199, 123}, {5804, 7845, 134}, {6370, 8411, 143}, + {6856, 8896, 151}, {7261, 9302, 158}, {7587, 9628, 164}, {7833, 9874, 168}, + {7999, 10039, 171}, {8084, 10124, 173}, {8089, 0, 0}}; + + static constexpr std::uint8_t cache_block_counts[] = { + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x56, 0x34, 0x12, 0x66, + 0x66, 0x45, 0x23, 0x61, 0x66, 0x66, 0x66, 0x45, 0x23, 0x61, 0x66, 0x66, 0x66, + 0x56, 0x34, 0x12, 0x66, 0x66, 0x66, 0x56, 0x34, 0x12, 0x66, 0x66, 0x66, 0x45, + 0x23, 0x61, 0x66, 0x56, 0x34, 0x12, 0x66, 0x56, 0x34, 0x12, 0x66, 0x45, 0x23, + 0x61, 0x45, 0x23, 0x41, 0x23, 0x31, 0x12, 0x12, 0x01}; +}; + +#ifdef BOOST_CXX17_INLINE_VARIABLES + +constexpr std::size_t extended_cache_compact::max_cache_blocks; +constexpr std::size_t extended_cache_compact::cache_bits_unit; +constexpr int extended_cache_compact::segment_length; +constexpr bool extended_cache_compact::constant_block_count; +constexpr int extended_cache_compact::collapse_factor; +constexpr int extended_cache_compact::e_min; +constexpr int extended_cache_compact::k_min; +constexpr int extended_cache_compact::cache_bit_index_offset_base; +constexpr int extended_cache_compact::cache_block_count_offset_base; +constexpr extended_cache_compact::multiplier_index_info extended_cache_compact::multiplier_index_info_table[]; +constexpr std::uint8_t extended_cache_compact::cache_block_counts[]; + +#endif + +struct extended_cache_super_compact +{ + static constexpr std::size_t max_cache_blocks = 15; + static constexpr std::size_t cache_bits_unit = 64; + static constexpr int segment_length = 252; + static constexpr bool constant_block_count = false; + static constexpr int collapse_factor = 128; + static constexpr int e_min = -1074; + static constexpr int k_min = -65; + static constexpr int cache_bit_index_offset_base = 1054; + static constexpr int cache_block_count_offset_base = 10; + + static constexpr std::uint64_t cache[] = { + 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, 0x6f99ee8b281c132a, 0x1c7262e905287f33, + 0xbf4f71a69f411989, 0xe95fb0bf35d5c518, 0x00d875ffe81c1457, 0x31f0fcb03c200323, + 0x6f64d6af592895a0, 0x45c073ee14c78fb0, 0x8744404cbdba226c, 0x8dbe2386885f0c74, + 0x279b6693e94ab813, 0x6df0a4a86ccbb52e, 0xa94baea98e947129, 0xfc2b4e9bb4cbe9a4, + 0x73bbc273e753c4ad, 0xc70c8ff8c19c1059, 0xb7da754b6db8b578, 0x5214cf7f2274988c, + 0x39b5c4db3b36b321, 0xda6f355441d9f234, 0x01ab018d850bd7e2, 0x36517c3f140b3bcf, + 0xd0e52375d8d125a7, 0xaf9709f49f3b8404, 0x022dd12dd219aa3f, 0x46e2ecebe43f459e, + 0xa428ebddeecd6636, 0x3a7d11bff7e2a722, 0xd35d40e9d3b97c7d, 0x60ef65c4478901f1, + 0x945301feb0da841a, 0x2028c054ab187f51, 0xbe94b1f686a8b684, 0x09c13fdc1c4868c9, + 0xf2325ac2bf88a4ce, 0x92980d8fa53b6888, 0x8f6e17c7572a3359, 0x2964c5bfdd7761f2, + 0xf60269fc4910b562, 0x3ca164c4a2183ab0, 0x13f4f9e5a06a95c9, 0xf75022e39380598a, + 0x0d3f3c870002ab76, 0x24a4beb4780b78ef, 0x17a59a8f5696d625, 0x0ad76de884cb489d, + 0x559d3d0681553d6a, 0x813dcf205788af76, 0xf42f9c3ad707bf72, 0x770d63ceb129026c, + 0xa604d413fc14c7c2, 0x3cfc19e01239c784, 0xec7ef19965cedd56, 0x7303dcb3b300b6fd, + 0x118059e1139c0f3c, 0x97097186308c91f7, 0x2ad91d77379dce42, 0xad396c61acbe15ec, + 0x728518461b5722b6, 0xb85c5bb1ed805ecd, 0x816abc04592a4974, 0x1866b17c7cfbd0d0, + 0x0000000000000000}; + + struct multiplier_index_info + { + std::uint16_t first_cache_bit_index; + std::uint16_t cache_bit_index_offset; + std::uint16_t cache_block_count_index_offset; + }; + + static constexpr multiplier_index_info multiplier_index_info_table[] = { + {0, 0, 0}, {860, 1698, 13}, {2506, 4181, 29}, {2941, 5069, 36}, + {3577, 5705, 41}, {3961, 6088, 44}, {4092, 0, 0}}; + + static constexpr std::uint8_t cache_block_counts[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xee, + 0xee, 0xee, 0xee, 0xee, 0xac, 0x68, + 0x24, 0x8a, 0x46, 0x62, 0x24, 0x13}; +}; + +#ifdef BOOST_CXX17_INLINE_VARIABLES + +constexpr std::size_t extended_cache_super_compact::max_cache_blocks; +constexpr std::size_t extended_cache_super_compact::cache_bits_unit; +constexpr int extended_cache_super_compact::segment_length; +constexpr bool extended_cache_super_compact::constant_block_count; +constexpr int extended_cache_super_compact::collapse_factor; +constexpr int extended_cache_super_compact::e_min; +constexpr int extended_cache_super_compact::k_min; +constexpr int extended_cache_super_compact::cache_bit_index_offset_base; +constexpr int extended_cache_super_compact::cache_block_count_offset_base; +constexpr std::uint64_t extended_cache_super_compact::cache[]; +constexpr extended_cache_super_compact::multiplier_index_info extended_cache_super_compact::multiplier_index_info_table[]; +constexpr std::uint8_t extended_cache_super_compact::cache_block_counts[]; + +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4100) // MSVC 14.0 warning of unused formal parameter is incorrect +#endif + +template <unsigned v1, unsigned v2, typename ExtendedCache> +bool has_further_digits(std::uint64_t significand, int exp2_base, int& k, boost::charconv::detail::uconst<v1> additional_neg_exp_of_2_c, boost::charconv::detail::uconst<v2> additional_neg_exp_of_10_c) noexcept +{ + constexpr auto additional_neg_exp_of_2_v = static_cast<int>(decltype(additional_neg_exp_of_2_c)::value + + decltype(additional_neg_exp_of_10_c)::value); + + constexpr auto additional_neg_exp_of_5_v = static_cast<int>(decltype(additional_neg_exp_of_10_c)::value); + + constexpr auto min_neg_exp_of_5 = (-ExtendedCache::k_min + additional_neg_exp_of_5_v) % ExtendedCache::segment_length; + + // k >= k_right_threshold iff k - k1 >= 0. + static_assert(additional_neg_exp_of_5_v + ExtendedCache::segment_length >= 1 + ExtendedCache::k_min, + "additional_neg_exp_of_5_v + ExtendedCache::segment_length >= 1 + ExtendedCache::k_min"); + + constexpr auto k_right_threshold = ExtendedCache::k_min + + ((additional_neg_exp_of_5_v + ExtendedCache::segment_length - 1 - + ExtendedCache::k_min) / + ExtendedCache::segment_length) * + ExtendedCache::segment_length; + + // When the smallest absolute value of negative exponent for 5 is too big, + // so whenever the exponent for 5 is negative, the result cannot be an + // integer. + BOOST_IF_CONSTEXPR (min_neg_exp_of_5 > 23) + { + return boost::charconv::detail::has_further_digits_impl::no_neg_k_can_be_integer< + k_right_threshold, additional_neg_exp_of_2_v>(k, exp2_base); + } + // When the smallest absolute value of negative exponent for 5 is big enough, so + // the only negative exponent for 5 that allows the result to be an integer is the + // smallest one. + else BOOST_IF_CONSTEXPR (min_neg_exp_of_5 + ExtendedCache::segment_length > 23) + { + // k < k_left_threshold iff k - k1 < -min_neg_exp_of_5. + static_assert(additional_neg_exp_of_5_v + ExtendedCache::segment_length >= min_neg_exp_of_5 + 1 + ExtendedCache::k_min, + "additional_neg_exp_of_5_v + ExtendedCache::segment_length >= min_neg_exp_of_5 + 1 + ExtendedCache::k_min"); + + constexpr auto k_left_threshold = + ExtendedCache::k_min + + ((additional_neg_exp_of_5_v - min_neg_exp_of_5 + + ExtendedCache::segment_length - 1 - ExtendedCache::k_min) / + ExtendedCache::segment_length) * + ExtendedCache::segment_length; + + return boost::charconv::detail::has_further_digits_impl::only_one_neg_k_can_be_integer< + k_left_threshold, k_right_threshold, additional_neg_exp_of_2_v, + min_neg_exp_of_5>(k, exp2_base, significand); + } + // When the smallest absolute value of negative exponent for 5 is big enough, so + // the only negative exponents for 5 that allows the result to be an integer are the + // smallest one and the next smallest one. + else + { + static_assert(min_neg_exp_of_5 + 2 * ExtendedCache::segment_length > 23, + "min_neg_exp_of_5 + 2 * ExtendedCache::segment_length > 23"); + + constexpr auto k_left_threshold = + ExtendedCache::k_min + + ((additional_neg_exp_of_5_v - min_neg_exp_of_5 - 1 - ExtendedCache::k_min) / + ExtendedCache::segment_length) * + ExtendedCache::segment_length; + + constexpr auto k_middle_threshold = + ExtendedCache::k_min + + ((additional_neg_exp_of_5_v - min_neg_exp_of_5 + + ExtendedCache::segment_length - 1 - ExtendedCache::k_min) / + ExtendedCache::segment_length) * + ExtendedCache::segment_length; + + return boost::charconv::detail::has_further_digits_impl::only_two_neg_k_can_be_integer< + k_left_threshold, k_middle_threshold, k_right_threshold, + additional_neg_exp_of_2_v, min_neg_exp_of_5, ExtendedCache::segment_length>( + k, exp2_base, significand); + } +} + +template <unsigned v1, unsigned v2, typename ExtendedCache> +inline bool has_further_digits(std::uint64_t significand, int exp2_base, int& k) +{ + boost::charconv::detail::uconst<v1> additional_neg_exp_of_2_c; + boost::charconv::detail::uconst<v2> additional_neg_exp_of_10_c; + + return has_further_digits<v1, v2, ExtendedCache>(significand, exp2_base, k, additional_neg_exp_of_2_c, additional_neg_exp_of_10_c); +} + +template <unsigned additional_neg_exp_of_2, unsigned additional_neg_exp_of_10, typename ExtendedCache> +bool compute_has_further_digits(unsigned remaining_subsegment_pairs, std::uint64_t significand, int exp2_base, int& k) noexcept +{ + #define BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(n) \ + case n: \ + return has_further_digits<additional_neg_exp_of_2, additional_neg_exp_of_10 + (n - 1) * 18, ExtendedCache>(significand, exp2_base, k) + switch (remaining_subsegment_pairs) { + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(1); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(2); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(3); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(4); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(5); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(6); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(7); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(8); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(9); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(10); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(11); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(12); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(13); + BOOST_CHARCONV_252_HAS_FURTHER_DIGITS(14); + + default: + BOOST_UNREACHABLE_RETURN(remaining_subsegment_pairs); // NOLINT + } + #undef BOOST_CHARCONV_252_HAS_FURTHER_DIGITS + + BOOST_UNREACHABLE_RETURN(false); // NOLINT +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +// Print 0.000...0 where precision is the number of 0's after the decimal dot. +inline to_chars_result print_zero_fixed(char* buffer, std::size_t buffer_size, const int precision) noexcept +{ + // No trailing decimal dot. + if (precision == 0) + { + *buffer = '0'; + return {buffer + 1, std::errc()}; + } + + if (buffer_size < static_cast<std::size_t>(precision) + 2U) + { + return {buffer + buffer_size, std::errc::value_too_large}; + } + + std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating + std::memset(buffer + 2, '0', static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating + return {buffer + 2 + precision, std::errc()}; +} + +// precision means the number of decimal significand digits minus 1. +// Assumes round-to-nearest, tie-to-even rounding. +template <typename MainCache = main_cache_full, typename ExtendedCache> +BOOST_CHARCONV_SAFEBUFFERS to_chars_result floff(const double x, int precision, char* first, char* last, + boost::charconv::chars_format fmt) noexcept +{ + if (first >= last) + { + return {last, std::errc::value_too_large}; + } + + auto buffer_size = static_cast<std::size_t>(last - first); + auto buffer = first; + + BOOST_CHARCONV_ASSERT(precision >= 0); + using namespace detail; + + std::uint64_t br = default_float_traits<double>::float_to_carrier(x); + bool is_negative = ((br >> 63) != 0); + br <<= 1; + int e = static_cast<int>(br >> (ieee754_binary64::significand_bits + 1)); + auto significand = (br & ((UINT64_C(1) << (ieee754_binary64::significand_bits + 1)) - 1)); // shifted by 1-bit. + + if (is_negative) + { + *buffer = '-'; + ++buffer; + --buffer_size; + + if (buffer_size == 0) + { + return {buffer, std::errc::value_too_large}; + } + } + + // Infinities or NaN + if (e == ((UINT32_C(1) << ieee754_binary64::exponent_bits) - 1)) + { + if (significand == 0) + { + constexpr std::size_t inf_chars = 3; + + if (buffer_size < inf_chars) + { + return {last, std::errc::value_too_large}; + } + + std::memcpy(buffer, "inf", inf_chars); // NOLINT : Specifically not null-terminating + return {buffer + inf_chars, std::errc()}; + } + else + { + // Significand values for NaN by type + // qNaN = 4503599627370496 + // sNaN = 2251799813685248 + // + if (significand == UINT64_C(4503599627370496)) + { + if (!is_negative) + { + constexpr std::size_t nan_chars = 3; + + if (buffer_size < nan_chars) + { + return {last, std::errc::value_too_large}; + } + + std::memcpy(buffer, "nan", nan_chars); // NOLINT : Specifically not null-terminating + return {buffer + nan_chars, std::errc()}; + } + else + { + constexpr std::size_t neg_nan_chars = 8; + + if (buffer_size < neg_nan_chars) + { + return {last, std::errc::value_too_large}; + } + + std::memcpy(buffer, "nan(ind)", neg_nan_chars); // NOLINT : Specifically not null-terminating + return {buffer + neg_nan_chars, std::errc()}; + } + } + else + { + constexpr std::size_t snan_chars = 9; + + if (buffer_size < snan_chars) + { + return {last, std::errc::value_too_large}; + } + + std::memcpy(buffer, "nan(snan)", snan_chars); // NOLINT : Specifically not null-terminating + return {buffer + snan_chars, std::errc()}; + } + } + } + else + { + // Normal numbers. + if (e != 0) + { + significand |= (decltype(significand)(1) << (ieee754_binary64::significand_bits + 1)); + e += (ieee754_binary64::exponent_bias - ieee754_binary64::significand_bits); + } + // Subnormal numbers. + else + { + // Zero + if (significand == 0) + { + if (fmt == boost::charconv::chars_format::general) + { + // For the case of chars_format::general, 0 is always printed as 0. + *buffer = '0'; + return {buffer + 1, std::errc()}; + } + else if (fmt == boost::charconv::chars_format::fixed) + { + return print_zero_fixed(buffer, buffer_size, precision); + } + // For the case of chars_format::scientific, print as many 0's as requested after the decimal dot, and then print e+00. + if (precision == 0) + { + constexpr std::size_t zero_chars = 5; + + if (buffer_size < zero_chars) + { + return {last, std::errc::value_too_large}; + } + + std::memcpy(buffer, "0e+00", zero_chars); + return {buffer + zero_chars, std::errc()}; + } + else + { + if (buffer_size < static_cast<std::size_t>(precision) + 6U) + { + return {last, std::errc::value_too_large}; + } + + std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating + std::memset(buffer + 2, '0', static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating + std::memcpy(buffer + 2 + precision, "e+00", 4); // NOLINT : Specifically not null-terminating + return {buffer + precision + 6, std::errc()}; + } + } + // Nonzero + e = ieee754_binary64::min_exponent - ieee754_binary64::significand_bits; + } + } + + constexpr int kappa = 2; + int k = kappa - log::floor_log10_pow2(e); + std::uint32_t current_digits {}; + char* const buffer_starting_pos = buffer; + char* decimal_dot_pos = buffer; // decimal_dot_pos == buffer_starting_pos indicates that there should be no decimal dot. + int decimal_exponent_normalized {}; + + // Number of digits to be printed. + int remaining_digits {}; + + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// Phase 1 - Print the first digit segment computed with the Dragonbox table. + ///////////////////////////////////////////////////////////////////////////////////////////////// + + { + // Compute the first digit segment. + const auto main_cache = MainCache::template get_cache<ieee754_binary64>(k); + const int beta = e + log::floor_log2_pow10(k); + + // Integer check is okay for binary64. + //auto [first_segment, has_more_segments] + compute_mul_result segments = [&] { + const auto r = umul192_upper128(significand << beta, main_cache); + return compute_mul_result{r.high, r.low == 0}; + }(); + + auto first_segment = segments.result; + auto has_more_segments = !segments.is_integer; + + // The first segment can be up to 19 digits. It is in fact always of either 18 or 19 + // digits except when the input is a subnormal number. For subnormal numbers, the + // smallest possible value of the first segment is 10^kappa, so it is of at least + // kappa+1 digits (i.e., 3 in this case). + + int first_segment_length = 19; + auto first_segment_aligned = first_segment; // Aligned to have 19 digits. + while (first_segment_aligned < UINT64_C(10000000000000000)) + { + first_segment_aligned *= 100; + first_segment_length -= 2; + } + if (first_segment_aligned < UINT64_C(1000000000000000000)) + { + first_segment_aligned *= 10; + first_segment_length -= 1; + } + // The decimal exponent when written as X.XXXX.... x 10^XX. + decimal_exponent_normalized = first_segment_length - k - 1; + + // Figure out the correct value of remaining_digits. + if (fmt == boost::charconv::chars_format::scientific) + { + remaining_digits = precision + 1; + int exponent_print_length = + decimal_exponent_normalized >= 100 ? 5 : + decimal_exponent_normalized <= -100 ? 6 : + decimal_exponent_normalized >= 0 ? 4 : 5; + + // No trailing decimal dot. + auto minimum_required_buffer_size = + static_cast<std::size_t>(remaining_digits + exponent_print_length + (precision != 0 ? 1 : 0)); + if (buffer_size < minimum_required_buffer_size) + { + return {last, std::errc::value_too_large}; + } + + if (precision != 0) + { + // Reserve a place for the decimal dot. + *buffer = '0'; + ++buffer; + ++decimal_dot_pos; + } + } + else if (fmt == boost::charconv::chars_format::fixed) + { + if (decimal_exponent_normalized >= 0) + { + remaining_digits = precision + decimal_exponent_normalized + 1; + + // No trailing decimal dot. + auto minimum_required_buffer_size = + static_cast<std::size_t>(remaining_digits + (precision != 0 ? 1 : 0)); + + // We need one more space if the rounding changes the exponent, + // but since we don't know at this point if that will actually happen, handle such a case later. + + if (buffer_size < minimum_required_buffer_size) + { + return {last, std::errc::value_too_large}; + } + + if (precision != 0) + { + // Reserve a place for the decimal dot. + *buffer = '0'; + ++buffer; + decimal_dot_pos += decimal_exponent_normalized + 1; + } + } + else + { + int number_of_leading_zeros = -decimal_exponent_normalized - 1; + + // When there are more than precision number of leading zeros, + // all the digits we need to print are 0. + if (number_of_leading_zeros > precision) + { + return print_zero_fixed(buffer, buffer_size, precision); + } + // When the number of leading zeros is exactly precision, + // then we might need to print 1 at the last digit due to rounding. + if (number_of_leading_zeros == precision) + { + // Since the last digit before rounding is 0, + // according to the "round-to-nearest, tie-to-even" rule, we round-up + // if and only if the input is strictly larger than the midpoint. + bool round_up = (first_segment_aligned + (has_more_segments ? 1 : 0)) > UINT64_C(5000000000000000000); + if (!round_up) + { + return print_zero_fixed(buffer, buffer_size, precision); + } + + // No trailing decimal dot. + if (precision == 0) + { + *buffer = '1'; + return {buffer + 1, std::errc()}; + } + + if (buffer_size < static_cast<std::size_t>(precision) + 2U) + { + return {buffer + buffer_size, std::errc::value_too_large}; + } + + std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating + std::memset(buffer + 2, '0', static_cast<std::size_t>(precision - 1)); // NOLINT : Specifically not null-terminating + buffer[1 + precision] = '1'; + return {buffer + 2 + precision, std::errc()}; + } + + remaining_digits = precision - number_of_leading_zeros; + + // Always have decimal dot. + BOOST_CHARCONV_ASSERT(precision > 0); + auto minimum_required_buffer_size = static_cast<std::size_t>(precision + 2); + if (buffer_size < minimum_required_buffer_size) + { + return {last, std::errc::value_too_large}; + } + + // Print leading zeros. + std::memset(buffer, '0', static_cast<std::size_t>(number_of_leading_zeros + 2)); + buffer += number_of_leading_zeros + 2; + ++decimal_dot_pos; + } + } + else + { + // fmt == boost::charconv::chars_format::general + if (precision == 0) + { + // For general format, precision = 0 is interpreted as precision = 1. + precision = 1; + } + remaining_digits = precision; + + // Use scientific format if decimal_exponent_normalized <= -6 or decimal_exponent_normalized >= precision. + // Use fixed format if -4 <= decimal_exponent_normalized <= precision - 2. + // If decimal_exponent_normalized == -5, use fixed format if and only if the rounding increases the exponent. + // If decimal_exponent_normalized == precision - 1, use scientific format if and only if the rounding increases the exponent. + // Since we cannot reliably decide which format to use, necessary corrections will be made in the last phase. + + // We may end up not printing the decimal dot if fixed format is chosen, but reserve a place anyway. + *buffer = '0'; + ++buffer; + decimal_dot_pos += (0 < decimal_exponent_normalized && decimal_exponent_normalized < precision) + ? decimal_exponent_normalized + 1 : 1; + } + + if (remaining_digits <= 2) + { + uint128 prod; + std::uint64_t fractional_part64; + std::uint64_t fractional_part_rounding_threshold64; + + // Convert to fixed-point form with 64/32-bit boundary for the fractional part. + + if (remaining_digits == 1) + { + prod = umul128(first_segment_aligned, UINT64_C(1329227995784915873)); + // ceil(2^63 + 2^64/10^18) + fractional_part_rounding_threshold64 = additional_static_data_holder::fractional_part_rounding_thresholds64[17]; + } + else + { + prod = umul128(first_segment_aligned, UINT64_C(13292279957849158730)); + // ceil(2^63 + 2^64/10^17) + fractional_part_rounding_threshold64 = additional_static_data_holder:: + fractional_part_rounding_thresholds64[16]; + } + fractional_part64 = (prod.low >> 56) | (prod.high << 8); + current_digits = static_cast<std::uint32_t>(prod.high >> 56); + + // Perform rounding, print the digit, and return. + if (remaining_digits == 1) + { + if (fractional_part64 >= fractional_part_rounding_threshold64 || + ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) + { + goto round_up_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + if (fractional_part64 >= fractional_part_rounding_threshold64 || + ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) + { + goto round_up_two_digits; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + goto insert_decimal_dot; + } // remaining_digits <= 2 + + // At this point, there are at least 3 digits to print. + // We split the segment into three chunks, each consisting of 9 digits, 8 digits, + // and 2 digits. + + // MSVC doesn't know how to do Grandlund-Montgomery for large 64-bit integers. + // 7922816251426433760 = ceil(2^96/10^10) = floor(2^96*(10^9/(10^19 - 1))) + const auto first_subsegment = + static_cast<std::uint32_t>(umul128_upper64(first_segment, UINT64_C(7922816251426433760)) >> 32); + + const auto second_third_subsegments = + first_segment - first_subsegment * UINT64_C(10000000000); + + BOOST_CHARCONV_ASSERT(first_subsegment < UINT64_C(1000000000)); + BOOST_CHARCONV_ASSERT(second_third_subsegments < UINT64_C(10000000000)); + + int remaining_digits_in_the_current_subsegment; + std::uint64_t prod; // holds intermediate values for digit generation. + + // Print the first subsegment. + if (first_subsegment != 0) + { + // 9 digits (19 digits in total). + if (first_subsegment >= 100000000) + { + // 1441151882 = ceil(2^57 / 10^8) + 1 + prod = first_subsegment * UINT64_C(1441151882); + prod >>= 25; + remaining_digits_in_the_current_subsegment = 8; + } + // 7 or 8 digits (17 or 18 digits in total). + else if (first_subsegment >= 1000000) + { + // 281474978 = ceil(2^48 / 10^6) + 1 + prod = first_subsegment * UINT64_C(281474978); + prod >>= 16; + remaining_digits_in_the_current_subsegment = 6; + } + // 5 or 6 digits (15 or 16 digits in total). + else if (first_subsegment >= 10000) + { + // 429497 = ceil(2^32 / 10^4) + prod = first_subsegment * UINT64_C(429497); + remaining_digits_in_the_current_subsegment = 4; + } + // 3 or 4 digits (13 or 14 digits in total). + else if (first_subsegment >= 100) + { + // 42949673 = ceil(2^32 / 10^2) + prod = first_subsegment * UINT64_C(42949673); + remaining_digits_in_the_current_subsegment = 2; + } + // 1 or 2 digits (11 or 12 digits in total). + else + { + prod = std::uint64_t(first_subsegment) << 32; + remaining_digits_in_the_current_subsegment = 0; + } + + const auto initial_digits = static_cast<std::uint32_t>(prod >> 32); + + buffer -= (initial_digits < 10 && buffer != first ? 1 : 0); + remaining_digits -= (2 - (initial_digits < 10 ? 1 : 0)); + + // Avoid the situation where we have a leading 0 that we don't need + // Typically used to account for inserting a decimal, but we know + // we won't need that in the 0 precision case + if (precision == 0 && initial_digits < 10) + { + print_1_digit(initial_digits, buffer); + ++buffer; + } + else + { + print_2_digits(initial_digits, buffer); + buffer += 2; + } + + if (remaining_digits > remaining_digits_in_the_current_subsegment) + { + remaining_digits -= remaining_digits_in_the_current_subsegment; + + for (; remaining_digits_in_the_current_subsegment > 0; remaining_digits_in_the_current_subsegment -= 2) + { + // Write next two digits. + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + } + else + { + for (int i = 0; i < (remaining_digits - 1) / 2; ++i) + { + // Write next two digits. + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + // Distinguish two cases of rounding. + if (remaining_digits_in_the_current_subsegment > remaining_digits) + { + if ((remaining_digits & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + } + else + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + } + + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + remaining_digits_in_the_current_subsegment - remaining_digits, + second_third_subsegments != 0 || has_more_segments)) + { + goto round_up; + } + + goto print_last_digits; + } + else + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<10>{second_third_subsegments}, + has_more_segments)) + { + goto round_up_two_digits; + } + + goto print_last_two_digits; + } + } + } + + // Print the second subsegment. + // The second subsegment cannot be zero even for subnormal numbers. + + if (remaining_digits <= 2) + { + // In this case the first subsegment must be nonzero. + + if (remaining_digits == 1) + { + const auto prod128 = umul128(second_third_subsegments, UINT64_C(18446744074)); + + current_digits = static_cast<std::uint32_t>(prod128.high); + const auto fractional_part64 = prod128.low + 1; + // 18446744074 is even, so prod.low cannot be equal to 2^64 - 1. + BOOST_CHARCONV_ASSERT(fractional_part64 != 0); + + if (fractional_part64 >= additional_static_data_holder::fractional_part_rounding_thresholds64[8] || + ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) + { + goto round_up_one_digit; + } + + goto print_last_one_digit; + } // remaining_digits == 1 + else + { + const auto prod128 = umul128(second_third_subsegments, UINT64_C(184467440738)); + + current_digits = static_cast<std::uint32_t>(prod128.high); + const auto fractional_part64 = prod128.low + 1; + // 184467440738 is even, so prod.low cannot be equal to 2^64 - 1. + BOOST_CHARCONV_ASSERT(fractional_part64 != 0); + + if (fractional_part64 >= additional_static_data_holder::fractional_part_rounding_thresholds64[7] || + ((fractional_part64 >> 63) & (has_more_segments | (current_digits & 1))) != 0) + { + goto round_up_two_digits; + } + + goto print_last_two_digits; + } + } // remaining_digits <= 2 + + // Compilers are not aware of how to leverage the maximum value of + // second_third_subsegments to find out a better magic number which allows us to + // eliminate an additional shift. + // 184467440737095517 = ceil(2^64/100) < floor(2^64*(10^8/(10^10 - 1))). + const auto second_subsegment = static_cast<std::uint32_t>( + umul128_upper64(second_third_subsegments, UINT64_C(184467440737095517))); + + // Since the final result is of 2 digits, we can do the computation in 32-bits. + const auto third_subsegment = + static_cast<std::uint32_t>(second_third_subsegments) - second_subsegment * 100; + + BOOST_CHARCONV_ASSERT(second_subsegment < 100000000); + BOOST_CHARCONV_ASSERT(third_subsegment < 100); + + { + std::uint32_t initial_digits; + if (first_subsegment != 0) + { + prod = ((second_subsegment * UINT64_C(281474977)) >> 16) + 1; + remaining_digits_in_the_current_subsegment = 6; + + initial_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits -= 2; + } + else + { + // 7 or 8 digits (9 or 10 digits in total). + if (second_subsegment >= 1000000) + { + prod = (second_subsegment * UINT64_C(281474978)) >> 16; + remaining_digits_in_the_current_subsegment = 6; + } + // 5 or 6 digits (7 or 8 digits in total). + else if (second_subsegment >= 10000) + { + prod = second_subsegment * UINT64_C(429497); + remaining_digits_in_the_current_subsegment = 4; + } + // 3 or 4 digits (5 or 6 digits in total). + else if (second_subsegment >= 100) + { + prod = second_subsegment * UINT64_C(42949673); + remaining_digits_in_the_current_subsegment = 2; + } + // 1 or 2 digits (3 or 4 digits in total). + else + { + prod = std::uint64_t(second_subsegment) << 32; + remaining_digits_in_the_current_subsegment = 0; + } + + initial_digits = static_cast<std::uint32_t>(prod >> 32); + buffer -= (initial_digits < 10 ? 1 : 0); + remaining_digits -= (2 - (initial_digits < 10 ? 1 : 0)); + } + + print_2_digits(initial_digits, buffer); + buffer += 2; + + if (remaining_digits > remaining_digits_in_the_current_subsegment) + { + remaining_digits -= remaining_digits_in_the_current_subsegment; + for (; remaining_digits_in_the_current_subsegment > 0; remaining_digits_in_the_current_subsegment -= 2) + { + // Write next two digits. + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + } + else + { + for (int i = 0; i < (remaining_digits - 1) / 2; ++i) + { + // Write next two digits. + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + // Distinguish two cases of rounding. + if (remaining_digits_in_the_current_subsegment > remaining_digits) + { + if ((remaining_digits & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + } + else + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + } + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + remaining_digits_in_the_current_subsegment - remaining_digits, + third_subsegment != 0 || has_more_segments)) + { + goto round_up; + } + + goto print_last_digits; + } + else + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<2>{third_subsegment}, + has_more_segments)) + { + goto round_up_two_digits; + } + + goto print_last_two_digits; + } + } + } + + // Print the third subsegment. + { + if (remaining_digits > 2) + { + print_2_digits(third_subsegment, buffer); + buffer += 2; + remaining_digits -= 2; + + // If there is no more segment, then fill remaining digits with 0's and return. + if (!has_more_segments) + { + goto fill_remaining_digits_with_0s; + } + } + else if (remaining_digits == 1) + { + prod = third_subsegment * UINT64_C(429496730); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 1, has_more_segments)) + { + goto round_up_one_digit; + } + + goto print_last_one_digit; + } + else + { + // remaining_digits == 2. + // If there is no more segment, then print the current two digits and return. + if (!has_more_segments) + { + print_2_digits(third_subsegment, buffer); + buffer += 2; + goto insert_decimal_dot; + } + + // Otherwise, for performing the rounding, we have to wait until the next + // segment becomes available. This state can be detected afterward by + // inspecting if remaining_digits == 0. + remaining_digits = 0; + current_digits = third_subsegment; + } + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// Phase 2 - Print further digit segments computed with the extended cache table. + ///////////////////////////////////////////////////////////////////////////////////////////////// + + { + auto multiplier_index = + static_cast<std::uint32_t>(k + ExtendedCache::segment_length - ExtendedCache::k_min) / + static_cast<std::uint32_t>(ExtendedCache::segment_length); + + int digits_in_the_second_segment; + { + const auto new_k = + ExtendedCache::k_min + static_cast<int>(multiplier_index) * ExtendedCache::segment_length; + digits_in_the_second_segment = new_k - k; + k = new_k; + } + + const auto exp2_base = e + boost::core::countr_zero(significand); + + using cache_block_type = typename std::decay<decltype(ExtendedCache::cache[0])>::type; + + cache_block_type blocks[ExtendedCache::max_cache_blocks]; + cache_block_count_t<ExtendedCache::constant_block_count, ExtendedCache::max_cache_blocks> cache_block_count; + + // Deal with the second segment. The second segment is special because it can have + // overlapping digits with the first segment. Note that we cannot just move the buffer + // pointer backward and print the whole segment from there, because it may contain + // leading zeros. + { + cache_block_count = + load_extended_cache<ExtendedCache, ExtendedCache::constant_block_count>( + blocks, e, k, multiplier_index); + + // Compute nm mod 2^Q. + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(significand, blocks, cache_block_count); + + BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 22) + { + // No rounding, continue. + if (remaining_digits > digits_in_the_second_segment) + { + remaining_digits -= digits_in_the_second_segment; + + if (digits_in_the_second_segment <= 2) + { + BOOST_CHARCONV_ASSERT(digits_in_the_second_segment != 0); + + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( + power_of_10[19], blocks, cache_block_count); + + auto subsegment = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[3], blocks, + cache_block_count); + + if (digits_in_the_second_segment == 1) + { + auto prod = subsegment * UINT64_C(429496730); + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + else + { + auto prod = subsegment * UINT64_C(42949673); + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + } // digits_in_the_second_segment <= 2 + else if (digits_in_the_second_segment <= 16) + { + BOOST_CHARCONV_ASSERT(22 - digits_in_the_second_segment <= 19); + + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( + compute_power(UINT64_C(10), 22 - digits_in_the_second_segment), + blocks, cache_block_count); + + // When there are at most 9 digits, we can store them in 32-bits. + if (digits_in_the_second_segment <= 9) + { + // The number of overlapping digits is in the range 13 ~ 19. + const auto subsegment = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[9], blocks, + cache_block_count); + + std::uint64_t prod; + if ((digits_in_the_second_segment & 1) != 0) + { + prod = ((subsegment * UINT64_C(720575941)) >> 24) + 1; + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + else + { + prod = ((subsegment * UINT64_C(450359963)) >> 20) + 1; + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + for (; digits_in_the_second_segment > 2; digits_in_the_second_segment -= 2) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + } // digits_in_the_second_segment <= 9 + else + { + // The number of digits in the segment is in the range 10 ~ 16. + const auto first_second_subsegments = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[16], blocks, + cache_block_count); + + // The first segment is of 8 digits, and the second segment is of + // 2 ~ 8 digits. + // ceil(2^(64+14)/10^8) = 3022314549036573 + // = floor(2^(64+14)*(10^8/(10^16 - 1))) + const auto first_subsegment = + static_cast<std::uint32_t>(umul128_upper64(first_second_subsegments, + UINT64_C(3022314549036573)) >> + 14); + const auto second_subsegment = + static_cast<std::uint32_t>(first_second_subsegments) - + UINT32_C(100000000) * first_subsegment; + + // Print the first subsegment. + print_8_digits(first_subsegment, buffer); + buffer += 8; + + // Print the second subsegment. + // There are at least 2 digits in the second subsegment. + auto prod = ((second_subsegment * UINT64_C(140737489)) >> 15) + 1; + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + digits_in_the_second_segment -= 10; + + for (; digits_in_the_second_segment > 1; digits_in_the_second_segment -= 2) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + if (digits_in_the_second_segment != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + } + } // digits_in_the_second_segment <= 16 + else + { + // The number of digits in the segment is in the range 17 ~ 22. + const auto first_subsegment = + fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate( + power_of_10[6], blocks, cache_block_count); + + const auto second_third_subsegments = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[16], blocks, + cache_block_count); + + // ceil(2^(64+14)/10^8) = 3022314549036573 + // = floor(2^(64+14)*(10^8/(10^16 - 1))) + const auto second_subsegment = + static_cast<std::uint32_t>(umul128_upper64(second_third_subsegments, + UINT64_C(3022314549036573)) >> + 14); + const auto third_subsegment = static_cast<std::uint32_t>(second_third_subsegments) - + UINT32_C(100000000) * second_subsegment; + + // Print the first subsegment (1 ~ 6 digits). + std::uint64_t prod {}; + auto remaining_digits_in_the_current_subsegment = + digits_in_the_second_segment - 16; + + switch (remaining_digits_in_the_current_subsegment) + { + case 1: + prod = first_subsegment * UINT64_C(429496730); + goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining; + + case 2: + prod = first_subsegment * UINT64_C(42949673); + goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining; + + case 3: + prod = first_subsegment * UINT64_C(4294968); + goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining; + + case 4: + prod = first_subsegment * UINT64_C(429497); + goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining; + + case 5: + prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; + goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining; + + case 6: + prod = first_subsegment * UINT64_C(429497); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + remaining_digits_in_the_current_subsegment = 4; + goto second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining; + + default: + BOOST_UNREACHABLE_RETURN(prod); // NOLINT + } + + second_segment22_more_than_16_digits_first_subsegment_no_rounding_odd_remaining + : + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + + second_segment22_more_than_16_digits_first_subsegment_no_rounding_even_remaining + : + for (; remaining_digits_in_the_current_subsegment > 1; + remaining_digits_in_the_current_subsegment -= 2) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + // Print the second and third subsegments (8 digits each). + print_8_digits(second_subsegment, buffer); + print_8_digits(third_subsegment, buffer + 8); + buffer += 16; + } + } // remaining_digits > digits_in_the_second_segment + + // Perform rounding and return. + else + { + if (digits_in_the_second_segment <= 2) + { + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( + power_of_10[19], blocks, cache_block_count); + + // Get one more bit for potential rounding on the segment boundary. + auto subsegment = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(2000, blocks, cache_block_count); + + bool segment_boundary_rounding_bit = ((subsegment & 1) != 0); + subsegment >>= 1; + + if (digits_in_the_second_segment == 2) + { + // Convert subsegment into fixed-point fractional form where the + // integer part is of one digit. The integer part is ignored. + // 42949673 = ceil(2^32/10^2) + auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(42949673); + + if (remaining_digits == 1) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + current_digits = static_cast<std::uint32_t>(prod >> 32); + const bool has_further_digits_v = has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0); + if (check_rounding_condition_inside_subsegment(current_digits, static_cast<std::uint32_t>(prod), 1, has_further_digits_v)) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + const auto next_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<2>{next_digits}, + has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + + current_digits = next_digits; + BOOST_CHARCONV_ASSERT(remaining_digits == 2); + } + else + { + BOOST_CHARCONV_ASSERT(digits_in_the_second_segment == 1); + // Convert subsegment into fixed-point fractional form where the + // integer part is of two digits. The integer part is ignored. + // 429496730 = ceil(2^32/10^1) + auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(429496730); + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + const auto next_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<1>{next_digits}, + has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + + current_digits = next_digits; + BOOST_CHARCONV_ASSERT(remaining_digits == 1); + } + + if (check_rounding_condition_with_next_bit( + current_digits, segment_boundary_rounding_bit, + has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) + { + goto round_up; + } + + goto print_last_digits; + } // digits_in_the_second_segment <= 2 + + // When there are at most 9 digits in the segment. + if (digits_in_the_second_segment <= 9) + { + // Throw away all overlapping digits. + BOOST_CHARCONV_ASSERT(22 - digits_in_the_second_segment <= 19); + + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( + compute_power(UINT64_C(10), 22 - digits_in_the_second_segment), + blocks, cache_block_count); + + // Get one more bit for potential rounding on the segment boundary. + auto segment = fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[9] << 1, blocks, + cache_block_count); + + std::uint64_t prod; + digits_in_the_second_segment -= remaining_digits; + + if ((remaining_digits & 1) != 0) + { + prod = ((segment * UINT64_C(1441151881)) >> 26) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + goto second_segment22_at_most_9_digits_rounding; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((segment * UINT64_C(1801439851)) >> 23) + 1; + const auto next_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<2>{next_digits}, [&] { + return static_cast<std::uint32_t>(prod) >= + (additional_static_data_holder:: + fractional_part_rounding_thresholds32[digits_in_the_second_segment - 3] & UINT32_C(0x7fffffff)) + || has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0); + })) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + else if (remaining_digits == 2) + { + current_digits = next_digits; + goto second_segment22_at_most_9_digits_rounding; + } + + print_2_digits(next_digits, buffer); + buffer += 2; + } + + BOOST_CHARCONV_ASSERT(remaining_digits >= 3); + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + if (digits_in_the_second_segment != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + + second_segment22_at_most_9_digits_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + digits_in_the_second_segment, has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, + uconst0))) + { + goto round_up; + } + + goto print_last_digits; + } + else + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(200); + current_digits = static_cast<std::uint32_t>(prod >> 32); + const auto segment_boundary_rounding_bit = (current_digits & 1) != 0; + current_digits >>= 1; + + if (check_rounding_condition_with_next_bit( + current_digits, segment_boundary_rounding_bit, + has_further_digits<0, 1, ExtendedCache>(significand, exp2_base, k, uconst0, uconst1))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + } // digits_in_the_second_segment <= 9 + + // first_second_subsegments is of 1 ~ 13 digits, and third_subsegment is + // of 9 digits. + // Get one more bit for potential rounding condition check. + auto first_second_subsegments = + fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate( + power_of_10[13] << 1, blocks, cache_block_count); + + bool first_bit_of_third_subsegment = ((first_second_subsegments & 1) != 0); + first_second_subsegments >>= 1; + + // Compilers are not aware of how to leverage the maximum value of + // first_second_subsegments to find out a better magic number which + // allows us to eliminate an additional shift. + // 1844674407371 = ceil(2^64/10^7) = floor(2^64*(10^6/(10^13 - 1))). + const auto first_subsegment = + static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64( + first_second_subsegments, 1844674407371)); + + const auto second_subsegment = + static_cast<std::uint32_t>(first_second_subsegments) - 10000000 * first_subsegment; + + int digits_in_the_second_subsegment; + + // Print the first subsegment (0 ~ 6 digits) if exists. + if (digits_in_the_second_segment > 16) + { + std::uint64_t prod; + int remaining_digits_in_the_current_subsegment = digits_in_the_second_segment - 16; + + // No rounding, continue. + if (remaining_digits > remaining_digits_in_the_current_subsegment) + { + remaining_digits -= remaining_digits_in_the_current_subsegment; + + // There is no overlap in the second subsegment. + digits_in_the_second_subsegment = 7; + + // When there is no overlapping digit. + if (remaining_digits_in_the_current_subsegment == 6) + { + prod = (first_subsegment * UINT64_C(429497)) + 1; + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + remaining_digits_in_the_current_subsegment -= 2; + } + // If there are overlapping digits, move all overlapping digits + // into the integer part. + else + { + prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; + prod *= compute_power(UINT64_C(10), 5 - remaining_digits_in_the_current_subsegment); + + if ((remaining_digits_in_the_current_subsegment & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + } + + for (; remaining_digits_in_the_current_subsegment > 1; remaining_digits_in_the_current_subsegment -= 2) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + } + // The first subsegment is the last subsegment to print. + else + { + if ((remaining_digits & 1) != 0) + { + prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; + + // If there are overlapping digits, move all overlapping digits + // into the integer part and then get the next digit. + if (remaining_digits_in_the_current_subsegment < 6) + { + prod *= compute_power(UINT64_C(10), 5 - remaining_digits_in_the_current_subsegment); + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + } + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits_in_the_current_subsegment -= remaining_digits; + + if (remaining_digits == 1) + { + goto second_segment22_more_than_9_digits_first_subsegment_rounding; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + // When there is no overlapping digit. + if (remaining_digits_in_the_current_subsegment == 6) + { + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<6>{ + first_subsegment}, + has_further_digits<1, 16, ExtendedCache>(significand, exp2_base, k, uconst1, uconst16))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + + prod = (first_subsegment * UINT64_C(429497)) + 1; + } + // Otherwise, convert the subsegment into a fixed-point + // fraction form, move all overlapping digits into the + // integer part, and then extract the next two digits. + else + { + prod = ((first_subsegment * UINT64_C(687195)) >> 4) + 1; + prod *= compute_power(UINT64_C(10), 5 - remaining_digits_in_the_current_subsegment); + + if (remaining_digits == 0) + { + goto second_segment22_more_than_9_digits_first_subsegment_rounding_inside_subsegment; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + } + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits_in_the_current_subsegment -= remaining_digits; + + if (remaining_digits == 2) + { + goto second_segment22_more_than_9_digits_first_subsegment_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + BOOST_CHARCONV_ASSERT(remaining_digits >= 3); + + if (remaining_digits > 4) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + + second_segment22_more_than_9_digits_first_subsegment_rounding: + if (remaining_digits_in_the_current_subsegment == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<7>{second_subsegment}, + has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, uconst1, uconst9))) + { + goto round_up; + } + } + else + { + second_segment22_more_than_9_digits_first_subsegment_rounding_inside_subsegment + : + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + remaining_digits_in_the_current_subsegment, + has_further_digits<1, 16, ExtendedCache>(significand, exp2_base, k, uconst1, uconst16))) + { + goto round_up; + } + } + goto print_last_digits; + } + } + else + { + digits_in_the_second_subsegment = digits_in_the_second_segment - 9; + } + + // Print the second subsegment (1 ~ 7 digits). + { + // No rounding, continue. + if (remaining_digits > digits_in_the_second_subsegment) + { + auto prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1; + remaining_digits -= digits_in_the_second_subsegment; + + // When there is no overlapping digit. + if (digits_in_the_second_subsegment == 7) + { + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + // If there are overlapping digits, move all overlapping digits + // into the integer part. + else + { + prod *= compute_power(UINT64_C(10), + 6 - digits_in_the_second_subsegment); + + if ((digits_in_the_second_subsegment & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + } + + for (; digits_in_the_second_subsegment > 1; digits_in_the_second_subsegment -= 2) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + } + // The second subsegment is the last subsegment to print. + else + { + std::uint64_t prod; + + if ((remaining_digits & 1) != 0) + { + prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1; + + // If there are overlapping digits, move all overlapping digits + // into the integer part and then get the next digit. + if (digits_in_the_second_subsegment < 7) + { + prod *= compute_power(UINT64_C(10), 6 - digits_in_the_second_subsegment); + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + } + current_digits = static_cast<std::uint32_t>(prod >> 32); + digits_in_the_second_subsegment -= remaining_digits; + + if (remaining_digits == 1) + { + goto second_segment22_more_than_9_digits_second_subsegment_rounding; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + // When there is no overlapping digit. + if (digits_in_the_second_subsegment == 7) + { + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<7>{ + second_subsegment}, + has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, uconst1, uconst9))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + + prod = ((second_subsegment * UINT64_C(10995117)) >> 8) + 1; + } + // Otherwise, convert the subsegment into a fixed-point + // fraction form, move all overlapping digits into the + // integer part, and then extract the next two digits. + else + { + prod = ((second_subsegment * UINT64_C(17592187)) >> 12) + 1; + prod *= compute_power(UINT64_C(10), 6 - digits_in_the_second_subsegment); + + if (remaining_digits == 0) + { + goto second_segment22_more_than_9_digits_second_subsegment_rounding_inside_subsegment; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + } + current_digits = static_cast<std::uint32_t>(prod >> 32); + digits_in_the_second_subsegment -= remaining_digits; + + if (remaining_digits == 2) + { + goto second_segment22_more_than_9_digits_second_subsegment_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + BOOST_CHARCONV_ASSERT(remaining_digits >= 3); + + if (remaining_digits > 4) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + + second_segment22_more_than_9_digits_second_subsegment_rounding: + if (digits_in_the_second_subsegment == 0) + { + if (check_rounding_condition_with_next_bit( + current_digits, first_bit_of_third_subsegment, + has_further_digits<0, 9, ExtendedCache>(significand, exp2_base, k, uconst0, uconst9))) + { + goto round_up; + } + } + else + { + second_segment22_more_than_9_digits_second_subsegment_rounding_inside_subsegment + : + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + digits_in_the_second_subsegment, has_further_digits<1, 9, ExtendedCache>(significand, exp2_base, k, + uconst1, uconst9))) + { + goto round_up; + } + } + goto print_last_digits; + } + } + + // Print the third subsegment (9 digits). + { + // Get one more bit if we need to check rounding conditions on + // the segment boundary. We already have shifted by 1-bit in the + // computation of first & second subsegments, so here we don't + // shift the multiplier. + auto third_subsegment = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[9], blocks, + cache_block_count); + + bool segment_boundary_rounding_bit = ((third_subsegment & 1) != 0); + third_subsegment >>= 1; + third_subsegment += (first_bit_of_third_subsegment ? 500000000 : 0); + + std::uint64_t prod; + if ((remaining_digits & 1) != 0) + { + prod = ((third_subsegment * UINT64_C(720575941)) >> 24) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 8, + has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((third_subsegment * UINT64_C(450359963)) >> 20) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto second_segment22_more_than_9_digits_third_subsegment_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits < 9) + { + second_segment22_more_than_9_digits_third_subsegment_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 9 - remaining_digits, + has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) + { + goto round_up_two_digits; + } + } + else + { + if (check_rounding_condition_with_next_bit( + current_digits, segment_boundary_rounding_bit, + has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) + { + goto round_up_two_digits; + } + } + goto print_last_two_digits; + } + } + } // ExtendedCache::segment_length == 22 + + else BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 252) + { + int overlapping_digits = 252 - digits_in_the_second_segment; + int remaining_subsegment_pairs = 14; + + while (overlapping_digits >= 18) + { + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper( + power_of_10[18], blocks, cache_block_count); + --remaining_subsegment_pairs; + overlapping_digits -= 18; + } + + auto subsegment_pair = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18] << 1, blocks, cache_block_count); + auto subsegment_boundary_rounding_bit = (subsegment_pair & 1) != 0; + subsegment_pair >>= 1; + + // Deal with the first subsegment pair. + { + // Divide it into two 9-digits subsegments. + const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]); + const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part); + + auto print_subsegment = [&](std::uint32_t subsegment, int digits_in_the_subsegment) + { + remaining_digits -= digits_in_the_subsegment; + + // Move all overlapping digits into the integer part. + auto prod = ((subsegment * UINT64_C(720575941)) >> 24) + 1; + if (digits_in_the_subsegment < 9) + { + prod *= compute_power(UINT32_C(10), 8 - digits_in_the_subsegment); + + if ((digits_in_the_subsegment & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + } + else + { + print_1_digit(static_cast<std::uint32_t>(prod >> 32), buffer); + ++buffer; + } + + for (; digits_in_the_subsegment > 1; digits_in_the_subsegment -= 2) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + }; + + // When the first part is not completely overlapping with the first segment. + int digits_in_the_second_part; + if (overlapping_digits < 9) + { + int digits_in_the_first_part = 9 - overlapping_digits; + + // No rounding, continue. + if (remaining_digits > digits_in_the_first_part) + { + digits_in_the_second_part = 9; + print_subsegment(first_part, digits_in_the_first_part); + } + // Perform rounding and return. + else + { + // When there is no overlapping digit. + std::uint64_t prod; + if (digits_in_the_first_part == 9) + { + if ((remaining_digits & 1) != 0) + { + prod = ((first_part * UINT64_C(720575941)) >> 24) + 1; + } + else + { + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<9>{first_part}, + compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + + prod = ((first_part * UINT64_C(450359963)) >> 20) + 1; + } + } + else + { + prod = ((first_part * UINT64_C(720575941)) >> 24) + 1; + prod *= compute_power(UINT32_C(10), 8 - digits_in_the_first_part); + + if ((remaining_digits & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + } + else + { + if (remaining_digits == 0) + { + goto second_segment252_first_subsegment_rounding_inside_subsegment; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + } + } + digits_in_the_first_part -= remaining_digits; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits > 2) + { + if ((remaining_digits & 1) != 0) + { + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + } + + if (digits_in_the_first_part != 0) + { + second_segment252_first_subsegment_rounding_inside_subsegment: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + digits_in_the_first_part, compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up; + } + } + else + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)}, + compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up; + } + } + goto print_last_digits; + } + } + else + { + digits_in_the_second_part = 18 - overlapping_digits; + } + + // Print the second part. + // No rounding, continue. + if (remaining_digits > digits_in_the_second_part) + { + print_subsegment(second_part, digits_in_the_second_part); + } + // Perform rounding and return. + else + { + // When there is no overlapping digit. + std::uint64_t prod; + if (digits_in_the_second_part == 9) + { + if ((remaining_digits & 1) != 0) + { + prod = ((second_part * UINT64_C(720575941)) >> 24) + 1; + } + else + { + if (remaining_digits == 0) + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)}, + compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + + prod = ((second_part * UINT64_C(450359963)) >> 20) + 1; + } + } + else + { + prod = ((second_part * UINT64_C(720575941)) >> 24) + 1; + prod *= compute_power(UINT32_C(10), 8 - digits_in_the_second_part); + + if ((remaining_digits & 1) != 0) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(10); + } + else + { + if (remaining_digits == 0) + { + goto second_segment252_second_subsegment_rounding_inside_subsegment; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + } + } + digits_in_the_second_part -= remaining_digits; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits > 2) + { + if ((remaining_digits & 1) != 0) + { + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + } + + if (digits_in_the_second_part != 0) + { + second_segment252_second_subsegment_rounding_inside_subsegment: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + digits_in_the_second_part, compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up; + } + } + else + { + if (check_rounding_condition_with_next_bit( + current_digits, subsegment_boundary_rounding_bit, + compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up; + } + } + goto print_last_digits; + } + } + + // Remaining subsegment pairs do not have overlapping digits. + --remaining_subsegment_pairs; + for (; remaining_subsegment_pairs > 0; --remaining_subsegment_pairs) + { + subsegment_pair = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18], blocks, cache_block_count); + + subsegment_pair += (subsegment_boundary_rounding_bit ? power_of_10[18] : 0); + subsegment_boundary_rounding_bit = (subsegment_pair & 1) != 0; + subsegment_pair >>= 1; + + const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]); + const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part); + + // The first part can be printed without rounding. + if (remaining_digits > 9) + { + print_9_digits(first_part, buffer); + + // The second part also can be printed without rounding. + if (remaining_digits > 18) + { + print_9_digits(second_part, buffer + 9); + } + // Otherwise, perform rounding and return. + else + { + buffer += 9; + remaining_digits -= 9; + + std::uint64_t prod; + int remaining_digits_in_the_current_subsegment = 9 - remaining_digits; + + if ((remaining_digits & 1) != 0) + { + prod = ((second_part * UINT64_C(720575941)) >> 24) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + goto second_segment252_loop_second_subsegment_rounding; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((second_part * UINT64_C(450359963)) >> 20) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto second_segment252_loop_second_subsegment_rounding; + } + + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + + if (remaining_digits_in_the_current_subsegment != 0) + { + second_segment252_loop_second_subsegment_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + remaining_digits_in_the_current_subsegment, + compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up; + } + goto print_last_digits; + } + else + { + if (check_rounding_condition_with_next_bit( + current_digits, subsegment_boundary_rounding_bit, + compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + } + } + // Otherwise, perform rounding and return. + else + { + std::uint64_t prod; + int remaining_digits_in_the_current_subsegment = 9 - remaining_digits; + if ((remaining_digits & 1) != 0) + { + prod = ((first_part * UINT64_C(720575941)) >> 24) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + goto second_segment252_loop_first_subsegment_rounding; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((first_part * UINT64_C(450359963)) >> 20) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto second_segment252_loop_first_subsegment_rounding; + } + + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + remaining_digits = 0; + + if (remaining_digits_in_the_current_subsegment != 0) + { + second_segment252_loop_first_subsegment_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + remaining_digits_in_the_current_subsegment, + compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up; + } + goto print_last_digits; + } + else + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)}, + compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + } + + buffer += 18; + remaining_digits -= 18; + } + } // ExtendedCache::segment_length == 252 + } + + // Print all remaining segments. + while (has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0)) + { + // Get new segment. + ++multiplier_index; + k += ExtendedCache::segment_length; + + cache_block_count = load_extended_cache<ExtendedCache, ExtendedCache::constant_block_count>(blocks, e, k, multiplier_index); + + // Compute nm mod 2^Q. + fixed_point_calculator<ExtendedCache::max_cache_blocks>::discard_upper(significand, blocks, cache_block_count); + + BOOST_CHARCONV_IF_CONSTEXPR (ExtendedCache::segment_length == 22) + { + // When at least two subsegments left. + if (remaining_digits > 16) + { + std::uint64_t first_second_subsegments = fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[16], blocks, cache_block_count); + + const auto first_subsegment = + static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(first_second_subsegments, UINT64_C(3022314549036573)) >> 14); + + const std::uint32_t second_subsegment = static_cast<std::uint32_t>(first_second_subsegments) - UINT32_C(100000000) * first_subsegment; + + print_8_digits(first_subsegment, buffer); + print_8_digits(second_subsegment, buffer + 8); + + // When more segments left. + if (remaining_digits > 22) + { + const auto third_subsegment = static_cast<std::uint32_t>( + fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate_and_discard_lower(power_of_10[6], blocks,cache_block_count)); + + print_6_digits(third_subsegment, buffer + 16); + buffer += 22; + remaining_digits -= 22; + } + // When this is the last segment. + else + { + buffer += 16; + remaining_digits -= 16; + + auto third_subsegment = fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[6] << 1, blocks, cache_block_count); + + bool segment_boundary_rounding_bit = ((third_subsegment & 1) != 0); + third_subsegment >>= 1; + + std::uint64_t prod; + if ((remaining_digits & 1) != 0) + { + prod = ((third_subsegment * UINT64_C(687195)) >> 4) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 5, + has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = (third_subsegment * UINT64_C(429497)) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto segment_loop22_more_than_16_digits_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + if (remaining_digits > 4) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + + if (remaining_digits == 6) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (check_rounding_condition_with_next_bit( + current_digits, segment_boundary_rounding_bit, + has_further_digits<0, 0, ExtendedCache>(significand, exp2_base, k, uconst0, uconst0))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + segment_loop22_more_than_16_digits_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 6 - remaining_digits, + has_further_digits<1, 0, ExtendedCache>(significand, exp2_base, k, uconst1, uconst0))) + { + goto round_up_two_digits; + } + goto print_last_two_digits; + } + } + // When two subsegments left. + else if (remaining_digits > 8) + { + // Get one more bit for potential rounding conditions check. + auto first_second_subsegments = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[16] << 1, blocks, cache_block_count); + + bool first_bit_of_third_subsegment = ((first_second_subsegments & 1) != 0); + first_second_subsegments >>= 1; + + // 3022314549036573 = ceil(2^78/10^8) = floor(2^78*(10^8/(10^16 - + // 1))). + const auto first_subsegment = + static_cast<std::uint32_t>(boost::charconv::detail::umul128_upper64(first_second_subsegments, UINT64_C(3022314549036573)) >> 14); + + const auto second_subsegment = static_cast<std::uint32_t>(first_second_subsegments) - UINT32_C(100000000) * first_subsegment; + + print_8_digits(first_subsegment, buffer); + buffer += 8; + remaining_digits -= 8; + + // Second subsegment (8 digits). + std::uint64_t prod; + if ((remaining_digits & 1) != 0) + { + prod = ((second_subsegment * UINT64_C(112589991)) >> 18) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 7, has_further_digits<1, 6, ExtendedCache>(significand, exp2_base, k, + uconst1, uconst6))) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((second_subsegment * UINT64_C(140737489)) >> 15) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto segment_loop22_more_than_8_digits_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits < 8) + { + segment_loop22_more_than_8_digits_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 8 - remaining_digits, + has_further_digits<1, 6, ExtendedCache>(significand, exp2_base, k, uconst1, uconst6))) + { + goto round_up_two_digits; + } + } + else { + if (check_rounding_condition_with_next_bit( + current_digits, first_bit_of_third_subsegment, + has_further_digits<0, 6, ExtendedCache>(significand, exp2_base, k, uconst0, uconst6))) + { + goto round_up_two_digits; + } + } + goto print_last_two_digits; + } + // remaining_digits is at most 8. + else + { + // Get one more bit for potential rounding conditions check. + auto first_subsegment = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[8] << 1, blocks, cache_block_count); + + bool first_bit_of_second_subsegment = ((first_subsegment & 1) != 0); + first_subsegment >>= 1; + + std::uint64_t prod; + if ((remaining_digits & 1) != 0) + { + prod = ((first_subsegment * UINT64_C(112589991)) >> 18) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 7, has_further_digits<1, 14, ExtendedCache>(significand, exp2_base, k, + uconst1, uconst14))) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((first_subsegment * UINT64_C(140737489)) >> 15) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto segment_loop22_at_most_8_digits_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits < 8) + { + segment_loop22_at_most_8_digits_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 8 - remaining_digits, + has_further_digits<1, 14, ExtendedCache>(significand, exp2_base, k, uconst1, uconst14))) + { + goto round_up_two_digits; + } + } + else + { + if (check_rounding_condition_with_next_bit( + current_digits, first_bit_of_second_subsegment, + has_further_digits<0, 14, ExtendedCache>(significand, exp2_base, k, uconst0, uconst14))) + { + goto round_up_two_digits; + } + } + goto print_last_two_digits; + } + } // ExtendedCache::segment_length == 22 + else if (ExtendedCache::segment_length == 252) + { + // Print as many 18-digits subsegment pairs as possible. + for (int remaining_subsegment_pairs = 14; remaining_subsegment_pairs > 0; + --remaining_subsegment_pairs) + { + // No rounding, continue. + if (remaining_digits > 18) + { + const auto subsegment_pair = + fixed_point_calculator<ExtendedCache::max_cache_blocks>::generate(power_of_10[18], blocks, cache_block_count); + + const auto first_part = static_cast<std::uint32_t>(subsegment_pair / power_of_10[9]); + const auto second_part = static_cast<std::uint32_t>(subsegment_pair - power_of_10[9] * first_part); + + print_9_digits(first_part, buffer); + print_9_digits(second_part, buffer + 9); + buffer += 18; + remaining_digits -= 18; + } + // Final subsegment pair. + else + { + auto last_subsegment_pair = + fixed_point_calculator<ExtendedCache::max_cache_blocks>:: + generate_and_discard_lower(power_of_10[18] << 1, blocks, cache_block_count); + + const bool subsegment_boundary_rounding_bit = ((last_subsegment_pair & 1) != 0); + last_subsegment_pair >>= 1; + + const auto first_part = static_cast<std::uint32_t>(last_subsegment_pair / power_of_10[9]); + const auto second_part = static_cast<std::uint32_t>(last_subsegment_pair) - power_of_10[9] * first_part; + + if (remaining_digits <= 9) + { + std::uint64_t prod; + + if ((remaining_digits & 1) != 0) + { + prod = ((first_part * UINT64_C(1441151881)) >> 25) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 8, + compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((first_part * UINT64_C(450359963)) >> 20) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto segment_loop252_final18_first_part_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits < 9) + { + segment_loop252_final18_first_part_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), + 9 - remaining_digits, compute_has_further_digits<1, 9, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + } + else + { + if (check_rounding_condition_subsegment_boundary_with_next_subsegment( + current_digits, + uint_with_known_number_of_digits<9>{static_cast<std::uint32_t>(second_part)}, + compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + } + goto print_last_two_digits; + } // remaining_digits <= 9 + + print_9_digits(first_part, buffer); + buffer += 9; + remaining_digits -= 9; + + std::uint64_t prod; + + if ((remaining_digits & 1) != 0) + { + prod = ((second_part * UINT64_C(1441151881)) >> 25) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 1) + { + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 8, + compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_one_digit; + } + goto print_last_one_digit; + } + + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + prod = ((second_part * UINT64_C(450359963)) >> 20) + 1; + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits == 2) + { + goto segment_loop252_final18_second_part_rounding; + } + + print_2_digits(current_digits, buffer); + buffer += 2; + } + + for (int i = 0; i < (remaining_digits - 3) / 2; ++i) + { + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + print_2_digits(static_cast<std::uint32_t>(prod >> 32), buffer); + buffer += 2; + } + + prod = static_cast<std::uint32_t>(prod) * UINT64_C(100); + current_digits = static_cast<std::uint32_t>(prod >> 32); + + if (remaining_digits < 9) + { + segment_loop252_final18_second_part_rounding: + if (check_rounding_condition_inside_subsegment( + current_digits, static_cast<std::uint32_t>(prod), 9 - remaining_digits, + compute_has_further_digits<1, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + } + else + { + if (check_rounding_condition_with_next_bit( + current_digits, subsegment_boundary_rounding_bit, + compute_has_further_digits<0, 0, ExtendedCache>, remaining_subsegment_pairs, significand, exp2_base, k)) + { + goto round_up_two_digits; + } + } + goto print_last_two_digits; + } + } + } // if (ExtendedCache::segment_length == 252) + } + } + + + ///////////////////////////////////////////////////////////////////////////////////////////////// + /// Phase 3 - Fill remaining digits with 0's, insert decimal dot, print exponent, and + /// return. + ///////////////////////////////////////////////////////////////////////////////////////////////// + +fill_remaining_digits_with_0s: + // This is probably not needed for the general format, but currently I am not 100% sure. + // (When fixed format is eventually chosen, we do not remove trailing zeros in the integer part. + // I am not sure if those trailing zeros are guaranteed to be already printed or not.) + std::memset(buffer, '0', static_cast<std::size_t>(remaining_digits)); + buffer += remaining_digits; + +insert_decimal_dot: + if (fmt == chars_format::general) + { + // Decide between fixed vs scientific. + if (-4 <= decimal_exponent_normalized && decimal_exponent_normalized < precision) + { + // Fixed. + if (decimal_exponent_normalized >= 0) + { + // Insert decimal dot. + decimal_dot_pos = buffer_starting_pos + decimal_exponent_normalized + 1; + std::memmove(buffer_starting_pos, buffer_starting_pos + 1, + static_cast<std::size_t>(decimal_dot_pos - buffer_starting_pos)); + *decimal_dot_pos = '.'; + } + else + { + // Print leading zeros and insert decimal dot. + int number_of_leading_zeros = -decimal_exponent_normalized - 1; + std::memmove(buffer_starting_pos + number_of_leading_zeros + 2, buffer_starting_pos + 1, + static_cast<std::size_t>(buffer - buffer_starting_pos - 1)); + std::memcpy(buffer_starting_pos, "0.", 2); + std::memset(buffer_starting_pos + 2, '0', static_cast<std::size_t>(number_of_leading_zeros)); + buffer += number_of_leading_zeros + 1; + } + // Don't print exponent. + fmt = chars_format::fixed; + } + else + { + // Scientific. + // Insert decimal dot. + *buffer_starting_pos = *(buffer_starting_pos + 1); + *(buffer_starting_pos + 1) = '.'; + } + + // Remove trailing zeros. + while (true) + { + auto prev = buffer - 1; + + // Remove decimal dot as well if there is no fractional digits. + if (*prev == '.') + { + buffer = prev; + break; + } + else if (*prev != '0') + { + break; + } + buffer = prev; + } + } + else if (decimal_dot_pos != buffer_starting_pos) + { + std::memmove(buffer_starting_pos, buffer_starting_pos + 1, + static_cast<std::size_t>(decimal_dot_pos - buffer_starting_pos)); + *decimal_dot_pos = '.'; + } + + if (fmt != chars_format::fixed) + { + if (decimal_exponent_normalized >= 0) + { + std::memcpy(buffer, "e+", 2); // NOLINT : Specifically not null-terminating + } + else + { + std::memcpy(buffer, "e-", 2); // NOLINT : Specifically not null-terminating + decimal_exponent_normalized = -decimal_exponent_normalized; + } + + buffer += 2; + if (decimal_exponent_normalized >= 100) + { + // d1 = decimal_exponent / 10; d2 = decimal_exponent % 10; + // 6554 = ceil(2^16 / 10) + auto prod = static_cast<std::uint32_t>(decimal_exponent_normalized) * UINT32_C(6554); + auto d1 = prod >> 16; + prod = static_cast<std::uint16_t>(prod) * UINT16_C(5); // * 10 + auto d2 = prod >> 15; // >> 16 + print_2_digits(d1, buffer); + print_1_digit(d2, buffer + 2); + buffer += 3; + } + else + { + print_2_digits(static_cast<std::uint32_t>(decimal_exponent_normalized), buffer); + buffer += 2; + } + } + + return {buffer, std::errc()}; + +round_up: + if ((remaining_digits & 1) != 0) + { + round_up_one_digit: + if (++current_digits == 10) + { + goto round_up_all_9s; + } + + goto print_last_one_digit; + } + else + { + round_up_two_digits: + if (++current_digits == 100) + { + goto round_up_all_9s; + } + + goto print_last_two_digits; + } + +print_last_digits: + if ((remaining_digits & 1) != 0) + { + print_last_one_digit: + print_1_digit(current_digits, buffer); + ++buffer; + } + else + { + print_last_two_digits: + print_2_digits(current_digits, buffer); + buffer += 2; + } + + goto insert_decimal_dot; + +round_up_all_9s: + char* first_9_pos = buffer; + buffer += (2 - (remaining_digits & 1)); + + // Find the starting position of printed digits. + char* digit_starting_pos = [&] { + // For negative exponent & fixed format, we already printed leading zeros. + if (fmt == chars_format::fixed && decimal_exponent_normalized < 0) + { + return buffer_starting_pos - decimal_exponent_normalized + 1; + } + // We reserved one slot for decimal dot, so the starting position of printed digits + // is buffer_starting_pos + 1 if we need to print decimal dot. + return buffer_starting_pos == decimal_dot_pos ? buffer_starting_pos + : buffer_starting_pos + 1; + }(); + // Find all preceding 9's. + if ((first_9_pos - digit_starting_pos) % 2 != 0) + { + if (*(first_9_pos - 1) != '9') + { + ++*(first_9_pos - 1); + if ((remaining_digits & 1) != 0) + { + *first_9_pos = '0'; + } + else + { + std::memcpy(first_9_pos, "00", 2); + } + goto insert_decimal_dot; + } + --first_9_pos; + } + while (first_9_pos != digit_starting_pos) + { + if (std::memcmp(first_9_pos - 2, "99", 2) != 0) + { + if (*(first_9_pos - 1) != '9') + { + ++*(first_9_pos - 1); + } + else + { + ++*(first_9_pos - 2); + *(first_9_pos - 1) = '0'; + } + std::memset(first_9_pos, '0', static_cast<std::size_t>(buffer - first_9_pos)); + goto insert_decimal_dot; + } + first_9_pos -= 2; + } + + // Every digit we wrote so far are all 9's. In this case, we have to shift the whole thing by 1. + ++decimal_exponent_normalized; + + if (fmt == chars_format::fixed) + { + if (decimal_exponent_normalized > 0) + { + // We need to print one more character. + if (buffer == last) + { + return {last, std::errc::value_too_large}; + } + ++buffer; + // If we were to print the decimal dot, we have to shift it to right + // since we now have one more digit in the integer part. + if (buffer_starting_pos != decimal_dot_pos) + { + ++decimal_dot_pos; + } + } + else if (decimal_exponent_normalized == 0) + { + // For the case 0.99...9 -> 1.00...0, the rounded digit is one before the first digit written. + // Note: decimal_exponent_normalized was negative before the increment (++decimal_exponent_normalized), + // so we already have printed "00" onto the buffer. + // Hence, --digit_starting_pos doesn't go more than the starting position of the buffer. + --digit_starting_pos; + } + } + + // Nolint is applied to the following two calls since we know they are not supposed to be null terminated + *digit_starting_pos = '1'; + std::memset(digit_starting_pos + 1, '0', static_cast<std::size_t>(buffer - digit_starting_pos - 1)); // NOLINT + + goto insert_decimal_dot; +} + +}}} // Namespaces + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // BOOST_CHARCONV_DETAIL_FLOFF diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/emulated128.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/emulated128.hpp new file mode 100644 index 00000000000..281b031cb42 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/emulated128.hpp @@ -0,0 +1,1005 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// If the architecture (e.g. Apple ARM) does not have __int128 we need to emulate it + +#ifndef BOOST_CHARCONV_DETAIL_EMULATED128_HPP +#define BOOST_CHARCONV_DETAIL_EMULATED128_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/config.hpp> +#include <boost/core/bit.hpp> +#include <type_traits> +#include <limits> +#include <cstdint> +#include <cassert> +#include <cmath> + +namespace boost { namespace charconv { namespace detail { + +// Compilers might support built-in 128-bit integer types. However, it seems that +// emulating them with a pair of 64-bit integers actually produces a better code, +// so we avoid using those built-ins. That said, they are still useful for +// implementing 64-bit x 64-bit -> 128-bit multiplication. + +// Memcpy-able temp class for uint128 +struct trivial_uint128 +{ + #if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE + std::uint64_t low; + std::uint64_t high; + #else + std::uint64_t high; + std::uint64_t low; + #endif +}; + +// Macro replacement lists can not be enclosed in parentheses +struct uint128 +{ + std::uint64_t high; + std::uint64_t low; + + // Constructors + constexpr uint128() noexcept : high {}, low {} {} + + constexpr uint128(const uint128& v) noexcept = default; + + constexpr uint128(uint128&& v) noexcept = default; + + constexpr uint128(std::uint64_t high_, std::uint64_t low_) noexcept : high {high_}, low {low_} {} + + constexpr uint128(const trivial_uint128& v) noexcept : high {v.high}, low {v.low} {} // NOLINT + + constexpr uint128(trivial_uint128&& v) noexcept : high {v.high}, low {v.low} {} // NOLINT + + #define SIGNED_CONSTRUCTOR(expr) constexpr uint128(expr v) noexcept : high {v < 0 ? UINT64_MAX : UINT64_C(0)}, low {static_cast<std::uint64_t>(v)} {} // NOLINT + #define UNSIGNED_CONSTRUCTOR(expr) constexpr uint128(expr v) noexcept : high {}, low {static_cast<std::uint64_t>(v)} {} // NOLINT + + SIGNED_CONSTRUCTOR(char) // NOLINT + SIGNED_CONSTRUCTOR(signed char) // NOLINT + SIGNED_CONSTRUCTOR(short) // NOLINT + SIGNED_CONSTRUCTOR(int) // NOLINT + SIGNED_CONSTRUCTOR(long) // NOLINT + SIGNED_CONSTRUCTOR(long long) // NOLINT + + UNSIGNED_CONSTRUCTOR(unsigned char) // NOLINT + UNSIGNED_CONSTRUCTOR(unsigned short) // NOLINT + UNSIGNED_CONSTRUCTOR(unsigned) // NOLINT + UNSIGNED_CONSTRUCTOR(unsigned long) // NOLINT + UNSIGNED_CONSTRUCTOR(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + constexpr uint128(boost::int128_type v) noexcept : // NOLINT : Allow implicit conversions + high {static_cast<std::uint64_t>(v >> 64)}, + low {static_cast<std::uint64_t>(static_cast<boost::uint128_type>(v) & ~UINT64_C(0))} {} + + constexpr uint128(boost::uint128_type v) noexcept : // NOLINT : Allow implicit conversions + high {static_cast<std::uint64_t>(v >> 64)}, + low {static_cast<std::uint64_t>(v & ~UINT64_C(0))} {} + #endif + + #undef SIGNED_CONSTRUCTOR + #undef UNSIGNED_CONSTRUCTOR + + // Assignment Operators + #define SIGNED_ASSIGNMENT_OPERATOR(expr) BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const expr& v) noexcept { high = v < 0 ? UINT64_MAX : UINT64_C(0); low = static_cast<std::uint64_t>(v); return *this; } // NOLINT + #define UNSIGNED_ASSIGNMENT_OPERATOR(expr) BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const expr& v) noexcept { high = 0U; low = static_cast<std::uint64_t>(v); return *this; } // NOLINT + + SIGNED_ASSIGNMENT_OPERATOR(char) // NOLINT + SIGNED_ASSIGNMENT_OPERATOR(signed char) // NOLINT + SIGNED_ASSIGNMENT_OPERATOR(short) // NOLINT + SIGNED_ASSIGNMENT_OPERATOR(int) // NOLINT + SIGNED_ASSIGNMENT_OPERATOR(long) // NOLINT + SIGNED_ASSIGNMENT_OPERATOR(long long) // NOLINT + + UNSIGNED_ASSIGNMENT_OPERATOR(unsigned char) // NOLINT + UNSIGNED_ASSIGNMENT_OPERATOR(unsigned short) // NOLINT + UNSIGNED_ASSIGNMENT_OPERATOR(unsigned) // NOLINT + UNSIGNED_ASSIGNMENT_OPERATOR(unsigned long) // NOLINT + UNSIGNED_ASSIGNMENT_OPERATOR(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const boost::int128_type& v) noexcept { *this = uint128(v); return *this; } + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const boost::uint128_type& v) noexcept { *this = uint128(v); return *this; } + #endif + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const trivial_uint128& v) noexcept { this->low = v.low; this->high = v.high; return *this; } + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const uint128&) noexcept; + + #undef SIGNED_ASSIGNMENT_OPERATOR + #undef UNSIGNED_ASSIGNMENT_OPERATOR + + // Conversion Operators + #define INTEGER_CONVERSION_OPERATOR(expr) explicit constexpr operator expr() const noexcept { return static_cast<expr>(low); } // NOLINT + #define FLOAT_CONVERSION_OPERATOR(expr) explicit operator expr() const noexcept { return std::ldexp(static_cast<expr>(high), 64) + static_cast<expr>(low); } // NOLINT + + INTEGER_CONVERSION_OPERATOR(char) // NOLINT + INTEGER_CONVERSION_OPERATOR(signed char) // NOLINT + INTEGER_CONVERSION_OPERATOR(short) // NOLINT + INTEGER_CONVERSION_OPERATOR(int) // NOLINT + INTEGER_CONVERSION_OPERATOR(long) // NOLINT + INTEGER_CONVERSION_OPERATOR(long long) // NOLINT + INTEGER_CONVERSION_OPERATOR(unsigned char) // NOLINT + INTEGER_CONVERSION_OPERATOR(unsigned short) // NOLINT + INTEGER_CONVERSION_OPERATOR(unsigned) // NOLINT + INTEGER_CONVERSION_OPERATOR(unsigned long) // NOLINT + INTEGER_CONVERSION_OPERATOR(unsigned long long) // NOLINT + + explicit constexpr operator bool() const noexcept { return high || low; } + + #ifdef BOOST_CHARCONV_HAS_INT128 + explicit constexpr operator boost::int128_type() const noexcept { return (static_cast<boost::int128_type>(high) << 64) + low; } + explicit constexpr operator boost::uint128_type() const noexcept { return (static_cast<boost::uint128_type>(high) << 64) + low; } + #endif + + FLOAT_CONVERSION_OPERATOR(float) // NOLINT + FLOAT_CONVERSION_OPERATOR(double) // NOLINT + FLOAT_CONVERSION_OPERATOR(long double) // NOLINT + + #undef INTEGER_CONVERSION_OPERATOR + #undef FLOAT_CONVERSION_OPERATOR + + // Unary Operators + constexpr friend uint128 operator-(uint128 val) noexcept; + constexpr friend uint128 operator+(uint128 val) noexcept; + + // Comparison Operators + + // Equality + #define INTEGER_OPERATOR_EQUAL(expr) constexpr friend bool operator==(uint128 lhs, expr rhs) noexcept { return lhs.high == 0 && rhs >= 0 && lhs.low == static_cast<std::uint64_t>(rhs); } // NOLINT + #define UNSIGNED_INTEGER_OPERATOR_EQUAL(expr) constexpr friend bool operator==(uint128 lhs, expr rhs) noexcept { return lhs.high == 0 && lhs.low == static_cast<std::uint64_t>(rhs); } // NOLINT + + INTEGER_OPERATOR_EQUAL(char) // NOLINT + INTEGER_OPERATOR_EQUAL(signed char) // NOLINT + INTEGER_OPERATOR_EQUAL(short) // NOLINT + INTEGER_OPERATOR_EQUAL(int) // NOLINT + INTEGER_OPERATOR_EQUAL(long) // NOLINT + INTEGER_OPERATOR_EQUAL(long long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned char) // NOLINT + UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned short) // NOLINT + UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned) // NOLINT + UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + constexpr friend bool operator==(uint128 lhs, boost::int128_type rhs) noexcept { return lhs == uint128(rhs); } + constexpr friend bool operator==(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs == uint128(rhs); } + #endif + + constexpr friend bool operator==(uint128 lhs, uint128 rhs) noexcept; + + #undef INTEGER_OPERATOR_EQUAL + #undef UNSIGNED_INTEGER_OPERATOR_EQUAL + + // Inequality + #define INTEGER_OPERATOR_NOTEQUAL(expr) constexpr friend bool operator!=(uint128 lhs, expr rhs) noexcept { return !(lhs == rhs); } // NOLINT + + INTEGER_OPERATOR_NOTEQUAL(char) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(signed char) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(short) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(int) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(long) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(long long) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(unsigned char) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(unsigned short) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(unsigned) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(unsigned long) // NOLINT + INTEGER_OPERATOR_NOTEQUAL(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + constexpr friend bool operator!=(uint128 lhs, boost::int128_type rhs) noexcept { return !(lhs == rhs); } + constexpr friend bool operator!=(uint128 lhs, boost::uint128_type rhs) noexcept { return !(lhs == rhs); } + #endif + + constexpr friend bool operator!=(uint128 lhs, uint128 rhs) noexcept; + + #undef INTEGER_OPERATOR_NOTEQUAL + + // Less than + #define INTEGER_OPERATOR_LESS_THAN(expr) constexpr friend bool operator<(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && rhs > 0 && lhs.low < static_cast<std::uint64_t>(rhs); } // NOLINT + #define UNSIGNED_INTEGER_OPERATOR_LESS_THAN(expr) constexpr friend bool operator<(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && lhs.low < static_cast<std::uint64_t>(rhs); } // NOLINT + + INTEGER_OPERATOR_LESS_THAN(char) // NOLINT + INTEGER_OPERATOR_LESS_THAN(signed char) // NOLINT + INTEGER_OPERATOR_LESS_THAN(short) // NOLINT + INTEGER_OPERATOR_LESS_THAN(int) // NOLINT + INTEGER_OPERATOR_LESS_THAN(long) // NOLINT + INTEGER_OPERATOR_LESS_THAN(long long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned char) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned short) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, boost::int128_type rhs) noexcept { return lhs < uint128(rhs); } + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs < uint128(rhs); } + #endif + + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, uint128 rhs) noexcept; + + #undef INTEGER_OPERATOR_LESS_THAN + #undef UNSIGNED_INTEGER_OPERATOR_LESS_THAN + + // Less than or equal to + #define INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator<=(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && rhs >= 0 && lhs.low <= static_cast<std::uint64_t>(rhs); } // NOLINT + #define UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator<=(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && lhs.low <= static_cast<std::uint64_t>(rhs); } // NOLINT + + INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(char) // NOLINT + INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(signed char) // NOLINT + INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(short) // NOLINT + INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(int) // NOLINT + INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(long) // NOLINT + INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(long long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned char) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned short) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, boost::int128_type rhs) noexcept { return lhs <= uint128(rhs); } + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs <= uint128(rhs); } + #endif + + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, uint128 rhs) noexcept; + + #undef INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO + #undef UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO + + // Greater than + #define INTEGER_OPERATOR_GREATER_THAN(expr) constexpr friend bool operator>(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || rhs < 0 || lhs.low > static_cast<std::uint64_t>(rhs); } // NOLINT + #define UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(expr) constexpr friend bool operator>(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || lhs.low > static_cast<std::uint64_t>(rhs); } // NOLINT + + INTEGER_OPERATOR_GREATER_THAN(char) // NOLINT + INTEGER_OPERATOR_GREATER_THAN(signed char) // NOLINT + INTEGER_OPERATOR_GREATER_THAN(short) // NOLINT + INTEGER_OPERATOR_GREATER_THAN(int) // NOLINT + INTEGER_OPERATOR_GREATER_THAN(long) // NOLINT + INTEGER_OPERATOR_GREATER_THAN(long long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned char) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned short) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, boost::int128_type rhs) noexcept { return lhs > uint128(rhs); } + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs > uint128(rhs); } + #endif + + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, uint128 rhs) noexcept; + + #undef INTEGER_OPERATOR_GREATER_THAN + #undef UNSIGNED_INTEGER_OPERATOR_GREATER_THAN + + // Greater than or equal to + #define INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator>=(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || rhs < 0 || lhs.low >= static_cast<std::uint64_t>(rhs); } // NOLINT + #define UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator>=(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || lhs.low >= static_cast<std::uint64_t>(rhs); } // NOLINT + + INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(char) // NOLINT + INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(signed char) // NOLINT + INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(short) // NOLINT + INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(int) // NOLINT + INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(long) // NOLINT + INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(long long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned char) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned short) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned long) // NOLINT + UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, boost::int128_type rhs) noexcept { return lhs >= uint128(rhs); } + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs >= uint128(rhs); } + #endif + + BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, uint128 rhs) noexcept; + + #undef INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO + #undef UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO + + // Binary Operators + + // Not + constexpr friend uint128 operator~(uint128 v) noexcept; + + // Or + #define INTEGER_BINARY_OPERATOR_OR(expr) constexpr friend uint128 operator|(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low | static_cast<std::uint64_t>(rhs)}; } // NOLINT + + INTEGER_BINARY_OPERATOR_OR(char) // NOLINT + INTEGER_BINARY_OPERATOR_OR(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_OR(short) // NOLINT + INTEGER_BINARY_OPERATOR_OR(int) // NOLINT + INTEGER_BINARY_OPERATOR_OR(long) // NOLINT + INTEGER_BINARY_OPERATOR_OR(long long) // NOLINT + INTEGER_BINARY_OPERATOR_OR(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_OR(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_OR(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_OR(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_OR(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + constexpr friend uint128 operator|(uint128 lhs, boost::int128_type rhs) noexcept { return lhs | uint128(rhs); } + constexpr friend uint128 operator|(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs | uint128(rhs); } + #endif + + constexpr friend uint128 operator|(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator|=(uint128 v) noexcept; + + #undef INTEGER_BINARY_OPERATOR_OR + + // And + #define INTEGER_BINARY_OPERATOR_AND(expr) constexpr friend uint128 operator&(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low & static_cast<std::uint64_t>(rhs)}; } // NOLINT + + INTEGER_BINARY_OPERATOR_AND(char) // NOLINT + INTEGER_BINARY_OPERATOR_AND(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_AND(short) // NOLINT + INTEGER_BINARY_OPERATOR_AND(int) // NOLINT + INTEGER_BINARY_OPERATOR_AND(long) // NOLINT + INTEGER_BINARY_OPERATOR_AND(long long) // NOLINT + INTEGER_BINARY_OPERATOR_AND(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_AND(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_AND(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_AND(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_AND(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + constexpr friend uint128 operator&(uint128 lhs, boost::int128_type rhs) noexcept { return lhs & uint128(rhs); } + constexpr friend uint128 operator&(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs & uint128(rhs); } + #endif + + constexpr friend uint128 operator&(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator&=(uint128 v) noexcept; + + #undef INTEGER_BINARY_OPERATOR_AND + + // Xor + #define INTEGER_BINARY_OPERATOR_XOR(expr) constexpr friend uint128 operator^(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low ^ static_cast<std::uint64_t>(rhs)}; } // NOLINT + + INTEGER_BINARY_OPERATOR_XOR(char) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(short) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(int) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(long) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(long long) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_XOR(unsigned long long) // NOLINT + + #ifdef BOOST_CHARCONV_HAS_INT128 + constexpr friend uint128 operator^(uint128 lhs, boost::int128_type rhs) noexcept { return lhs ^ uint128(rhs); } + constexpr friend uint128 operator^(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs ^ uint128(rhs); } + #endif + + constexpr friend uint128 operator^(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator^=(uint128 v) noexcept; + + #undef INTEGER_BINARY_OPERATOR_XOR + + // Left shift + #define INTEGER_BINARY_OPERATOR_LEFT_SHIFT(expr) \ + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator<<(uint128 lhs, expr rhs) noexcept \ + { \ + if (rhs >= 64) \ + { \ + return {lhs.low << (rhs - 64), 0}; \ + } \ + else if (rhs == 0) \ + { \ + return lhs; \ + } \ + \ + return {(lhs.high << rhs) | (lhs.low >> (64 - rhs)), lhs.low << rhs}; \ + } // NOLINT + + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(char) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(short) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(int) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(long) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(long long) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned long long) // NOLINT + + #define INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(expr) \ + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator<<=(expr amount) noexcept \ + { \ + *this = *this << amount; \ + return *this; \ + } // NOLINT + + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(char) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(short) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(int) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(long) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(long long) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned long long) // NOLINT + + #undef INTEGER_BINARY_OPERATOR_LEFT_SHIFT + #undef INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT + + // Right Shift + #define INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(expr) \ + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator>>(uint128 lhs, expr amount) noexcept \ + { \ + if (amount >= 64) \ + { \ + return {0, lhs.high >> (amount - 64)}; \ + } \ + else if (amount == 0) \ + { \ + return lhs; \ + } \ + \ + return {lhs.high >> amount, (lhs.low >> amount) | (lhs.high << (64 - amount))}; \ + } // NOLINT + + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(char) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(short) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(int) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(long) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(long long) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned long long) // NOLINT + + #define INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(expr) \ + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator>>=(expr amount) noexcept \ + { \ + *this = *this >> amount; \ + return *this; \ + } // NOLINT + + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(char) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(signed char) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(short) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(int) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(long) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(long long) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned char) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned short) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned long) // NOLINT + INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned long long) // NOLINT + + #undef INTEGER_BINARY_OPERATOR_RIGHT_SHIFT + #undef INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT + + // Arithmetic operators (Add, sub, mul, div, mod) + inline uint128 &operator+=(std::uint64_t n) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator+(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator+=(uint128 v) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator++() noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 operator++(int) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator-(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator-=(uint128 v) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator--() noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 operator--(int) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator*(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator*=(uint128 v) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator/(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator/=(uint128 v) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator%(uint128 lhs, uint128 rhs) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator%=(uint128 v) noexcept; + +private: + BOOST_CHARCONV_CXX14_CONSTEXPR friend int high_bit(uint128 v) noexcept; + + BOOST_CHARCONV_CXX14_CONSTEXPR friend void + div_impl(uint128 lhs, uint128 rhs, uint128 "ient, uint128 &remainder) noexcept; +}; + +constexpr uint128 operator-(uint128 val) noexcept +{ + return {~val.high + static_cast<std::uint64_t>(val.low == 0), ~val.low + 1}; +} + +constexpr uint128 operator+(uint128 val) noexcept +{ + return val; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator=(const uint128& v) noexcept // NOLINT : User defined for older compilers +{ + low = v.low; + high = v.high; + return *this; +} + +constexpr bool operator==(uint128 lhs, uint128 rhs) noexcept +{ + return lhs.high == rhs.high && lhs.low == rhs.low; +} + +constexpr bool operator!=(uint128 lhs, uint128 rhs) noexcept +{ + return !(lhs == rhs); +} + +BOOST_CHARCONV_CXX14_CONSTEXPR bool operator<(uint128 lhs, uint128 rhs) noexcept +{ + if (lhs.high == rhs.high) + { + return lhs.low < rhs.low; + } + + return lhs.high < rhs.high; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR bool operator<=(uint128 lhs, uint128 rhs) noexcept +{ + return !(rhs < lhs); +} + +BOOST_CHARCONV_CXX14_CONSTEXPR bool operator>(uint128 lhs, uint128 rhs) noexcept +{ + return rhs < lhs; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR bool operator>=(uint128 lhs, uint128 rhs) noexcept +{ + return !(lhs < rhs); +} + +constexpr uint128 operator~(uint128 v) noexcept +{ + return {~v.high, ~v.low}; +} + +constexpr uint128 operator|(uint128 lhs, uint128 rhs) noexcept +{ + return {lhs.high | rhs.high, lhs.low | rhs.low}; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator|=(uint128 v) noexcept +{ + *this = *this | v; + return *this; +} + +constexpr uint128 operator&(uint128 lhs, uint128 rhs) noexcept +{ + return {lhs.high & rhs.high, lhs.low & rhs.low}; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator&=(uint128 v) noexcept +{ + *this = *this & v; + return *this; +} + +constexpr uint128 operator^(uint128 lhs, uint128 rhs) noexcept +{ + return {lhs.high ^ rhs.high, lhs.low ^ rhs.low}; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator^=(uint128 v) noexcept +{ + *this = *this ^ v; + return *this; +} + +inline uint128 &uint128::operator+=(std::uint64_t n) noexcept +{ + #if BOOST_CHARCONV_HAS_BUILTIN(__builtin_addcll) + + unsigned long long carry {}; + low = __builtin_addcll(low, n, 0, &carry); + high = __builtin_addcll(high, 0, carry, &carry); + + #elif BOOST_CHARCONV_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) + + unsigned long long result {}; + auto carry = __builtin_ia32_addcarryx_u64(0, low, n, &result); + low = result; + __builtin_ia32_addcarryx_u64(carry, high, 0, &result); + high = result; + + #elif defined(BOOST_MSVC) && defined(_M_X64) + + auto carry = _addcarry_u64(0, low, n, &low); + _addcarry_u64(carry, high, 0, &high); + + #else + + auto sum = low + n; + high += (sum < low ? 1 : 0); + low = sum; + + #endif + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator+(uint128 lhs, uint128 rhs) noexcept +{ + const uint128 temp = {lhs.high + rhs.high, lhs.low + rhs.low}; + + // Need to carry a bit into rhs + if (temp.low < lhs.low) + { + return {temp.high + 1, temp.low}; + } + + return temp; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator+=(uint128 v) noexcept +{ + *this = *this + v; + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator++() noexcept +{ + if (this->low == UINT64_MAX) + { + this->low = 0; + ++this->high; + } + else + { + ++this->low; + } + + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 uint128::operator++(int) noexcept +{ + return ++(*this); +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator-(uint128 lhs, uint128 rhs) noexcept +{ + const uint128 temp {lhs.high - rhs.high, lhs.low - rhs.low}; + + // Check for carry + if (lhs.low < rhs.low) + { + return {temp.high - 1, temp.low}; + } + + return temp; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator-=(uint128 v) noexcept +{ + *this = *this - v; + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator--() noexcept +{ + if (this->low == 0) + { + this->low = UINT64_MAX; + --this->high; + } + else // NOLINT + { + --this->low; + } + + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 uint128::operator--(int) noexcept +{ + return --(*this); +} +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator*(uint128 lhs, uint128 rhs) noexcept +{ + const auto a = static_cast<std::uint64_t>(lhs.low >> 32); + const auto b = static_cast<std::uint64_t>(lhs.low & UINT32_MAX); + const auto c = static_cast<std::uint64_t>(rhs.low >> 32); + const auto d = static_cast<std::uint64_t>(rhs.low & UINT32_MAX); + + uint128 result { lhs.high * rhs.low + lhs.low * rhs.high + a * c, b * d }; + result += uint128(a * d) << 32; + result += uint128(b * c) << 32; + return result; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator*=(uint128 v) noexcept +{ + *this = *this * v; + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR int high_bit(uint128 v) noexcept +{ + if (v.high != 0) + { + return 127 - boost::core::countl_zero(v.high); + } + else if (v.low != 0) + { + return 63 - boost::core::countl_zero(v.low); + } + + return 0; +} + +// See: https://stackoverflow.com/questions/5386377/division-without-using +BOOST_CHARCONV_CXX14_CONSTEXPR void div_impl(uint128 lhs, uint128 rhs, uint128& quotient, uint128& remainder) noexcept +{ + constexpr uint128 one {0, 1}; + + if (rhs > lhs) + { + quotient = 0U; + remainder = 0U; + } + else if (lhs == rhs) + { + quotient = 1U; + remainder = 0U; + } + + uint128 denom = rhs; + quotient = 0U; + + std::int32_t shift = high_bit(lhs) - high_bit(rhs); + if (shift < 0) + { + shift = 32 - shift; + } + denom <<= shift; + + for (int i = 0; i <= shift; ++i) + { + quotient <<= 1; + if (lhs >= denom) + { + lhs -= denom; + quotient |= one; + } + denom >>= 1; + } + + remainder = lhs; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator/(uint128 lhs, uint128 rhs) noexcept +{ + uint128 quotient {0, 0}; + uint128 remainder {0, 0}; + div_impl(lhs, rhs, quotient, remainder); + + return quotient; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator/=(uint128 v) noexcept +{ + *this = *this / v; + return *this; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator%(uint128 lhs, uint128 rhs) noexcept +{ + uint128 quotient {0, 0}; + uint128 remainder {0, 0}; + div_impl(lhs, rhs, quotient, remainder); + + return remainder; +} + +BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator%=(uint128 v) noexcept +{ + *this = *this % v; + return *this; +} + +static inline std::uint64_t umul64(std::uint32_t x, std::uint32_t y) noexcept +{ + // __emulu is not available on ARM https://learn.microsoft.com/en-us/cpp/intrinsics/emul-emulu?view=msvc-170 + #if defined(BOOST_CHARCONV_HAS_MSVC_32BIT_INTRINSICS) && !defined(_M_ARM) + + return __emulu(x, y); + + #else + + return x * static_cast<std::uint64_t>(y); + + #endif +} + +// Get 128-bit result of multiplication of two 64-bit unsigned integers. +BOOST_CHARCONV_SAFEBUFFERS inline uint128 umul128(std::uint64_t x, std::uint64_t y) noexcept +{ + #if defined(BOOST_CHARCONV_HAS_INT128) + + auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y); + return {static_cast<std::uint64_t>(result >> 64), static_cast<std::uint64_t>(result)}; + + // _umul128 is x64 only https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-170 + #elif defined(BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS) && !defined(_M_ARM64) + + unsigned long long high; + std::uint64_t low = _umul128(x, y, &high); + return {static_cast<std::uint64_t>(high), low}; + + // https://developer.arm.com/documentation/dui0802/a/A64-General-Instructions/UMULH + #elif defined(_M_ARM64) && !defined(__MINGW32__) + + std::uint64_t high = __umulh(x, y); + std::uint64_t low = x * y; + return {high, low}; + + #else + + auto a = static_cast<std::uint32_t>(x >> 32); + auto b = static_cast<std::uint32_t>(x); + auto c = static_cast<std::uint32_t>(y >> 32); + auto d = static_cast<std::uint32_t>(y); + + auto ac = umul64(a, c); + auto bc = umul64(b, c); + auto ad = umul64(a, d); + auto bd = umul64(b, d); + + auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc); + + return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), + (intermediate << 32) + static_cast<std::uint32_t>(bd)}; + + #endif +} + +BOOST_CHARCONV_SAFEBUFFERS inline std::uint64_t umul128_upper64(std::uint64_t x, std::uint64_t y) noexcept +{ + #if defined(BOOST_CHARCONV_HAS_INT128) + + auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y); + return static_cast<std::uint64_t>(result >> 64); + + #elif defined(BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS) + + return __umulh(x, y); + + #else + + auto a = static_cast<std::uint32_t>(x >> 32); + auto b = static_cast<std::uint32_t>(x); + auto c = static_cast<std::uint32_t>(y >> 32); + auto d = static_cast<std::uint32_t>(y); + + auto ac = umul64(a, c); + auto bc = umul64(b, c); + auto ad = umul64(a, d); + auto bd = umul64(b, d); + + auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc); + + return ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32); + + #endif +} + +// Get upper 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit +// unsigned integer. +BOOST_CHARCONV_SAFEBUFFERS inline uint128 umul192_upper128(std::uint64_t x, uint128 y) noexcept +{ + auto r = umul128(x, y.high); + r += umul128_upper64(x, y.low); + return r; +} + +// Get upper 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit +// unsigned integer. +inline std::uint64_t umul96_upper64(std::uint32_t x, std::uint64_t y) noexcept +{ + #if defined(BOOST_CHARCONV_HAS_INT128) || defined(BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS) + + return umul128_upper64(static_cast<std::uint64_t>(x) << 32, y); + + #else + + auto yh = static_cast<std::uint32_t>(y >> 32); + auto yl = static_cast<std::uint32_t>(y); + + auto xyh = umul64(x, yh); + auto xyl = umul64(x, yl); + + return xyh + (xyl >> 32); + + #endif +} + +// Get lower 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit +// unsigned integer. +BOOST_CHARCONV_SAFEBUFFERS inline uint128 umul192_lower128(std::uint64_t x, uint128 y) noexcept +{ + auto high = x * y.high; + auto highlow = umul128(x, y.low); + return {high + highlow.high, highlow.low}; +} + +// Get lower 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit +// unsigned integer. +inline std::uint64_t umul96_lower64(std::uint32_t x, std::uint64_t y) noexcept +{ + return x * y; +} + +}}} // Namespaces + +// Non-standard libraries may add specializations for library-provided types +namespace std { + +template <> +struct numeric_limits<boost::charconv::detail::uint128> +{ + // Member constants + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true; + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_signed = false; + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_integer = true; + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_exact = true; + BOOST_ATTRIBUTE_UNUSED static constexpr bool has_infinity = false; + BOOST_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = false; + BOOST_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = false; + BOOST_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_toward_zero; + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false; + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true; + BOOST_ATTRIBUTE_UNUSED static constexpr bool is_modulo = true; + BOOST_ATTRIBUTE_UNUSED static constexpr int digits = 128; + BOOST_ATTRIBUTE_UNUSED static constexpr int digits10 = 38; + BOOST_ATTRIBUTE_UNUSED static constexpr int max_digits10 = 0; + BOOST_ATTRIBUTE_UNUSED static constexpr int radix = 2; + BOOST_ATTRIBUTE_UNUSED static constexpr int min_exponent = 0; + BOOST_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = 0; + BOOST_ATTRIBUTE_UNUSED static constexpr int max_exponent = 0; + BOOST_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = 0; + BOOST_ATTRIBUTE_UNUSED static constexpr bool traps = std::numeric_limits<std::uint64_t>::traps; + BOOST_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = false; + + // Member functions + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 (min)() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 lowest() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 (max)() { return {UINT64_MAX, UINT64_MAX}; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 epsilon() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 round_error() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 infinity() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 quiet_NaN() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 signaling_NaN() { return 0; } + BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 (denorm_min)() { return 0; } +}; + +} // Namespace std + +#endif // BOOST_CHARCONV_DETAIL_EMULATED128_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fallback_routines.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fallback_routines.hpp new file mode 100644 index 00000000000..94f87b82b9e --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fallback_routines.hpp @@ -0,0 +1,245 @@ +// Copyright 2024 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_FALLBACK_ROUTINES_HPP +#define BOOST_FALLBACK_ROUTINES_HPP + +#include <boost/charconv/detail/to_chars_integer_impl.hpp> +#include <boost/charconv/detail/dragonbox/floff.hpp> +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/from_chars_result.hpp> +#include <boost/charconv/chars_format.hpp> +#include <system_error> +#include <type_traits> +#include <locale> +#include <clocale> +#include <cstring> +#include <cstdio> + +namespace boost { +namespace charconv { +namespace detail { + +template <typename T> +inline int print_val(char* first, std::size_t size, char* format, T value) noexcept +{ + return std::snprintf(first, size, format, value); +} + +template <typename T> +to_chars_result to_chars_printf_impl(char* first, char* last, T value, chars_format fmt, int precision) +{ + // v % + . + num_digits(INT_MAX) + specifier + null terminator + // 1 + 1 + 10 + 1 + 1 + char format[14] {}; + std::memcpy(format, "%", 1); // NOLINT : No null terminator is purposeful + std::size_t pos = 1; + + // precision of -1 is unspecified + if (precision != -1 && fmt != chars_format::fixed) + { + format[pos] = '.'; + ++pos; + const auto unsigned_precision = static_cast<std::uint32_t>(precision); + if (unsigned_precision < 10) + { + boost::charconv::detail::print_1_digit(unsigned_precision, format + pos); + ++pos; + } + else if (unsigned_precision < 100) + { + boost::charconv::detail::print_2_digits(unsigned_precision, format + pos); + pos += 2; + } + else + { + boost::charconv::detail::to_chars_int(format + pos, format + sizeof(format), precision); + pos = std::strlen(format); + } + } + else if (fmt == chars_format::fixed) + { + // Force 0 decimal places + std::memcpy(format + pos, ".0", 2); // NOLINT : No null terminator is purposeful + pos += 2; + } + + // Add the type identifier + BOOST_CHARCONV_IF_CONSTEXPR (std::is_same<T, long double>::value) + { + format[pos] = 'L'; + ++pos; + } + + // Add the format character + switch (fmt) + { + case boost::charconv::chars_format::general: + format[pos] = 'g'; + break; + + case boost::charconv::chars_format::scientific: + format[pos] = 'e'; + break; + + case boost::charconv::chars_format::fixed: + format[pos] = 'f'; + break; + + case boost::charconv::chars_format::hex: + format[pos] = 'a'; + break; + } + + const auto rv = print_val(first, static_cast<std::size_t>(last - first), format, value); + + if (rv <= 0) + { + return {last, static_cast<std::errc>(errno)}; + } + + return {first + rv, std::errc()}; +} + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4244) // Implict converion when BOOST_IF_CONSTEXPR expands to if +#elif defined(__GNUC__) && __GNUC__ >= 5 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +# pragma GCC diagnostic ignored "-Wfloat-conversion" +#elif defined(__clang__) && __clang_major__ > 7 +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wimplicit-float-conversion" +#elif defined(__clang__) && __clang_major__ <= 7 +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wconversion" +#endif + +// We know that the string is in the "C" locale because it would have previously passed through our parser. +// Convert the string into the current locale so that the strto* family of functions +// works correctly for the given locale. +// +// We are operating on our own copy of the buffer, so we are free to modify it. +inline void convert_string_locale(char* buffer) noexcept +{ + const auto locale_decimal_point = *std::localeconv()->decimal_point; + if (locale_decimal_point != '.') + { + auto p = std::strchr(buffer, '.'); + if (p != nullptr) + { + *p = locale_decimal_point; + } + } +} + +template <typename T> +from_chars_result from_chars_strtod_impl(const char* first, const char* last, T& value, char* buffer) noexcept +{ + // For strto(f/d) + // Floating point value corresponding to the contents of str on success. + // If the converted value falls out of range of corresponding return type, range error occurs and HUGE_VAL, HUGE_VALF or HUGE_VALL is returned. + // If no conversion can be performed, 0 is returned and *str_end is set to str. + + std::memcpy(buffer, first, static_cast<std::size_t>(last - first)); + buffer[last - first] = '\0'; + convert_string_locale(buffer); + + char* str_end; + T return_value {}; + from_chars_result r {nullptr, std::errc()}; + + BOOST_IF_CONSTEXPR (std::is_same<T, float>::value) + { + return_value = std::strtof(buffer, &str_end); + + #ifndef __INTEL_LLVM_COMPILER + if (return_value == HUGE_VALF) + #else + if (return_value >= (std::numeric_limits<T>::max)()) + #endif + { + r = {last, std::errc::result_out_of_range}; + } + } + else BOOST_IF_CONSTEXPR (std::is_same<T, double>::value) + { + return_value = std::strtod(buffer, &str_end); + + #ifndef __INTEL_LLVM_COMPILER + if (return_value == HUGE_VAL) + #else + if (return_value >= (std::numeric_limits<T>::max)()) + #endif + { + r = {last, std::errc::result_out_of_range}; + } + } + else BOOST_IF_CONSTEXPR (std::is_same<T, long double>::value) + { + return_value = std::strtold(buffer, &str_end); + + #ifndef __INTEL_LLVM_COMPILER + if (return_value == HUGE_VALL) + #else + if (return_value >= (std::numeric_limits<T>::max)()) + #endif + { + r = {last, std::errc::result_out_of_range}; + } + } + + // Since this is a fallback routine we are safe to check for 0 + if (return_value == 0 && str_end == last) + { + r = {first, std::errc::result_out_of_range}; + } + + if (r) + { + value = return_value; + r = {first + (str_end - buffer), std::errc()}; + } + + return r; +} + +template <typename T> +inline from_chars_result from_chars_strtod(const char* first, const char* last, T& value) noexcept +{ + if (last - first < 1024) + { + char buffer[1024]; + return from_chars_strtod_impl(first, last, value, buffer); + } + + // If the string to be parsed does not fit into the 1024 byte static buffer than we have to allocate a buffer. + // malloc is used here because it does not throw on allocation failure. + + char* buffer = static_cast<char*>(std::malloc(static_cast<std::size_t>(last - first + 1))); + if (buffer == nullptr) + { + return {first, std::errc::not_enough_memory}; + } + + auto r = from_chars_strtod_impl(first, last, value, buffer); + std::free(buffer); + + return r; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#elif defined(__GNUC__) && __GNUC__ >= 5 +# pragma GCC diagnostic pop +#elif defined(__clang__) +# pragma clang diagnostic pop +#endif + +} //namespace detail +} //namespace charconv +} //namespace boost + +#endif //BOOST_FALLBACK_ROUTINES_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/ascii_number.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/ascii_number.hpp new file mode 100644 index 00000000000..159a7661d02 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/ascii_number.hpp @@ -0,0 +1,288 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP + +#include <boost/charconv/detail/fast_float/float_common.hpp> +#include <cctype> +#include <cstdint> +#include <cstring> +#include <iterator> + +namespace boost { namespace charconv { namespace detail { namespace fast_float { + +// Next function can be micro-optimized, but compilers are entirely +// able to optimize it well. +template <typename UC> +BOOST_FORCEINLINE constexpr bool is_integer(UC c) noexcept { + return !(c > UC('9') || c < UC('0')); +} + +BOOST_FORCEINLINE 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; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +uint64_t read_u64(const char *chars) { + if (cpp20_and_in_constexpr()) { + uint64_t val = 0; + for(int i = 0; i < 8; ++i) { + val |= uint64_t(*chars) << (i*8); + ++chars; + } + return val; + } + uint64_t val; + ::memcpy(&val, chars, sizeof(uint64_t)); +#if BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN == 1 + // Need to read as-if the number was in little-endian order. + val = byteswap(val); +#endif + return val; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void write_u64(uint8_t *chars, uint64_t val) { + if (cpp20_and_in_constexpr()) { + for(int i = 0; i < 8; ++i) { + *chars = uint8_t(val); + val >>= 8; + ++chars; + } + return; + } +#if BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN == 1 + // Need to read as-if the number was in little-endian order. + val = byteswap(val); +#endif + ::memcpy(chars, &val, sizeof(uint64_t)); +} + +// credit @aqrit +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +uint32_t parse_eight_digits_unrolled(uint64_t val) { + constexpr uint64_t mask = 0x000000FF000000FF; + constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) + constexpr uint64_t 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); +} + +BOOST_FORCEINLINE constexpr +uint32_t parse_eight_digits_unrolled(const char16_t *) noexcept { + return 0; +} + +BOOST_FORCEINLINE constexpr +uint32_t parse_eight_digits_unrolled(const char32_t *) noexcept { + return 0; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +uint32_t parse_eight_digits_unrolled(const char *chars) noexcept { + return parse_eight_digits_unrolled(read_u64(chars)); +} + +// credit @aqrit +BOOST_FORCEINLINE constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept { + return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & 0x8080808080808080)); +} + +BOOST_FORCEINLINE constexpr +bool is_made_of_eight_digits_fast(const char16_t *) noexcept { + return false; +} + +BOOST_FORCEINLINE constexpr +bool is_made_of_eight_digits_fast(const char32_t *) noexcept { + return false; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool is_made_of_eight_digits_fast(const char *chars) noexcept { + return is_made_of_eight_digits_fast(read_u64(chars)); +} + +template <typename UC> +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<const UC> integer{}; // non-nullable + span<const UC> fraction{}; // nullable +}; +using byte_span = span<char>; +using parsed_number_string = parsed_number_string_t<char>; +// Assuming that you use no more than 19 digits, this will +// parse an ASCII string. +template <typename UC> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept { + chars_format const fmt = options.format; + UC const decimal_point = options.decimal_point; + + parsed_number_string_t<UC> answer; + answer.valid = false; + answer.too_many_digits = false; + answer.negative = (*p == UC('-')); +#ifdef BOOST_CHARCONV_FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default + if ((*p == UC('-')) || (*p == UC('+'))) +#else + if (*p == UC('-')) // C++17 20.19.3.(7.1) explicitly forbids '+' sign here +#endif + { + ++p; + if (p == pend) { + return answer; + } + if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot + return answer; + } + } + 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<const UC>(start_digits, size_t(digit_count)); + int64_t exponent = 0; + if ((p != pend) && (*p == 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. + if (std::is_same<UC,char>::value) { + while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) { + i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok + p += 8; + } + } + 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<const UC>(before, size_t(p - before)); + digit_count -= exponent; + } + // we must have encountered at least one integer! + if (digit_count == 0) { + return answer; + } + int64_t exp_number = 0; // explicit exponential part + if ((static_cast<unsigned>(fmt) & static_cast<unsigned>(chars_format::scientific)) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) { + UC const * location_of_e = 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(!(static_cast<unsigned>(fmt) & static_cast<unsigned>(chars_format::fixed))) { + // We are in error. + return answer; + } + // 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((static_cast<unsigned>(fmt) & static_cast<unsigned>(chars_format::scientific)) && + !(static_cast<unsigned>(fmt) & static_cast<unsigned>(chars_format::fixed))) + { + return answer; + } + } + 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 check 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(); + constexpr uint64_t 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 integers + 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; +} + +}}}} // namespace s + +#endif diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/bigint.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/bigint.hpp new file mode 100644 index 00000000000..fd98590cd79 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/bigint.hpp @@ -0,0 +1,623 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_BIGINT_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_BIGINT_HPP + +#include <boost/charconv/detail/fast_float/float_common.hpp> +#include <algorithm> +#include <cstdint> +#include <climits> +#include <cstring> + +namespace boost { namespace charconv { namespace detail { 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(BOOST_CHARCONV_FASTFLOAT_64BIT) && !defined(__sparc) +#define BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB 1 +typedef uint64_t limb; +constexpr size_t limb_bits = 64; +#else +#define BOOST_CHARCONV_FASTFLOAT_32BIT_LIMB +typedef uint32_t limb; +constexpr size_t limb_bits = 32; +#endif + +typedef span<limb> 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 <uint16_t size> +struct stackvec { + limb data[size]; + // we never need more than 150 limbs + uint16_t length{0}; + + stackvec() = default; + stackvec(const stackvec &) = delete; + stackvec &operator=(const stackvec &) = delete; + stackvec(stackvec &&) = delete; + stackvec &operator=(stackvec &&other) = delete; + + // create stack vector from existing limb span. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) { + BOOST_CHARCONV_FASTFLOAT_ASSERT(try_extend(s)); + } + + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 limb& operator[](size_t index) noexcept { + BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length); + return data[index]; + } + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 const limb& operator[](size_t index) const noexcept { + BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length); + return data[index]; + } + // index from the end of the container + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 const limb& rindex(size_t index) const noexcept { + BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length); + size_t rindex = length - index - 1; + return data[rindex]; + } + + // set the length, without bounds checking. + BOOST_CHARCONV_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 + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { + data[length] = value; + length++; + } + // append item to vector, returning if item was added + BOOST_CHARCONV_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 + BOOST_CHARCONV_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 + BOOST_CHARCONV_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. + BOOST_CHARCONV_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. + BOOST_CHARCONV_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. + BOOST_CHARCONV_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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 void normalize() noexcept { + while (len() > 0 && rindex(0) == 0) { + length--; + } + } +}; + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +uint64_t empty_hi64(bool& truncated) noexcept { + truncated = false; + return 0; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +uint64_t uint64_hi64(uint64_t r0, bool& truncated) noexcept { + truncated = false; + int shl = leading_zeroes(r0); + return r0 << shl; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_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); + } +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +uint64_t uint32_hi64(uint32_t r0, bool& truncated) noexcept { + return uint64_hi64(r0, truncated); +} + +BOOST_FORCEINLINE BOOST_CHARCONV_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); +} + +BOOST_FORCEINLINE BOOST_CHARCONV_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. +BOOST_FORCEINLINE BOOST_CHARCONV_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. +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +limb scalar_mul(limb x, limb y, limb& carry) noexcept { +#ifdef BOOST_CHARCONV_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 <uint16_t size> +inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool small_add_from(stackvec<size>& 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) { + BOOST_CHARCONV_FASTFLOAT_TRY(vec.try_push(carry)); + } + return true; +} + +// add scalar value to bigint. +template <uint16_t size> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool small_add(stackvec<size>& vec, limb y) noexcept { + return small_add_from(vec, y, 0); +} + +// multiply bigint by scalar value. +template <uint16_t size> +inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool small_mul(stackvec<size>& 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) { + BOOST_CHARCONV_FASTFLOAT_TRY(vec.try_push(carry)); + } + return true; +} + +// add bigint to bigint starting from index. +// used in grade school multiplication +template <uint16_t size> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool large_add_from(stackvec<size>& 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) { + BOOST_CHARCONV_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) { + BOOST_CHARCONV_FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start)); + } + return true; +} + +// add bigint to bigint. +template <uint16_t size> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool large_add_from(stackvec<size>& x, limb_span y) noexcept { + return large_add_from(x, y, 0); +} + +// grade-school multiplication algorithm +template <uint16_t size> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool long_mul(stackvec<size>& x, limb_span y) noexcept { + limb_span xs = limb_span(x.data, x.len()); + stackvec<size> z(xs); + limb_span zs = limb_span(z.data, z.len()); + + if (y.len() != 0) { + limb y0 = y[0]; + BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(x, y0)); + for (size_t index = 1; index < y.len(); index++) { + limb yi = y[index]; + stackvec<size> zi; + if (yi != 0) { + // re-use the same buffer throughout + zi.set_len(0); + BOOST_CHARCONV_FASTFLOAT_TRY(zi.try_extend(zs)); + BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(zi, yi)); + limb_span zis = limb_span(zi.data, zi.len()); + BOOST_CHARCONV_FASTFLOAT_TRY(large_add_from(x, zis, index)); + } + } + } + + x.normalize(); + return true; +} + +// grade-school multiplication algorithm +template <uint16_t size> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool large_mul(stackvec<size>& x, limb_span y) noexcept { + if (y.len() == 1) { + BOOST_CHARCONV_FASTFLOAT_TRY(small_mul(x, y[0])); + } else { + BOOST_CHARCONV_FASTFLOAT_TRY(long_mul(x, y)); + } + return true; +} + +template <typename = void> +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 BOOST_CHARCONV_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 +}; + +template <typename T> +constexpr uint32_t pow5_tables<T>::large_step; + +template <typename T> +constexpr uint64_t pow5_tables<T>::small_power_of_5[]; + +template <typename T> +constexpr limb pow5_tables<T>::large_power_of_5[]; + +// 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<bigint_limbs> vec; + + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bigint(): vec() {} + bigint(const bigint &) = delete; + bigint &operator=(const bigint &) = delete; + bigint(bigint &&) = delete; + bigint &operator=(bigint &&other) = delete; + + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bigint(uint64_t value): vec() { +#ifdef BOOST_CHARCONV_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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool& truncated) const noexcept { +#ifdef BOOST_CHARCONV_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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 int compare(const bigint& 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. + BOOST_CHARCONV_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 + BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(n != 0); + BOOST_CHARCONV_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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept { + BOOST_CHARCONV_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; + const limb* 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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { + size_t rem = n % limb_bits; + size_t div = n / limb_bits; + if (rem != 0) { + BOOST_CHARCONV_FASTFLOAT_TRY(shl_bits(rem)); + } + if (div != 0) { + BOOST_CHARCONV_FASTFLOAT_TRY(shl_limbs(div)); + } + return true; + } + + // get the number of leading zeros in the bigint. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept { + if (vec.is_empty()) { + return 0; + } else { +#ifdef BOOST_CHARCONV_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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept { + int lz = ctlz(); + return int(limb_bits * vec.len()) - lz; + } + + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { + return small_mul(vec, y); + } + + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { + return small_add(vec, y); + } + + // multiply as if by 2 raised to a power. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { + return shl(exp); + } + + // multiply as if by 5 raised to a power. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept { + // multiply by a power of 5 + constexpr 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) { + BOOST_CHARCONV_FASTFLOAT_TRY(large_mul(vec, large)); + exp -= large_step; + } +#ifdef BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB + constexpr uint32_t small_step = 27; + constexpr limb max_native = 7450580596923828125UL; +#else + constexpr uint32_t small_step = 13; + constexpr limb max_native = 1220703125U; +#endif + while (exp >= small_step) { + BOOST_CHARCONV_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 + BOOST_CHARCONV_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. + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept { + BOOST_CHARCONV_FASTFLOAT_TRY(pow5(exp)); + return pow2(exp); + } +}; + +}}}} // namespace fast_float + +#endif diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/constexpr_feature_detect.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/constexpr_feature_detect.hpp new file mode 100644 index 00000000000..1ac1e4aabf5 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/constexpr_feature_detect.hpp @@ -0,0 +1,47 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_CONSTEXPR_FEATURE_DETECT_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_CONSTEXPR_FEATURE_DETECT_HPP + +#ifdef __has_include +#if __has_include(<version>) +#include <version> +#endif +#endif + +// Testing for https://wg21.link/N3652, adopted in C++14 +#if __cpp_constexpr >= 201304 +#define BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 constexpr +#else +#define BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +#endif + +#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L +#define BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST 1 +#else +#define BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST 0 +#endif + +#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L +#define BOOST_CHARCONV_FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 +#else +#define BOOST_CHARCONV_FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 +#endif + +// Testing for relevant C++20 constexpr library features +#if BOOST_CHARCONV_FASTFLOAT_HAS_IS_CONSTANT_EVALUATED \ + && BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST \ + && __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/ +#define BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 constexpr +#define BOOST_CHARCONV_FASTFLOAT_IS_CONSTEXPR 1 +#else +#define BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +#define BOOST_CHARCONV_FASTFLOAT_IS_CONSTEXPR 0 +#endif + +#endif // BOOST_CHARCONV_FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/decimal_to_binary.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/decimal_to_binary.hpp new file mode 100644 index 00000000000..4a76a6eeb69 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/decimal_to_binary.hpp @@ -0,0 +1,196 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_DECIMAL_TO_BINARY_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_DECIMAL_TO_BINARY_HPP + +#include <boost/charconv/detail/fast_float/float_common.hpp> +#include <boost/charconv/detail/fast_float/fast_table.hpp> +#include <cfloat> +#include <cinttypes> +#include <cmath> +#include <cstdint> +#include <cstdlib> +#include <cstring> + +namespace boost { namespace charconv { namespace detail { 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 <int bit_precision> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +value128 compute_product_approximation(int64_t q, uint64_t w) { + const int 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 BOOST_FORCEINLINE 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 <typename binary> +BOOST_FORCEINLINE BOOST_CHARCONV_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 <typename binary> +BOOST_FORCEINLINE BOOST_CHARCONV_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<binary::mantissa_explicit_bits() + 3>(q, w); + return compute_error_scaled<binary>(q, product.high, lz); +} + +// w * 10 ** q +// The returned value should be a valid ieee64 number that simply need 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 <typename binary> +BOOST_FORCEINLINE BOOST_CHARCONV_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<binary::mantissa_explicit_bits() + 3>(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); + + answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3); + + 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. + 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 << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) == 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/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/digit_comparison.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/digit_comparison.hpp new file mode 100644 index 00000000000..231279410a2 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/digit_comparison.hpp @@ -0,0 +1,442 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_DIGIT_COMPARISON_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_DIGIT_COMPARISON_HPP + +#include <boost/charconv/detail/fast_float/float_common.hpp> +#include <boost/charconv/detail/fast_float/bigint.hpp> +#include <boost/charconv/detail/fast_float/ascii_number.hpp> +#include <algorithm> +#include <cstdint> +#include <cstring> +#include <iterator> + +namespace boost { namespace charconv { namespace detail { 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. +template <typename UC> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept { + uint64_t mantissa = num.mantissa; + int32_t exponent = int32_t(num.exponent); + 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 <typename T> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +adjusted_mantissa to_extended(T value) noexcept { + using equiv_uint = typename binary_format<T>::equiv_uint; + constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask(); + constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask(); + constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask(); + + adjusted_mantissa am; + int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent(); + equiv_uint bits; +#if BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST + bits = std::bit_cast<equiv_uint>(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<T>::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 <typename T> +BOOST_FORCEINLINE BOOST_CHARCONV_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 <typename T, typename callback> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +void round(adjusted_mantissa& am, callback cb) noexcept { + int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1; + if (-am.power2 >= mantissa_shift) { + // have a denormal float + int32_t shift = -am.power2 + 1; + cb(am, std::min<int32_t>(shift, 64)); + // check for round-up: if rounding-nearest carried us to the hidden bit. + am.power2 = (am.mantissa < (uint64_t(1) << binary_format<T>::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<T>::mantissa_explicit_bits())) { + am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits()); + am.power2++; + } + + // check for infinite: we could have carried to an infinite power + am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits()); + if (am.power2 >= binary_format<T>::infinite_power()) { + am.power2 = binary_format<T>::infinite_power(); + am.mantissa = 0; + } +} + +template <typename callback> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +void round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) noexcept { + const uint64_t mask + = (shift == 64) + ? UINT64_MAX + : (uint64_t(1) << shift) - 1; + const uint64_t 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)); +} + +BOOST_FORCEINLINE BOOST_CHARCONV_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 <typename UC> +BOOST_FORCEINLINE BOOST_CHARCONV_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<UC>()) { + ::memcpy(&val, first, sizeof(uint64_t)); + if (val != int_cmp_zeros<UC>()) { + break; + } + first += int_cmp_len<UC>(); + } + while (first != last) { + if (*first != UC('0')) { + break; + } + first++; + } +} + +// determine if any non-zero digits were truncated. +// all characters must be valid digits. +template <typename UC> +BOOST_FORCEINLINE BOOST_CHARCONV_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<UC>()) { + ::memcpy(&val, first, sizeof(uint64_t)); + if (val != int_cmp_zeros<UC>()) { + return true; + } + first += int_cmp_len<UC>(); + } + while (first != last) { + if (*first != UC('0')) { + return true; + } + ++first; + } + return false; +} +template <typename UC> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +bool is_truncated(span<const UC> s) noexcept { + return is_truncated(s.ptr, s.ptr + s.len()); +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void parse_eight_digits(const char16_t*& , limb& , size_t& , size_t& ) noexcept { + // currently unused +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void parse_eight_digits(const char32_t*& , limb& , size_t& , size_t& ) noexcept { + // currently unused +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void parse_eight_digits(const char*& 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 <typename UC> +BOOST_FORCEINLINE BOOST_CHARCONV_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++; +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void add_native(bigint& big, limb power, limb value) noexcept { + big.mul(power); + big.add(value); +} + +BOOST_FORCEINLINE BOOST_CHARCONV_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 <typename UC> +inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void parse_mantissa(bigint& result, parsed_number_string_t<UC>& 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 BOOST_CHARCONV_FASTFLOAT_64BIT_LIMB + constexpr size_t step = 19; +#else + constexpr 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) { + if (std::is_same<UC,char>::value) { + 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) { + if (std::is_same<UC,char>::value) { + 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 <typename T> +inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept { + BOOST_CHARCONV_FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); + adjusted_mantissa answer; + bool truncated; + answer.mantissa = bigmant.hi64(truncated); + int bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent(); + answer.power2 = bigmant.bit_length() - 64 + bias; + + round<T>(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 <typename T> +inline BOOST_CHARCONV_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<T>(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) { + BOOST_CHARCONV_FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); + } + if (pow2_exp > 0) { + BOOST_CHARCONV_FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp))); + } else if (pow2_exp < 0) { + BOOST_CHARCONV_FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp))); + } + + // compare digits, and use it to director rounding + int ord = real_digits.compare(theor_digits); + adjusted_mantissa answer = am; + round<T>(answer, [ord](adjusted_mantissa& a, int32_t shift) { + round_nearest_tie_even(a, shift, [ord](bool is_odd, bool, bool) -> bool { + 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 <typename T, typename UC> +inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept { + // remove the invalid exponent bias + am.power2 -= invalid_am_bias; + + int32_t sci_exp = scientific_exponent(num); + size_t max_digits = binary_format<T>::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<T>(bigmant, exponent); + } else { + return negative_digit_comp<T>(bigmant, am, exponent); + } +} + +}}}} // namespace fast_float + +#endif diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/fast_float.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/fast_float.hpp new file mode 100644 index 00000000000..00bb6c52331 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/fast_float.hpp @@ -0,0 +1,48 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_FAST_FLOAT_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_FAST_FLOAT_HPP + +#include <boost/charconv/detail/fast_float/float_common.hpp> + +namespace boost { namespace charconv { namespace detail { namespace fast_float { +/** + * This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting + * a locale-independent 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<typename T, typename UC = char> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +from_chars_result_t<UC> 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. + */ +template<typename T, typename UC = char> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last, + T &value, parse_options_t<UC> options) noexcept; + +}}}} // namespace fast_float +#include <boost/charconv/detail/fast_float/parse_number.hpp> +#endif // BOOST_CHARCONV_FASTFLOAT_FAST_FLOAT_H diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/fast_table.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/fast_table.hpp new file mode 100644 index 00000000000..e08eb314562 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/fast_table.hpp @@ -0,0 +1,708 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_FAST_TABLE_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_FAST_TABLE_HPP + +#include <boost/charconv/detail/fast_float/float_common.hpp> +#include <cstdint> + +namespace boost { namespace charconv { namespace detail { 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 <class unused = void> +struct powers_template { + +constexpr static int smallest_power_of_five = binary_format<double>::smallest_power_of_ten(); +constexpr static int largest_power_of_five = binary_format<double>::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,}; +}; + +template <class unused> +constexpr uint64_t powers_template<unused>::power_of_five_128[number_of_entries]; + +using powers = powers_template<>; + +}}}} // namespace fast_float + +#endif diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/float_common.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/float_common.hpp new file mode 100644 index 00000000000..0b9d3aee584 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/float_common.hpp @@ -0,0 +1,628 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP + +#include <boost/charconv/detail/fast_float/constexpr_feature_detect.hpp> +#include <boost/charconv/detail/from_chars_result.hpp> +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/chars_format.hpp> +#include <cfloat> +#include <cstdint> +#include <cassert> +#include <cstring> +#include <type_traits> +#include <system_error> + +namespace boost { namespace charconv { namespace detail { namespace fast_float { + + +template <typename UC> +struct parse_options_t { + constexpr explicit parse_options_t(chars_format fmt = chars_format::general, + UC dot = UC('.')) + : format(fmt), decimal_point(dot) {} + + /** Which number formats are accepted */ + chars_format format; + /** The character used as decimal point */ + UC decimal_point; +}; +using parse_options = parse_options_t<char>; + +}}}} + +#if BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST +#include <bit> +#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__)) ) +#define BOOST_CHARCONV_FASTFLOAT_64BIT 1 +#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) \ + || defined(__arm__) || defined(_M_ARM) || defined(__ppc__) \ + || defined(__MINGW32__) || defined(__EMSCRIPTEN__)) +#define BOOST_CHARCONV_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 BOOST_CHARCONV_FASTFLOAT_32BIT 1 + #elif SIZE_MAX == 0xffffffffffffffff + #define BOOST_CHARCONV_FASTFLOAT_64BIT 1 + #else + #error Unknown platform (not 32-bit, not 64-bit?) + #endif +#endif + +#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) +#include <intrin.h> +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define BOOST_CHARCONV_FASTFLOAT_VISUAL_STUDIO 1 +#endif + +#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ +#define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#elif defined _WIN32 +#define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 +#else +#if defined(__APPLE__) || defined(__FreeBSD__) +#include <machine/endian.h> +#elif defined(sun) || defined(__sun) +#include <sys/byteorder.h> +#else +#ifdef __has_include +#if __has_include(<endian.h>) +#include <endian.h> +#endif //__has_include(<endian.h>) +#endif //__has_include +#endif +# +#ifndef __BYTE_ORDER__ +// safe choice +#define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 +#endif +# +#ifndef __ORDER_LITTLE_ENDIAN__ +// safe choice +#define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 +#endif +# +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 +#else +#define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 1 +#endif +#endif + +#ifndef BOOST_CHARCONV_FASTFLOAT_ASSERT +#define BOOST_CHARCONV_FASTFLOAT_ASSERT(x) { ((void)(x)); } +#endif + +#ifndef BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT +#define BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(x) { ((void)(x)); } +#endif + +// rust style `try!()` macro, or `?` operator +#define BOOST_CHARCONV_FASTFLOAT_TRY(x) { if (!(x)) return false; } + +namespace boost { namespace charconv { namespace detail { namespace fast_float { + +BOOST_FORCEINLINE constexpr bool cpp20_and_in_constexpr() { +#if BOOST_CHARCONV_FASTFLOAT_HAS_IS_CONSTANT_EVALUATED + return std::is_constant_evaluated(); +#else + return false; +#endif +} + +// Compares two ASCII strings in a case insensitive manner. +template <typename UC> +inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 bool +fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) { + char running_diff{0}; + for (size_t i = 0; i < length; ++i) { + running_diff |= (char(input1[i]) ^ char(input2[i])); + } + return (running_diff == 0) || (running_diff == 32); +} + +#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 <typename T> +struct span { + const T* ptr; + size_t length; + constexpr span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {} + constexpr span() : ptr(nullptr), length(0) {} + + constexpr size_t len() const noexcept { + return length; + } + + BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 const T& operator[](size_t index) const noexcept { + BOOST_CHARCONV_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++11 constexpr generic implementation of leading_zeroes */ +BOOST_FORCEINLINE constexpr +int leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { + return ( + ((input_num & uint64_t(0xffffffff00000000)) && (input_num >>= 32, last_bit |= 32)), + ((input_num & uint64_t( 0xffff0000)) && (input_num >>= 16, last_bit |= 16)), + ((input_num & uint64_t( 0xff00)) && (input_num >>= 8, last_bit |= 8)), + ((input_num & uint64_t( 0xf0)) && (input_num >>= 4, last_bit |= 4)), + ((input_num & uint64_t( 0xc)) && (input_num >>= 2, last_bit |= 2)), + ((input_num & uint64_t( 0x2)) && (input_num >>= 1, last_bit |= 1)), + 63 - last_bit + ); +} + +/* result might be undefined when input_num is zero */ +BOOST_FORCEINLINE BOOST_CHARCONV_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 BOOST_CHARCONV_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 +} + +// slow emulation routine for 32-bit +BOOST_FORCEINLINE constexpr uint64_t emulu(uint32_t x, uint32_t y) { + return x * static_cast<uint64_t>(y); +} + +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +uint64_t umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { + uint64_t ad = emulu(static_cast<uint32_t>(ab >> 32), static_cast<uint32_t>(cd)); + uint64_t bd = emulu(static_cast<uint32_t>(ab), static_cast<uint32_t>(cd)); + uint64_t adbc = ad + emulu(static_cast<uint32_t>(ab), static_cast<uint32_t>(cd >> 32)); + uint64_t adbc_carry = !!(adbc < ad); + uint64_t lo = bd + (adbc << 32); + *hi = emulu(static_cast<uint32_t>(ab >> 32), static_cast<uint32_t>(cd >> 32)) + (adbc >> 32) + + (adbc_carry << 32) + !!(lo < bd); + return lo; +} + +#ifdef BOOST_CHARCONV_FASTFLOAT_32BIT + +// slow emulation routine for 32-bit +#if !defined(__MINGW64__) +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { + return umul128_generic(ab, cd, hi); +} +#endif // !__MINGW64__ + +#endif // BOOST_CHARCONV_FASTFLOAT_32BIT + + +// compute 64-bit a*b +BOOST_FORCEINLINE BOOST_CHARCONV_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(BOOST_CHARCONV_FASTFLOAT_32BIT) || \ + (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64)) + unsigned long long high; + answer.low = _umul128(a, b, &high); // _umul128 not available on ARM64 + answer.high = static_cast<uint64_t>(high); +#elif defined(BOOST_CHARCONV_FASTFLOAT_64BIT) + __uint128_t r = (static_cast<__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==(const adjusted_mantissa &o) const { + return mantissa == o.mantissa && power2 == o.power2; + } + constexpr bool operator!=(const adjusted_mantissa &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<T>::max_mantissa +constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; + +template <typename T, typename U = void> +struct binary_format_lookup_tables; + +template <typename T> struct binary_format : binary_format_lookup_tables<T> { + using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type; + + static inline constexpr int mantissa_explicit_bits(); + static inline constexpr int minimum_exponent(); + static inline constexpr int infinite_power(); + static inline constexpr int sign_index(); + static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST + static inline constexpr int max_exponent_fast_path(); + static inline constexpr int max_exponent_round_to_even(); + static inline constexpr int min_exponent_round_to_even(); + static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); + static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST + static inline constexpr int largest_power_of_ten(); + static inline constexpr int smallest_power_of_ten(); + static inline constexpr T exact_power_of_ten(int64_t power); + static inline constexpr size_t max_digits(); + static inline constexpr equiv_uint exponent_mask(); + static inline constexpr equiv_uint mantissa_mask(); + static inline constexpr equiv_uint hidden_bit_mask(); +}; + +template <typename U> +struct binary_format_lookup_tables<double, U> { + 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. + // 0x10000000000000 == 1 << 53 + static constexpr std::uint64_t max_mantissa[] = { + UINT64_C(0x10000000000000), + UINT64_C(0x10000000000000) / UINT64_C(5), + UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555), + UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5))}; +}; + +template <typename U> +constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[]; + +template <typename U> +constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[]; + +template <typename U> +struct binary_format_lookup_tables<float, U> { + 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[] = { + UINT64_C(0x1000000), + UINT64_C(0x1000000) / UINT64_C(5), + UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x1000000) / (constant_55555), + UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5)), + UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), + UINT64_C(0x1000000) / (constant_55555 * constant_55555), + UINT64_C(0x1000000) / (constant_55555 * constant_55555 * UINT64_C(5))}; +}; + +template <typename U> +constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[]; + +template <typename U> +constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[]; + +template <> inline constexpr int binary_format<double>::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<float>::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<double>::mantissa_explicit_bits() { + return 52; +} +template <> inline constexpr int binary_format<float>::mantissa_explicit_bits() { + return 23; +} + +template <> inline constexpr int binary_format<double>::max_exponent_round_to_even() { + return 23; +} + +template <> inline constexpr int binary_format<float>::max_exponent_round_to_even() { + return 10; +} + +template <> inline constexpr int binary_format<double>::min_exponent_round_to_even() { + return -4; +} + +template <> inline constexpr int binary_format<float>::min_exponent_round_to_even() { + return -17; +} + +template <> inline constexpr int binary_format<double>::minimum_exponent() { + return -1023; +} +template <> inline constexpr int binary_format<float>::minimum_exponent() { + return -127; +} + +template <> inline constexpr int binary_format<double>::infinite_power() { + return 0x7FF; +} +template <> inline constexpr int binary_format<float>::infinite_power() { + return 0xFF; +} + +template <> inline constexpr int binary_format<double>::sign_index() { return 63; } +template <> inline constexpr int binary_format<float>::sign_index() { return 31; } + +template <> inline constexpr int binary_format<double>::max_exponent_fast_path() { + return 22; +} +template <> inline constexpr int binary_format<float>::max_exponent_fast_path() { + return 10; +} + +template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} +template <> inline constexpr uint64_t binary_format<double>::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<float>::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} +template <> inline constexpr uint64_t binary_format<float>::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<double>::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<float>::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<double>::largest_power_of_ten() { + return 308; +} +template <> +inline constexpr int binary_format<float>::largest_power_of_ten() { + return 38; +} + +template <> +inline constexpr int binary_format<double>::smallest_power_of_ten() { + return -342; +} +template <> +inline constexpr int binary_format<float>::smallest_power_of_ten() { + return -65; +} + +template <> inline constexpr size_t binary_format<double>::max_digits() { + return 769; +} +template <> inline constexpr size_t binary_format<float>::max_digits() { + return 114; +} + +template <> inline constexpr binary_format<float>::equiv_uint + binary_format<float>::exponent_mask() { + return 0x7F800000; +} +template <> inline constexpr binary_format<double>::equiv_uint + binary_format<double>::exponent_mask() { + return 0x7FF0000000000000; +} + +template <> inline constexpr binary_format<float>::equiv_uint + binary_format<float>::mantissa_mask() { + return 0x007FFFFF; +} +template <> inline constexpr binary_format<double>::equiv_uint + binary_format<double>::mantissa_mask() { + return 0x000FFFFFFFFFFFFF; +} + +template <> inline constexpr binary_format<float>::equiv_uint + binary_format<float>::hidden_bit_mask() { + return 0x00800000; +} +template <> inline constexpr binary_format<double>::equiv_uint + binary_format<double>::hidden_bit_mask() { + return 0x0010000000000000; +} + +template<typename T> +BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +void to_float(bool negative, adjusted_mantissa am, T &value) { + using uint = typename binary_format<T>::equiv_uint; + uint word = static_cast<uint>(am.mantissa); + word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits(); + word |= uint(negative) << binary_format<T>::sign_index(); +#if BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST + value = std::bit_cast<T>(word); +#else + ::memcpy(&value, &word, sizeof(T)); +#endif +} + +#ifdef BOOST_CHARCONV_FASTFLOAT_SKIP_WHITE_SPACE // disabled by default +template <typename = void> +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}; +}; + +template <typename T> +constexpr bool space_lut<T>::value[]; + +inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; } +#endif + +template<typename UC> +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<typename UC> +static constexpr int int_cmp_len() +{ + return sizeof(uint64_t) / sizeof(UC); +} +template<typename UC> +static constexpr UC const * str_const_nan() +{ + return nullptr; +} +template<> +constexpr char const * str_const_nan<char>() +{ + return "nan"; +} +template<> +constexpr wchar_t const * str_const_nan<wchar_t>() +{ + return L"nan"; +} +template<> +constexpr char16_t const * str_const_nan<char16_t>() +{ + return u"nan"; +} +template<> +constexpr char32_t const * str_const_nan<char32_t>() +{ + return U"nan"; +} +template<typename UC> +static constexpr UC const * str_const_inf() +{ + return nullptr; +} +template<> +constexpr char const * str_const_inf<char>() +{ + return "infinity"; +} +template<> +constexpr wchar_t const * str_const_inf<wchar_t>() +{ + return L"infinity"; +} +template<> +constexpr char16_t const * str_const_inf<char16_t>() +{ + return u"infinity"; +} +template<> +constexpr char32_t const * str_const_inf<char32_t>() +{ + return U"infinity"; +} + +}}}} // namespaces + +#endif diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/parse_number.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/parse_number.hpp new file mode 100644 index 00000000000..9f71d45c246 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/fast_float/parse_number.hpp @@ -0,0 +1,247 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// Derivative of: https://github.com/fastfloat/fast_float + +#ifndef BOOST_CHARCONV_DETAIL_FASTFLOAT_PARSE_NUMBER_HPP +#define BOOST_CHARCONV_DETAIL_FASTFLOAT_PARSE_NUMBER_HPP + +#include <boost/charconv/detail/fast_float/ascii_number.hpp> +#include <boost/charconv/detail/fast_float/decimal_to_binary.hpp> +#include <boost/charconv/detail/fast_float/digit_comparison.hpp> +#include <boost/charconv/detail/fast_float/float_common.hpp> + +#include <cmath> +#include <cstring> +#include <limits> +#include <system_error> + +namespace boost { namespace charconv { namespace detail { 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. + **/ + +#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +template <typename T, typename UC> +from_chars_result_t<UC> BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 +parse_infnan(UC const * first, UC const * last, T &value) noexcept { + from_chars_result_t<UC> answer{}; + answer.ptr = first; + answer.ec = std::errc(); // be optimistic + bool minusSign = false; + if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here + minusSign = true; + ++first; + } +#ifdef BOOST_CHARCONV_FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default + if (*first == UC('+')) { + ++first; + } +#endif + if (last - first >= 3) { + if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) { + answer.ptr = (first += 3); + value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::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_strncasecmp(first, str_const_inf<UC>(), 3)) { + if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) { + answer.ptr = first + 8; + } else { + answer.ptr = first + 3; + } + value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity(); + return answer; + } + } + answer.ec = std::errc::invalid_argument; + return answer; +} + +#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) +# pragma GCC diagnostic pop +#endif + +/** + * 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 + */ +BOOST_FORCEINLINE 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 <cfenv> + // return fegetround() == FE_TONEAREST; + // However, it is expected to be much faster than the fegetround() + // function call. + // + // The volatile keywoard 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<float>::min)(), any small + // value so that 1 + x should round to 1 would do (after accounting for excess + // precision, as in 387 instructions). + static volatile float fmin = (std::numeric_limits<float>::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 BOOST_CHARCONV_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 BOOST_CHARCONV_FASTFLOAT_VISUAL_STUDIO + # pragma warning(pop) + #elif defined(__clang__) + # pragma clang diagnostic pop + #elif defined(__GNUC__) + # pragma GCC diagnostic pop + #endif +} + +} // namespace detail + +template<typename T, typename UC> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +from_chars_result_t<UC> from_chars(UC const * first, UC const * last, + T &value, chars_format fmt /*= chars_format::general*/) noexcept { + return from_chars_advanced(first, last, value, parse_options_t<UC>{fmt}); +} + +template<typename T, typename UC> +BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 +from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last, + T &value, parse_options_t<UC> options) noexcept { + + static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported"); + static_assert (std::is_same<UC, char>::value || + std::is_same<UC, wchar_t>::value || + std::is_same<UC, char16_t>::value || + std::is_same<UC, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported"); + + from_chars_result_t<UC> answer; +#ifdef BOOST_CHARCONV_FASTFLOAT_SKIP_WHITE_SPACE // disabled by default + while ((first != last) && fast_float::is_space(uint8_t(*first))) { + first++; + } +#endif + if (first == last) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options); + if (!pns.valid) { + return detail::parse_infnan(first, last, value); + } + answer.ec = std::errc(); // be optimistic + answer.ptr = pns.lastmatch; + // 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<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && !pns.too_many_digits) { + // 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 (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) { + value = T(pns.mantissa); + if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); } + else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); } + if (pns.negative) { value = -value; } + return answer; + } + } 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 (pns.exponent >= 0 && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent)) { +#if defined(__clang__) + // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD + if(pns.mantissa == 0) { + value = pns.negative ? -0. : 0.; + return answer; + } +#endif + value = T(pns.mantissa) * binary_format<T>::exact_power_of_ten(pns.exponent); + if (pns.negative) { value = -value; } + return answer; + } + } + } + adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa); + if(pns.too_many_digits && am.power2 >= 0) { + if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) { + am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa); + } + } + // If we called compute_float<binary_format<T>>(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<T>(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<T>::infinite_power()) { + answer.ec = std::errc::result_out_of_range; + } + return answer; +} + +}}}} // namespace fast_float + +#endif diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/from_chars_integer_impl.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/from_chars_integer_impl.hpp new file mode 100644 index 00000000000..a069fd96892 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/from_chars_integer_impl.hpp @@ -0,0 +1,333 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP +#define BOOST_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP + +#include <boost/charconv/detail/apply_sign.hpp> +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/from_chars_result.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/detail/type_traits.hpp> +#include <boost/charconv/config.hpp> +#include <boost/config.hpp> +#include <system_error> +#include <type_traits> +#include <limits> +#include <cstdlib> +#include <cerrno> +#include <cstddef> +#include <cstdint> + +namespace boost { namespace charconv { namespace detail { + +static constexpr unsigned char uchar_values[] = + {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_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char"); + +static constexpr double log_2_table[] = +{ + 0.0, + 0.0, + 1.0, + 0.630929753571, + 0.5, + 0.430676558073, + 0.386852807235, + 0.356207187108, + 0.333333333333, + 0.315464876786, + 0.301029995664, + 0.289064826318, + 0.278942945651, + 0.270238154427, + 0.262649535037, + 0.255958024810, + 0.25, + 0.244650542118, + 0.239812466568, + 0.235408913367, + 0.231378213160, + 0.227670248697, + 0.224243824218, + 0.221064729458, + 0.218104291986, + 0.215338279037, + 0.212746053553, + 0.210309917857, + 0.208014597677, + 0.205846832460, + 0.203795047091, + 0.201849086582, + 0.2, + 0.198239863171, + 0.196561632233, + 0.194959021894, + 0.193426403617 +}; + +// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 +constexpr unsigned char digit_from_char(char val) noexcept +{ + return uchar_values[static_cast<unsigned char>(val)]; +} + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned +# pragma warning(disable: 4189) // 'is_negative': local variable is initialized but not referenced + +#elif defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wconstant-conversion" + +#elif defined(__GNUC__) && (__GNUC__ < 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Woverflow" +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" + +#elif defined(__GNUC__) && (__GNUC__ >= 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +# pragma GCC diagnostic ignored "-Wconversion" + +#endif + +template <typename Integer, typename Unsigned_Integer> +BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept +{ + Unsigned_Integer result = 0; + Unsigned_Integer overflow_value = 0; + Unsigned_Integer max_digit = 0; + + // Check pre-conditions + if (!((first <= last) && (base >= 2 && base <= 36))) + { + return {first, std::errc::invalid_argument}; + } + + const auto unsigned_base = static_cast<Unsigned_Integer>(base); + + // Strip sign if the type is signed + // Negative sign will be appended at the end of parsing + BOOST_ATTRIBUTE_UNUSED bool is_negative = false; + auto next = first; + + BOOST_CHARCONV_IF_CONSTEXPR (is_signed<Integer>::value) + { + if (next != last) + { + if (*next == '-') + { + is_negative = true; + ++next; + } + else if (*next == '+' || *next == ' ') + { + return {next, std::errc::invalid_argument}; + } + } + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value) + { + overflow_value = BOOST_CHARCONV_INT128_MAX; + max_digit = BOOST_CHARCONV_INT128_MAX; + } + else + #endif + { + overflow_value = (std::numeric_limits<Integer>::max)(); + max_digit = (std::numeric_limits<Integer>::max)(); + } + + if (is_negative) + { + ++overflow_value; + ++max_digit; + } + } + else + { + if (next != last && (*next == '-' || *next == '+' || *next == ' ')) + { + return {first, std::errc::invalid_argument}; + } + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::uint128_type>::value) + { + overflow_value = BOOST_CHARCONV_UINT128_MAX; + max_digit = BOOST_CHARCONV_UINT128_MAX; + } + else + #endif + { + overflow_value = (std::numeric_limits<Unsigned_Integer>::max)(); + max_digit = (std::numeric_limits<Unsigned_Integer>::max)(); + } + } + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value) + { + overflow_value /= unsigned_base; + max_digit %= unsigned_base; + #ifndef __GLIBCXX_TYPE_INT_N_0 + if (base != 10) + { + // Overflow value would cause INT128_MIN in non-base10 to fail + overflow_value *= static_cast<Unsigned_Integer>(2); + } + #endif + } + else + #endif + { + overflow_value /= unsigned_base; + max_digit %= unsigned_base; + } + + // If the only character was a sign abort now + if (next == last) + { + return {first, std::errc::invalid_argument}; + } + + bool overflowed = false; + + const std::ptrdiff_t nc = last - next; + + // In non-GNU mode on GCC numeric limits may not be specialized + #if defined(BOOST_CHARCONV_HAS_INT128) && !defined(__GLIBCXX_TYPE_INT_N_0) + constexpr std::ptrdiff_t nd_2 = std::is_same<Integer, boost::int128_type>::value ? 127 : + std::is_same<Integer, boost::uint128_type>::value ? 128 : + std::numeric_limits<Integer>::digits10; + #else + constexpr std::ptrdiff_t nd_2 = std::numeric_limits<Integer>::digits; + #endif + + const auto nd = static_cast<std::ptrdiff_t>(nd_2 * log_2_table[static_cast<std::size_t>(unsigned_base)]); + + { + // Check that the first character is valid before proceeding + const unsigned char first_digit = digit_from_char(*next); + + if (first_digit >= unsigned_base) + { + return {first, std::errc::invalid_argument}; + } + + result = static_cast<Unsigned_Integer>(result * unsigned_base + first_digit); + ++next; + std::ptrdiff_t i = 1; + + for( ; i < nd && i < nc; ++i ) + { + // overflow is not possible in the first nd characters + + const unsigned char current_digit = digit_from_char(*next); + + if (current_digit >= unsigned_base) + { + break; + } + + result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit); + ++next; + } + + for( ; i < nc; ++i ) + { + const unsigned char current_digit = digit_from_char(*next); + + if (current_digit >= unsigned_base) + { + break; + } + + if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) + { + result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit); + } + else + { + // Required to keep updating the value of next, but the result is garbage + overflowed = true; + } + + ++next; + } + } + + // Return the parsed value, adding the sign back if applicable + // If we have overflowed then we do not return the result + if (overflowed) + { + return {next, std::errc::result_out_of_range}; + } + + value = static_cast<Integer>(result); + + BOOST_IF_CONSTEXPR (is_signed<Integer>::value) + { + if (is_negative) + { + value = static_cast<Integer>(-(static_cast<Unsigned_Integer>(value))); + } + } + + return {next, std::errc()}; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#elif defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + +// Only from_chars for integer types is constexpr (as of C++23) +template <typename Integer> +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept +{ + using Unsigned_Integer = typename std::make_unsigned<Integer>::type; + return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +template <typename Integer> +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars128(const char* first, const char* last, Integer& value, int base = 10) noexcept +{ + using Unsigned_Integer = boost::uint128_type; + return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base); +} +#endif + +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars128(const char* first, const char* last, uint128& value, int base = 10) noexcept +{ + return from_chars_integer_impl<uint128, uint128>(first, last, value, base); +} + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/from_chars_result.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/from_chars_result.hpp new file mode 100644 index 00000000000..e4302cfab18 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/from_chars_result.hpp @@ -0,0 +1,41 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP +#define BOOST_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP + +#include <system_error> + +namespace boost { namespace charconv { + +// 22.13.3, Primitive numerical input conversion + +template <typename UC> +struct from_chars_result_t +{ + const UC* ptr; + + // Values: + // 0 = no error + // EINVAL = invalid_argument + // ERANGE = result_out_of_range + std::errc ec; + + friend constexpr bool operator==(const from_chars_result_t<UC>& lhs, const from_chars_result_t<UC>& rhs) noexcept + { + return lhs.ptr == rhs.ptr && lhs.ec == rhs.ec; + } + + friend constexpr bool operator!=(const from_chars_result_t<UC>& lhs, const from_chars_result_t<UC>& rhs) noexcept + { + return !(lhs == rhs); // NOLINT : Expression can not be simplified since this is the definition + } + + constexpr explicit operator bool() const noexcept { return ec == std::errc{}; } +}; +using from_chars_result = from_chars_result_t<char>; + +}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/integer_search_trees.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/integer_search_trees.hpp new file mode 100644 index 00000000000..9b4de091357 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/integer_search_trees.hpp @@ -0,0 +1,274 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP +#define BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP + +// https://stackoverflow.com/questions/1489830/efficient-way-to-determine-number-of-digits-in-an-integer?page=1&tab=scoredesc#tab-top +// https://graphics.stanford.edu/~seander/bithacks.html + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <limits> +#include <array> +#include <cstdint> + +namespace boost { namespace charconv { namespace detail { + +// Generic solution +template <typename T> +BOOST_CHARCONV_CXX14_CONSTEXPR int num_digits(T x) noexcept +{ + int digits = 0; + + while (x) + { + x /= 10; + ++digits; + } + + return digits; +} + +template <> +BOOST_CHARCONV_CXX14_CONSTEXPR int num_digits(std::uint32_t x) noexcept +{ + if (x >= UINT32_C(10000)) + { + if (x >= UINT32_C(10000000)) + { + if (x >= UINT32_C(100000000)) + { + if (x >= UINT32_C(1000000000)) + { + return 10; + } + return 9; + } + return 8; + } + + else if (x >= UINT32_C(100000)) + { + if (x >= UINT32_C(1000000)) + { + return 7; + } + return 6; + } + return 5; + } + else if (x >= UINT32_C(100)) + { + if (x >= UINT32_C(1000)) + { + return 4; + } + return 3; + } + else if (x >= UINT32_C(10)) + { + return 2; + } + + return 1; +} + +template <> +BOOST_CHARCONV_CXX14_CONSTEXPR int num_digits(std::uint64_t x) noexcept +{ + if (x >= UINT64_C(10000000000)) + { + if (x >= UINT64_C(100000000000000)) + { + if (x >= UINT64_C(10000000000000000)) + { + if (x >= UINT64_C(100000000000000000)) + { + if (x >= UINT64_C(1000000000000000000)) + { + if (x >= UINT64_C(10000000000000000000)) + { + return 20; + } + return 19; + } + return 18; + } + return 17; + } + else if (x >= UINT64_C(1000000000000000)) + { + return 16; + } + return 15; + } + if (x >= UINT64_C(1000000000000)) + { + if (x >= UINT64_C(10000000000000)) + { + return 14; + } + return 13; + } + if (x >= UINT64_C(100000000000)) + { + return 12; + } + return 11; + } + else if (x >= UINT64_C(100000)) + { + if (x >= UINT64_C(10000000)) + { + if (x >= UINT64_C(100000000)) + { + if (x >= UINT64_C(1000000000)) + { + return 10; + } + return 9; + } + return 8; + } + if (x >= UINT64_C(1000000)) + { + return 7; + } + return 6; + } + if (x >= UINT64_C(100)) + { + if (x >= UINT64_C(1000)) + { + if (x >= UINT64_C(10000)) + { + return 5; + } + return 4; + } + return 3; + } + if (x >= UINT64_C(10)) + { + return 2; + } + return 1; +} + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4307) // MSVC 14.1 warns of intergral constant overflow +#endif + +BOOST_CHARCONV_CXX14_CONSTEXPR int num_digits(uint128 x) noexcept +{ + if (x.high == 0) + { + return num_digits(x.low); + } + + BOOST_CHARCONV_CXX14_CONSTEXPR_NO_INLINE uint128 digits_39 = static_cast<uint128>(UINT64_C(10000000000000000000)) * + static_cast<uint128>(UINT64_C(10000000000000000000)); + uint128 current_power_of_10 = digits_39; + + for (int i = 39; i > 0; --i) + { + if (x >= current_power_of_10) + { + return i; + } + + current_power_of_10 /= 10U; + } + + return 1; +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#ifdef BOOST_CHARCONV_HAS_INT128 +static constexpr std::array<std::uint64_t, 20> powers_of_10 = +{{ + UINT64_C(1), UINT64_C(10), UINT64_C(100), UINT64_C(1000), UINT64_C(10000), UINT64_C(100000), UINT64_C(1000000), + UINT64_C(10000000), UINT64_C(100000000), UINT64_C(1000000000), UINT64_C(10000000000), UINT64_C(100000000000), + UINT64_C(1000000000000), UINT64_C(10000000000000), UINT64_C(100000000000000), UINT64_C(1000000000000000), + UINT64_C(10000000000000000), UINT64_C(100000000000000000), UINT64_C(1000000000000000000), UINT64_C(10000000000000000000) +}}; + +// Assume that if someone is using 128 bit ints they are favoring the top end of the range +// Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits) +BOOST_CHARCONV_CXX14_CONSTEXPR int num_digits(boost::uint128_type x) noexcept +{ + // There is no literal for boost::uint128_type, so we need to calculate them using the max value of the + // std::uint64_t powers of 10 + constexpr boost::uint128_type digits_39 = static_cast<boost::uint128_type>(UINT64_C(10000000000000000000)) * + static_cast<boost::uint128_type>(UINT64_C(10000000000000000000)); + + constexpr boost::uint128_type digits_38 = digits_39 / 10; + constexpr boost::uint128_type digits_37 = digits_38 / 10; + constexpr boost::uint128_type digits_36 = digits_37 / 10; + constexpr boost::uint128_type digits_35 = digits_36 / 10; + constexpr boost::uint128_type digits_34 = digits_35 / 10; + constexpr boost::uint128_type digits_33 = digits_34 / 10; + constexpr boost::uint128_type digits_32 = digits_33 / 10; + constexpr boost::uint128_type digits_31 = digits_32 / 10; + constexpr boost::uint128_type digits_30 = digits_31 / 10; + constexpr boost::uint128_type digits_29 = digits_30 / 10; + constexpr boost::uint128_type digits_28 = digits_29 / 10; + constexpr boost::uint128_type digits_27 = digits_28 / 10; + constexpr boost::uint128_type digits_26 = digits_27 / 10; + constexpr boost::uint128_type digits_25 = digits_26 / 10; + constexpr boost::uint128_type digits_24 = digits_25 / 10; + constexpr boost::uint128_type digits_23 = digits_24 / 10; + constexpr boost::uint128_type digits_22 = digits_23 / 10; + constexpr boost::uint128_type digits_21 = digits_22 / 10; + + return (x >= digits_39) ? 39 : + (x >= digits_38) ? 38 : + (x >= digits_37) ? 37 : + (x >= digits_36) ? 36 : + (x >= digits_35) ? 35 : + (x >= digits_34) ? 34 : + (x >= digits_33) ? 33 : + (x >= digits_32) ? 32 : + (x >= digits_31) ? 31 : + (x >= digits_30) ? 30 : + (x >= digits_29) ? 29 : + (x >= digits_28) ? 28 : + (x >= digits_27) ? 27 : + (x >= digits_26) ? 26 : + (x >= digits_25) ? 25 : + (x >= digits_24) ? 24 : + (x >= digits_23) ? 23 : + (x >= digits_22) ? 22 : + (x >= digits_21) ? 21 : + (x >= powers_of_10[19]) ? 20 : + (x >= powers_of_10[18]) ? 19 : + (x >= powers_of_10[17]) ? 18 : + (x >= powers_of_10[16]) ? 17 : + (x >= powers_of_10[15]) ? 16 : + (x >= powers_of_10[14]) ? 15 : + (x >= powers_of_10[13]) ? 14 : + (x >= powers_of_10[12]) ? 13 : + (x >= powers_of_10[11]) ? 12 : + (x >= powers_of_10[10]) ? 11 : + (x >= powers_of_10[9]) ? 10 : + (x >= powers_of_10[8]) ? 9 : + (x >= powers_of_10[7]) ? 8 : + (x >= powers_of_10[6]) ? 7 : + (x >= powers_of_10[5]) ? 6 : + (x >= powers_of_10[4]) ? 5 : + (x >= powers_of_10[3]) ? 4 : + (x >= powers_of_10[2]) ? 3 : + (x >= powers_of_10[1]) ? 2 : + (x >= powers_of_10[0]) ? 1 : 0; +} +#endif + +}}} // Namespace boost::charconv::detail + +#endif // BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/issignaling.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/issignaling.hpp new file mode 100644 index 00000000000..0780c2e8935 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/issignaling.hpp @@ -0,0 +1,85 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_ISSIGNALING_HPP +#define BOOST_CHARCONV_DETAIL_ISSIGNALING_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <cstdint> +#include <cstring> + +namespace boost { namespace charconv { namespace detail { + +template <typename T> +inline bool issignaling BOOST_PREVENT_MACRO_SUBSTITUTION (T x) noexcept; + +#if BOOST_CHARCONV_LDBL_BITS == 128 || defined(BOOST_CHARCONV_HAS_QUADMATH) + +struct words128 +{ +#if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE + std::uint64_t lo; + std::uint64_t hi; +#else + std::uint64_t hi; + std::uint64_t lo; +#endif +}; + +template <typename T> +inline bool issignaling BOOST_PREVENT_MACRO_SUBSTITUTION (T x) noexcept +{ + words128 bits; + std::memcpy(&bits, &x, sizeof(T)); + + std::uint64_t hi_word = bits.hi; + std::uint64_t lo_word = bits.lo; + + hi_word ^= UINT64_C(0x0000800000000000); + hi_word |= (lo_word | -lo_word) >> 63; + return ((hi_word & INT64_MAX) > UINT64_C(0x7FFF800000000000)); +} + +#endif + +// 16-bit non-finite bit values: +// +// float16_t +// SNAN: 0x7D00 +// QNAN: 0x7E00 +// INF: 0x7C00 +// +// bfloat16_t +// SNAN: 0x7FA0 +// QNAN: 0x7FC0 +// INF: 0x7F80 + +#ifdef BOOST_CHARCONV_HAS_FLOAT16 + +template <> +inline bool issignaling<std::float16_t> BOOST_PREVENT_MACRO_SUBSTITUTION (std::float16_t x) noexcept +{ + std::uint16_t bits; + std::memcpy(&bits, &x, sizeof(std::uint16_t)); + return bits >= UINT16_C(0x7D00) && bits < UINT16_C(0x7E00); +} + +#endif + +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 + +template <> +inline bool issignaling<std::bfloat16_t> BOOST_PREVENT_MACRO_SUBSTITUTION (std::bfloat16_t x) noexcept +{ + std::uint16_t bits; + std::memcpy(&bits, &x, sizeof(std::uint16_t)); + return bits >= UINT16_C(0x7FA0) && bits < UINT16_C(0x7FC0); +} + +#endif + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_ISSIGNALING_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/memcpy.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/memcpy.hpp new file mode 100644 index 00000000000..1e68315f42f --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/memcpy.hpp @@ -0,0 +1,78 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_MEMCPY_HPP +#define BOOST_CHARCONV_DETAIL_MEMCPY_HPP + +#include <boost/charconv/detail/config.hpp> +#include <cstring> +#include <cstdint> + +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89689 +// GCC 10 added checks for length of memcpy which yields the following warning (converted to error with -Werror) +// /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:33: error: +// ‘void* __builtin___memcpy_chk(void*, const void*, long unsigned int, long unsigned int)’ specified size between +// 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=] +// +// memcpy is defined as taking a size_t for the count and the largest count this will recieve is the number of digits +// in a 128-bit int (39) so we can safely ignore +#if defined(__GNUC__) && __GNUC__ >= 10 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstringop-overflow" +# define BOOST_CHARCONV_STRINGOP_OVERFLOW_DISABLED +#endif + +namespace boost { namespace charconv { namespace detail { + +#if !defined(BOOST_CHARCONV_NO_CONSTEXPR_DETECTION) && defined(BOOST_CXX14_CONSTEXPR) + +#define BOOST_CHARCONV_CONSTEXPR constexpr + +constexpr char* memcpy(char* dest, const char* src, std::size_t count) +{ + if (BOOST_CHARCONV_IS_CONSTANT_EVALUATED(count)) + { + for (std::size_t i = 0; i < count; ++i) + { + *(dest + i) = *(src + i); + } + + return dest; + } + else + { + // Workaround for GCC-11 because it does not honor GCC diagnostic ignored + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431 + // Hopefully the optimizer turns this into memcpy + #if defined(__GNUC__) && __GNUC__ == 11 + for (std::size_t i = 0; i < count; ++i) + { + *(dest + i) = *(src + i); + } + + return dest; + #else + return static_cast<char*>(std::memcpy(dest, src, count)); + #endif + } +} + +#else // Either not C++14 or no way of telling if we are in a constexpr context + +#define BOOST_CHARCONV_CONSTEXPR inline + +inline void* memcpy(void* dest, const void* src, std::size_t count) +{ + return std::memcpy(dest, src, count); +} + +#endif + +}}} // Namespace boost::charconv::detail + +#ifdef BOOST_CHARCONV_STRINGOP_OVERFLOW_DISABLED +# pragma GCC diagnostic pop +#endif + +#endif // BOOST_CHARCONV_DETAIL_MEMCPY_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/parser.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/parser.hpp new file mode 100644 index 00000000000..660de688495 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/parser.hpp @@ -0,0 +1,471 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_PARSER_HPP +#define BOOST_CHARCONV_DETAIL_PARSER_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/from_chars_result.hpp> +#include <boost/charconv/detail/from_chars_integer_impl.hpp> +#include <boost/charconv/detail/integer_search_trees.hpp> +#include <boost/charconv/limits.hpp> +#include <boost/charconv/chars_format.hpp> +#include <system_error> +#include <type_traits> +#include <limits> +#include <cerrno> +#include <cstdint> +#include <cstring> + +#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +namespace boost { namespace charconv { namespace detail { + +inline bool is_integer_char(char c) noexcept +{ + return (c >= '0') && (c <= '9'); +} + +inline bool is_hex_char(char c) noexcept +{ + return is_integer_char(c) || (((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'))); +} + +inline bool is_delimiter(char c, chars_format fmt) noexcept +{ + if (fmt != chars_format::hex) + { + return !is_integer_char(c) && c != 'e' && c != 'E'; + } + + return !is_hex_char(c) && c != 'p' && c != 'P'; +} + +inline from_chars_result from_chars_dispatch(const char* first, const char* last, std::uint64_t& value, int base) noexcept +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +inline from_chars_result from_chars_dispatch(const char* first, const char* last, uint128& value, int base) noexcept +{ + return boost::charconv::detail::from_chars128(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +inline from_chars_result from_chars_dispatch(const char* first, const char* last, boost::uint128_type& value, int base) noexcept +{ + return boost::charconv::detail::from_chars128(first, last, value, base); +} +#endif + +template<typename Unsigned_Integer> +typename std::enable_if<std::is_unsigned<Unsigned_Integer>::value && + std::numeric_limits<Unsigned_Integer>::is_integer && + sizeof(Unsigned_Integer) < sizeof(std::uint64_t), + from_chars_result>::type + from_chars_dispatch(const char* first, const char* last, Unsigned_Integer& value, int base) noexcept +{ + std::uint64_t tmp_value; + auto result = boost::charconv::detail::from_chars(first, last, tmp_value, base); + if (result) { + if (tmp_value > (std::numeric_limits<Unsigned_Integer>::max)()) + result.ec = std::errc::result_out_of_range; + else + value = static_cast<Unsigned_Integer>(tmp_value); + } + return result; +} + +template <typename Unsigned_Integer, typename Integer> +inline from_chars_result parser(const char* first, const char* last, bool& sign, Unsigned_Integer& significand, Integer& exponent, chars_format fmt = chars_format::general) noexcept +{ + if (first > last) + { + return {first, std::errc::invalid_argument}; + } + + auto next = first; + bool all_zeros = true; + + // First extract the sign + if (*next == '-') + { + sign = true; + ++next; + } + else if (*next == '+') + { + return {next, std::errc::invalid_argument}; + } + else + { + sign = false; + } + + // Handle non-finite values + // Stl allows for string like "iNf" to return inf + // + // This is nested ifs rather than a big one-liner to ensure that once we hit an invalid character + // or an end of buffer we return the correct value of next + if (next != last && (*next == 'i' || *next == 'I')) + { + ++next; + if (next != last && (*next == 'n' || *next == 'N')) + { + ++next; + if (next != last && (*next == 'f' || *next == 'F')) + { + significand = 0; + return {next, std::errc::value_too_large}; + } + } + + return {next, std::errc::invalid_argument}; + } + else if (next != last && (*next == 'n' || *next == 'N')) + { + ++next; + if (next != last && (*next == 'a' || *next == 'A')) + { + ++next; + if (next != last && (*next == 'n' || *next == 'N')) + { + ++next; + if (next != last && (*next == '(')) + { + ++next; + if (next != last && (*next == 's' || *next == 'S')) + { + significand = 1; + return {next, std::errc::not_supported}; + } + else if (next != last && (*next == 'i' || *next == 'I')) + { + significand = 0; + return {next, std::errc::not_supported}; + } + } + else + { + significand = 0; + return {next, std::errc::not_supported}; + } + } + } + + return {next, std::errc::invalid_argument}; + } + + // Ignore leading zeros (e.g. 00005 or -002.3e+5) + while (next != last && *next == '0') + { + ++next; + } + + // If the number is 0 we can abort now + char exp_char; + char capital_exp_char; + if (fmt != chars_format::hex) + { + exp_char = 'e'; + capital_exp_char = 'E'; + } + else + { + exp_char = 'p'; + capital_exp_char = 'P'; + } + + if (next == last || *next == exp_char || *next == -capital_exp_char) + { + significand = 0; + exponent = 0; + return {next, std::errc()}; + } + + // Next we get the significand + constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10; // Base 10 or 16 + char significand_buffer[significand_buffer_size] {}; + std::size_t i = 0; + std::size_t dot_position = 0; + Integer extra_zeros = 0; + Integer leading_zero_powers = 0; + const auto char_validation_func = (fmt != boost::charconv::chars_format::hex) ? is_integer_char : is_hex_char; + const int base = (fmt != boost::charconv::chars_format::hex) ? 10 : 16; + + while (next != last && char_validation_func(*next) && i < significand_buffer_size) + { + all_zeros = false; + significand_buffer[i] = *next; + ++next; + ++i; + } + + bool fractional = false; + if (next == last) + { + // if fmt is chars_format::scientific the e is required + if (fmt == chars_format::scientific) + { + return {first, std::errc::invalid_argument}; + } + + exponent = 0; + std::size_t offset = i; + + from_chars_result r = from_chars_dispatch(significand_buffer, significand_buffer + offset, significand, base); + switch (r.ec) + { + case std::errc::invalid_argument: + return {first, std::errc::invalid_argument}; + case std::errc::result_out_of_range: + return {next, std::errc::result_out_of_range}; + default: + return {next, std::errc()}; + } + } + else if (*next == '.') + { + ++next; + fractional = true; + dot_position = i; + + // Process the fractional part if we have it + // + // if fmt is chars_format::scientific the e is required + // if fmt is chars_format::fixed and not scientific the e is disallowed + // if fmt is chars_format::general (which is scientific and fixed) the e is optional + + // If we have the value 0.00001 we can continue to chop zeros and adjust the exponent + // so that we get the useful parts of the fraction + if (all_zeros) + { + while (next != last && *next == '0') + { + ++next; + --leading_zero_powers; + } + + if (next == last) + { + significand = 0; + exponent = 0; + return {last, std::errc()}; + } + } + + while (next != last && char_validation_func(*next) && i < significand_buffer_size) + { + significand_buffer[i] = *next; + ++next; + ++i; + } + } + + if (i == significand_buffer_size) + { + // We can not process any more significant figures into the significand so skip to the end + // or the exponent part and capture the additional orders of magnitude for the exponent + bool found_dot = false; + while (next != last && (char_validation_func(*next) || *next == '.')) + { + ++next; + if (!fractional && !found_dot) + { + ++extra_zeros; + } + if (next != last && *next == '.') + { + found_dot = true; + } + } + } + + if (next == last || is_delimiter(*next, fmt)) + { + if (fmt == chars_format::scientific) + { + return {first, std::errc::invalid_argument}; + } + if (dot_position != 0 || fractional) + { + exponent = static_cast<Integer>(dot_position) - static_cast<Integer>(i) + extra_zeros + leading_zero_powers; + } + else + { + exponent = extra_zeros + leading_zero_powers; + } + std::size_t offset = i; + + from_chars_result r = from_chars_dispatch(significand_buffer, significand_buffer + offset, significand, base); + switch (r.ec) + { + case std::errc::invalid_argument: + return {first, std::errc::invalid_argument}; + case std::errc::result_out_of_range: + return {next, std::errc::result_out_of_range}; + default: + return {next, std::errc()}; + } + } + else if (*next == exp_char || *next == capital_exp_char) + { + // Would be a number without a significand e.g. e+03 + if (next == first) + { + return {next, std::errc::invalid_argument}; + } + + ++next; + if (fmt == chars_format::fixed) + { + return {first, std::errc::invalid_argument}; + } + + std::size_t offset = i; + bool round = false; + // If more digits are present than representable in the significand of the target type + // we set the maximum + if (offset > significand_buffer_size) + { + offset = significand_buffer_size - 1; + i = significand_buffer_size; + if (significand_buffer[offset] == '5' || + significand_buffer[offset] == '6' || + significand_buffer[offset] == '7' || + significand_buffer[offset] == '8' || + significand_buffer[offset] == '9') + { + round = true; + } + } + + // If the significand is 0 from chars will return std::errc::invalid_argument because there is nothing in the buffer, + // but it is a valid value. We need to continue parsing to get the correct value of ptr even + // though we know we could bail now. + // + // See GitHub issue #29: https://github.com/cppalliance/charconv/issues/29 + if (offset != 0) + { + from_chars_result r = from_chars_dispatch(significand_buffer, significand_buffer + offset, significand, base); + switch (r.ec) + { + case std::errc::invalid_argument: + return {first, std::errc::invalid_argument}; + case std::errc::result_out_of_range: + return {next, std::errc::result_out_of_range}; + default: + break; + } + + if (round) + { + significand = static_cast<Unsigned_Integer>(significand + 1u); + } + } + else + significand = 0; + } + else + { + return {first, std::errc::invalid_argument}; + } + + // Finally we get the exponent + constexpr std::size_t exponent_buffer_size = 6; // Float128 min exp is −16382 + char exponent_buffer[exponent_buffer_size] {}; + const auto significand_digits = i; + i = 0; + + // Get the sign first + if (next != last && *next == '-') + { + exponent_buffer[i] = *next; + ++next; + ++i; + } + else if (next != last && *next == '+') + { + ++next; + } + + // Next strip any leading zeros + while (next != last && *next == '0') + { + ++next; + } + + // Process the significant values + while (next != last && is_integer_char(*next) && i < exponent_buffer_size) + { + exponent_buffer[i] = *next; + ++next; + ++i; + } + + // If the exponent can't fit in the buffer the number is not representable + if (next != last && i == exponent_buffer_size) + { + return {next, std::errc::result_out_of_range}; + } + + // If the exponent was e+00 or e-00 + if (i == 0 || (i == 1 && exponent_buffer[0] == '-')) + { + if (fractional) + { + exponent = static_cast<Integer>(dot_position - significand_digits); + } + else + { + exponent = extra_zeros; + } + + return {next, std::errc()}; + } + + const auto r = from_chars(exponent_buffer, exponent_buffer + i, exponent); + + exponent += leading_zero_powers; + + switch (r.ec) + { + case std::errc::invalid_argument: + return {first, std::errc::invalid_argument}; + case std::errc::result_out_of_range: + return {next, std::errc::result_out_of_range}; + default: + if (fractional) + { + // Need to take the offset from 1.xxx because compute_floatXXX assumes the significand is an integer + // so the exponent is off by the number of digits in the significand - 1 + if (fmt == chars_format::hex) + { + // In hex the number of digits parsed is possibly less than the number of digits in base10 + exponent -= num_digits(significand) - static_cast<Integer>(dot_position); + } + else + { + exponent -= static_cast<Integer>(significand_digits - dot_position); + } + } + else + { + exponent += extra_zeros; + } + + return {next, std::errc()}; + } +} + +}}} // Namespaces + +#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) +# pragma GCC diagnostic pop +#endif + +#endif // BOOST_CHARCONV_DETAIL_PARSER_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/ryu/generic_128.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/ryu/generic_128.hpp new file mode 100644 index 00000000000..23c5234ddf4 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/ryu/generic_128.hpp @@ -0,0 +1,558 @@ +// Copyright 2018 - 2023 Ulf Adams +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_RYU_GENERIC_128_HPP +#define BOOST_CHARCONV_DETAIL_RYU_GENERIC_128_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/integer_search_trees.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <cstdint> + +#define BOOST_CHARCONV_POW5_TABLE_SIZE 56 +#define BOOST_CHARCONV_POW5_BITCOUNT 249 +#define BOOST_CHARCONV_POW5_INV_BITCOUNT 249 + +namespace boost { namespace charconv { namespace detail { namespace ryu { + +#ifdef BOOST_CHARCONV_HAS_INT128 +using unsigned_128_type = boost::uint128_type; +#else +using unsigned_128_type = uint128; +#endif + +// These tables are ~4.5 kByte total, compared to ~160 kByte for the full tables. +// +// There's no way to define 128-bit constants in C, so we use little-endian +// pairs of 64-bit constants. + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) +template <bool b> +struct ryu_tables_template +#else +struct ryu_tables +#endif +{ + static constexpr uint64_t GENERIC_POW5_TABLE[BOOST_CHARCONV_POW5_TABLE_SIZE][2] = { + {1u, 0u}, + {5u, 0u}, + {25u, 0u}, + {125u, 0u}, + {625u, 0u}, + {3125u, 0u}, + {15625u, 0u}, + {78125u, 0u}, + {390625u, 0u}, + {1953125u, 0u}, + {9765625u, 0u}, + {48828125u, 0u}, + {244140625u, 0u}, + {1220703125u, 0u}, + {6103515625u, 0u}, + {30517578125u, 0u}, + {152587890625u, 0u}, + {762939453125u, 0u}, + {3814697265625u, 0u}, + {19073486328125u, 0u}, + {95367431640625u, 0u}, + {476837158203125u, 0u}, + {2384185791015625u, 0u}, + {11920928955078125u, 0u}, + {59604644775390625u, 0u}, + {298023223876953125u, 0u}, + {1490116119384765625u, 0u}, + {7450580596923828125u, 0u}, + {359414837200037393u, 2u}, + {1797074186000186965u, 10u}, + {8985370930000934825u, 50u}, + {8033366502585570893u, 252u}, + {3273344365508751233u, 1262u}, + {16366721827543756165u, 6310u}, + {8046632842880574361u, 31554u}, + {3339676066983768573u, 157772u}, + {16698380334918842865u, 788860u}, + {9704925379756007861u, 3944304u}, + {11631138751360936073u, 19721522u}, + {2815461535676025517u, 98607613u}, + {14077307678380127585u, 493038065u}, + {15046306170771983077u, 2465190328u}, + {1444554559021708921u, 12325951644u}, + {7222772795108544605u, 61629758220u}, + {17667119901833171409u, 308148791101u}, + {14548623214327650581u, 1540743955509u}, + {17402883850509598057u, 7703719777548u}, + {13227442957709783821u, 38518598887744u}, + {10796982567420264257u, 192592994438723u}, + {17091424689682218053u, 962964972193617u}, + {11670147153572883801u, 4814824860968089u}, + {3010503546735764157u, 24074124304840448u}, + {15052517733678820785u, 120370621524202240u}, + {1475612373555897461u, 601853107621011204u}, + {7378061867779487305u, 3009265538105056020u}, + {18443565265187884909u, 15046327690525280101u} + }; + + static constexpr uint64_t GENERIC_POW5_SPLIT[89][4] = { + {0u, 0u, 0u, 72057594037927936u}, + {0u, 5206161169240293376u, 4575641699882439235u, 73468396926392969u}, + {3360510775605221349u, 6983200512169538081u, 4325643253124434363u, 74906821675075173u}, + {11917660854915489451u, 9652941469841108803u, 946308467778435600u, 76373409087490117u}, + {1994853395185689235u, 16102657350889591545u, 6847013871814915412u, 77868710555449746u}, + {958415760277438274u, 15059347134713823592u, 7329070255463483331u, 79393288266368765u}, + {2065144883315240188u, 7145278325844925976u, 14718454754511147343u, 80947715414629833u}, + {8980391188862868935u, 13709057401304208685u, 8230434828742694591u, 82532576417087045u}, + {432148644612782575u, 7960151582448466064u, 12056089168559840552u, 84148467132788711u}, + {484109300864744403u, 15010663910730448582u, 16824949663447227068u, 85795995087002057u}, + {14793711725276144220u, 16494403799991899904u, 10145107106505865967u, 87475779699624060u}, + {15427548291869817042u, 12330588654550505203u, 13980791795114552342u, 89188452518064298u}, + {9979404135116626552u, 13477446383271537499u, 14459862802511591337u, 90934657454687378u}, + {12385121150303452775u, 9097130814231585614u, 6523855782339765207u, 92715051028904201u}, + {1822931022538209743u, 16062974719797586441u, 3619180286173516788u, 94530302614003091u}, + {12318611738248470829u, 13330752208259324507u, 10986694768744162601u, 96381094688813589u}, + {13684493829640282333u, 7674802078297225834u, 15208116197624593182u, 98268123094297527u}, + {5408877057066295332u, 6470124174091971006u, 15112713923117703147u, 100192097295163851u}, + {11407083166564425062u, 18189998238742408185u, 4337638702446708282u, 102153740646605557u}, + {4112405898036935485u, 924624216579956435u, 14251108172073737125u, 104153790666259019u}, + {16996739107011444789u, 10015944118339042475u, 2395188869672266257u, 106192999311487969u}, + {4588314690421337879u, 5339991768263654604u, 15441007590670620066u, 108272133262096356u}, + {2286159977890359825u, 14329706763185060248u, 5980012964059367667u, 110391974208576409u}, + {9654767503237031099u, 11293544302844823188u, 11739932712678287805u, 112553319146000238u}, + {11362964448496095896u, 7990659682315657680u, 251480263940996374u, 114756980673665505u}, + {1423410421096377129u, 14274395557581462179u, 16553482793602208894u, 117003787300607788u}, + {2070444190619093137u, 11517140404712147401u, 11657844572835578076u, 119294583757094535u}, + {7648316884775828921u, 15264332483297977688u, 247182277434709002u, 121630231312217685u}, + {17410896758132241352u, 10923914482914417070u, 13976383996795783649u, 124011608097704390u}, + {9542674537907272703u, 3079432708831728956u, 14235189590642919676u, 126439609438067572u}, + {10364666969937261816u, 8464573184892924210u, 12758646866025101190u, 128915148187220428u}, + {14720354822146013883u, 11480204489231511423u, 7449876034836187038u, 131439155071681461u}, + {1692907053653558553u, 17835392458598425233u, 1754856712536736598u, 134012579040499057u}, + {5620591334531458755u, 11361776175667106627u, 13350215315297937856u, 136636387622027174u}, + {17455759733928092601u, 10362573084069962561u, 11246018728801810510u, 139311567287686283u}, + {2465404073814044982u, 17694822665274381860u, 1509954037718722697u, 142039123822846312u}, + {2152236053329638369u, 11202280800589637091u, 16388426812920420176u, 72410041352485523u}, + {17319024055671609028u, 10944982848661280484u, 2457150158022562661u, 73827744744583080u}, + {17511219308535248024u, 5122059497846768077u, 2089605804219668451u, 75273205100637900u}, + {10082673333144031533u, 14429008783411894887u, 12842832230171903890u, 76746965869337783u}, + {16196653406315961184u, 10260180891682904501u, 10537411930446752461u, 78249581139456266u}, + {15084422041749743389u, 234835370106753111u, 16662517110286225617u, 79781615848172976u}, + {8199644021067702606u, 3787318116274991885u, 7438130039325743106u, 81343645993472659u}, + {12039493937039359765u, 9773822153580393709u, 5945428874398357806u, 82936258850702722u}, + {984543865091303961u, 7975107621689454830u, 6556665988501773347u, 84560053193370726u}, + {9633317878125234244u, 16099592426808915028u, 9706674539190598200u, 86215639518264828u}, + {6860695058870476186u, 4471839111886709592u, 7828342285492709568u, 87903640274981819u}, + {14583324717644598331u, 4496120889473451238u, 5290040788305728466u, 89624690099949049u}, + {18093669366515003715u, 12879506572606942994u, 18005739787089675377u, 91379436055028227u}, + {17997493966862379937u, 14646222655265145582u, 10265023312844161858u, 93168537870790806u}, + {12283848109039722318u, 11290258077250314935u, 9878160025624946825u, 94992668194556404u}, + {8087752761883078164u, 5262596608437575693u, 11093553063763274413u, 96852512843287537u}, + {15027787746776840781u, 12250273651168257752u, 9290470558712181914u, 98748771061435726u}, + {15003915578366724489u, 2937334162439764327u, 5404085603526796602u, 100682155783835929u}, + {5225610465224746757u, 14932114897406142027u, 2774647558180708010u, 102653393903748137u}, + {17112957703385190360u, 12069082008339002412u, 3901112447086388439u, 104663226546146909u}, + {4062324464323300238u, 3992768146772240329u, 15757196565593695724u, 106712409346361594u}, + {5525364615810306701u, 11855206026704935156u, 11344868740897365300u, 108801712734172003u}, + {9274143661888462646u, 4478365862348432381u, 18010077872551661771u, 110931922223466333u}, + {12604141221930060148u, 8930937759942591500u, 9382183116147201338u, 113103838707570263u}, + {14513929377491886653u, 1410646149696279084u, 587092196850797612u, 115318278760358235u}, + {2226851524999454362u, 7717102471110805679u, 7187441550995571734u, 117576074943260147u}, + {5527526061344932763u, 2347100676188369132u, 16976241418824030445u, 119878076118278875u}, + {6088479778147221611u, 17669593130014777580u, 10991124207197663546u, 122225147767136307u}, + {11107734086759692041u, 3391795220306863431u, 17233960908859089158u, 124618172316667879u}, + {7913172514655155198u, 17726879005381242552u, 641069866244011540u, 127058049470587962u}, + {12596991768458713949u, 15714785522479904446u, 6035972567136116512u, 129545696547750811u}, + {16901996933781815980u, 4275085211437148707u, 14091642539965169063u, 132082048827034281u}, + {7524574627987869240u, 15661204384239316051u, 2444526454225712267u, 134668059898975949u}, + {8199251625090479942u, 6803282222165044067u, 16064817666437851504u, 137304702024293857u}, + {4453256673338111920u, 15269922543084434181u, 3139961729834750852u, 139992966499426682u}, + {15841763546372731299u, 3013174075437671812u, 4383755396295695606u, 142733864029230733u}, + {9771896230907310329u, 4900659362437687569u, 12386126719044266361u, 72764212553486967u}, + {9420455527449565190u, 1859606122611023693u, 6555040298902684281u, 74188850200884818u}, + {5146105983135678095u, 2287300449992174951u, 4325371679080264751u, 75641380576797959u}, + {11019359372592553360u, 8422686425957443718u, 7175176077944048210u, 77122349788024458u}, + {11005742969399620716u, 4132174559240043701u, 9372258443096612118u, 78632314633490790u}, + {8887589641394725840u, 8029899502466543662u, 14582206497241572853u, 80171842813591127u}, + {360247523705545899u, 12568341805293354211u, 14653258284762517866u, 81741513143625247u}, + {12314272731984275834u, 4740745023227177044u, 6141631472368337539u, 83341915771415304u}, + {441052047733984759u, 7940090120939869826u, 11750200619921094248u, 84973652399183278u}, + {3436657868127012749u, 9187006432149937667u, 16389726097323041290u, 86637336509772529u}, + {13490220260784534044u, 15339072891382896702u, 8846102360835316895u, 88333593597298497u}, + {4125672032094859833u, 158347675704003277u, 10592598512749774447u, 90063061402315272u}, + {12189928252974395775u, 2386931199439295891u, 7009030566469913276u, 91826390151586454u}, + {9256479608339282969u, 2844900158963599229u, 11148388908923225596u, 93624242802550437u}, + {11584393507658707408u, 2863659090805147914u, 9873421561981063551u, 95457295292572042u}, + {13984297296943171390u, 1931468383973130608u, 12905719743235082319u, 97326236793074198u}, + {5837045222254987499u, 10213498696735864176u, 14893951506257020749u, 99231769968645227u} + }; + + // Unfortunately, the results are sometimes off by one or two. We use an additional + // lookup table to store those cases and adjust the result. + static constexpr uint64_t POW5_ERRORS[156] = { + 0x0000000000000000u, 0x0000000000000000u, 0x0000000000000000u, 0x9555596400000000u, + 0x65a6569525565555u, 0x4415551445449655u, 0x5105015504144541u, 0x65a69969a6965964u, + 0x5054955969959656u, 0x5105154515554145u, 0x4055511051591555u, 0x5500514455550115u, + 0x0041140014145515u, 0x1005440545511051u, 0x0014405450411004u, 0x0414440010500000u, + 0x0044000440010040u, 0x5551155000004001u, 0x4554555454544114u, 0x5150045544005441u, + 0x0001111400054501u, 0x6550955555554554u, 0x1504159645559559u, 0x4105055141454545u, + 0x1411541410405454u, 0x0415555044545555u, 0x0014154115405550u, 0x1540055040411445u, + 0x0000000500000000u, 0x5644000000000000u, 0x1155555591596555u, 0x0410440054569565u, + 0x5145100010010005u, 0x0555041405500150u, 0x4141450455140450u, 0x0000000144000140u, + 0x5114004001105410u, 0x4444100404005504u, 0x0414014410001015u, 0x5145055155555015u, + 0x0141041444445540u, 0x0000100451541414u, 0x4105041104155550u, 0x0500501150451145u, + 0x1001050000004114u, 0x5551504400141045u, 0x5110545410151454u, 0x0100001400004040u, + 0x5040010111040000u, 0x0140000150541100u, 0x4400140400104110u, 0x5011014405545004u, + 0x0000000044155440u, 0x0000000010000000u, 0x1100401444440001u, 0x0040401010055111u, + 0x5155155551405454u, 0x0444440015514411u, 0x0054505054014101u, 0x0451015441115511u, + 0x1541411401140551u, 0x4155104514445110u, 0x4141145450145515u, 0x5451445055155050u, + 0x4400515554110054u, 0x5111145104501151u, 0x565a655455500501u, 0x5565555555525955u, + 0x0550511500405695u, 0x4415504051054544u, 0x6555595965555554u, 0x0100915915555655u, + 0x5540001510001001u, 0x5450051414000544u, 0x1405010555555551u, 0x5555515555644155u, + 0x5555055595496555u, 0x5451045004415000u, 0x5450510144040144u, 0x5554155555556455u, + 0x5051555495415555u, 0x5555554555555545u, 0x0000000010005455u, 0x4000005000040000u, + 0x5565555555555954u, 0x5554559555555505u, 0x9645545495552555u, 0x4000400055955564u, + 0x0040000000000001u, 0x4004100100000000u, 0x5540040440000411u, 0x4565555955545644u, + 0x1140659549651556u, 0x0100000410010000u, 0x5555515400004001u, 0x5955545555155255u, + 0x5151055545505556u, 0x5051454510554515u, 0x0501500050415554u, 0x5044154005441005u, + 0x1455445450550455u, 0x0010144055144545u, 0x0000401100000004u, 0x1050145050000010u, + 0x0415004554011540u, 0x1000510100151150u, 0x0100040400001144u, 0x0000000000000000u, + 0x0550004400000100u, 0x0151145041451151u, 0x0000400400005450u, 0x0000100044010004u, + 0x0100054100050040u, 0x0504400005410010u, 0x4011410445500105u, 0x0000404000144411u, + 0x0101504404500000u, 0x0000005044400400u, 0x0000000014000100u, 0x0404440414000000u, + 0x5554100410000140u, 0x4555455544505555u, 0x5454105055455455u, 0x0115454155454015u, + 0x4404110000045100u, 0x4400001100101501u, 0x6596955956966a94u, 0x0040655955665965u, + 0x5554144400100155u, 0xa549495401011041u, 0x5596555565955555u, 0x5569965959549555u, + 0x969565a655555456u, 0x0000001000000000u, 0x0000000040000140u, 0x0000040100000000u, + 0x1415454400000000u, 0x5410415411454114u, 0x0400040104000154u, 0x0504045000000411u, + 0x0000001000000010u, 0x5554000000001040u, 0x5549155551556595u, 0x1455541055515555u, + 0x0510555454554541u, 0x9555555555540455u, 0x6455456555556465u, 0x4524565555654514u, + 0x5554655255559545u, 0x9555455441155556u, 0x0000000051515555u, 0x0010005040000550u, + 0x5044044040000000u, 0x1045040440010500u, 0x0000400000040000u, 0x0000000000000000u + }; + + static constexpr uint64_t GENERIC_POW5_INV_SPLIT[89][4] = { + {0u, 0u, 0u, 144115188075855872u}, + {1573859546583440065u, 2691002611772552616u, 6763753280790178510u, 141347765182270746u}, + {12960290449513840412u, 12345512957918226762u, 18057899791198622765u, 138633484706040742u}, + {7615871757716765416u, 9507132263365501332u, 4879801712092008245u, 135971326161092377u}, + {7869961150745287587u, 5804035291554591636u, 8883897266325833928u, 133360288657597085u}, + {2942118023529634767u, 15128191429820565086u, 10638459445243230718u, 130799390525667397u}, + {14188759758411913794u, 5362791266439207815u, 8068821289119264054u, 128287668946279217u}, + {7183196927902545212u, 1952291723540117099u, 12075928209936341512u, 125824179589281448u}, + {5672588001402349748u, 17892323620748423487u, 9874578446960390364u, 123407996258356868u}, + {4442590541217566325u, 4558254706293456445u, 10343828952663182727u, 121038210542800766u}, + {3005560928406962566u, 2082271027139057888u, 13961184524927245081u, 118713931475986426u}, + {13299058168408384786u, 17834349496131278595u, 9029906103900731664u, 116434285200389047u}, + {5414878118283973035u, 13079825470227392078u, 17897304791683760280u, 114198414639042157u}, + {14609755883382484834u, 14991702445765844156u, 3269802549772755411u, 112005479173303009u}, + {15967774957605076027u, 2511532636717499923u, 16221038267832563171u, 109854654326805788u}, + {9269330061621627145u, 3332501053426257392u, 16223281189403734630u, 107745131455483836u}, + {16739559299223642282u, 1873986623300664530u, 6546709159471442872u, 105676117443544318u}, + {17116435360051202055u, 1359075105581853924u, 2038341371621886470u, 103646834405281051u}, + {17144715798009627550u, 3201623802661132408u, 9757551605154622431u, 101656519392613377u}, + {17580479792687825857u, 6546633380567327312u, 15099972427870912398u, 99704424108241124u}, + {9726477118325522902u, 14578369026754005435u, 11728055595254428803u, 97789814624307808u}, + {134593949518343635u, 5715151379816901985u, 1660163707976377376u, 95911971106466306u}, + {5515914027713859358u, 7124354893273815720u, 5548463282858794077u, 94070187543243255u}, + {6188403395862945512u, 5681264392632320838u, 15417410852121406654u, 92263771480600430u}, + {15908890877468271457u, 10398888261125597540u, 4817794962769172309u, 90492043761593298u}, + {1413077535082201005u, 12675058125384151580u, 7731426132303759597u, 88754338271028867u}, + {1486733163972670293u, 11369385300195092554u, 11610016711694864110u, 87050001685026843u}, + {8788596583757589684u, 3978580923851924802u, 9255162428306775812u, 85378393225389919u}, + {7203518319660962120u, 15044736224407683725u, 2488132019818199792u, 83738884418690858u}, + {4004175967662388707u, 18236988667757575407u, 15613100370957482671u, 82130858859985791u}, + {18371903370586036463u, 53497579022921640u, 16465963977267203307u, 80553711981064899u}, + {10170778323887491315u, 1999668801648976001u, 10209763593579456445u, 79006850823153334u}, + {17108131712433974546u, 16825784443029944237u, 2078700786753338945u, 77489693813976938u}, + {17221789422665858532u, 12145427517550446164u, 5391414622238668005u, 76001670549108934u}, + {4859588996898795878u, 1715798948121313204u, 3950858167455137171u, 74542221577515387u}, + {13513469241795711526u, 631367850494860526u, 10517278915021816160u, 73110798191218799u}, + {11757513142672073111u, 2581974932255022228u, 17498959383193606459u, 143413724438001539u}, + {14524355192525042817u, 5640643347559376447u, 1309659274756813016u, 140659771648132296u}, + {2765095348461978538u, 11021111021896007722u, 3224303603779962366u, 137958702611185230u}, + {12373410389187981037u, 13679193545685856195u, 11644609038462631561u, 135309501808182158u}, + {12813176257562780151u, 3754199046160268020u, 9954691079802960722u, 132711173221007413u}, + {17557452279667723458u, 3237799193992485824u, 17893947919029030695u, 130162739957935629u}, + {14634200999559435155u, 4123869946105211004u, 6955301747350769239u, 127663243886350468u}, + {2185352760627740240u, 2864813346878886844u, 13049218671329690184u, 125211745272516185u}, + {6143438674322183002u, 10464733336980678750u, 6982925169933978309u, 122807322428266620u}, + {1099509117817174576u, 10202656147550524081u, 754997032816608484u, 120449071364478757u}, + {2410631293559367023u, 17407273750261453804u, 15307291918933463037u, 118136105451200587u}, + {12224968375134586697u, 1664436604907828062u, 11506086230137787358u, 115867555084305488u}, + {3495926216898000888u, 18392536965197424288u, 10992889188570643156u, 113642567358547782u}, + {8744506286256259680u, 3966568369496879937u, 18342264969761820037u, 111460305746896569u}, + {7689600520560455039u, 5254331190877624630u, 9628558080573245556u, 109319949786027263u}, + {11862637625618819436u, 3456120362318976488u, 14690471063106001082u, 107220694767852583u}, + {5697330450030126444u, 12424082405392918899u, 358204170751754904u, 105161751436977040u}, + {11257457505097373622u, 15373192700214208870u, 671619062372033814u, 103142345693961148u}, + {16850355018477166700u, 1913910419361963966u, 4550257919755970531u, 101161718304283822u}, + {9670835567561997011u, 10584031339132130638u, 3060560222974851757u, 99219124612893520u}, + {7698686577353054710u, 11689292838639130817u, 11806331021588878241u, 97313834264240819u}, + {12233569599615692137u, 3347791226108469959u, 10333904326094451110u, 95445130927687169u}, + {13049400362825383933u, 17142621313007799680u, 3790542585289224168u, 93612312028186576u}, + {12430457242474442072u, 5625077542189557960u, 14765055286236672238u, 91814688482138969u}, + {4759444137752473128u, 2230562561567025078u, 4954443037339580076u, 90051584438315940u}, + {7246913525170274758u, 8910297835195760709u, 4015904029508858381u, 88322337023761438u}, + {12854430245836432067u, 8135139748065431455u, 11548083631386317976u, 86626296094571907u}, + {4848827254502687803u, 4789491250196085625u, 3988192420450664125u, 84962823991462151u}, + {7435538409611286684u, 904061756819742353u, 14598026519493048444u, 83331295300025028u}, + {11042616160352530997u, 8948390828345326218u, 10052651191118271927u, 81731096615594853u}, + {11059348291563778943u, 11696515766184685544u, 3783210511290897367u, 80161626312626082u}, + {7020010856491885826u, 5025093219346041680u, 8960210401638911765u, 78622294318500592u}, + {17732844474490699984u, 7820866704994446502u, 6088373186798844243u, 77112521891678506u}, + {688278527545590501u, 3045610706602776618u, 8684243536999567610u, 75631741404109150u}, + {2734573255120657297u, 3903146411440697663u, 9470794821691856713u, 74179396127820347u}, + {15996457521023071259u, 4776627823451271680u, 12394856457265744744u, 72754940025605801u}, + {13492065758834518331u, 7390517611012222399u, 1630485387832860230u, 142715675091463768u}, + {13665021627282055864u, 9897834675523659302u, 17907668136755296849u, 139975126841173266u}, + {9603773719399446181u, 10771916301484339398u, 10672699855989487527u, 137287204938390542u}, + {3630218541553511265u, 8139010004241080614u, 2876479648932814543u, 134650898807055963u}, + {8318835909686377084u, 9525369258927993371u, 2796120270400437057u, 132065217277054270u}, + {11190003059043290163u, 12424345635599592110u, 12539346395388933763u, 129529188211565064u}, + {8701968833973242276u, 820569587086330727u, 2315591597351480110u, 127041858141569228u}, + {5115113890115690487u, 16906305245394587826u, 9899749468931071388u, 124602291907373862u}, + {15543535488939245974u, 10945189844466391399u, 3553863472349432246u, 122209572307020975u}, + {7709257252608325038u, 1191832167690640880u, 15077137020234258537u, 119862799751447719u}, + {7541333244210021737u, 9790054727902174575u, 5160944773155322014u, 117561091926268545u}, + {12297384708782857832u, 1281328873123467374u, 4827925254630475769u, 115303583460052092u}, + {13243237906232367265u, 15873887428139547641u, 3607993172301799599u, 113089425598968120u}, + {11384616453739611114u, 15184114243769211033u, 13148448124803481057u, 110917785887682141u}, + {17727970963596660683u, 1196965221832671990u, 14537830463956404138u, 108787847856377790u}, + {17241367586707330931u, 8880584684128262874u, 11173506540726547818u, 106698810713789254u}, + {7184427196661305643u, 14332510582433188173u, 14230167953789677901u, 104649889046128358u} + }; + + static constexpr uint64_t POW5_INV_ERRORS[154] = { + 0x1144155514145504u, 0x0000541555401141u, 0x0000000000000000u, 0x0154454000000000u, + 0x4114105515544440u, 0x0001001111500415u, 0x4041411410011000u, 0x5550114515155014u, + 0x1404100041554551u, 0x0515000450404410u, 0x5054544401140004u, 0x5155501005555105u, + 0x1144141000105515u, 0x0541500000500000u, 0x1104105540444140u, 0x4000015055514110u, + 0x0054010450004005u, 0x4155515404100005u, 0x5155145045155555u, 0x1511555515440558u, + 0x5558544555515555u, 0x0000000000000010u, 0x5004000000000050u, 0x1415510100000010u, + 0x4545555444514500u, 0x5155151555555551u, 0x1441540144044554u, 0x5150104045544400u, + 0x5450545401444040u, 0x5554455045501400u, 0x4655155555555145u, 0x1000010055455055u, + 0x1000004000055004u, 0x4455405104000005u, 0x4500114504150545u, 0x0000000014000000u, + 0x5450000000000000u, 0x5514551511445555u, 0x4111501040555451u, 0x4515445500054444u, + 0x5101500104100441u, 0x1545115155545055u, 0x0000000000000000u, 0x1554000000100000u, + 0x5555545595551555u, 0x5555051851455955u, 0x5555555555555559u, 0x0000400011001555u, + 0x0000004400040000u, 0x5455511555554554u, 0x5614555544115445u, 0x6455156145555155u, + 0x5455855455415455u, 0x5515555144555545u, 0x0114400000145155u, 0x0000051000450511u, + 0x4455154554445100u, 0x4554150141544455u, 0x65955555559a5965u, 0x5555555854559559u, + 0x9569654559616595u, 0x1040044040005565u, 0x1010010500011044u, 0x1554015545154540u, + 0x4440555401545441u, 0x1014441450550105u, 0x4545400410504145u, 0x5015111541040151u, + 0x5145051154000410u, 0x1040001044545044u, 0x4001400000151410u, 0x0540000044040000u, + 0x0510555454411544u, 0x0400054054141550u, 0x1001041145001100u, 0x0000000140000000u, + 0x0000000014100000u, 0x1544005454000140u, 0x4050055505445145u, 0x0011511104504155u, + 0x5505544415045055u, 0x1155154445515554u, 0x0000000000004555u, 0x0000000000000000u, + 0x5101010510400004u, 0x1514045044440400u, 0x5515519555515555u, 0x4554545441555545u, + 0x1551055955551515u, 0x0150000011505515u, 0x0044005040400000u, 0x0004001004010050u, + 0x0000051004450414u, 0x0114001101001144u, 0x0401000001000001u, 0x4500010001000401u, + 0x0004100000005000u, 0x0105000441101100u, 0x0455455550454540u, 0x5404050144105505u, + 0x4101510540555455u, 0x1055541411451555u, 0x5451445110115505u, 0x1154110010101545u, + 0x1145140450054055u, 0x5555565415551554u, 0x1550559555555555u, 0x5555541545045141u, + 0x4555455450500100u, 0x5510454545554555u, 0x1510140115045455u, 0x1001050040111510u, + 0x5555454555555504u, 0x9954155545515554u, 0x6596656555555555u, 0x0140410051555559u, + 0x0011104010001544u, 0x965669659a680501u, 0x5655a55955556955u, 0x4015111014404514u, + 0x1414155554505145u, 0x0540040011051404u, 0x1010000000015005u, 0x0010054050004410u, + 0x5041104014000100u, 0x4440010500100001u, 0x1155510504545554u, 0x0450151545115541u, + 0x4000100400110440u, 0x1004440010514440u, 0x0000115050450000u, 0x0545404455541500u, + 0x1051051555505101u, 0x5505144554544144u, 0x4550545555515550u, 0x0015400450045445u, + 0x4514155400554415u, 0x4555055051050151u, 0x1511441450001014u, 0x4544554510404414u, + 0x4115115545545450u, 0x5500541555551555u, 0x5550010544155015u, 0x0144414045545500u, + 0x4154050001050150u, 0x5550511111000145u, 0x1114504055000151u, 0x5104041101451040u, + 0x0010501401051441u, 0x0010501450504401u, 0x4554585440044444u, 0x5155555951450455u, + 0x0040000400105555u, 0x0000000000000001u, + }; + +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <bool b> constexpr uint64_t ryu_tables_template<b>::GENERIC_POW5_TABLE[BOOST_CHARCONV_POW5_TABLE_SIZE][2]; +template <bool b> constexpr uint64_t ryu_tables_template<b>::GENERIC_POW5_SPLIT[89][4]; +template <bool b> constexpr uint64_t ryu_tables_template<b>::GENERIC_POW5_INV_SPLIT[89][4]; +template <bool b> constexpr uint64_t ryu_tables_template<b>::POW5_ERRORS[156]; +template <bool b> constexpr uint64_t ryu_tables_template<b>::POW5_INV_ERRORS[154]; + +#endif + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +using ryu_tables = ryu_tables_template<true>; + +#endif + +// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 32768. +static BOOST_CHARCONV_CXX14_CONSTEXPR uint32_t pow5bits(const uint32_t e) noexcept +{ + BOOST_CHARCONV_ASSERT(e <= 1 << 15); + return static_cast<uint32_t>(((e * UINT64_C(163391164108059)) >> 46) + 1); +} + +static BOOST_CHARCONV_CXX14_CONSTEXPR +void mul_128_256_shift( + const uint64_t* const a, const uint64_t* const b, + const uint32_t shift, const uint32_t corr, + uint64_t* const result) noexcept +{ + BOOST_CHARCONV_ASSERT(shift > 0); + BOOST_CHARCONV_ASSERT(shift < 256); + const unsigned_128_type b00 = static_cast<unsigned_128_type>(a[0]) * b[0]; // 0 + const unsigned_128_type b01 = static_cast<unsigned_128_type>(a[0]) * b[1]; // 64 + const unsigned_128_type b02 = static_cast<unsigned_128_type>(a[0]) * b[2]; // 128 + const unsigned_128_type b03 = static_cast<unsigned_128_type>(a[0]) * b[3]; // 196 + const unsigned_128_type b10 = static_cast<unsigned_128_type>(a[1]) * b[0]; // 64 + const unsigned_128_type b11 = static_cast<unsigned_128_type>(a[1]) * b[1]; // 128 + const unsigned_128_type b12 = static_cast<unsigned_128_type>(a[1]) * b[2]; // 196 + const unsigned_128_type b13 = static_cast<unsigned_128_type>(a[1]) * b[3]; // 256 + + const unsigned_128_type s0 = b00; // 0 x + const unsigned_128_type s1 = b01 + b10; // 64 x + const unsigned_128_type c1 = s1 < b01; // 196 x + const unsigned_128_type s2 = b02 + b11; // 128 x + const unsigned_128_type c2 = s2 < b02; // 256 x + const unsigned_128_type s3 = b03 + b12; // 196 x + const unsigned_128_type c3 = s3 < b03; // 324 x + + const unsigned_128_type p0 = s0 + (s1 << 64); // 0 + const unsigned_128_type d0 = p0 < b00; // 128 + const unsigned_128_type q1 = s2 + (s1 >> 64) + (s3 << 64); // 128 + const unsigned_128_type d1 = q1 < s2; // 256 + const unsigned_128_type p1 = q1 + (c1 << 64) + d0; // 128 + const unsigned_128_type d2 = p1 < q1; // 256 + const unsigned_128_type p2 = b13 + (s3 >> 64) + c2 + (c3 << 64) + d1 + d2; // 256 + + if (shift < 128) + { + const unsigned_128_type r0 = corr + ((p0 >> shift) | (p1 << (128 - shift))); + const unsigned_128_type r1 = ((p1 >> shift) | (p2 << (128 - shift))) + (r0 < corr); + result[0] = static_cast<uint64_t>(r0); + result[1] = static_cast<uint64_t>(r0 >> 64); + result[2] = static_cast<uint64_t>(r1); + result[3] = static_cast<uint64_t>(r1 >> 64); + } + else if (shift == 128) + { + const unsigned_128_type r0 = corr + p1; + const unsigned_128_type r1 = p2 + (r0 < corr); + result[0] = static_cast<uint64_t>(r0); + result[1] = static_cast<uint64_t>(r0 >> 64); + result[2] = static_cast<uint64_t>(r1); + result[3] = static_cast<uint64_t>(r1 >> 64); + } + else + { + const unsigned_128_type r0 = corr + ((p1 >> (shift - 128)) | (p2 << (256 - shift))); + const unsigned_128_type r1 = (p2 >> (shift - 128)) + (r0 < corr); + result[0] = static_cast<uint64_t>(r0); + result[1] = static_cast<uint64_t>(r0 >> 64); + result[2] = static_cast<uint64_t>(r1); + result[3] = static_cast<uint64_t>(r1 >> 64); + } +} + +// Computes 5^i in the form required by Ryu, and stores it in the given pointer. +static BOOST_CXX14_CONSTEXPR void generic_computePow5(const uint32_t i, uint64_t* const result) noexcept +{ + const uint32_t base = i / BOOST_CHARCONV_POW5_TABLE_SIZE; + const uint32_t base2 = base * BOOST_CHARCONV_POW5_TABLE_SIZE; + const uint64_t* const mul = ryu_tables::GENERIC_POW5_SPLIT[base]; + if (i == base2) + { + result[0] = mul[0]; + result[1] = mul[1]; + result[2] = mul[2]; + result[3] = mul[3]; + } + else + { + const uint32_t offset = i - base2; + const uint64_t* const m = ryu_tables::GENERIC_POW5_TABLE[offset]; + const uint32_t delta = pow5bits(i) - pow5bits(base2); + const uint32_t corr = static_cast<uint32_t>((ryu_tables::POW5_ERRORS[i / 32] >> (2 * (i % 32))) & 3); + mul_128_256_shift(m, mul, delta, corr, result); + } +} + +// Computes 5^-i in the form required by Ryu, and stores it in the given pointer. +static BOOST_CXX14_CONSTEXPR void generic_computeInvPow5(const uint32_t i, uint64_t* const result) noexcept +{ + const uint32_t base = (i + BOOST_CHARCONV_POW5_TABLE_SIZE - 1) / BOOST_CHARCONV_POW5_TABLE_SIZE; + const uint32_t base2 = base * BOOST_CHARCONV_POW5_TABLE_SIZE; + const uint64_t* const mul = ryu_tables::GENERIC_POW5_INV_SPLIT[base]; // 1/5^base2 + if (i == base2) + { + result[0] = mul[0] + 1; + result[1] = mul[1]; + result[2] = mul[2]; + result[3] = mul[3]; + } + else + { + const uint32_t offset = base2 - i; + const uint64_t* const m = ryu_tables::GENERIC_POW5_TABLE[offset]; // 5^offset + const uint32_t delta = pow5bits(base2) - pow5bits(i); + const uint32_t corr = static_cast<uint32_t>((ryu_tables::POW5_INV_ERRORS[i / 32] >> (2 * (i % 32))) & 3) + UINT32_C(1); + mul_128_256_shift(m, mul, delta, corr, result); + } +} + +static BOOST_CXX14_CONSTEXPR uint32_t pow5Factor(unsigned_128_type value) noexcept +{ + for (uint32_t count = 0; value > 0; ++count) + { + if (value % 5 != 0) + { + return count; + } + value /= 5; + } + return 0; +} + +// Returns true if value is divisible by 5^p. +static BOOST_CHARCONV_CXX14_CONSTEXPR bool multipleOfPowerOf5(const unsigned_128_type value, const uint32_t p) noexcept +{ + // I tried a case distinction on p, but there was no performance difference. + return pow5Factor(value) >= p; +} + +// Returns true if value is divisible by 2^p. +static BOOST_CHARCONV_CXX14_CONSTEXPR bool multipleOfPowerOf2(const unsigned_128_type value, const uint32_t p) noexcept +{ + return (value & ((static_cast<unsigned_128_type>(1) << p) - 1)) == 0; +} + +static BOOST_CHARCONV_CXX14_CONSTEXPR +unsigned_128_type mulShift(const unsigned_128_type m, const uint64_t* const mul, const int32_t j) noexcept +{ + BOOST_CHARCONV_ASSERT(j > 128); + uint64_t a[2] {}; + a[0] = static_cast<uint64_t>(m); + a[1] = static_cast<uint64_t>(m >> 64); + uint64_t result[4] {}; + mul_128_256_shift(a, mul, static_cast<uint32_t>(j), 0, result); + return (static_cast<unsigned_128_type>(result[1]) << 64) | result[0]; +} + +// Returns floor(log_10(2^e)). +static BOOST_CHARCONV_CXX14_CONSTEXPR uint32_t log10Pow2(const int32_t e) noexcept +{ + // The first value this approximation fails for is 2^1651 which is just greater than 10^297. + BOOST_CHARCONV_ASSERT(e >= 0); + BOOST_CHARCONV_ASSERT(e <= 1 << 15); + return static_cast<uint32_t>((static_cast<uint64_t>(e) * UINT64_C(169464822037455)) >> 49); +} + +// Returns floor(log_10(5^e)). +static BOOST_CHARCONV_CXX14_CONSTEXPR uint32_t log10Pow5(const int32_t e) noexcept +{ + // The first value this approximation fails for is 5^2621 which is just greater than 10^1832. + assert(e >= 0); + assert(e <= 1 << 15); + return static_cast<uint32_t>((static_cast<uint64_t>(e) * UINT64_C(196742565691928)) >> 48); +} + +}}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_RYU_GENERIC_128_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/ryu/ryu_generic_128.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/ryu/ryu_generic_128.hpp new file mode 100644 index 00000000000..2047d9a70f2 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/ryu/ryu_generic_128.hpp @@ -0,0 +1,767 @@ +// Copyright 2018 - 2023 Ulf Adams +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_RYU_RYU_GENERIC_128_HPP +#define BOOST_CHARCONV_DETAIL_RYU_RYU_GENERIC_128_HPP + +#include <boost/charconv/detail/ryu/generic_128.hpp> +#include <boost/charconv/detail/integer_search_trees.hpp> +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <boost/charconv/to_chars.hpp> +#include <cinttypes> +#include <cstdio> +#include <cstdint> + +#ifdef BOOST_CHARCONV_DEBUG +# include <iostream> +#endif + +namespace boost { namespace charconv { namespace detail { namespace ryu { + +static constexpr int32_t fd128_exceptional_exponent = 0x7FFFFFFF; +static constexpr unsigned_128_type one = 1; + +struct floating_decimal_128 +{ + unsigned_128_type mantissa; + int32_t exponent; + bool sign; +}; + +#ifdef BOOST_CHARCONV_DEBUG +static char* s(unsigned_128_type v) { + int len = num_digits(v); + char* b = static_cast<char*>(malloc((len + 1) * sizeof(char))); + for (int i = 0; i < len; i++) { + const uint32_t c = static_cast<uint32_t>(v % 10); + v /= 10; + b[len - 1 - i] = static_cast<char>('0' + c); + } + b[len] = 0; + return b; +} +#endif + +static inline struct floating_decimal_128 generic_binary_to_decimal( + const unsigned_128_type bits, + const uint32_t mantissaBits, const uint32_t exponentBits, const bool explicitLeadingBit) noexcept +{ + #ifdef BOOST_CHARCONV_DEBUG + printf("IN="); + for (int32_t bit = 127; bit >= 0; --bit) + { + printf("%u", static_cast<uint32_t>((bits >> bit) & 1)); + } + printf("\n"); + #endif + + const uint32_t bias = (1u << (exponentBits - 1)) - 1; + const bool ieeeSign = ((bits >> (mantissaBits + exponentBits)) & 1) != 0; + const unsigned_128_type ieeeMantissa = bits & ((one << mantissaBits) - 1); + const uint32_t ieeeExponent = static_cast<uint32_t>((bits >> mantissaBits) & ((one << exponentBits) - 1u)); + + if (ieeeExponent == 0 && ieeeMantissa == 0) + { + struct floating_decimal_128 fd {0, 0, ieeeSign}; + return fd; + } + if (ieeeExponent == ((1u << exponentBits) - 1u)) + { + struct floating_decimal_128 fd; + fd.mantissa = explicitLeadingBit ? ieeeMantissa & ((one << (mantissaBits - 1)) - 1) : ieeeMantissa; + fd.exponent = fd128_exceptional_exponent; + fd.sign = ieeeSign; + return fd; + } + + int32_t e2; + unsigned_128_type m2; + // We subtract 2 in all cases so that the bounds computation has 2 additional bits. + if (explicitLeadingBit) + { + // mantissaBits includes the explicit leading bit, so we need to correct for that here. + if (ieeeExponent == 0) + { + e2 = static_cast<int32_t>(1 - bias - mantissaBits + 1 - 2); + } + else + { + e2 = static_cast<int32_t>(ieeeExponent - bias - mantissaBits + 1 - 2); + } + m2 = ieeeMantissa; + } + else + { + if (ieeeExponent == 0) + { + e2 = static_cast<int32_t>(1 - bias - mantissaBits - 2); + m2 = ieeeMantissa; + } else + { + e2 = static_cast<int32_t>(ieeeExponent - bias - mantissaBits - 2U); + m2 = (one << mantissaBits) | ieeeMantissa; + } + } + const bool even = (m2 & 1) == 0; + const bool acceptBounds = even; + + #ifdef BOOST_CHARCONV_DEBUG + printf("-> %s %s * 2^%d\n", ieeeSign ? "-" : "+", s(m2), e2 + 2); + #endif + + // Step 2: Determine the interval of legal decimal representations. + const unsigned_128_type mv = 4 * m2; + // Implicit bool -> int conversion. True is 1, false is 0. + const uint32_t mmShift = + (ieeeMantissa != (explicitLeadingBit ? one << (mantissaBits - 1) : 0)) + || (ieeeExponent == 0); + + // Step 3: Convert to a decimal power base using 128-bit arithmetic. + unsigned_128_type vr; + unsigned_128_type vp; + unsigned_128_type vm; + int32_t e10; + bool vmIsTrailingZeros = false; + bool vrIsTrailingZeros = false; + if (e2 >= 0) + { + // I tried special-casing q == 0, but there was no effect on performance. + // This expression is slightly faster than max(0, log10Pow2(e2) - 1). + const uint32_t q = log10Pow2(e2) - (e2 > 3); + e10 = static_cast<int32_t>(q); + const int32_t k = BOOST_CHARCONV_POW5_INV_BITCOUNT + static_cast<int32_t>(pow5bits(q)) - 1; + const int32_t i = -e2 + static_cast<int32_t>(q) + k; + uint64_t pow5[4]; + generic_computeInvPow5(q, pow5); + vr = mulShift(4 * m2, pow5, i); + vp = mulShift(4 * m2 + 2, pow5, i); + vm = mulShift(4 * m2 - 1 - mmShift, pow5, i); + + #ifdef BOOST_CHARCONV_DEBUG + printf("%s * 2^%d / 10^%d\n", s(mv), e2, q); + printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm)); + #endif + + // floor(log_5(2^128)) = 55, this is very conservative + if (q <= 55) + { + // Only one of mp, mv, and mm can be a multiple of 5, if any. + if (mv % 5 == 0) + { + vrIsTrailingZeros = multipleOfPowerOf5(mv, q - 1); + } + else if (acceptBounds) + { + // Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q + // <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q + // <=> true && pow5Factor(mm) >= q, since e2 >= q. + vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q); + } + else + { + // Same as min(e2 + 1, pow5Factor(mp)) >= q. + vp -= multipleOfPowerOf5(mv + 2, q); + } + } + } + else + { + // This expression is slightly faster than max(0, log10Pow5(-e2) - 1). + const uint32_t q = log10Pow5(-e2) - static_cast<uint32_t>(-e2 > 1); + e10 = static_cast<int32_t>(q) + e2; + const int32_t i = -e2 - static_cast<int32_t>(q); + const int32_t k = static_cast<int32_t>(pow5bits(static_cast<uint32_t>(i))) - BOOST_CHARCONV_POW5_BITCOUNT; + const int32_t j = static_cast<int32_t>(q) - k; + uint64_t pow5[4]; + generic_computePow5(static_cast<uint32_t>(i), pow5); + vr = mulShift(4 * m2, pow5, j); + vp = mulShift(4 * m2 + 2, pow5, j); + vm = mulShift(4 * m2 - 1 - mmShift, pow5, j); + + #ifdef BOOST_CHARCONV_DEBUG + printf("%s * 5^%d / 10^%d\n", s(mv), -e2, q); + printf("%d %d %d %d\n", q, i, k, j); + printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm)); + #endif + + if (q <= 1) + { + // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. + // mv = 4 m2, so it always has at least two trailing 0 bits. + vrIsTrailingZeros = true; + if (acceptBounds) + { + // mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1. + vmIsTrailingZeros = mmShift == 1; + } + else + { + // mp = mv + 2, so it always has at least one trailing 0 bit. + --vp; + } + } + else if (q < 127) + { + // We need to compute min(ntz(mv), pow5Factor(mv) - e2) >= q-1 + // <=> ntz(mv) >= q-1 && pow5Factor(mv) - e2 >= q-1 + // <=> ntz(mv) >= q-1 (e2 is negative and -e2 >= q) + // <=> (mv & ((1 << (q-1)) - 1)) == 0 + // We also need to make sure that the left shift does not overflow. + vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1); + + #ifdef BOOST_CHARCONV_DEBUG + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); + #endif + } + } + + #ifdef BOOST_CHARCONV_DEBUG + printf("e10=%d\n", e10); + printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm)); + printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false"); + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); + #endif + + // Step 4: Find the shortest decimal representation in the interval of legal representations. + uint32_t removed = 0; + uint8_t lastRemovedDigit = 0; + unsigned_128_type output; + + while (vp / 10 > vm / 10) + { + vmIsTrailingZeros &= vm % 10 == 0; + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = static_cast<uint8_t>(vr % 10); + vr /= 10; + vp /= 10; + vm /= 10; + ++removed; + } + + #ifdef BOOST_CHARCONV_DEBUG + printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm)); + printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false"); + #endif + + if (vmIsTrailingZeros) + { + while (vm % 10 == 0) + { + vrIsTrailingZeros &= lastRemovedDigit == 0; + lastRemovedDigit = static_cast<uint8_t>(vr % 10); + vr /= 10; + vp /= 10; + vm /= 10; + ++removed; + } + } + + #ifdef BOOST_CHARCONV_DEBUG + printf("%s %d\n", s(vr), lastRemovedDigit); + printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false"); + #endif + + if (vrIsTrailingZeros && (lastRemovedDigit == 5) && (vr % 2 == 0)) + { + // Round even if the exact numbers is .....50..0. + lastRemovedDigit = 4; + } + // We need to take vr+1 if vr is outside bounds, or we need to round up. + output = vr + static_cast<unsigned_128_type>((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || (lastRemovedDigit >= 5)); + const int32_t exp = e10 + static_cast<int32_t>(removed); + + #ifdef BOOST_CHARCONV_DEBUG + printf("V+=%s\nV =%s\nV-=%s\n", s(vp), s(vr), s(vm)); + printf("O=%s\n", s(output)); + printf("EXP=%d\n", exp); + #endif + + return {output, exp, ieeeSign}; +} + +static inline int copy_special_str(char* result, const std::ptrdiff_t result_size, const struct floating_decimal_128 fd) noexcept +{ + if (fd.sign) + { + *result = '-'; + ++result; + } + + if (fd.mantissa) + { + if (fd.sign) + { + if (fd.mantissa == static_cast<unsigned_128_type>(2305843009213693952) || + fd.mantissa == static_cast<unsigned_128_type>(6917529027641081856) || + fd.mantissa == static_cast<unsigned_128_type>(1) << 110) // 2^110 + { + if (result_size >= 10) + { + std::memcpy(result, "nan(snan)", 9); + return 10; + } + else + { + return -1; + } + } + else + { + if (result_size >= 9) + { + std::memcpy(result, "nan(ind)", 8); + return 9; + } + else + { + return -1; + } + } + } + else + { + if (fd.mantissa == static_cast<unsigned_128_type>(2305843009213693952) || + fd.mantissa == static_cast<unsigned_128_type>(6917529027641081856) || + fd.mantissa == static_cast<unsigned_128_type>(1) << 110) // 2^110 + { + if (result_size >= 9) + { + std::memcpy(result, "nan(snan)", 9); + return 9; + } + else + { + return -1; + } + } + else + { + if (result_size >= 3) + { + std::memcpy(result, "nan", 3); + return 3; + } + else + { + return -1; + } + } + } + } + + if (result_size >= 3 + static_cast<std::ptrdiff_t>(fd.sign)) + { + memcpy(result, "inf", 3); + return static_cast<int>(fd.sign) + 3; + } + + return -1; +} + +static inline int generic_to_chars_fixed(const struct floating_decimal_128 v, char* result, const ptrdiff_t result_size, int precision) noexcept +{ + if (v.exponent == fd128_exceptional_exponent) + { + return copy_special_str(result, result_size, v); + } + + // Step 5: Print the decimal representation. + if (v.sign) + { + *result++ = '-'; + } + + unsigned_128_type output = v.mantissa; + const auto r = to_chars_128integer_impl(result, result + result_size, output); + if (r.ec != std::errc()) + { + return -static_cast<int>(r.ec); + } + + auto current_len = static_cast<int>(r.ptr - result); + + #ifdef BOOST_CHARCONV_DEBUG + char* man_print = s(v.mantissa); + std::cerr << "Exp: " << v.exponent + << "\nMantissa: " << man_print + << "\nMan len: " << current_len << std::endl; + free(man_print); + #endif + + if (v.exponent == 0) + { + // Option 1: We need to do nothing but insert 0s + if (precision > 0) + { + result[current_len++] = '.'; + memset(result+current_len, '0', static_cast<size_t>(precision)); + current_len += precision; + precision = 0; + } + } + else if (v.exponent > 0) + { + // Option 2: Append 0s to the end of the number until we get the proper significand value + // Then we need precison worth of zeros after the decimal point as applicable + if (current_len + v.exponent > result_size) + { + return -static_cast<int>(std::errc::value_too_large); + } + + result = r.ptr; + memset(result, '0', static_cast<std::size_t>(v.exponent)); + result += static_cast<std::size_t>(v.exponent); + *result++ = '.'; + current_len += v.exponent + 1; + } + else if ((-v.exponent) < current_len) + { + // Option 3: Insert a decimal point into the middle of the existing number + if (current_len + v.exponent + 1 > result_size) + { + return -static_cast<int>(std::errc::result_out_of_range); + } + + memmove(result + current_len + v.exponent + 1, result + current_len + v.exponent, static_cast<std::size_t>(-v.exponent)); + const auto shift = result + current_len + v.exponent; + const auto shift_width = (shift - result) + 1; + memcpy(shift, ".", 1U); + ++current_len; + if (current_len - shift_width > precision) + { + if (precision > 0) + { + current_len = static_cast<int>(shift_width) + precision; + } + + precision = 0; + // Since we wrote additional characters into the buffer we need to add a null terminator, + // so they are not read + const auto round_val = result[current_len]; + result[current_len] = '\0'; + + // More complicated rounding situations like 9999.999999 are already handled + // so we don't need to worry about rounding past the decimal point + if (round_val >= '5') + { + auto current_spot = current_len - 1; + bool continue_rounding = true; + while (result[current_spot] != '.' && continue_rounding) + { + if (result[current_spot] < '9') + { + result[current_spot] = static_cast<char>(static_cast<int>(result[current_spot]) + 1); + continue_rounding = false; + } + else + { + result[current_spot] = '0'; + continue_rounding = true; + } + --current_spot; + } + BOOST_CHARCONV_ASSERT(!continue_rounding); + } + } + else + { + precision -= current_len - static_cast<int>(shift_width); + result += current_len + v.exponent + 1; + } + } + else + { + // Option 4: Leading 0s + if (-v.exponent + 2 > result_size) + { + return -static_cast<int>(std::errc::value_too_large); + } + + memmove(result - v.exponent - current_len + 2, result, static_cast<std::size_t>(current_len)); + memcpy(result, "0.", 2U); + memset(result + 2, '0', static_cast<std::size_t>(0 - v.exponent - current_len)); + current_len = -v.exponent + 2; + precision -= current_len - 2; + result += current_len; + } + + if (precision > 0) + { + if (current_len + precision > result_size) + { + return -static_cast<int>(std::errc::result_out_of_range); + } + + memset(result, '0', static_cast<std::size_t>(precision)); + current_len += precision; + } + + return current_len + static_cast<int>(v.sign); +} + +// Converts the given decimal floating point number to a string, writing to result, and returning +// the number characters written. Does not terminate the buffer with a 0. In the worst case, this +// function can write up to 53 characters. +// +// Maximal char buffer requirement: +// sign + mantissa digits + decimal dot + 'E' + exponent sign + exponent digits +// = 1 + 39 + 1 + 1 + 1 + 10 = 53 +static inline int generic_to_chars(const struct floating_decimal_128 v, char* result, const ptrdiff_t result_size, + chars_format fmt = chars_format::general, int precision = -1) noexcept +{ + if (v.exponent == fd128_exceptional_exponent) + { + return copy_special_str(result, result_size, v); + } + + unsigned_128_type output = v.mantissa; + const uint32_t olength = static_cast<uint32_t>(num_digits(output)); + + #ifdef BOOST_CHARCONV_DEBUG + printf("DIGITS=%s\n", s(v.mantissa)); + printf("OLEN=%u\n", olength); + printf("EXP=%u\n", v.exponent + olength); + #endif + + // See: https://github.com/cppalliance/charconv/issues/64 + if (fmt == chars_format::general) + { + const int64_t exp = v.exponent + static_cast<int64_t>(olength); + if (std::abs(exp) <= olength) + { + auto ptr = generic_to_chars_fixed(v, result, result_size, precision); + if (ptr >= 1 && result[ptr - 1] == '0') + { + --ptr; + while (ptr > 0 && result[ptr] == '0') + { + --ptr; + } + ++ptr; + } + return ptr; + } + } + + // Step 5: Print the decimal representation. + size_t index = 0; + if (v.sign) + { + result[index++] = '-'; + } + + if (index + olength > static_cast<size_t>(result_size)) + { + return -static_cast<int>(std::errc::value_too_large); + } + else if (olength == 0) + { + return -2; // Something has gone horribly wrong + } + + for (uint32_t i = 0; i < olength - 1; ++i) + { + const auto c = static_cast<uint32_t>(output % 10); + output /= 10; + result[index + olength - i] = static_cast<char>('0' + c); + } + BOOST_CHARCONV_ASSERT(output < 10); + result[index] = static_cast<char>('0' + static_cast<uint32_t>(output % 10)); // output should be < 10 by now. + + // Print decimal point if needed. + if (olength > 1) + { + result[index + 1] = '.'; + index += olength + 1; + } + else + { + ++index; + } + + // Reset the index to where the required precision should be + if (precision != -1) + { + if (static_cast<size_t>(precision) < index) + { + if (fmt != chars_format::scientific) + { + index = static_cast<size_t>(precision) + 1 + static_cast<size_t>(v.sign); // Precision is number of characters not just the decimal portion + } + else + { + index = static_cast<size_t>(precision) + 2 + static_cast<size_t>(v.sign); // In scientific format the precision is just the decimal places + } + + // Now we need to see if we need to round + if (result[index] >= '5' && index < olength + 1 + static_cast<size_t>(v.sign)) + { + bool continue_rounding = false; + auto current_index = index; + do + { + --current_index; + if (result[current_index] == '9') + { + continue_rounding = true; + result[current_index] = '0'; + } + else + { + continue_rounding = false; + result[current_index] = static_cast<char>(result[current_index] + static_cast<char>(1)); + } + } while (continue_rounding && current_index > 2); + } + + // If the last digit is a zero than overwrite that as well, but not in scientific formatting + if (fmt != chars_format::scientific) + { + while (result[index - 1] == '0') + { + --index; + } + } + else + { + // In scientific formatting we may need a final 0 to achieve the correct precision + if (precision + 1 > static_cast<int>(olength)) + { + result[index - 1] = '0'; + } + } + } + else if (static_cast<size_t>(precision) > index) + { + // Use our fallback routine that will capture more of the precision + return -1; + } + } + + // Print the exponent. + result[index++] = 'e'; + int32_t exp = v.exponent + static_cast<int32_t>(olength) - 1; + if (exp < 0) + { + result[index++] = '-'; + exp = -exp; + } + else + { + result[index++] = '+'; + } + + uint32_t elength = static_cast<uint32_t>(num_digits(exp)); + for (uint32_t i = 0; i < elength; ++i) + { + // Always print a minimum of 2 characters in the exponent field + if (elength == 1) + { + result[index + elength - 1 - i] = '0'; + ++index; + } + + const uint32_t c = static_cast<uint32_t>(exp % 10); + exp /= 10; + result[index + elength - 1 - i] = static_cast<char>('0' + c); + } + if (elength == 0) + { + result[index++] = '0'; + result[index++] = '0'; + } + + index += elength; + return static_cast<int>(index); +} + +static inline struct floating_decimal_128 float_to_fd128(float f) noexcept +{ + static_assert(sizeof(float) == sizeof(uint32_t), "Float is not 32 bits"); + uint32_t bits = 0; + std::memcpy(&bits, &f, sizeof(float)); + return generic_binary_to_decimal(bits, 23, 8, false); +} + +static inline struct floating_decimal_128 double_to_fd128(double d) noexcept +{ + static_assert(sizeof(double) == sizeof(uint64_t), "Double is not 64 bits"); + uint64_t bits = 0; + std::memcpy(&bits, &d, sizeof(double)); + return generic_binary_to_decimal(bits, 52, 11, false); +} + +// https://en.cppreference.com/w/cpp/types/floating-point#Fixed_width_floating-point_types + +#ifdef BOOST_CHARCONV_HAS_FLOAT16 + +static inline struct floating_decimal_128 float16_t_to_fd128(std::float16_t f) noexcept +{ + uint16_t bits = 0; + std::memcpy(&bits, &f, sizeof(std::float16_t)); + return generic_binary_to_decimal(bits, 10, 5, false); +} + +#endif + +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 + +static inline struct floating_decimal_128 float16_t_to_fd128(std::bfloat16_t f) noexcept +{ + uint16_t bits = 0; + std::memcpy(&bits, &f, sizeof(std::bfloat16_t)); + return generic_binary_to_decimal(bits, 7, 8, false); +} + +#endif + +#if BOOST_CHARCONV_LDBL_BITS == 80 + +static inline struct floating_decimal_128 long_double_to_fd128(long double d) noexcept +{ + #ifdef BOOST_CHARCONV_HAS_INT128 + unsigned_128_type bits = 0; + std::memcpy(&bits, &d, sizeof(long double)); + #else + trivial_uint128 trivial_bits; + std::memcpy(&trivial_bits, &d, sizeof(long double)); + unsigned_128_type bits {trivial_bits}; + #endif + + #ifdef BOOST_CHARCONV_DEBUG + // For some odd reason, this ends up with noise in the top 48 bits. We can + // clear out those bits with the following line; this is not required, the + // conversion routine should ignore those bits, but the debug output can be + // confusing if they aren't 0s. + bits &= (one << 80) - 1; + #endif + + return generic_binary_to_decimal(bits, 64, 15, true); +} + +#elif BOOST_CHARCONV_LDBL_BITS == 128 + +static inline struct floating_decimal_128 long_double_to_fd128(long double d) noexcept +{ + unsigned_128_type bits = 0; + std::memcpy(&bits, &d, sizeof(long double)); + + #if LDBL_MANT_DIG == 113 // binary128 (e.g. ARM, S390X, PPC64LE) + # ifdef __PPC64__ + return generic_binary_to_decimal(bits, 112, 15, false); + # else + return generic_binary_to_decimal(bits, 112, 15, true); + # endif + #elif LDBL_MANT_DIG == 106 // ibm128 (e.g. PowerPC) + return generic_binary_to_decimal(bits, 105, 11, true); + #endif +} + +#endif + +}}}} // Namespaces + +#endif //BOOST_RYU_GENERIC_128_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/significand_tables.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/significand_tables.hpp new file mode 100644 index 00000000000..51dd71f456e --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/significand_tables.hpp @@ -0,0 +1,691 @@ +// Copyright 2020-2023 Daniel Lemire +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_SIGNIFICAND_TABLES_HPP +#define BOOST_CHARCONV_DETAIL_SIGNIFICAND_TABLES_HPP + +#include <boost/charconv/detail/config.hpp> +#include <cstdint> + +// The significand of a floating point number is often referred to as the mantissa. +// Using the term mantissa is discouraged by IEEE 1516 + +namespace boost { namespace charconv { namespace detail { + + // The significands of powers of ten from -308 to 308, extended out to sixty four + // bits. The array contains the powers of ten approximated + // as a 64-bit significand. It goes from 10^BOOST_CHARCONV_FASTFLOAT_SMALLEST_POWER to + // 10^BOOST_CHARCONV_FASTFLOAT_LARGEST_POWER (inclusively). + // The significand is truncated, and never rounded up. + // Uses about 5KB. + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) +template <bool b> +struct significand_template +#else +struct significands_table +#endif +{ + static constexpr std::uint64_t significand_64[] = { + 0xa5ced43b7e3e9188, 0xcf42894a5dce35ea, + 0x818995ce7aa0e1b2, 0xa1ebfb4219491a1f, + 0xca66fa129f9b60a6, 0xfd00b897478238d0, + 0x9e20735e8cb16382, 0xc5a890362fddbc62, + 0xf712b443bbd52b7b, 0x9a6bb0aa55653b2d, + 0xc1069cd4eabe89f8, 0xf148440a256e2c76, + 0x96cd2a865764dbca, 0xbc807527ed3e12bc, + 0xeba09271e88d976b, 0x93445b8731587ea3, + 0xb8157268fdae9e4c, 0xe61acf033d1a45df, + 0x8fd0c16206306bab, 0xb3c4f1ba87bc8696, + 0xe0b62e2929aba83c, 0x8c71dcd9ba0b4925, + 0xaf8e5410288e1b6f, 0xdb71e91432b1a24a, + 0x892731ac9faf056e, 0xab70fe17c79ac6ca, + 0xd64d3d9db981787d, 0x85f0468293f0eb4e, + 0xa76c582338ed2621, 0xd1476e2c07286faa, + 0x82cca4db847945ca, 0xa37fce126597973c, + 0xcc5fc196fefd7d0c, 0xff77b1fcbebcdc4f, + 0x9faacf3df73609b1, 0xc795830d75038c1d, + 0xf97ae3d0d2446f25, 0x9becce62836ac577, + 0xc2e801fb244576d5, 0xf3a20279ed56d48a, + 0x9845418c345644d6, 0xbe5691ef416bd60c, + 0xedec366b11c6cb8f, 0x94b3a202eb1c3f39, + 0xb9e08a83a5e34f07, 0xe858ad248f5c22c9, + 0x91376c36d99995be, 0xb58547448ffffb2d, + 0xe2e69915b3fff9f9, 0x8dd01fad907ffc3b, + 0xb1442798f49ffb4a, 0xdd95317f31c7fa1d, + 0x8a7d3eef7f1cfc52, 0xad1c8eab5ee43b66, + 0xd863b256369d4a40, 0x873e4f75e2224e68, + 0xa90de3535aaae202, 0xd3515c2831559a83, + 0x8412d9991ed58091, 0xa5178fff668ae0b6, + 0xce5d73ff402d98e3, 0x80fa687f881c7f8e, + 0xa139029f6a239f72, 0xc987434744ac874e, + 0xfbe9141915d7a922, 0x9d71ac8fada6c9b5, + 0xc4ce17b399107c22, 0xf6019da07f549b2b, + 0x99c102844f94e0fb, 0xc0314325637a1939, + 0xf03d93eebc589f88, 0x96267c7535b763b5, + 0xbbb01b9283253ca2, 0xea9c227723ee8bcb, + 0x92a1958a7675175f, 0xb749faed14125d36, + 0xe51c79a85916f484, 0x8f31cc0937ae58d2, + 0xb2fe3f0b8599ef07, 0xdfbdcece67006ac9, + 0x8bd6a141006042bd, 0xaecc49914078536d, + 0xda7f5bf590966848, 0x888f99797a5e012d, + 0xaab37fd7d8f58178, 0xd5605fcdcf32e1d6, + 0x855c3be0a17fcd26, 0xa6b34ad8c9dfc06f, + 0xd0601d8efc57b08b, 0x823c12795db6ce57, + 0xa2cb1717b52481ed, 0xcb7ddcdda26da268, + 0xfe5d54150b090b02, 0x9efa548d26e5a6e1, + 0xc6b8e9b0709f109a, 0xf867241c8cc6d4c0, + 0x9b407691d7fc44f8, 0xc21094364dfb5636, + 0xf294b943e17a2bc4, 0x979cf3ca6cec5b5a, + 0xbd8430bd08277231, 0xece53cec4a314ebd, + 0x940f4613ae5ed136, 0xb913179899f68584, + 0xe757dd7ec07426e5, 0x9096ea6f3848984f, + 0xb4bca50b065abe63, 0xe1ebce4dc7f16dfb, + 0x8d3360f09cf6e4bd, 0xb080392cc4349dec, + 0xdca04777f541c567, 0x89e42caaf9491b60, + 0xac5d37d5b79b6239, 0xd77485cb25823ac7, + 0x86a8d39ef77164bc, 0xa8530886b54dbdeb, + 0xd267caa862a12d66, 0x8380dea93da4bc60, + 0xa46116538d0deb78, 0xcd795be870516656, + 0x806bd9714632dff6, 0xa086cfcd97bf97f3, + 0xc8a883c0fdaf7df0, 0xfad2a4b13d1b5d6c, + 0x9cc3a6eec6311a63, 0xc3f490aa77bd60fc, + 0xf4f1b4d515acb93b, 0x991711052d8bf3c5, + 0xbf5cd54678eef0b6, 0xef340a98172aace4, + 0x9580869f0e7aac0e, 0xbae0a846d2195712, + 0xe998d258869facd7, 0x91ff83775423cc06, + 0xb67f6455292cbf08, 0xe41f3d6a7377eeca, + 0x8e938662882af53e, 0xb23867fb2a35b28d, + 0xdec681f9f4c31f31, 0x8b3c113c38f9f37e, + 0xae0b158b4738705e, 0xd98ddaee19068c76, + 0x87f8a8d4cfa417c9, 0xa9f6d30a038d1dbc, + 0xd47487cc8470652b, 0x84c8d4dfd2c63f3b, + 0xa5fb0a17c777cf09, 0xcf79cc9db955c2cc, + 0x81ac1fe293d599bf, 0xa21727db38cb002f, + 0xca9cf1d206fdc03b, 0xfd442e4688bd304a, + 0x9e4a9cec15763e2e, 0xc5dd44271ad3cdba, + 0xf7549530e188c128, 0x9a94dd3e8cf578b9, + 0xc13a148e3032d6e7, 0xf18899b1bc3f8ca1, + 0x96f5600f15a7b7e5, 0xbcb2b812db11a5de, + 0xebdf661791d60f56, 0x936b9fcebb25c995, + 0xb84687c269ef3bfb, 0xe65829b3046b0afa, + 0x8ff71a0fe2c2e6dc, 0xb3f4e093db73a093, + 0xe0f218b8d25088b8, 0x8c974f7383725573, + 0xafbd2350644eeacf, 0xdbac6c247d62a583, + 0x894bc396ce5da772, 0xab9eb47c81f5114f, + 0xd686619ba27255a2, 0x8613fd0145877585, + 0xa798fc4196e952e7, 0xd17f3b51fca3a7a0, + 0x82ef85133de648c4, 0xa3ab66580d5fdaf5, + 0xcc963fee10b7d1b3, 0xffbbcfe994e5c61f, + 0x9fd561f1fd0f9bd3, 0xc7caba6e7c5382c8, + 0xf9bd690a1b68637b, 0x9c1661a651213e2d, + 0xc31bfa0fe5698db8, 0xf3e2f893dec3f126, + 0x986ddb5c6b3a76b7, 0xbe89523386091465, + 0xee2ba6c0678b597f, 0x94db483840b717ef, + 0xba121a4650e4ddeb, 0xe896a0d7e51e1566, + 0x915e2486ef32cd60, 0xb5b5ada8aaff80b8, + 0xe3231912d5bf60e6, 0x8df5efabc5979c8f, + 0xb1736b96b6fd83b3, 0xddd0467c64bce4a0, + 0x8aa22c0dbef60ee4, 0xad4ab7112eb3929d, + 0xd89d64d57a607744, 0x87625f056c7c4a8b, + 0xa93af6c6c79b5d2d, 0xd389b47879823479, + 0x843610cb4bf160cb, 0xa54394fe1eedb8fe, + 0xce947a3da6a9273e, 0x811ccc668829b887, + 0xa163ff802a3426a8, 0xc9bcff6034c13052, + 0xfc2c3f3841f17c67, 0x9d9ba7832936edc0, + 0xc5029163f384a931, 0xf64335bcf065d37d, + 0x99ea0196163fa42e, 0xc06481fb9bcf8d39, + 0xf07da27a82c37088, 0x964e858c91ba2655, + 0xbbe226efb628afea, 0xeadab0aba3b2dbe5, + 0x92c8ae6b464fc96f, 0xb77ada0617e3bbcb, + 0xe55990879ddcaabd, 0x8f57fa54c2a9eab6, + 0xb32df8e9f3546564, 0xdff9772470297ebd, + 0x8bfbea76c619ef36, 0xaefae51477a06b03, + 0xdab99e59958885c4, 0x88b402f7fd75539b, + 0xaae103b5fcd2a881, 0xd59944a37c0752a2, + 0x857fcae62d8493a5, 0xa6dfbd9fb8e5b88e, + 0xd097ad07a71f26b2, 0x825ecc24c873782f, + 0xa2f67f2dfa90563b, 0xcbb41ef979346bca, + 0xfea126b7d78186bc, 0x9f24b832e6b0f436, + 0xc6ede63fa05d3143, 0xf8a95fcf88747d94, + 0x9b69dbe1b548ce7c, 0xc24452da229b021b, + 0xf2d56790ab41c2a2, 0x97c560ba6b0919a5, + 0xbdb6b8e905cb600f, 0xed246723473e3813, + 0x9436c0760c86e30b, 0xb94470938fa89bce, + 0xe7958cb87392c2c2, 0x90bd77f3483bb9b9, + 0xb4ecd5f01a4aa828, 0xe2280b6c20dd5232, + 0x8d590723948a535f, 0xb0af48ec79ace837, + 0xdcdb1b2798182244, 0x8a08f0f8bf0f156b, + 0xac8b2d36eed2dac5, 0xd7adf884aa879177, + 0x86ccbb52ea94baea, 0xa87fea27a539e9a5, + 0xd29fe4b18e88640e, 0x83a3eeeef9153e89, + 0xa48ceaaab75a8e2b, 0xcdb02555653131b6, + 0x808e17555f3ebf11, 0xa0b19d2ab70e6ed6, + 0xc8de047564d20a8b, 0xfb158592be068d2e, + 0x9ced737bb6c4183d, 0xc428d05aa4751e4c, + 0xf53304714d9265df, 0x993fe2c6d07b7fab, + 0xbf8fdb78849a5f96, 0xef73d256a5c0f77c, + 0x95a8637627989aad, 0xbb127c53b17ec159, + 0xe9d71b689dde71af, 0x9226712162ab070d, + 0xb6b00d69bb55c8d1, 0xe45c10c42a2b3b05, + 0x8eb98a7a9a5b04e3, 0xb267ed1940f1c61c, + 0xdf01e85f912e37a3, 0x8b61313bbabce2c6, + 0xae397d8aa96c1b77, 0xd9c7dced53c72255, + 0x881cea14545c7575, 0xaa242499697392d2, + 0xd4ad2dbfc3d07787, 0x84ec3c97da624ab4, + 0xa6274bbdd0fadd61, 0xcfb11ead453994ba, + 0x81ceb32c4b43fcf4, 0xa2425ff75e14fc31, + 0xcad2f7f5359a3b3e, 0xfd87b5f28300ca0d, + 0x9e74d1b791e07e48, 0xc612062576589dda, + 0xf79687aed3eec551, 0x9abe14cd44753b52, + 0xc16d9a0095928a27, 0xf1c90080baf72cb1, + 0x971da05074da7bee, 0xbce5086492111aea, + 0xec1e4a7db69561a5, 0x9392ee8e921d5d07, + 0xb877aa3236a4b449, 0xe69594bec44de15b, + 0x901d7cf73ab0acd9, 0xb424dc35095cd80f, + 0xe12e13424bb40e13, 0x8cbccc096f5088cb, + 0xafebff0bcb24aafe, 0xdbe6fecebdedd5be, + 0x89705f4136b4a597, 0xabcc77118461cefc, + 0xd6bf94d5e57a42bc, 0x8637bd05af6c69b5, + 0xa7c5ac471b478423, 0xd1b71758e219652b, + 0x83126e978d4fdf3b, 0xa3d70a3d70a3d70a, + 0xcccccccccccccccc, 0x8000000000000000, + 0xa000000000000000, 0xc800000000000000, + 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, + 0x9896800000000000, 0xbebc200000000000, + 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, + 0x9184e72a00000000, 0xb5e620f480000000, + 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, + 0x8ac7230489e80000, 0xad78ebc5ac620000, + 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, + 0x84595161401484a0, 0xa56fa5b99019a5c8, + 0xcecb8f27f4200f3a, 0x813f3978f8940984, + 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, + 0xfc6f7c4045812296, 0x9dc5ada82b70b59d, + 0xc5371912364ce305, 0xf684df56c3e01bc6, + 0x9a130b963a6c115c, 0xc097ce7bc90715b3, + 0xf0bdc21abb48db20, 0x96769950b50d88f4, + 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, + 0x92efd1b8d0cf37be, 0xb7abc627050305ad, + 0xe596b7b0c643c719, 0x8f7e32ce7bea5c6f, + 0xb35dbf821ae4f38b, 0xe0352f62a19e306e, + 0x8c213d9da502de45, 0xaf298d050e4395d6, + 0xdaf3f04651d47b4c, 0x88d8762bf324cd0f, + 0xab0e93b6efee0053, 0xd5d238a4abe98068, + 0x85a36366eb71f041, 0xa70c3c40a64e6c51, + 0xd0cf4b50cfe20765, 0x82818f1281ed449f, + 0xa321f2d7226895c7, 0xcbea6f8ceb02bb39, + 0xfee50b7025c36a08, 0x9f4f2726179a2245, + 0xc722f0ef9d80aad6, 0xf8ebad2b84e0d58b, + 0x9b934c3b330c8577, 0xc2781f49ffcfa6d5, + 0xf316271c7fc3908a, 0x97edd871cfda3a56, + 0xbde94e8e43d0c8ec, 0xed63a231d4c4fb27, + 0x945e455f24fb1cf8, 0xb975d6b6ee39e436, + 0xe7d34c64a9c85d44, 0x90e40fbeea1d3a4a, + 0xb51d13aea4a488dd, 0xe264589a4dcdab14, + 0x8d7eb76070a08aec, 0xb0de65388cc8ada8, + 0xdd15fe86affad912, 0x8a2dbf142dfcc7ab, + 0xacb92ed9397bf996, 0xd7e77a8f87daf7fb, + 0x86f0ac99b4e8dafd, 0xa8acd7c0222311bc, + 0xd2d80db02aabd62b, 0x83c7088e1aab65db, + 0xa4b8cab1a1563f52, 0xcde6fd5e09abcf26, + 0x80b05e5ac60b6178, 0xa0dc75f1778e39d6, + 0xc913936dd571c84c, 0xfb5878494ace3a5f, + 0x9d174b2dcec0e47b, 0xc45d1df942711d9a, + 0xf5746577930d6500, 0x9968bf6abbe85f20, + 0xbfc2ef456ae276e8, 0xefb3ab16c59b14a2, + 0x95d04aee3b80ece5, 0xbb445da9ca61281f, + 0xea1575143cf97226, 0x924d692ca61be758, + 0xb6e0c377cfa2e12e, 0xe498f455c38b997a, + 0x8edf98b59a373fec, 0xb2977ee300c50fe7, + 0xdf3d5e9bc0f653e1, 0x8b865b215899f46c, + 0xae67f1e9aec07187, 0xda01ee641a708de9, + 0x884134fe908658b2, 0xaa51823e34a7eede, + 0xd4e5e2cdc1d1ea96, 0x850fadc09923329e, + 0xa6539930bf6bff45, 0xcfe87f7cef46ff16, + 0x81f14fae158c5f6e, 0xa26da3999aef7749, + 0xcb090c8001ab551c, 0xfdcb4fa002162a63, + 0x9e9f11c4014dda7e, 0xc646d63501a1511d, + 0xf7d88bc24209a565, 0x9ae757596946075f, + 0xc1a12d2fc3978937, 0xf209787bb47d6b84, + 0x9745eb4d50ce6332, 0xbd176620a501fbff, + 0xec5d3fa8ce427aff, 0x93ba47c980e98cdf, + 0xb8a8d9bbe123f017, 0xe6d3102ad96cec1d, + 0x9043ea1ac7e41392, 0xb454e4a179dd1877, + 0xe16a1dc9d8545e94, 0x8ce2529e2734bb1d, + 0xb01ae745b101e9e4, 0xdc21a1171d42645d, + 0x899504ae72497eba, 0xabfa45da0edbde69, + 0xd6f8d7509292d603, 0x865b86925b9bc5c2, + 0xa7f26836f282b732, 0xd1ef0244af2364ff, + 0x8335616aed761f1f, 0xa402b9c5a8d3a6e7, + 0xcd036837130890a1, 0x802221226be55a64, + 0xa02aa96b06deb0fd, 0xc83553c5c8965d3d, + 0xfa42a8b73abbf48c, 0x9c69a97284b578d7, + 0xc38413cf25e2d70d, 0xf46518c2ef5b8cd1, + 0x98bf2f79d5993802, 0xbeeefb584aff8603, + 0xeeaaba2e5dbf6784, 0x952ab45cfa97a0b2, + 0xba756174393d88df, 0xe912b9d1478ceb17, + 0x91abb422ccb812ee, 0xb616a12b7fe617aa, + 0xe39c49765fdf9d94, 0x8e41ade9fbebc27d, + 0xb1d219647ae6b31c, 0xde469fbd99a05fe3, + 0x8aec23d680043bee, 0xada72ccc20054ae9, + 0xd910f7ff28069da4, 0x87aa9aff79042286, + 0xa99541bf57452b28, 0xd3fa922f2d1675f2, + 0x847c9b5d7c2e09b7, 0xa59bc234db398c25, + 0xcf02b2c21207ef2e, 0x8161afb94b44f57d, + 0xa1ba1ba79e1632dc, 0xca28a291859bbf93, + 0xfcb2cb35e702af78, 0x9defbf01b061adab, + 0xc56baec21c7a1916, 0xf6c69a72a3989f5b, + 0x9a3c2087a63f6399, 0xc0cb28a98fcf3c7f, + 0xf0fdf2d3f3c30b9f, 0x969eb7c47859e743, + 0xbc4665b596706114, 0xeb57ff22fc0c7959, + 0x9316ff75dd87cbd8, 0xb7dcbf5354e9bece, + 0xe5d3ef282a242e81, 0x8fa475791a569d10, + 0xb38d92d760ec4455, 0xe070f78d3927556a, + 0x8c469ab843b89562, 0xaf58416654a6babb, + 0xdb2e51bfe9d0696a, 0x88fcf317f22241e2, + 0xab3c2fddeeaad25a, 0xd60b3bd56a5586f1, + 0x85c7056562757456, 0xa738c6bebb12d16c, + 0xd106f86e69d785c7, 0x82a45b450226b39c, + 0xa34d721642b06084, 0xcc20ce9bd35c78a5, + 0xff290242c83396ce, 0x9f79a169bd203e41, + 0xc75809c42c684dd1, 0xf92e0c3537826145, + 0x9bbcc7a142b17ccb, 0xc2abf989935ddbfe, + 0xf356f7ebf83552fe, 0x98165af37b2153de, + 0xbe1bf1b059e9a8d6, 0xeda2ee1c7064130c, + 0x9485d4d1c63e8be7, 0xb9a74a0637ce2ee1, + 0xe8111c87c5c1ba99, 0x910ab1d4db9914a0, + 0xb54d5e4a127f59c8, 0xe2a0b5dc971f303a, + 0x8da471a9de737e24, 0xb10d8e1456105dad, + 0xdd50f1996b947518, 0x8a5296ffe33cc92f, + 0xace73cbfdc0bfb7b, 0xd8210befd30efa5a, + 0x8714a775e3e95c78, 0xa8d9d1535ce3b396, + 0xd31045a8341ca07c, 0x83ea2b892091e44d, + 0xa4e4b66b68b65d60, 0xce1de40642e3f4b9, + 0x80d2ae83e9ce78f3, 0xa1075a24e4421730, + 0xc94930ae1d529cfc, 0xfb9b7cd9a4a7443c, + 0x9d412e0806e88aa5, 0xc491798a08a2ad4e, + 0xf5b5d7ec8acb58a2, 0x9991a6f3d6bf1765, + 0xbff610b0cc6edd3f, 0xeff394dcff8a948e, + 0x95f83d0a1fb69cd9, 0xbb764c4ca7a4440f, + 0xea53df5fd18d5513, 0x92746b9be2f8552c, + 0xb7118682dbb66a77, 0xe4d5e82392a40515, + 0x8f05b1163ba6832d, 0xb2c71d5bca9023f8, + 0xdf78e4b2bd342cf6, 0x8bab8eefb6409c1a, + 0xae9672aba3d0c320, 0xda3c0f568cc4f3e8, + 0x8865899617fb1871, 0xaa7eebfb9df9de8d, + 0xd51ea6fa85785631, 0x8533285c936b35de, + 0xa67ff273b8460356, 0xd01fef10a657842c, + 0x8213f56a67f6b29b, 0xa298f2c501f45f42, + 0xcb3f2f7642717713, 0xfe0efb53d30dd4d7, + 0x9ec95d1463e8a506, 0xc67bb4597ce2ce48, + 0xf81aa16fdc1b81da, 0x9b10a4e5e9913128, + 0xc1d4ce1f63f57d72, 0xf24a01a73cf2dccf, + 0x976e41088617ca01, 0xbd49d14aa79dbc82, + 0xec9c459d51852ba2, 0x93e1ab8252f33b45, + 0xb8da1662e7b00a17, 0xe7109bfba19c0c9d, + 0x906a617d450187e2, 0xb484f9dc9641e9da, + 0xe1a63853bbd26451, 0x8d07e33455637eb2, + 0xb049dc016abc5e5f, 0xdc5c5301c56b75f7, + 0x89b9b3e11b6329ba, 0xac2820d9623bf429, + 0xd732290fbacaf133, 0x867f59a9d4bed6c0, + 0xa81f301449ee8c70, 0xd226fc195c6a2f8c, + 0x83585d8fd9c25db7, 0xa42e74f3d032f525, + 0xcd3a1230c43fb26f, 0x80444b5e7aa7cf85, + 0xa0555e361951c366, 0xc86ab5c39fa63440, + 0xfa856334878fc150, 0x9c935e00d4b9d8d2, + 0xc3b8358109e84f07, 0xf4a642e14c6262c8, + 0x98e7e9cccfbd7dbd, 0xbf21e44003acdd2c, + 0xeeea5d5004981478, 0x95527a5202df0ccb, + 0xbaa718e68396cffd, 0xe950df20247c83fd, + 0x91d28b7416cdd27e, 0xb6472e511c81471d, + 0xe3d8f9e563a198e5, 0x8e679c2f5e44ff8f + }; + + // A complement to significand_64 + // complete to a 128-bit significand. + // Uses about 5KB but is rarely accessed. + static constexpr std::uint64_t significand_128[] = { + 0x419ea3bd35385e2d, 0x52064cac828675b9, + 0x7343efebd1940993, 0x1014ebe6c5f90bf8, + 0xd41a26e077774ef6, 0x8920b098955522b4, + 0x55b46e5f5d5535b0, 0xeb2189f734aa831d, + 0xa5e9ec7501d523e4, 0x47b233c92125366e, + 0x999ec0bb696e840a, 0xc00670ea43ca250d, + 0x380406926a5e5728, 0xc605083704f5ecf2, + 0xf7864a44c633682e, 0x7ab3ee6afbe0211d, + 0x5960ea05bad82964, 0x6fb92487298e33bd, + 0xa5d3b6d479f8e056, 0x8f48a4899877186c, + 0x331acdabfe94de87, 0x9ff0c08b7f1d0b14, + 0x7ecf0ae5ee44dd9, 0xc9e82cd9f69d6150, + 0xbe311c083a225cd2, 0x6dbd630a48aaf406, + 0x92cbbccdad5b108, 0x25bbf56008c58ea5, + 0xaf2af2b80af6f24e, 0x1af5af660db4aee1, + 0x50d98d9fc890ed4d, 0xe50ff107bab528a0, + 0x1e53ed49a96272c8, 0x25e8e89c13bb0f7a, + 0x77b191618c54e9ac, 0xd59df5b9ef6a2417, + 0x4b0573286b44ad1d, 0x4ee367f9430aec32, + 0x229c41f793cda73f, 0x6b43527578c1110f, + 0x830a13896b78aaa9, 0x23cc986bc656d553, + 0x2cbfbe86b7ec8aa8, 0x7bf7d71432f3d6a9, + 0xdaf5ccd93fb0cc53, 0xd1b3400f8f9cff68, + 0x23100809b9c21fa1, 0xabd40a0c2832a78a, + 0x16c90c8f323f516c, 0xae3da7d97f6792e3, + 0x99cd11cfdf41779c, 0x40405643d711d583, + 0x482835ea666b2572, 0xda3243650005eecf, + 0x90bed43e40076a82, 0x5a7744a6e804a291, + 0x711515d0a205cb36, 0xd5a5b44ca873e03, + 0xe858790afe9486c2, 0x626e974dbe39a872, + 0xfb0a3d212dc8128f, 0x7ce66634bc9d0b99, + 0x1c1fffc1ebc44e80, 0xa327ffb266b56220, + 0x4bf1ff9f0062baa8, 0x6f773fc3603db4a9, + 0xcb550fb4384d21d3, 0x7e2a53a146606a48, + 0x2eda7444cbfc426d, 0xfa911155fefb5308, + 0x793555ab7eba27ca, 0x4bc1558b2f3458de, + 0x9eb1aaedfb016f16, 0x465e15a979c1cadc, + 0xbfacd89ec191ec9, 0xcef980ec671f667b, + 0x82b7e12780e7401a, 0xd1b2ecb8b0908810, + 0x861fa7e6dcb4aa15, 0x67a791e093e1d49a, + 0xe0c8bb2c5c6d24e0, 0x58fae9f773886e18, + 0xaf39a475506a899e, 0x6d8406c952429603, + 0xc8e5087ba6d33b83, 0xfb1e4a9a90880a64, + 0x5cf2eea09a55067f, 0xf42faa48c0ea481e, + 0xf13b94daf124da26, 0x76c53d08d6b70858, + 0x54768c4b0c64ca6e, 0xa9942f5dcf7dfd09, + 0xd3f93b35435d7c4c, 0xc47bc5014a1a6daf, + 0x359ab6419ca1091b, 0xc30163d203c94b62, + 0x79e0de63425dcf1d, 0x985915fc12f542e4, + 0x3e6f5b7b17b2939d, 0xa705992ceecf9c42, + 0x50c6ff782a838353, 0xa4f8bf5635246428, + 0x871b7795e136be99, 0x28e2557b59846e3f, + 0x331aeada2fe589cf, 0x3ff0d2c85def7621, + 0xfed077a756b53a9, 0xd3e8495912c62894, + 0x64712dd7abbbd95c, 0xbd8d794d96aacfb3, + 0xecf0d7a0fc5583a0, 0xf41686c49db57244, + 0x311c2875c522ced5, 0x7d633293366b828b, + 0xae5dff9c02033197, 0xd9f57f830283fdfc, + 0xd072df63c324fd7b, 0x4247cb9e59f71e6d, + 0x52d9be85f074e608, 0x67902e276c921f8b, + 0xba1cd8a3db53b6, 0x80e8a40eccd228a4, + 0x6122cd128006b2cd, 0x796b805720085f81, + 0xcbe3303674053bb0, 0xbedbfc4411068a9c, + 0xee92fb5515482d44, 0x751bdd152d4d1c4a, + 0xd262d45a78a0635d, 0x86fb897116c87c34, + 0xd45d35e6ae3d4da0, 0x8974836059cca109, + 0x2bd1a438703fc94b, 0x7b6306a34627ddcf, + 0x1a3bc84c17b1d542, 0x20caba5f1d9e4a93, + 0x547eb47b7282ee9c, 0xe99e619a4f23aa43, + 0x6405fa00e2ec94d4, 0xde83bc408dd3dd04, + 0x9624ab50b148d445, 0x3badd624dd9b0957, + 0xe54ca5d70a80e5d6, 0x5e9fcf4ccd211f4c, + 0x7647c3200069671f, 0x29ecd9f40041e073, + 0xf468107100525890, 0x7182148d4066eeb4, + 0xc6f14cd848405530, 0xb8ada00e5a506a7c, + 0xa6d90811f0e4851c, 0x908f4a166d1da663, + 0x9a598e4e043287fe, 0x40eff1e1853f29fd, + 0xd12bee59e68ef47c, 0x82bb74f8301958ce, + 0xe36a52363c1faf01, 0xdc44e6c3cb279ac1, + 0x29ab103a5ef8c0b9, 0x7415d448f6b6f0e7, + 0x111b495b3464ad21, 0xcab10dd900beec34, + 0x3d5d514f40eea742, 0xcb4a5a3112a5112, + 0x47f0e785eaba72ab, 0x59ed216765690f56, + 0x306869c13ec3532c, 0x1e414218c73a13fb, + 0xe5d1929ef90898fa, 0xdf45f746b74abf39, + 0x6b8bba8c328eb783, 0x66ea92f3f326564, + 0xc80a537b0efefebd, 0xbd06742ce95f5f36, + 0x2c48113823b73704, 0xf75a15862ca504c5, + 0x9a984d73dbe722fb, 0xc13e60d0d2e0ebba, + 0x318df905079926a8, 0xfdf17746497f7052, + 0xfeb6ea8bedefa633, 0xfe64a52ee96b8fc0, + 0x3dfdce7aa3c673b0, 0x6bea10ca65c084e, + 0x486e494fcff30a62, 0x5a89dba3c3efccfa, + 0xf89629465a75e01c, 0xf6bbb397f1135823, + 0x746aa07ded582e2c, 0xa8c2a44eb4571cdc, + 0x92f34d62616ce413, 0x77b020baf9c81d17, + 0xace1474dc1d122e, 0xd819992132456ba, + 0x10e1fff697ed6c69, 0xca8d3ffa1ef463c1, + 0xbd308ff8a6b17cb2, 0xac7cb3f6d05ddbde, + 0x6bcdf07a423aa96b, 0x86c16c98d2c953c6, + 0xe871c7bf077ba8b7, 0x11471cd764ad4972, + 0xd598e40d3dd89bcf, 0x4aff1d108d4ec2c3, + 0xcedf722a585139ba, 0xc2974eb4ee658828, + 0x733d226229feea32, 0x806357d5a3f525f, + 0xca07c2dcb0cf26f7, 0xfc89b393dd02f0b5, + 0xbbac2078d443ace2, 0xd54b944b84aa4c0d, + 0xa9e795e65d4df11, 0x4d4617b5ff4a16d5, + 0x504bced1bf8e4e45, 0xe45ec2862f71e1d6, + 0x5d767327bb4e5a4c, 0x3a6a07f8d510f86f, + 0x890489f70a55368b, 0x2b45ac74ccea842e, + 0x3b0b8bc90012929d, 0x9ce6ebb40173744, + 0xcc420a6a101d0515, 0x9fa946824a12232d, + 0x47939822dc96abf9, 0x59787e2b93bc56f7, + 0x57eb4edb3c55b65a, 0xede622920b6b23f1, + 0xe95fab368e45eced, 0x11dbcb0218ebb414, + 0xd652bdc29f26a119, 0x4be76d3346f0495f, + 0x6f70a4400c562ddb, 0xcb4ccd500f6bb952, + 0x7e2000a41346a7a7, 0x8ed400668c0c28c8, + 0x728900802f0f32fa, 0x4f2b40a03ad2ffb9, + 0xe2f610c84987bfa8, 0xdd9ca7d2df4d7c9, + 0x91503d1c79720dbb, 0x75a44c6397ce912a, + 0xc986afbe3ee11aba, 0xfbe85badce996168, + 0xfae27299423fb9c3, 0xdccd879fc967d41a, + 0x5400e987bbc1c920, 0x290123e9aab23b68, + 0xf9a0b6720aaf6521, 0xf808e40e8d5b3e69, + 0xb60b1d1230b20e04, 0xb1c6f22b5e6f48c2, + 0x1e38aeb6360b1af3, 0x25c6da63c38de1b0, + 0x579c487e5a38ad0e, 0x2d835a9df0c6d851, + 0xf8e431456cf88e65, 0x1b8e9ecb641b58ff, + 0xe272467e3d222f3f, 0x5b0ed81dcc6abb0f, + 0x98e947129fc2b4e9, 0x3f2398d747b36224, + 0x8eec7f0d19a03aad, 0x1953cf68300424ac, + 0x5fa8c3423c052dd7, 0x3792f412cb06794d, + 0xe2bbd88bbee40bd0, 0x5b6aceaeae9d0ec4, + 0xf245825a5a445275, 0xeed6e2f0f0d56712, + 0x55464dd69685606b, 0xaa97e14c3c26b886, + 0xd53dd99f4b3066a8, 0xe546a8038efe4029, + 0xde98520472bdd033, 0x963e66858f6d4440, + 0xdde7001379a44aa8, 0x5560c018580d5d52, + 0xaab8f01e6e10b4a6, 0xcab3961304ca70e8, + 0x3d607b97c5fd0d22, 0x8cb89a7db77c506a, + 0x77f3608e92adb242, 0x55f038b237591ed3, + 0x6b6c46dec52f6688, 0x2323ac4b3b3da015, + 0xabec975e0a0d081a, 0x96e7bd358c904a21, + 0x7e50d64177da2e54, 0xdde50bd1d5d0b9e9, + 0x955e4ec64b44e864, 0xbd5af13bef0b113e, + 0xecb1ad8aeacdd58e, 0x67de18eda5814af2, + 0x80eacf948770ced7, 0xa1258379a94d028d, + 0x96ee45813a04330, 0x8bca9d6e188853fc, + 0x775ea264cf55347d, 0x95364afe032a819d, + 0x3a83ddbd83f52204, 0xc4926a9672793542, + 0x75b7053c0f178293, 0x5324c68b12dd6338, + 0xd3f6fc16ebca5e03, 0x88f4bb1ca6bcf584, + 0x2b31e9e3d06c32e5, 0x3aff322e62439fcf, + 0x9befeb9fad487c2, 0x4c2ebe687989a9b3, + 0xf9d37014bf60a10, 0x538484c19ef38c94, + 0x2865a5f206b06fb9, 0xf93f87b7442e45d3, + 0xf78f69a51539d748, 0xb573440e5a884d1b, + 0x31680a88f8953030, 0xfdc20d2b36ba7c3d, + 0x3d32907604691b4c, 0xa63f9a49c2c1b10f, + 0xfcf80dc33721d53, 0xd3c36113404ea4a8, + 0x645a1cac083126e9, 0x3d70a3d70a3d70a3, + 0xcccccccccccccccc, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x4000000000000000, + 0x5000000000000000, 0xa400000000000000, + 0x4d00000000000000, 0xf020000000000000, + 0x6c28000000000000, 0xc732000000000000, + 0x3c7f400000000000, 0x4b9f100000000000, + 0x1e86d40000000000, 0x1314448000000000, + 0x17d955a000000000, 0x5dcfab0800000000, + 0x5aa1cae500000000, 0xf14a3d9e40000000, + 0x6d9ccd05d0000000, 0xe4820023a2000000, + 0xdda2802c8a800000, 0xd50b2037ad200000, + 0x4526f422cc340000, 0x9670b12b7f410000, + 0x3c0cdd765f114000, 0xa5880a69fb6ac800, + 0x8eea0d047a457a00, 0x72a4904598d6d880, + 0x47a6da2b7f864750, 0x999090b65f67d924, + 0xfff4b4e3f741cf6d, 0xbff8f10e7a8921a4, + 0xaff72d52192b6a0d, 0x9bf4f8a69f764490, + 0x2f236d04753d5b4, 0x1d762422c946590, + 0x424d3ad2b7b97ef5, 0xd2e0898765a7deb2, + 0x63cc55f49f88eb2f, 0x3cbf6b71c76b25fb, + 0x8bef464e3945ef7a, 0x97758bf0e3cbb5ac, + 0x3d52eeed1cbea317, 0x4ca7aaa863ee4bdd, + 0x8fe8caa93e74ef6a, 0xb3e2fd538e122b44, + 0x60dbbca87196b616, 0xbc8955e946fe31cd, + 0x6babab6398bdbe41, 0xc696963c7eed2dd1, + 0xfc1e1de5cf543ca2, 0x3b25a55f43294bcb, + 0x49ef0eb713f39ebe, 0x6e3569326c784337, + 0x49c2c37f07965404, 0xdc33745ec97be906, + 0x69a028bb3ded71a3, 0xc40832ea0d68ce0c, + 0xf50a3fa490c30190, 0x792667c6da79e0fa, + 0x577001b891185938, 0xed4c0226b55e6f86, + 0x544f8158315b05b4, 0x696361ae3db1c721, + 0x3bc3a19cd1e38e9, 0x4ab48a04065c723, + 0x62eb0d64283f9c76, 0x3ba5d0bd324f8394, + 0xca8f44ec7ee36479, 0x7e998b13cf4e1ecb, + 0x9e3fedd8c321a67e, 0xc5cfe94ef3ea101e, + 0xbba1f1d158724a12, 0x2a8a6e45ae8edc97, + 0xf52d09d71a3293bd, 0x593c2626705f9c56, + 0x6f8b2fb00c77836c, 0xb6dfb9c0f956447, + 0x4724bd4189bd5eac, 0x58edec91ec2cb657, + 0x2f2967b66737e3ed, 0xbd79e0d20082ee74, + 0xecd8590680a3aa11, 0xe80e6f4820cc9495, + 0x3109058d147fdcdd, 0xbd4b46f0599fd415, + 0x6c9e18ac7007c91a, 0x3e2cf6bc604ddb0, + 0x84db8346b786151c, 0xe612641865679a63, + 0x4fcb7e8f3f60c07e, 0xe3be5e330f38f09d, + 0x5cadf5bfd3072cc5, 0x73d9732fc7c8f7f6, + 0x2867e7fddcdd9afa, 0xb281e1fd541501b8, + 0x1f225a7ca91a4226, 0x3375788de9b06958, + 0x52d6b1641c83ae, 0xc0678c5dbd23a49a, + 0xf840b7ba963646e0, 0xb650e5a93bc3d898, + 0xa3e51f138ab4cebe, 0xc66f336c36b10137, + 0xb80b0047445d4184, 0xa60dc059157491e5, + 0x87c89837ad68db2f, 0x29babe4598c311fb, + 0xf4296dd6fef3d67a, 0x1899e4a65f58660c, + 0x5ec05dcff72e7f8f, 0x76707543f4fa1f73, + 0x6a06494a791c53a8, 0x487db9d17636892, + 0x45a9d2845d3c42b6, 0xb8a2392ba45a9b2, + 0x8e6cac7768d7141e, 0x3207d795430cd926, + 0x7f44e6bd49e807b8, 0x5f16206c9c6209a6, + 0x36dba887c37a8c0f, 0xc2494954da2c9789, + 0xf2db9baa10b7bd6c, 0x6f92829494e5acc7, + 0xcb772339ba1f17f9, 0xff2a760414536efb, + 0xfef5138519684aba, 0x7eb258665fc25d69, + 0xef2f773ffbd97a61, 0xaafb550ffacfd8fa, + 0x95ba2a53f983cf38, 0xdd945a747bf26183, + 0x94f971119aeef9e4, 0x7a37cd5601aab85d, + 0xac62e055c10ab33a, 0x577b986b314d6009, + 0xed5a7e85fda0b80b, 0x14588f13be847307, + 0x596eb2d8ae258fc8, 0x6fca5f8ed9aef3bb, + 0x25de7bb9480d5854, 0xaf561aa79a10ae6a, + 0x1b2ba1518094da04, 0x90fb44d2f05d0842, + 0x353a1607ac744a53, 0x42889b8997915ce8, + 0x69956135febada11, 0x43fab9837e699095, + 0x94f967e45e03f4bb, 0x1d1be0eebac278f5, + 0x6462d92a69731732, 0x7d7b8f7503cfdcfe, + 0x5cda735244c3d43e, 0x3a0888136afa64a7, + 0x88aaa1845b8fdd0, 0x8aad549e57273d45, + 0x36ac54e2f678864b, 0x84576a1bb416a7dd, + 0x656d44a2a11c51d5, 0x9f644ae5a4b1b325, + 0x873d5d9f0dde1fee, 0xa90cb506d155a7ea, + 0x9a7f12442d588f2, 0xc11ed6d538aeb2f, + 0x8f1668c8a86da5fa, 0xf96e017d694487bc, + 0x37c981dcc395a9ac, 0x85bbe253f47b1417, + 0x93956d7478ccec8e, 0x387ac8d1970027b2, + 0x6997b05fcc0319e, 0x441fece3bdf81f03, + 0xd527e81cad7626c3, 0x8a71e223d8d3b074, + 0xf6872d5667844e49, 0xb428f8ac016561db, + 0xe13336d701beba52, 0xecc0024661173473, + 0x27f002d7f95d0190, 0x31ec038df7b441f4, + 0x7e67047175a15271, 0xf0062c6e984d386, + 0x52c07b78a3e60868, 0xa7709a56ccdf8a82, + 0x88a66076400bb691, 0x6acff893d00ea435, + 0x583f6b8c4124d43, 0xc3727a337a8b704a, + 0x744f18c0592e4c5c, 0x1162def06f79df73, + 0x8addcb5645ac2ba8, 0x6d953e2bd7173692, + 0xc8fa8db6ccdd0437, 0x1d9c9892400a22a2, + 0x2503beb6d00cab4b, 0x2e44ae64840fd61d, + 0x5ceaecfed289e5d2, 0x7425a83e872c5f47, + 0xd12f124e28f77719, 0x82bd6b70d99aaa6f, + 0x636cc64d1001550b, 0x3c47f7e05401aa4e, + 0x65acfaec34810a71, 0x7f1839a741a14d0d, + 0x1ede48111209a050, 0x934aed0aab460432, + 0xf81da84d5617853f, 0x36251260ab9d668e, + 0xc1d72b7c6b426019, 0xb24cf65b8612f81f, + 0xdee033f26797b627, 0x169840ef017da3b1, + 0x8e1f289560ee864e, 0xf1a6f2bab92a27e2, + 0xae10af696774b1db, 0xacca6da1e0a8ef29, + 0x17fd090a58d32af3, 0xddfc4b4cef07f5b0, + 0x4abdaf101564f98e, 0x9d6d1ad41abe37f1, + 0x84c86189216dc5ed, 0x32fd3cf5b4e49bb4, + 0x3fbc8c33221dc2a1, 0xfabaf3feaa5334a, + 0x29cb4d87f2a7400e, 0x743e20e9ef511012, + 0x914da9246b255416, 0x1ad089b6c2f7548e, + 0xa184ac2473b529b1, 0xc9e5d72d90a2741e, + 0x7e2fa67c7a658892, 0xddbb901b98feeab7, + 0x552a74227f3ea565, 0xd53a88958f87275f, + 0x8a892abaf368f137, 0x2d2b7569b0432d85, + 0x9c3b29620e29fc73, 0x8349f3ba91b47b8f, + 0x241c70a936219a73, 0xed238cd383aa0110, + 0xf4363804324a40aa, 0xb143c6053edcd0d5, + 0xdd94b7868e94050a, 0xca7cf2b4191c8326, + 0xfd1c2f611f63a3f0, 0xbc633b39673c8cec, + 0xd5be0503e085d813, 0x4b2d8644d8a74e18, + 0xddf8e7d60ed1219e, 0xcabb90e5c942b503, + 0x3d6a751f3b936243, 0xcc512670a783ad4, + 0x27fb2b80668b24c5, 0xb1f9f660802dedf6, + 0x5e7873f8a0396973, 0xdb0b487b6423e1e8, + 0x91ce1a9a3d2cda62, 0x7641a140cc7810fb, + 0xa9e904c87fcb0a9d, 0x546345fa9fbdcd44, + 0xa97c177947ad4095, 0x49ed8eabcccc485d, + 0x5c68f256bfff5a74, 0x73832eec6fff3111, + 0xc831fd53c5ff7eab, 0xba3e7ca8b77f5e55, + 0x28ce1bd2e55f35eb, 0x7980d163cf5b81b3, + 0xd7e105bcc332621f, 0x8dd9472bf3fefaa7, + 0xb14f98f6f0feb951, 0x6ed1bf9a569f33d3, + 0xa862f80ec4700c8, 0xcd27bb612758c0fa, + 0x8038d51cb897789c, 0xe0470a63e6bd56c3, + 0x1858ccfce06cac74, 0xf37801e0c43ebc8, + 0xd30560258f54e6ba, 0x47c6b82ef32a2069, + 0x4cdc331d57fa5441, 0xe0133fe4adf8e952, + 0x58180fddd97723a6, 0x570f09eaa7ea7648 + }; + +}; + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <bool b> constexpr std::uint64_t significand_template<b>::significand_64[]; +template <bool b> constexpr std::uint64_t significand_template<b>::significand_128[]; + +#endif + +#if (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +using significands_table = significand_template<true>; + +#endif + +}}} // Namespaces + +#endif // BOOST_CHARCONV_DETAIL_SIGNIFICAND_TABLES_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/to_chars_integer_impl.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/to_chars_integer_impl.hpp new file mode 100644 index 00000000000..1ef54a2f061 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/to_chars_integer_impl.hpp @@ -0,0 +1,459 @@ +// Copyright 2020-2023 Junekey Jeon +// Copyright 2022 Peter Dimov +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_TO_CHARS_INTEGER_IMPL_HPP +#define BOOST_CHARCONV_DETAIL_TO_CHARS_INTEGER_IMPL_HPP + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/memcpy.hpp> +#include <boost/charconv/detail/to_chars_result.hpp> +#include <boost/charconv/detail/integer_search_trees.hpp> +#include <boost/charconv/detail/emulated128.hpp> +#include <boost/charconv/detail/apply_sign.hpp> +#include <limits> +#include <system_error> +#include <type_traits> +#include <array> +#include <limits> +#include <utility> +#include <cstring> +#include <cstdio> +#include <cerrno> +#include <cstdint> +#include <climits> +#include <cmath> + +namespace boost { namespace charconv { namespace detail { + + +static constexpr char radix_table[] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', + '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', + '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', + '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', + '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', + '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', + '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', + '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', + '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', + '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', + '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', + '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', + '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', + '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', + '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', + '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', + '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', + '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', + '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' +}; + +static constexpr char digit_table[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z' +}; + +// See: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ +// https://arxiv.org/abs/2101.11408 +BOOST_CHARCONV_CONSTEXPR char* decompose32(std::uint32_t value, char* buffer) noexcept +{ + constexpr auto mask = (std::uint64_t(1) << 57) - 1; + auto y = value * std::uint64_t(1441151881); + + for (std::size_t i {}; i < 10; i += 2) + { + boost::charconv::detail::memcpy(buffer + i, radix_table + static_cast<std::size_t>(y >> 57) * 2, 2); + y &= mask; + y *= 100; + } + + return buffer + 10; +} + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127 4146) +#endif + +template <typename Integer> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char* last, Integer value) noexcept +{ + using Unsigned_Integer = typename std::make_unsigned<Integer>::type; + Unsigned_Integer unsigned_value {}; + + char buffer[10] {}; + int converted_value_digits {}; + bool is_negative = false; + + if (first > last) + { + return {last, std::errc::invalid_argument}; + } + + // Strip the sign from the value and apply at the end after parsing if the type is signed + BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value) + { + if (value < 0) + { + is_negative = true; + unsigned_value = apply_sign(value); + } + else + { + unsigned_value = static_cast<Unsigned_Integer>(value); + } + } + else + { + unsigned_value = static_cast<Unsigned_Integer>(value); + } + + const std::ptrdiff_t user_buffer_size = last - first - static_cast<std::ptrdiff_t>(is_negative); + + // If the type is less than 32 bits we can use this without change + // If the type is greater than 32 bits we use a binary search tree to figure out how many digits + // are present and then decompose the value into two (or more) std::uint32_t of known length so that we + // don't have the issue of removing leading zeros from the least significant digits + + // Yields: warning C4127: conditional expression is constant because first half of the expression is constant, + // but we need to short circuit to avoid UB on the second half + if (std::numeric_limits<Integer>::digits <= std::numeric_limits<std::uint32_t>::digits || + unsigned_value <= static_cast<Unsigned_Integer>((std::numeric_limits<std::uint32_t>::max)())) + { + const auto converted_value = static_cast<std::uint32_t>(unsigned_value); + converted_value_digits = num_digits(converted_value); + + if (converted_value_digits > user_buffer_size) + { + return {last, std::errc::value_too_large}; + } + + decompose32(converted_value, buffer); + + if (is_negative) + { + *first++ = '-'; + } + + boost::charconv::detail::memcpy(first, buffer + (sizeof(buffer) - static_cast<unsigned>(converted_value_digits)), + static_cast<std::size_t>(converted_value_digits)); + } + else if (std::numeric_limits<Integer>::digits <= std::numeric_limits<std::uint64_t>::digits || + static_cast<std::uint64_t>(unsigned_value) <= (std::numeric_limits<std::uint64_t>::max)()) + { + auto converted_value = static_cast<std::uint64_t>(unsigned_value); + converted_value_digits = num_digits(converted_value); + + if (converted_value_digits > user_buffer_size) + { + return {last, std::errc::value_too_large}; + } + + if (is_negative) + { + *first++ = '-'; + } + + // Only store 9 digits in each to avoid overflow + if (num_digits(converted_value) <= 18) + { + const auto x = static_cast<std::uint32_t>(converted_value / UINT64_C(1000000000)); + const auto y = static_cast<std::uint32_t>(converted_value % UINT64_C(1000000000)); + const int first_value_chars = num_digits(x); + + decompose32(x, buffer); + boost::charconv::detail::memcpy(first, buffer + (sizeof(buffer) - static_cast<unsigned>(first_value_chars)), + static_cast<std::size_t>(first_value_chars)); + + decompose32(y, buffer); + boost::charconv::detail::memcpy(first + first_value_chars, buffer + 1, sizeof(buffer) - 1); + } + else + { + const auto x = static_cast<std::uint32_t>(converted_value / UINT64_C(100000000000)); + converted_value -= x * UINT64_C(100000000000); + const auto y = static_cast<std::uint32_t>(converted_value / UINT64_C(100)); + const auto z = static_cast<std::uint32_t>(converted_value % UINT64_C(100)); + + if (converted_value_digits == 19) + { + decompose32(x, buffer); + boost::charconv::detail::memcpy(first, buffer + 2, sizeof(buffer) - 2); + + decompose32(y, buffer); + boost::charconv::detail::memcpy(first + 8, buffer + 1, sizeof(buffer) - 1); + + // Always prints 2 digits last + boost::charconv::detail::memcpy(first + 17, radix_table + z * 2, 2); + } + else // 20 + { + decompose32(x, buffer); + boost::charconv::detail::memcpy(first, buffer + 1, sizeof(buffer) - 1); + + decompose32(y, buffer); + boost::charconv::detail::memcpy(first + 9, buffer + 1, sizeof(buffer) - 1); + + // Always prints 2 digits last + boost::charconv::detail::memcpy(first + 18, radix_table + z * 2, 2); + } + } + } + + return {first + converted_value_digits, std::errc()}; +} + +// Prior to GCC 10.3 std::numeric_limits was not specialized for __int128 which breaks the above control flow +// Here we find if the 128-bit type will fit into a 64-bit type and use the above, or we use string manipulation +// to extract the digits +// +// See: https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/ +template <typename Integer> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, char* last, Integer value) noexcept +{ + #ifdef BOOST_CHARCONV_HAS_INT128 + using Unsigned_Integer = boost::uint128_type; + #else + using Unsigned_Integer = uint128; + #endif + + Unsigned_Integer unsigned_value {}; + + const std::ptrdiff_t user_buffer_size = last - first; + BOOST_ATTRIBUTE_UNUSED bool is_negative = false; + + if (first > last) + { + return {last, std::errc::invalid_argument}; + } + + // Strip the sign from the value and apply at the end after parsing if the type is signed + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same<boost::int128_type, Integer>::value) + { + if (value < 0) + { + is_negative = true; + unsigned_value = -(static_cast<Unsigned_Integer>(value)); + } + else + { + unsigned_value = static_cast<Unsigned_Integer>(value); + } + } + else + #endif + { + unsigned_value = static_cast<Unsigned_Integer>(value); + } + + auto converted_value = static_cast<Unsigned_Integer>(unsigned_value); + + const int converted_value_digits = num_digits(converted_value); + + if (converted_value_digits > user_buffer_size) + { + return {last, std::errc::value_too_large}; + } + + if (is_negative) + { + *first++ = '-'; + } + + // If the value fits into 64 bits use the other method of processing + if (converted_value < (std::numeric_limits<std::uint64_t>::max)()) + { + return to_chars_integer_impl(first, last, static_cast<std::uint64_t>(value)); + } + + constexpr std::uint32_t ten_9 = UINT32_C(1000000000); + char buffer[5][10] {}; + int num_chars[5] {}; + int i = 0; + + while (converted_value != 0) + { + auto digits = static_cast<std::uint32_t>(converted_value % ten_9); + num_chars[i] = num_digits(digits); + decompose32(digits, buffer[i]); // Always returns 10 digits (to include leading 0s) which we want + converted_value = (converted_value - digits) / ten_9; + ++i; + } + + --i; + auto offset = static_cast<std::size_t>(num_chars[i]); + boost::charconv::detail::memcpy(first, buffer[i] + 10 - offset, offset); + + while (i > 0) + { + --i; + boost::charconv::detail::memcpy(first + offset, buffer[i] + 1, 9); + offset += 9; + } + + return {first + converted_value_digits, std::errc()}; +} + +// Conversion warning from shift operators with unsigned char +#if defined(__GNUC__) && __GNUC__ >= 5 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +#elif defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wconversion" +#endif + +// All other bases +// Use a simple lookup table to put together the Integer in character form +template <typename Integer, typename Unsigned_Integer> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char* last, Integer value, int base) noexcept +{ + if (!((first <= last) && (base >= 2 && base <= 36))) + { + return {last, std::errc::invalid_argument}; + } + + if (value == 0) + { + *first++ = '0'; + return {first, std::errc()}; + } + + Unsigned_Integer unsigned_value {}; + const auto unsigned_base = static_cast<Unsigned_Integer>(base); + + BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value) + { + if (value < 0) + { + *first++ = '-'; + unsigned_value = static_cast<Unsigned_Integer>(detail::apply_sign(value)); + } + else + { + unsigned_value = static_cast<Unsigned_Integer>(value); + } + } + else + { + unsigned_value = static_cast<Unsigned_Integer>(value); + } + + const std::ptrdiff_t output_length = last - first; + + constexpr Unsigned_Integer zero = 48U; // Char for '0' + constexpr auto buffer_size = sizeof(Unsigned_Integer) * CHAR_BIT; + char buffer[buffer_size] {}; + const char* buffer_end = buffer + buffer_size; + char* end = buffer + buffer_size - 1; + + // Work from LSB to MSB + switch (base) + { + case 2: + while (unsigned_value != 0) + { + *end-- = static_cast<char>(zero + (unsigned_value & 1U)); // 1<<1 - 1 + unsigned_value >>= static_cast<Unsigned_Integer>(1); + } + break; + + case 4: + while (unsigned_value != 0) + { + *end-- = static_cast<char>(zero + (unsigned_value & 3U)); // 1<<2 - 1 + unsigned_value >>= static_cast<Unsigned_Integer>(2); + } + break; + + case 8: + while (unsigned_value != 0) + { + *end-- = static_cast<char>(zero + (unsigned_value & 7U)); // 1<<3 - 1 + unsigned_value >>= static_cast<Unsigned_Integer>(3); + } + break; + + case 16: + while (unsigned_value != 0) + { + *end-- = digit_table[unsigned_value & 15U]; // 1<<4 - 1 + unsigned_value >>= static_cast<Unsigned_Integer>(4); + } + break; + + case 32: + while (unsigned_value != 0) + { + *end-- = digit_table[unsigned_value & 31U]; // 1<<5 - 1 + unsigned_value >>= static_cast<Unsigned_Integer>(5); + } + break; + + default: + while (unsigned_value != 0) + { + *end-- = digit_table[unsigned_value % unsigned_base]; + unsigned_value /= unsigned_base; + } + break; + } + + const std::ptrdiff_t num_chars = buffer_end - end - 1; + + if (num_chars > output_length) + { + return {last, std::errc::value_too_large}; + } + + boost::charconv::detail::memcpy(first, buffer + (buffer_size - static_cast<unsigned long>(num_chars)), + static_cast<std::size_t>(num_chars)); + + return {first + num_chars, std::errc()}; +} + +#if defined(__GNUC__) && __GNUC__ >= 5 +# pragma GCC diagnostic pop +#elif defined(__clang__) +# pragma clang diagnostic pop +#endif + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template <typename Integer> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_int(char* first, char* last, Integer value, int base = 10) noexcept +{ + using Unsigned_Integer = typename std::make_unsigned<Integer>::type; + if (base == 10) + { + return to_chars_integer_impl(first, last, value); + } + + return to_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +template <typename Integer> +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars128(char* first, char* last, Integer value, int base = 10) noexcept +{ + if (base == 10) + { + return to_chars_128integer_impl(first, last, value); + } + + return to_chars_integer_impl<Integer, boost::uint128_type>(first, last, value, base); +} +#endif + +}}} // Namespaces + +#endif //BOOST_CHARCONV_DETAIL_TO_CHARS_INTEGER_IMPL_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/to_chars_result.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/to_chars_result.hpp new file mode 100644 index 00000000000..e564fe6cd7b --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/to_chars_result.hpp @@ -0,0 +1,34 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_TO_CHARS_RESULT_HPP +#define BOOST_CHARCONV_DETAIL_TO_CHARS_RESULT_HPP + +#include <system_error> + +// 22.13.2, Primitive numerical output conversion + +namespace boost { namespace charconv { + +struct to_chars_result +{ + char *ptr; + std::errc ec; + + constexpr friend bool operator==(const to_chars_result &lhs, const to_chars_result &rhs) noexcept + { + return lhs.ptr == rhs.ptr && lhs.ec == rhs.ec; + } + + constexpr friend bool operator!=(const to_chars_result &lhs, const to_chars_result &rhs) noexcept + { + return !(lhs == rhs); + } + + constexpr explicit operator bool() const noexcept { return ec == std::errc{}; } +}; + +}} // Namespaces + +#endif //BOOST_CHARCONV_DETAIL_TO_CHARS_RESULT_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/detail/type_traits.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/detail/type_traits.hpp new file mode 100644 index 00000000000..4160555162d --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/detail/type_traits.hpp @@ -0,0 +1,67 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_TYPE_TRAITS_HPP +#define BOOST_CHARCONV_DETAIL_TYPE_TRAITS_HPP + +#include <boost/charconv/detail/config.hpp> +#include <type_traits> + +namespace boost { namespace charconv { namespace detail { + +template <typename T> +struct is_signed { static constexpr bool value = std::is_signed<T>::value; }; + +#ifdef BOOST_CHARCONV_HAS_INT128 + +template <> +struct is_signed<boost::int128_type> { static constexpr bool value = true; }; + +template <> +struct is_signed<boost::uint128_type> { static constexpr bool value = false; }; + +#endif + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) && (!defined(BOOST_MSVC) || BOOST_MSVC != 1900) + +template <typename T> +constexpr bool is_signed<T>::value; + +#endif + +template <typename T> +struct make_unsigned { using type = typename std::make_unsigned<T>::type; }; + +template <> +struct make_unsigned<uint128> { using type = uint128; }; + +#ifdef BOOST_CHARCONV_HAS_INT128 + +template <> +struct make_unsigned<boost::int128_type> { using type = boost::uint128_type; }; + +template <> +struct make_unsigned<boost::uint128_type> { using type = boost::uint128_type; }; + +#endif + +template <typename T> +using make_unsigned_t = typename make_unsigned<T>::type; + +template <typename T> +struct make_signed { using type = typename std::make_signed<T>::type; }; + +#ifdef BOOST_CHARCONV_HAS_INT128 + +template <> +struct make_signed<boost::int128_type> { using type = boost::int128_type; }; + +template <> +struct make_signed<boost::uint128_type> { using type = boost::int128_type; }; + +#endif + +}}} // Namespaces + +#endif //BOOST_CHARCONV_DETAIL_TYPE_TRAITS_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/from_chars.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/from_chars.hpp new file mode 100644 index 00000000000..0bef0b5f5db --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/from_chars.hpp @@ -0,0 +1,255 @@ +// Copyright 2022 Peter Dimov +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_FROM_CHARS_HPP_INCLUDED +#define BOOST_CHARCONV_FROM_CHARS_HPP_INCLUDED + +#include <boost/charconv/detail/config.hpp> +#include <boost/charconv/detail/from_chars_result.hpp> +#include <boost/charconv/detail/from_chars_integer_impl.hpp> +#include <boost/charconv/detail/bit_layouts.hpp> +#include <boost/charconv/config.hpp> +#include <boost/charconv/chars_format.hpp> +#include <boost/core/detail/string_view.hpp> +#include <system_error> + +namespace boost { namespace charconv { + +// integer overloads + +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, bool& value, int base = 10) noexcept = delete; +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, signed char& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, int& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned int& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, long long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned long long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, boost::int128_type& value, int base = 10) noexcept +{ + return detail::from_chars128(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, boost::uint128_type& value, int base = 10) noexcept +{ + return detail::from_chars128(first, last, value, base); +} +#endif + +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, bool& value, int base = 10) noexcept = delete; +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, char& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, signed char& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned char& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, short& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned short& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, int& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned int& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, long& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned long& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, long long& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned long long& value, int base = 10) noexcept +{ + return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, boost::int128_type& value, int base = 10) noexcept +{ + return detail::from_chars128(sv.data(), sv.data() + sv.size(), value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, boost::uint128_type& value, int base = 10) noexcept +{ + return detail::from_chars128(sv.data(), sv.data() + sv.size(), value, base); +} +#endif + +//---------------------------------------------------------------------------------------------------------------------- +// Floating Point +//---------------------------------------------------------------------------------------------------------------------- + +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, float& value, chars_format fmt = chars_format::general) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, double& value, chars_format fmt = chars_format::general) noexcept; + +#ifndef BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, long double& value, chars_format fmt = chars_format::general) noexcept; +#endif + +#ifdef BOOST_CHARCONV_HAS_QUADMATH +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, __float128& value, chars_format fmt = chars_format::general) noexcept; +#endif + +// <stdfloat> types +#ifdef BOOST_CHARCONV_HAS_FLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, std::float16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT32 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, std::float32_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT64 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, std::float64_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH) +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, std::float128_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif + +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, float& value, chars_format fmt = chars_format::general) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, double& value, chars_format fmt = chars_format::general) noexcept; + +#ifndef BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, long double& value, chars_format fmt = chars_format::general) noexcept; +#endif + +#ifdef BOOST_CHARCONV_HAS_QUADMATH +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, __float128& value, chars_format fmt = chars_format::general) noexcept; +#endif + +// <stdfloat> types +#ifdef BOOST_CHARCONV_HAS_FLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT32 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float32_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT64 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float64_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH) +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float128_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif + +// The following adhere to the standard library definition with std::errc::result_out_of_range +// Returns value unmodified +// See: https://github.com/cppalliance/charconv/issues/110 + +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, float& value, chars_format fmt = chars_format::general) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt = chars_format::general) noexcept; + +#ifndef BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long double& value, chars_format fmt = chars_format::general) noexcept; +#endif + +#ifdef BOOST_CHARCONV_HAS_QUADMATH +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, __float128& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, std::float16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT32 +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, std::float32_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT64 +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, std::float64_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH) +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, std::float128_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif + +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, float& value, chars_format fmt = chars_format::general) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, double& value, chars_format fmt = chars_format::general) noexcept; + +#ifndef BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, long double& value, chars_format fmt = chars_format::general) noexcept; +#endif + +#ifdef BOOST_CHARCONV_HAS_QUADMATH +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, __float128& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT32 +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float32_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT64 +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float64_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH) +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float128_t& value, chars_format fmt = chars_format::general) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 +BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept; +#endif + +} // namespace charconv +} // namespace boost + +#endif // #ifndef BOOST_CHARCONV_FROM_CHARS_HPP_INCLUDED diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/limits.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/limits.hpp new file mode 100644 index 00000000000..f62809f30c7 --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/limits.hpp @@ -0,0 +1,96 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_LIMITS_HPP +#define BOOST_CHARCONV_LIMITS_HPP + +#include <boost/charconv/detail/config.hpp> +#include <limits> +#include <type_traits> + +namespace boost { namespace charconv { + +// limits<T>::max_chars10: the minimum size of the buffer that needs to be +// passed to to_chars to guarantee successful conversion for all values of +// type T, when either no base is passed, or base 10 is passed +// +// limits<T>::max_chars: the minimum size of the buffer that needs to be +// passed to to_chars to guarantee successful conversion for all values of +// type T, for any value of base + +namespace detail +{ + +constexpr int exp_digits( int exp ) +{ + return exp < 100? 2: exp < 1000? 3: exp < 10000? 4: 5; +} + +#if defined(BOOST_HAS_INT128) + +template<class T> struct is_int128: std::is_same<T, boost::int128_type> {}; +template<class T> struct is_uint128: std::is_same<T, boost::int128_type> {}; + +#else + +template<class T> struct is_int128: std::false_type {}; +template<class T> struct is_uint128: std::false_type {}; + +#endif + +} // namespace detail + +template<typename T> struct limits +{ + BOOST_ATTRIBUTE_UNUSED static constexpr int max_chars10 = + + // int128_t + detail::is_int128<T>::value? 38+2: // digits10 + 1 + sign + + // uint128_t + detail::is_uint128<T>::value? 38+1: // digits10 + 1 + + // integral + std::numeric_limits<T>::is_integer? std::numeric_limits<T>::digits10 + 1 + std::numeric_limits<T>::is_signed: + + // floating point + std::numeric_limits<T>::max_digits10 + 3 + 2 + detail::exp_digits( std::numeric_limits<T>::max_exponent10 ); // -1.(max_digits10)e+(max_exp) + + BOOST_ATTRIBUTE_UNUSED static constexpr int max_chars = + + // int128_t + detail::is_int128<T>::value? 127+2: // digits + 1 + sign + + // uint128_t + detail::is_uint128<T>::value? 128+1: // digits + 1 + + // integral + std::numeric_limits<T>::is_integer? std::numeric_limits<T>::digits + 1 + std::numeric_limits<T>::is_signed: + + // floating point + std::numeric_limits<T>::max_digits10 + 3 + 2 + detail::exp_digits( std::numeric_limits<T>::max_exponent10 ); // as above +}; + +#if defined(BOOST_CHARCONV_HAS_QUADMATH) + +template <> struct limits<__float128> +{ + BOOST_ATTRIBUTE_UNUSED static constexpr int max_chars10 = 33 + 3 + 2 + 5; + BOOST_ATTRIBUTE_UNUSED static constexpr int max_chars = max_chars10; +}; + +#endif + +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) + +// Definitions of in-class constexpr members are allowed but deprecated in C++17 + +template<typename T> BOOST_ATTRIBUTE_UNUSED constexpr int limits<T>::max_chars10; +template<typename T> BOOST_ATTRIBUTE_UNUSED constexpr int limits<T>::max_chars; + +#endif // defined(BOOST_NO_CXX17_INLINE_VARIABLES) + +}} // namespace boost::charconv + +#endif // BOOST_CHARCONV_LIMITS_HPP diff --git a/contrib/restricted/boost/charconv/include/boost/charconv/to_chars.hpp b/contrib/restricted/boost/charconv/include/boost/charconv/to_chars.hpp new file mode 100644 index 00000000000..7192fda578b --- /dev/null +++ b/contrib/restricted/boost/charconv/include/boost/charconv/to_chars.hpp @@ -0,0 +1,147 @@ +// Copyright 2022 Peter Dimov +// Copyright 2023 Matt Borland +// Copyright 2023 Junekey Jeon +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_TO_CHARS_HPP_INCLUDED +#define BOOST_CHARCONV_TO_CHARS_HPP_INCLUDED + +#include <boost/charconv/detail/to_chars_integer_impl.hpp> +#include <boost/charconv/detail/to_chars_result.hpp> +#include <boost/charconv/config.hpp> +#include <boost/charconv/chars_format.hpp> + +namespace boost { +namespace charconv { + +// integer overloads +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, bool value, int base) noexcept = delete; +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, char value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, signed char value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned char value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, short value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned short value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, int value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned int value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, long value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned long value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, long long value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned long long value, int base = 10) noexcept +{ + return detail::to_chars_int(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, boost::int128_type value, int base = 10) noexcept +{ + return detail::to_chars128(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, boost::uint128_type value, int base = 10) noexcept +{ + return detail::to_chars128(first, last, value, base); +} +#endif + +//---------------------------------------------------------------------------------------------------------------------- +// Floating Point +//---------------------------------------------------------------------------------------------------------------------- + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, float value, + chars_format fmt = chars_format::general) noexcept; +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, double value, + chars_format fmt = chars_format::general) noexcept; + +#ifndef BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, long double value, + chars_format fmt = chars_format::general) noexcept; +#endif + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, float value, + chars_format fmt, int precision) noexcept; +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, double value, + chars_format fmt, int precision) noexcept; + +#ifndef BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, long double value, + chars_format fmt, int precision) noexcept; +#endif + +#ifdef BOOST_CHARCONV_HAS_QUADMATH +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, __float128 value, + chars_format fmt = chars_format::general) noexcept; + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, __float128 value, + chars_format fmt, int precision) noexcept; +#endif + +#ifdef BOOST_CHARCONV_HAS_FLOAT16 +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float16_t value, + chars_format fmt = chars_format::general) noexcept; + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float16_t value, + chars_format fmt, int precision) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT32 +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float32_t value, + chars_format fmt = chars_format::general) noexcept; + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float32_t value, + chars_format fmt, int precision) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_FLOAT64 +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float64_t value, + chars_format fmt = chars_format::general) noexcept; + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float64_t value, + chars_format fmt, int precision) noexcept; +#endif +#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH) +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float128_t value, + chars_format fmt = chars_format::general) noexcept; + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float128_t value, + chars_format fmt, int precision) noexcept; +#endif +#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::bfloat16_t value, + chars_format fmt = chars_format::general) noexcept; + +BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::bfloat16_t value, + chars_format fmt, int precision) noexcept; +#endif + +} // namespace charconv +} // namespace boost + +#endif // #ifndef BOOST_CHARCONV_TO_CHARS_HPP_INCLUDED diff --git a/contrib/restricted/boost/charconv/ya.make b/contrib/restricted/boost/charconv/ya.make new file mode 100644 index 00000000000..c502c16a98e --- /dev/null +++ b/contrib/restricted/boost/charconv/ya.make @@ -0,0 +1,31 @@ +# Generated by devtools/yamaker from nixpkgs 24.05. + +LIBRARY() + +LICENSE( + Apache-2.0 AND + Apache-2.0 WITH LLVM-exception AND + BSL-1.0 +) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +VERSION(1.88.0) + +ORIGINAL_SOURCE(https://github.com/boostorg/charconv/archive/boost-1.88.0.tar.gz) + +PEERDIR( + contrib/restricted/boost/assert + contrib/restricted/boost/config + contrib/restricted/boost/core +) + +ADDINCL( + GLOBAL contrib/restricted/boost/charconv/include +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +END() diff --git a/contrib/restricted/boost/locale/.yandex_meta/__init__.py b/contrib/restricted/boost/locale/.yandex_meta/__init__.py index dc25b4c73b1..84e7d1f0736 100644 --- a/contrib/restricted/boost/locale/.yandex_meta/__init__.py +++ b/contrib/restricted/boost/locale/.yandex_meta/__init__.py @@ -6,13 +6,13 @@ from devtools.yamaker.project import NixSourceProject def post_install(self): # fmt: off posix_srcs = set(fileutil.files( - f"{self.dstdir}/src/boost/locale/posix", + f"{self.dstdir}/src/posix", rel=self.dstdir, test=pathutil.is_source, )) win_srcs = set(fileutil.files( - f"{self.dstdir}/src/boost/locale/win32", + f"{self.dstdir}/src/win32", rel=self.dstdir, test=pathutil.is_source, )) diff --git a/contrib/restricted/boost/locale/.yandex_meta/default.nix b/contrib/restricted/boost/locale/.yandex_meta/default.nix index d2e5b89c52c..9c73e061e2b 100644 --- a/contrib/restricted/boost/locale/.yandex_meta/default.nix +++ b/contrib/restricted/boost/locale/.yandex_meta/default.nix @@ -1,13 +1,13 @@ self: super: with self; { boost_locale = stdenv.mkDerivation rec { pname = "boost_locale"; - version = "1.87.0"; + version = "1.88.0"; src = fetchFromGitHub { owner = "boostorg"; repo = "locale"; rev = "boost-${version}"; - hash = "sha256-KQg12DCqTqG3KcBLobg6+B/XEDzaag8JiC52p6ecJ6Y="; + hash = "sha256-2GL7iq6xpJDYbHk6B85CKTyV1E7873phb9MERw4Z2Cc="; }; }; } diff --git a/contrib/restricted/boost/locale/.yandex_meta/devtools.copyrights.report b/contrib/restricted/boost/locale/.yandex_meta/devtools.copyrights.report index b8639e01536..3aa4d118eec 100644 --- a/contrib/restricted/boost/locale/.yandex_meta/devtools.copyrights.report +++ b/contrib/restricted/boost/locale/.yandex_meta/devtools.copyrights.report @@ -54,13 +54,13 @@ BELONGS ya.make include/boost/locale/conversion.hpp [2:2] include/boost/locale/date_time.hpp [2:2] include/boost/locale/date_time_facet.hpp [2:2] - include/boost/locale/encoding.hpp [2:2] + include/boost/locale/encoding.hpp [2:3] include/boost/locale/encoding_errors.hpp [2:2] include/boost/locale/encoding_utf.hpp [2:3] include/boost/locale/format.hpp [2:3] include/boost/locale/formatting.hpp [2:3] include/boost/locale/generator.hpp [2:2] - include/boost/locale/gnu_gettext.hpp [2:2] + include/boost/locale/gnu_gettext.hpp [2:3] include/boost/locale/info.hpp [2:3] include/boost/locale/localization_backend.hpp [2:2] include/boost/locale/message.hpp [2:3] @@ -68,75 +68,74 @@ BELONGS ya.make include/boost/locale/utf.hpp [2:2] include/boost/locale/util.hpp [2:3] include/boost/locale/util/locale_data.hpp [2:3] - src/boost/locale/encoding/codepage.cpp [2:3] - src/boost/locale/encoding/iconv_converter.hpp [2:2] - src/boost/locale/encoding/uconv_converter.hpp [2:2] - src/boost/locale/encoding/wconv_converter.hpp [2:2] - src/boost/locale/icu/all_generator.hpp [2:2] - src/boost/locale/icu/boundary.cpp [2:3] - src/boost/locale/icu/cdata.hpp [2:2] - src/boost/locale/icu/codecvt.cpp [2:3] - src/boost/locale/icu/codecvt.hpp [2:2] - src/boost/locale/icu/collator.cpp [2:2] - src/boost/locale/icu/conversion.cpp [2:3] - src/boost/locale/icu/date_time.cpp [2:3] - src/boost/locale/icu/formatter.cpp [2:3] - src/boost/locale/icu/formatter.hpp [2:2] - src/boost/locale/icu/formatters_cache.cpp [2:3] - src/boost/locale/icu/formatters_cache.hpp [2:3] - src/boost/locale/icu/icu_backend.cpp [2:3] - src/boost/locale/icu/icu_backend.hpp [2:2] - src/boost/locale/icu/icu_util.hpp [2:3] - src/boost/locale/icu/numeric.cpp [2:2] - src/boost/locale/icu/time_zone.cpp [2:2] - src/boost/locale/icu/time_zone.hpp [2:2] - src/boost/locale/icu/uconv.hpp [2:3] - src/boost/locale/posix/all_generator.hpp [2:2] - src/boost/locale/posix/codecvt.cpp [2:3] - src/boost/locale/posix/collate.cpp [2:2] - src/boost/locale/posix/converter.cpp [2:2] - src/boost/locale/posix/numeric.cpp [2:2] - src/boost/locale/posix/posix_backend.cpp [2:3] - src/boost/locale/posix/posix_backend.hpp [2:2] - src/boost/locale/shared/date_time.cpp [2:3] - src/boost/locale/shared/format.cpp [2:2] - src/boost/locale/shared/formatting.cpp [2:2] - src/boost/locale/shared/generator.cpp [2:2] - src/boost/locale/shared/iconv_codecvt.cpp [2:3] - src/boost/locale/shared/iconv_codecvt.hpp [2:2] - src/boost/locale/shared/ids.cpp [2:3] - src/boost/locale/shared/ios_prop.hpp [2:3] - src/boost/locale/shared/localization_backend.cpp [2:2] - src/boost/locale/shared/mo_hash.hpp [2:2] - src/boost/locale/shared/mo_lambda.cpp [2:3] - src/boost/locale/shared/mo_lambda.hpp [2:3] - src/boost/locale/std/all_generator.hpp [2:2] - src/boost/locale/std/codecvt.cpp [2:2] - src/boost/locale/std/collate.cpp [2:2] - src/boost/locale/std/converter.cpp [2:2] - src/boost/locale/std/numeric.cpp [2:2] - src/boost/locale/std/std_backend.cpp [2:3] - src/boost/locale/std/std_backend.hpp [2:2] - src/boost/locale/util/codecvt_converter.cpp [2:3] - src/boost/locale/util/default_locale.cpp [2:2] - src/boost/locale/util/encoding.cpp [2:3] - src/boost/locale/util/encoding.hpp [2:3] - src/boost/locale/util/gregorian.cpp [2:2] - src/boost/locale/util/gregorian.hpp [2:2] - src/boost/locale/util/iconv.hpp [2:2] - src/boost/locale/util/info.cpp [2:3] - src/boost/locale/util/locale_data.cpp [2:3] - src/boost/locale/util/numeric.hpp [2:2] - src/boost/locale/util/timezone.hpp [2:2] - src/boost/locale/win32/all_generator.hpp [2:2] - src/boost/locale/win32/api.hpp [2:2] - src/boost/locale/win32/collate.cpp [2:2] - src/boost/locale/win32/converter.cpp [2:2] - src/boost/locale/win32/lcid.cpp [2:2] - src/boost/locale/win32/lcid.hpp [2:2] - src/boost/locale/win32/numeric.cpp [2:2] - src/boost/locale/win32/win_backend.cpp [2:3] - src/boost/locale/win32/win_backend.hpp [2:2] + src/encoding/codepage.cpp [2:3] + src/encoding/iconv_converter.hpp [2:2] + src/encoding/uconv_converter.hpp [2:2] + src/encoding/wconv_converter.hpp [2:2] + src/icu/all_generator.hpp [2:2] + src/icu/boundary.cpp [2:3] + src/icu/cdata.hpp [2:2] + src/icu/codecvt.cpp [2:3] + src/icu/codecvt.hpp [2:2] + src/icu/collator.cpp [2:3] + src/icu/conversion.cpp [2:3] + src/icu/date_time.cpp [2:3] + src/icu/formatter.cpp [2:3] + src/icu/formatter.hpp [2:3] + src/icu/formatters_cache.cpp [2:3] + src/icu/formatters_cache.hpp [2:3] + src/icu/icu_backend.cpp [2:3] + src/icu/icu_backend.hpp [2:2] + src/icu/icu_util.hpp [2:3] + src/icu/numeric.cpp [2:3] + src/icu/time_zone.hpp [2:3] + src/icu/uconv.hpp [2:3] + src/posix/all_generator.hpp [2:2] + src/posix/codecvt.cpp [2:3] + src/posix/collate.cpp [2:2] + src/posix/converter.cpp [2:2] + src/posix/numeric.cpp [2:2] + src/posix/posix_backend.cpp [2:3] + src/posix/posix_backend.hpp [2:2] + src/shared/date_time.cpp [2:3] + src/shared/format.cpp [2:3] + src/shared/formatting.cpp [2:2] + src/shared/generator.cpp [2:3] + src/shared/iconv_codecvt.cpp [2:3] + src/shared/iconv_codecvt.hpp [2:2] + src/shared/ids.cpp [2:3] + src/shared/ios_prop.hpp [2:3] + src/shared/localization_backend.cpp [2:2] + src/shared/mo_hash.hpp [2:2] + src/shared/mo_lambda.cpp [2:3] + src/shared/mo_lambda.hpp [2:3] + src/std/all_generator.hpp [2:2] + src/std/codecvt.cpp [2:2] + src/std/collate.cpp [2:2] + src/std/converter.cpp [2:2] + src/std/numeric.cpp [2:2] + src/std/std_backend.cpp [2:3] + src/std/std_backend.hpp [2:2] + src/util/codecvt_converter.cpp [2:3] + src/util/default_locale.cpp [2:2] + src/util/encoding.cpp [2:3] + src/util/encoding.hpp [2:3] + src/util/gregorian.cpp [2:2] + src/util/gregorian.hpp [2:2] + src/util/iconv.hpp [2:2] + src/util/info.cpp [2:3] + src/util/locale_data.cpp [2:3] + src/util/numeric.hpp [2:2] + src/util/timezone.hpp [2:2] + src/win32/all_generator.hpp [2:2] + src/win32/api.hpp [2:2] + src/win32/collate.cpp [2:2] + src/win32/converter.cpp [2:2] + src/win32/lcid.cpp [2:2] + src/win32/lcid.hpp [2:2] + src/win32/numeric.cpp [2:2] + src/win32/win_backend.cpp [2:3] + src/win32/win_backend.hpp [2:2] KEEP COPYRIGHT_SERVICE_LABEL 0aacc38a77bc0373054292f93600d25a BELONGS ya.make @@ -148,7 +147,19 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - src/boost/locale/icu/uconv.hpp [2:3] + src/icu/uconv.hpp [2:3] + +KEEP COPYRIGHT_SERVICE_LABEL 10d0d960009e0367294c74e986494399 +BELONGS ya.make + License text: + // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) + // Copyright (c) 2025 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/locale/encoding.hpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL 187d73eada66cef6d5d08ed727437603 BELONGS ya.make @@ -160,8 +171,40 @@ BELONGS ya.make Match type : COPYRIGHT Files with this license: include/boost/locale/detail/allocator_traits.hpp [2:2] - src/boost/locale/shared/ids.cpp [2:3] - src/boost/locale/shared/std_collate_adapter.hpp [2:2] + src/icu/formatter.hpp [2:3] + src/icu/numeric.cpp [2:3] + src/shared/format.cpp [2:3] + src/shared/generator.cpp [2:3] + src/shared/ids.cpp [2:3] + src/shared/std_collate_adapter.hpp [2:2] + +KEEP COPYRIGHT_SERVICE_LABEL 21fa899f7deb226d35fdddb2e22eb4ea +BELONGS ya.make + License text: + // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) + // Copyright (c) 2021-2025 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + src/icu/boundary.cpp [2:3] + src/shared/message.cpp [2:3] + +KEEP COPYRIGHT_SERVICE_LABEL 5283dadfabe6a307c3ae77a03b4204e6 +BELONGS ya.make + License text: + // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) + // Copyright (c) 2021-2024 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/locale/format.hpp [2:3] + src/icu/date_time.cpp [2:3] + src/icu/formatter.cpp [2:3] + src/icu/formatters_cache.cpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL 5f6f0ebf2d6180caac56d446585150fe BELONGS ya.make @@ -187,6 +230,11 @@ BELONGS ya.make Match type : COPYRIGHT Files with this license: include/boost/locale/encoding_utf.hpp [2:3] + include/boost/locale/gnu_gettext.hpp [2:3] + src/icu/collator.cpp [2:3] + src/icu/conversion.cpp [2:3] + src/icu/time_zone.hpp [2:3] + src/util/locale_data.cpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL 8d04644911f5fff0cef0ea7eeadf74ee BELONGS ya.make @@ -198,11 +246,20 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - src/boost/locale/icu/boundary.cpp [2:3] - src/boost/locale/icu/date_time.cpp [2:3] - src/boost/locale/icu/formatters_cache.cpp [2:3] - src/boost/locale/icu/formatters_cache.hpp [2:3] - src/boost/locale/icu/icu_util.hpp [2:3] + src/icu/formatters_cache.hpp [2:3] + src/icu/icu_util.hpp [2:3] + +KEEP COPYRIGHT_SERVICE_LABEL a63a0062b2f0e3cc2d4c206ed25fb44c +BELONGS ya.make + License text: + // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) + // Copyright (c) 2023-2024 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/locale/util/locale_data.hpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL a999dc6b43b371fa616fd4c0c30cf6f3 BELONGS ya.make @@ -213,10 +270,23 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - include/boost/locale/detail/any_string.hpp [2:2] - include/boost/locale/util/locale_data.hpp [2:3] - src/boost/locale/shared/message.hpp [2:2] - src/boost/locale/util/make_std_unique.hpp [2:2] + src/shared/message.hpp [2:2] + src/util/make_std_unique.hpp [2:2] + +KEEP COPYRIGHT_SERVICE_LABEL aa7339758a526244dab153b34cc3dcef +BELONGS ya.make + License text: + // Copyright (c) 2022-2025 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/locale/detail/encoding.hpp [2:2] + src/encoding/codepage.cpp [2:3] + src/icu/codecvt.cpp [2:3] + src/util/encoding.cpp [2:3] + src/util/encoding.hpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL c75aae6c76ff96e098e51412b5d4691b BELONGS ya.make @@ -228,40 +298,44 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - include/boost/locale/detail/encoding.hpp [2:2] include/boost/locale/detail/facet_id.hpp [2:2] include/boost/locale/detail/is_supported_char.hpp [2:2] include/boost/locale/formatting.hpp [2:3] include/boost/locale/info.hpp [2:3] include/boost/locale/util.hpp [2:3] include/boost/locale/util/string.hpp [2:2] - src/boost/locale/encoding/codepage.cpp [2:3] - src/boost/locale/icu/codecvt.cpp [2:3] - src/boost/locale/icu/conversion.cpp [2:3] - src/boost/locale/icu/icu_backend.cpp [2:3] - src/boost/locale/posix/codecvt.cpp [2:3] - src/boost/locale/posix/posix_backend.cpp [2:3] - src/boost/locale/shared/date_time.cpp [2:3] - src/boost/locale/shared/iconv_codecvt.cpp [2:3] - src/boost/locale/std/std_backend.cpp [2:3] - src/boost/locale/util/codecvt_converter.cpp [2:3] - src/boost/locale/util/encoding.cpp [2:3] - src/boost/locale/util/encoding.hpp [2:3] - src/boost/locale/util/info.cpp [2:3] - src/boost/locale/util/locale_data.cpp [2:3] - src/boost/locale/win32/win_backend.cpp [2:3] + src/icu/icu_backend.cpp [2:3] + src/posix/codecvt.cpp [2:3] + src/posix/posix_backend.cpp [2:3] + src/shared/date_time.cpp [2:3] + src/shared/iconv_codecvt.cpp [2:3] + src/std/std_backend.cpp [2:3] + src/util/codecvt_converter.cpp [2:3] + src/util/info.cpp [2:3] + src/win32/win_backend.cpp [2:3] + +KEEP COPYRIGHT_SERVICE_LABEL c7b0fea325502e648cff49d8a76577a4 +BELONGS ya.make + License text: + // Copyright (c) 2024-2025 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + src/util/numeric_conversion.hpp [2:2] KEEP COPYRIGHT_SERVICE_LABEL c9d011950648c03f29cc58f664ea728e BELONGS ya.make License text: // Copyright (c) 2009-2015 Artyom Beilis (Tonkikh) - // Copyright (c) 2021-2023 Alexander Grund + // Copyright (c) 2021-2025 Alexander Grund Scancode info: Original SPDX id: COPYRIGHT_SERVICE_LABEL Score : 100.00 Match type : COPYRIGHT Files with this license: - src/boost/locale/shared/message.cpp [2:3] + src/shared/message.cpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL ce25033e7c274b09a88738980e8ddeb6 BELONGS ya.make @@ -273,25 +347,33 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - src/boost/locale/shared/ios_prop.hpp [2:3] + src/shared/ios_prop.hpp [2:3] + +KEEP COPYRIGHT_SERVICE_LABEL d1d2857cd6a3cb1945f79fec36352462 +BELONGS ya.make + License text: + // Copyright (c) 2023-2025 Alexander Grund + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + include/boost/locale/detail/any_string.hpp [2:2] KEEP COPYRIGHT_SERVICE_LABEL f3772b68b272fd4e5066ca5b643faab9 BELONGS ya.make License text: - // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) + // Copyright (c) 2015 Artyom Beilis (Tonkikh) // Copyright (c) 2021-2023 Alexander Grund Scancode info: Original SPDX id: COPYRIGHT_SERVICE_LABEL Score : 100.00 Match type : COPYRIGHT Files with this license: - include/boost/locale/format.hpp [2:3] include/boost/locale/generic_codecvt.hpp [2:3] include/boost/locale/message.hpp [2:3] - src/boost/locale/icu/formatter.cpp [2:3] - src/boost/locale/shared/message.cpp [2:3] - src/boost/locale/shared/mo_lambda.cpp [2:3] - src/boost/locale/shared/mo_lambda.hpp [2:3] + src/shared/mo_lambda.cpp [2:3] + src/shared/mo_lambda.hpp [2:3] KEEP COPYRIGHT_SERVICE_LABEL f9f21cf5cc873fe5cc18d20988035289 BELONGS ya.make @@ -313,4 +395,4 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - src/boost/locale/util/foreach_char.hpp [2:2] + src/util/foreach_char.hpp [2:2] diff --git a/contrib/restricted/boost/locale/.yandex_meta/devtools.licenses.report b/contrib/restricted/boost/locale/.yandex_meta/devtools.licenses.report index 7173da13541..5c88ba923ad 100644 --- a/contrib/restricted/boost/locale/.yandex_meta/devtools.licenses.report +++ b/contrib/restricted/boost/locale/.yandex_meta/devtools.licenses.report @@ -53,7 +53,7 @@ BELONGS ya.make Match type : NOTICE Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0 Files with this license: - README.md [64:64] + README.md [66:66] KEEP BSL-1.0 a84b62b7fab19a18e7129119ab661542 BELONGS ya.make @@ -89,7 +89,7 @@ BELONGS ya.make include/boost/locale/detail/allocator_traits.hpp [5:5] include/boost/locale/detail/encoding.hpp [5:5] include/boost/locale/detail/is_supported_char.hpp [5:5] - include/boost/locale/encoding.hpp [5:5] + include/boost/locale/encoding.hpp [6:6] include/boost/locale/encoding_errors.hpp [5:5] include/boost/locale/encoding_utf.hpp [6:6] include/boost/locale/formatting.hpp [6:6] @@ -99,49 +99,50 @@ BELONGS ya.make include/boost/locale/time_zone.hpp [5:5] include/boost/locale/utf8_codecvt.hpp [5:5] include/boost/locale/util/locale_data.hpp [6:6] - src/boost/locale/encoding/codepage.cpp [6:6] - src/boost/locale/encoding/iconv_converter.hpp [5:5] - src/boost/locale/icu/all_generator.hpp [5:5] - src/boost/locale/icu/boundary.cpp [6:6] - src/boost/locale/icu/cdata.hpp [5:5] - src/boost/locale/icu/codecvt.hpp [5:5] - src/boost/locale/icu/formatter.hpp [5:5] - src/boost/locale/icu/icu_backend.hpp [5:5] - src/boost/locale/icu/uconv.hpp [6:6] - src/boost/locale/posix/all_generator.hpp [5:5] - src/boost/locale/posix/codecvt.cpp [6:6] - src/boost/locale/posix/collate.cpp [5:5] - src/boost/locale/posix/converter.cpp [5:5] - src/boost/locale/posix/numeric.cpp [5:5] - src/boost/locale/posix/posix_backend.hpp [5:5] - src/boost/locale/shared/date_time.cpp [6:6] - src/boost/locale/shared/formatting.cpp [5:5] - src/boost/locale/shared/iconv_codecvt.hpp [5:5] - src/boost/locale/shared/ids.cpp [6:6] - src/boost/locale/shared/ios_prop.hpp [6:6] - src/boost/locale/shared/message.hpp [5:5] - src/boost/locale/shared/std_collate_adapter.hpp [5:5] - src/boost/locale/std/codecvt.cpp [5:5] - src/boost/locale/std/collate.cpp [5:5] - src/boost/locale/std/converter.cpp [5:5] - src/boost/locale/std/numeric.cpp [5:5] - src/boost/locale/std/std_backend.hpp [5:5] - src/boost/locale/util/codecvt_converter.cpp [6:6] - src/boost/locale/util/default_locale.cpp [5:5] - src/boost/locale/util/encoding.cpp [6:6] - src/boost/locale/util/encoding.hpp [6:6] - src/boost/locale/util/foreach_char.hpp [5:5] - src/boost/locale/util/gregorian.hpp [5:5] - src/boost/locale/util/iconv.hpp [5:5] - src/boost/locale/util/info.cpp [6:6] - src/boost/locale/util/locale_data.cpp [6:6] - src/boost/locale/util/make_std_unique.hpp [5:5] - src/boost/locale/win32/all_generator.hpp [5:5] - src/boost/locale/win32/collate.cpp [5:5] - src/boost/locale/win32/converter.cpp [5:5] - src/boost/locale/win32/lcid.cpp [5:5] - src/boost/locale/win32/numeric.cpp [5:5] - src/boost/locale/win32/win_backend.hpp [5:5] + src/encoding/codepage.cpp [6:6] + src/encoding/iconv_converter.hpp [5:5] + src/icu/all_generator.hpp [5:5] + src/icu/boundary.cpp [6:6] + src/icu/cdata.hpp [5:5] + src/icu/codecvt.hpp [5:5] + src/icu/formatter.hpp [6:6] + src/icu/icu_backend.hpp [5:5] + src/icu/uconv.hpp [6:6] + src/posix/all_generator.hpp [5:5] + src/posix/codecvt.cpp [6:6] + src/posix/collate.cpp [5:5] + src/posix/converter.cpp [5:5] + src/posix/numeric.cpp [5:5] + src/posix/posix_backend.hpp [5:5] + src/shared/date_time.cpp [6:6] + src/shared/formatting.cpp [5:5] + src/shared/iconv_codecvt.hpp [5:5] + src/shared/ids.cpp [6:6] + src/shared/ios_prop.hpp [6:6] + src/shared/message.hpp [5:5] + src/shared/std_collate_adapter.hpp [5:5] + src/std/codecvt.cpp [5:5] + src/std/collate.cpp [5:5] + src/std/converter.cpp [5:5] + src/std/numeric.cpp [5:5] + src/std/std_backend.hpp [5:5] + src/util/codecvt_converter.cpp [6:6] + src/util/default_locale.cpp [5:5] + src/util/encoding.cpp [6:6] + src/util/encoding.hpp [6:6] + src/util/foreach_char.hpp [5:5] + src/util/gregorian.hpp [5:5] + src/util/iconv.hpp [5:5] + src/util/info.cpp [6:6] + src/util/locale_data.cpp [6:6] + src/util/make_std_unique.hpp [5:5] + src/util/numeric.hpp [5:5] + src/win32/all_generator.hpp [5:5] + src/win32/collate.cpp [5:5] + src/win32/converter.cpp [5:5] + src/win32/lcid.cpp [5:5] + src/win32/numeric.cpp [5:5] + src/win32/win_backend.hpp [5:5] KEEP BSL-1.0 e03c043ca7052925e34194f3fe2631e4 BELONGS ya.make @@ -164,7 +165,7 @@ BELONGS ya.make include/boost/locale/detail/allocator_traits.hpp [4:4] include/boost/locale/detail/encoding.hpp [4:4] include/boost/locale/detail/is_supported_char.hpp [4:4] - include/boost/locale/encoding.hpp [4:4] + include/boost/locale/encoding.hpp [5:5] include/boost/locale/encoding_errors.hpp [4:4] include/boost/locale/encoding_utf.hpp [5:5] include/boost/locale/formatting.hpp [5:5] @@ -174,49 +175,50 @@ BELONGS ya.make include/boost/locale/time_zone.hpp [4:4] include/boost/locale/utf8_codecvt.hpp [4:4] include/boost/locale/util/locale_data.hpp [5:5] - src/boost/locale/encoding/codepage.cpp [5:5] - src/boost/locale/encoding/iconv_converter.hpp [4:4] - src/boost/locale/icu/all_generator.hpp [4:4] - src/boost/locale/icu/boundary.cpp [5:5] - src/boost/locale/icu/cdata.hpp [4:4] - src/boost/locale/icu/codecvt.hpp [4:4] - src/boost/locale/icu/formatter.hpp [4:4] - src/boost/locale/icu/icu_backend.hpp [4:4] - src/boost/locale/icu/uconv.hpp [5:5] - src/boost/locale/posix/all_generator.hpp [4:4] - src/boost/locale/posix/codecvt.cpp [5:5] - src/boost/locale/posix/collate.cpp [4:4] - src/boost/locale/posix/converter.cpp [4:4] - src/boost/locale/posix/numeric.cpp [4:4] - src/boost/locale/posix/posix_backend.hpp [4:4] - src/boost/locale/shared/date_time.cpp [5:5] - src/boost/locale/shared/formatting.cpp [4:4] - src/boost/locale/shared/iconv_codecvt.hpp [4:4] - src/boost/locale/shared/ids.cpp [5:5] - src/boost/locale/shared/ios_prop.hpp [5:5] - src/boost/locale/shared/message.hpp [4:4] - src/boost/locale/shared/std_collate_adapter.hpp [4:4] - src/boost/locale/std/codecvt.cpp [4:4] - src/boost/locale/std/collate.cpp [4:4] - src/boost/locale/std/converter.cpp [4:4] - src/boost/locale/std/numeric.cpp [4:4] - src/boost/locale/std/std_backend.hpp [4:4] - src/boost/locale/util/codecvt_converter.cpp [5:5] - src/boost/locale/util/default_locale.cpp [4:4] - src/boost/locale/util/encoding.cpp [5:5] - src/boost/locale/util/encoding.hpp [5:5] - src/boost/locale/util/foreach_char.hpp [4:4] - src/boost/locale/util/gregorian.hpp [4:4] - src/boost/locale/util/iconv.hpp [4:4] - src/boost/locale/util/info.cpp [5:5] - src/boost/locale/util/locale_data.cpp [5:5] - src/boost/locale/util/make_std_unique.hpp [4:4] - src/boost/locale/win32/all_generator.hpp [4:4] - src/boost/locale/win32/collate.cpp [4:4] - src/boost/locale/win32/converter.cpp [4:4] - src/boost/locale/win32/lcid.cpp [4:4] - src/boost/locale/win32/numeric.cpp [4:4] - src/boost/locale/win32/win_backend.hpp [4:4] + src/encoding/codepage.cpp [5:5] + src/encoding/iconv_converter.hpp [4:4] + src/icu/all_generator.hpp [4:4] + src/icu/boundary.cpp [5:5] + src/icu/cdata.hpp [4:4] + src/icu/codecvt.hpp [4:4] + src/icu/formatter.hpp [5:5] + src/icu/icu_backend.hpp [4:4] + src/icu/uconv.hpp [5:5] + src/posix/all_generator.hpp [4:4] + src/posix/codecvt.cpp [5:5] + src/posix/collate.cpp [4:4] + src/posix/converter.cpp [4:4] + src/posix/numeric.cpp [4:4] + src/posix/posix_backend.hpp [4:4] + src/shared/date_time.cpp [5:5] + src/shared/formatting.cpp [4:4] + src/shared/iconv_codecvt.hpp [4:4] + src/shared/ids.cpp [5:5] + src/shared/ios_prop.hpp [5:5] + src/shared/message.hpp [4:4] + src/shared/std_collate_adapter.hpp [4:4] + src/std/codecvt.cpp [4:4] + src/std/collate.cpp [4:4] + src/std/converter.cpp [4:4] + src/std/numeric.cpp [4:4] + src/std/std_backend.hpp [4:4] + src/util/codecvt_converter.cpp [5:5] + src/util/default_locale.cpp [4:4] + src/util/encoding.cpp [5:5] + src/util/encoding.hpp [5:5] + src/util/foreach_char.hpp [4:4] + src/util/gregorian.hpp [4:4] + src/util/iconv.hpp [4:4] + src/util/info.cpp [5:5] + src/util/locale_data.cpp [5:5] + src/util/make_std_unique.hpp [4:4] + src/util/numeric.hpp [4:4] + src/win32/all_generator.hpp [4:4] + src/win32/collate.cpp [4:4] + src/win32/converter.cpp [4:4] + src/win32/lcid.cpp [4:4] + src/win32/numeric.cpp [4:4] + src/win32/win_backend.hpp [4:4] KEEP BSL-1.0 e9df2954141aa96551bf39192c39d2fe BELONGS ya.make @@ -237,40 +239,39 @@ BELONGS ya.make include/boost/locale/detail/facet_id.hpp [4:5] include/boost/locale/format.hpp [5:6] include/boost/locale/generator.hpp [4:5] - include/boost/locale/gnu_gettext.hpp [4:5] + include/boost/locale/gnu_gettext.hpp [5:6] include/boost/locale/hold_ptr.hpp [4:5] include/boost/locale/localization_backend.hpp [4:5] include/boost/locale/utf.hpp [4:5] include/boost/locale/util.hpp [5:6] include/boost/locale/util/string.hpp [4:5] - src/boost/locale/encoding/uconv_converter.hpp [4:5] - src/boost/locale/encoding/wconv_converter.hpp [4:5] - src/boost/locale/icu/codecvt.cpp [5:6] - src/boost/locale/icu/collator.cpp [4:5] - src/boost/locale/icu/conversion.cpp [5:6] - src/boost/locale/icu/date_time.cpp [5:6] - src/boost/locale/icu/formatter.cpp [5:6] - src/boost/locale/icu/formatters_cache.cpp [5:6] - src/boost/locale/icu/formatters_cache.hpp [5:6] - src/boost/locale/icu/icu_backend.cpp [5:6] - src/boost/locale/icu/icu_util.hpp [5:6] - src/boost/locale/icu/numeric.cpp [4:5] - src/boost/locale/icu/time_zone.cpp [4:5] - src/boost/locale/icu/time_zone.hpp [4:5] - src/boost/locale/posix/posix_backend.cpp [5:6] - src/boost/locale/shared/format.cpp [4:5] - src/boost/locale/shared/generator.cpp [4:5] - src/boost/locale/shared/iconv_codecvt.cpp [5:6] - src/boost/locale/shared/localization_backend.cpp [4:5] - src/boost/locale/shared/message.cpp [5:6] - src/boost/locale/shared/mo_hash.hpp [4:5] - src/boost/locale/shared/mo_lambda.cpp [5:6] - src/boost/locale/shared/mo_lambda.hpp [5:6] - src/boost/locale/std/all_generator.hpp [4:5] - src/boost/locale/std/std_backend.cpp [5:6] - src/boost/locale/util/gregorian.cpp [4:5] - src/boost/locale/util/numeric.hpp [4:5] - src/boost/locale/util/timezone.hpp [4:5] - src/boost/locale/win32/api.hpp [4:5] - src/boost/locale/win32/lcid.hpp [4:5] - src/boost/locale/win32/win_backend.cpp [5:6] + src/encoding/uconv_converter.hpp [4:5] + src/encoding/wconv_converter.hpp [4:5] + src/icu/codecvt.cpp [5:6] + src/icu/collator.cpp [5:6] + src/icu/conversion.cpp [5:6] + src/icu/date_time.cpp [5:6] + src/icu/formatter.cpp [5:6] + src/icu/formatters_cache.cpp [5:6] + src/icu/formatters_cache.hpp [5:6] + src/icu/icu_backend.cpp [5:6] + src/icu/icu_util.hpp [5:6] + src/icu/numeric.cpp [5:6] + src/icu/time_zone.hpp [5:6] + src/posix/posix_backend.cpp [5:6] + src/shared/format.cpp [5:6] + src/shared/generator.cpp [5:6] + src/shared/iconv_codecvt.cpp [5:6] + src/shared/localization_backend.cpp [4:5] + src/shared/message.cpp [5:6] + src/shared/mo_hash.hpp [4:5] + src/shared/mo_lambda.cpp [5:6] + src/shared/mo_lambda.hpp [5:6] + src/std/all_generator.hpp [4:5] + src/std/std_backend.cpp [5:6] + src/util/gregorian.cpp [4:5] + src/util/numeric_conversion.hpp [4:5] + src/util/timezone.hpp [4:5] + src/win32/api.hpp [4:5] + src/win32/lcid.hpp [4:5] + src/win32/win_backend.cpp [5:6] diff --git a/contrib/restricted/boost/locale/.yandex_meta/licenses.list.txt b/contrib/restricted/boost/locale/.yandex_meta/licenses.list.txt index 2769441dcd4..dcd90b21aef 100644 --- a/contrib/restricted/boost/locale/.yandex_meta/licenses.list.txt +++ b/contrib/restricted/boost/locale/.yandex_meta/licenses.list.txt @@ -62,7 +62,12 @@ DEALINGS IN THE SOFTWARE. ====================COPYRIGHT==================== // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2023 Alexander Grund +// Copyright (c) 2021-2024 Alexander Grund + + +====================COPYRIGHT==================== +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2021-2025 Alexander Grund ====================COPYRIGHT==================== @@ -81,8 +86,18 @@ DEALINGS IN THE SOFTWARE. ====================COPYRIGHT==================== +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2023-2024 Alexander Grund + + +====================COPYRIGHT==================== +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2025 Alexander Grund + + +====================COPYRIGHT==================== // Copyright (c) 2009-2015 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2023 Alexander Grund +// Copyright (c) 2021-2025 Alexander Grund ====================COPYRIGHT==================== @@ -95,6 +110,10 @@ DEALINGS IN THE SOFTWARE. ====================COPYRIGHT==================== +// Copyright (c) 2022-2025 Alexander Grund + + +====================COPYRIGHT==================== // Copyright (c) 2023 Alexander Grund @@ -103,4 +122,12 @@ DEALINGS IN THE SOFTWARE. ====================COPYRIGHT==================== +// Copyright (c) 2023-2025 Alexander Grund + + +====================COPYRIGHT==================== // Copyright (c) 2024 Alexander Grund + + +====================COPYRIGHT==================== +// Copyright (c) 2024-2025 Alexander Grund diff --git a/contrib/restricted/boost/locale/README.md b/contrib/restricted/boost/locale/README.md index ea18e02d993..127384b09bb 100644 --- a/contrib/restricted/boost/locale/README.md +++ b/contrib/restricted/boost/locale/README.md @@ -35,9 +35,11 @@ Sacrificing some less important features, Boost.Locale becomes less powerful but Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). -### Properties +### Properties / Requirements * C++11 +* ICU 4.8.1 or newer for full feature support. + ICU 50.1 is not supported, please use a newer version. * Formatted with clang-format, see [`tools/format_sources.sh`](https://github.com/boostorg/locale/blob/develop/tools/format_sources.sh) ### Build Status diff --git a/contrib/restricted/boost/locale/include/boost/locale/boundary/boundary_point.hpp b/contrib/restricted/boost/locale/include/boost/locale/boundary/boundary_point.hpp index 370dd5f816b..0743347cc3f 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/boundary/boundary_point.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/boundary/boundary_point.hpp @@ -100,7 +100,7 @@ namespace boost { namespace locale { namespace boundary { typedef boundary_point<std::string::const_iterator> sboundary_point; ///< convenience typedef typedef boundary_point<std::wstring::const_iterator> wsboundary_point; ///< convenience typedef -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t typedef boundary_point<std::u8string::const_iterator> u8sboundary_point; ///< convenience typedef #endif #ifdef BOOST_LOCALE_ENABLE_CHAR16_T diff --git a/contrib/restricted/boost/locale/include/boost/locale/boundary/index.hpp b/contrib/restricted/boost/locale/include/boost/locale/boundary/index.hpp index 92b7613fd3b..249ef877f2d 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/boundary/index.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/boundary/index.hpp @@ -868,7 +868,7 @@ namespace boost { namespace locale { namespace boundary { typedef segment_index<std::string::const_iterator> ssegment_index; ///< convenience typedef typedef segment_index<std::wstring::const_iterator> wssegment_index; ///< convenience typedef -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t typedef segment_index<std::u8string::const_iterator> u8ssegment_index; ///< convenience typedef #endif #ifdef BOOST_LOCALE_ENABLE_CHAR16_T @@ -892,7 +892,7 @@ namespace boost { namespace locale { namespace boundary { typedef boundary_point_index<std::string::const_iterator> sboundary_point_index; ///< convenience typedef typedef boundary_point_index<std::wstring::const_iterator> wsboundary_point_index; ///< convenience typedef -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t typedef boundary_point_index<std::u8string::const_iterator> u8sboundary_point_index; ///< convenience typedef #endif #ifdef BOOST_LOCALE_ENABLE_CHAR16_T diff --git a/contrib/restricted/boost/locale/include/boost/locale/boundary/segment.hpp b/contrib/restricted/boost/locale/include/boost/locale/boundary/segment.hpp index 24e129dcf1b..84243abea16 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/boundary/segment.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/boundary/segment.hpp @@ -340,7 +340,7 @@ namespace boost { namespace locale { namespace boundary { typedef segment<std::string::const_iterator> ssegment; ///< convenience typedef typedef segment<std::wstring::const_iterator> wssegment; ///< convenience typedef -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t typedef segment<std::u8string::const_iterator> u8ssegment; ///< convenience typedef #endif #ifdef BOOST_LOCALE_ENABLE_CHAR16_T diff --git a/contrib/restricted/boost/locale/include/boost/locale/config.hpp b/contrib/restricted/boost/locale/include/boost/locale/config.hpp index 1c69c92dc43..2064810d193 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/config.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/config.hpp @@ -89,11 +89,6 @@ # define BOOST_LOCALE_NO_SANITIZE(what) #endif -#if !defined(__cpp_lib_char8_t) || BOOST_WORKAROUND(BOOST_CLANG_VERSION, < 150000) -// No std::basic_string<char8_t> or bug in Clang: https://github.com/llvm/llvm-project/issues/55560 -# define BOOST_LOCALE_NO_CXX20_STRING8 -#endif - /// \endcond #endif // boost/locale/config.hpp diff --git a/contrib/restricted/boost/locale/include/boost/locale/detail/any_string.hpp b/contrib/restricted/boost/locale/include/boost/locale/detail/any_string.hpp index c0cc7ffb3e0..473d07e7db1 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/detail/any_string.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/detail/any_string.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Alexander Grund +// Copyright (c) 2023-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -9,7 +9,7 @@ #include <boost/locale/config.hpp> #include <boost/assert.hpp> -#include <boost/utility/string_view.hpp> +#include <boost/core/detail/string_view.hpp> #include <memory> #include <stdexcept> #include <string> @@ -31,7 +31,7 @@ namespace boost { namespace locale { namespace detail { }; template<typename Char> struct BOOST_SYMBOL_VISIBLE impl : base { - explicit impl(const boost::basic_string_view<Char> value) : s(value) {} + explicit impl(const core::basic_string_view<Char> value) : s(value) {} impl* clone() const override { return new impl(*this); } std::basic_string<Char> s; }; @@ -49,7 +49,7 @@ namespace boost { namespace locale { namespace detail { } template<typename Char> - void set(const boost::basic_string_view<Char> s) + void set(const core::basic_string_view<Char> s) { BOOST_ASSERT(!s.empty()); s_.reset(new impl<Char>(s)); diff --git a/contrib/restricted/boost/locale/include/boost/locale/detail/encoding.hpp b/contrib/restricted/boost/locale/include/boost/locale/detail/encoding.hpp index ee669349a19..2e37c308a36 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/detail/encoding.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/detail/encoding.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -9,7 +9,7 @@ #include <boost/locale/config.hpp> #include <boost/locale/encoding_errors.hpp> -#include <boost/utility/string_view.hpp> +#include <boost/core/detail/string_view.hpp> #include <memory> #include <string> @@ -24,7 +24,7 @@ namespace boost { namespace locale { namespace conv { namespace detail { virtual ~charset_converter() = default; virtual string_type convert(const CharIn* begin, const CharIn* end) = 0; - string_type convert(const boost::basic_string_view<CharIn>& text) + string_type convert(const core::basic_string_view<CharIn> text) { return convert(text.data(), text.data() + text.length()); } diff --git a/contrib/restricted/boost/locale/include/boost/locale/encoding.hpp b/contrib/restricted/boost/locale/include/boost/locale/encoding.hpp index d0e1d9d07e9..abc68bacdf4 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/encoding.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/encoding.hpp @@ -1,5 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -240,11 +241,11 @@ namespace boost { namespace locale { /// Convert \a text to UTF /// /// \throws conversion_error: Conversion failed - string_type convert(const boost::string_view& text) const { return impl_->convert(text); } + string_type convert(const core::string_view text) const { return impl_->convert(text); } /// Convert \a text to UTF /// /// \throws conversion_error: Conversion failed - string_type operator()(const boost::string_view& text) const { return convert(text); } + string_type operator()(const core::string_view text) const { return convert(text); } }; /// Converter class to decode an UTF string and encode it using a local encoding @@ -254,7 +255,7 @@ namespace boost { namespace locale { public: using char_type = CharType; - using stringview_type = boost::basic_string_view<CharType>; + using stringview_type = core::basic_string_view<CharType>; /// Create an instance to convert UTF text to text encoded with \a charset according to policy \a how /// @@ -298,11 +299,11 @@ namespace boost { namespace locale { /// Convert \a text /// /// \throws conversion_error: Conversion failed - std::string convert(const boost::string_view& text) const { return impl_->convert(text); } + std::string convert(const core::string_view text) const { return impl_->convert(text); } /// Convert \a text /// /// \throws conversion_error: Conversion failed - std::string operator()(const boost::string_view& text) const { return convert(text); } + std::string operator()(const core::string_view text) const { return convert(text); } }; } // namespace conv }} // namespace boost::locale diff --git a/contrib/restricted/boost/locale/include/boost/locale/format.hpp b/contrib/restricted/boost/locale/include/boost/locale/format.hpp index 6adb844031d..68020a4c35a 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/format.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/format.hpp @@ -1,6 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2023 Alexander Grund +// Copyright (c) 2021-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -418,7 +418,7 @@ namespace boost { namespace locale { typedef basic_format<char> format; /// Definition of wchar_t based format typedef basic_format<wchar_t> wformat; -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t /// Definition of char8_t based format typedef basic_format<char8_t> u8format; #endif diff --git a/contrib/restricted/boost/locale/include/boost/locale/formatting.hpp b/contrib/restricted/boost/locale/include/boost/locale/formatting.hpp index e3c8619e489..1844398ad7a 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/formatting.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/formatting.hpp @@ -122,7 +122,7 @@ namespace boost { namespace locale { /// Set time zone for formatting dates and time void time_zone(const std::string&); /// Get time zone for formatting dates and time - std::string time_zone() const; + const std::string& time_zone() const; /// Set date/time pattern (strftime like) template<typename CharType> diff --git a/contrib/restricted/boost/locale/include/boost/locale/generator.hpp b/contrib/restricted/boost/locale/include/boost/locale/generator.hpp index 675aa604b68..119e65659fc 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/generator.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/generator.hpp @@ -190,9 +190,6 @@ namespace locale { private: void set_all_options(localization_backend& backend, const std::string& id) const; - generator(const generator&); - void operator=(const generator&); - struct data; hold_ptr<data> d; }; diff --git a/contrib/restricted/boost/locale/include/boost/locale/gnu_gettext.hpp b/contrib/restricted/boost/locale/include/boost/locale/gnu_gettext.hpp index aff76b1cdca..6612e84ffd3 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/gnu_gettext.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/gnu_gettext.hpp @@ -1,11 +1,12 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2022-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#ifndef BOOST_LOCLAE_GNU_GETTEXT_HPP -#define BOOST_LOCLAE_GNU_GETTEXT_HPP +#ifndef BOOST_LOCALE_GNU_GETTEXT_HPP +#define BOOST_LOCALE_GNU_GETTEXT_HPP #include <boost/locale/detail/is_supported_char.hpp> #include <boost/locale/message.hpp> diff --git a/contrib/restricted/boost/locale/include/boost/locale/message.hpp b/contrib/restricted/boost/locale/include/boost/locale/message.hpp index 88a4aefbf11..fafff385167 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/message.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/message.hpp @@ -341,7 +341,7 @@ namespace boost { namespace locale { typedef basic_message<char> message; /// Convenience typedef for wchar_t typedef basic_message<wchar_t> wmessage; -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t /// Convenience typedef for char8_t typedef basic_message<char8_t> u8message; #endif diff --git a/contrib/restricted/boost/locale/include/boost/locale/util/locale_data.hpp b/contrib/restricted/boost/locale/include/boost/locale/util/locale_data.hpp index 397c404d604..cbd7f696f52 100644 --- a/contrib/restricted/boost/locale/include/boost/locale/util/locale_data.hpp +++ b/contrib/restricted/boost/locale/include/boost/locale/util/locale_data.hpp @@ -1,6 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2023 Alexander Grund +// Copyright (c) 2023-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -21,6 +21,7 @@ namespace boost { namespace locale { namespace util { /// Holder and parser for locale names/identifiers class BOOST_LOCALE_DECL locale_data { std::string language_; + std::string script_; std::string country_; std::string encoding_; std::string variant_; @@ -36,6 +37,8 @@ namespace boost { namespace locale { namespace util { /// Return language (usually 2 lowercase letters, i.e. ISO-639 or 'C') const std::string& language() const { return language_; } + /// Return the ISO-15924 abbreviation script code if present + const std::string& script() const { return script_; } /// Return country (usually 2 uppercase letters, i.e. ISO-3166) const std::string& country() const { return country_; } /// Return encoding/codeset, e.g. ISO8859-1 or UTF-8 @@ -48,12 +51,13 @@ namespace boost { namespace locale { namespace util { /// Return iff the encoding is UTF-8 bool is_utf8() const { return utf8_; } - /// Parse a locale identifier of the form `[language[_territory][.codeset][@modifier]]` + /// Parse a locale identifier of the form `[language[_script][_territory][.codeset][@modifier]]` /// /// Allows a dash as the delimiter: `[language-territory]` /// Return true if the identifier is valid: /// - `language` is given and consists of ASCII letters - /// - `territory`, if given, consists of ASCII letters + /// - `script` is only considered if it consists of exactly 4 ASCII letters + /// - `territory`, if given, consists of ASCII letters (usually ISO-3166) /// - Any field started by a delimiter (`_`, `-`, `.`, `@`) is not empty /// Otherwise parsing is aborted. Valid values already parsed stay set, other are defaulted. bool parse(const std::string& locale_name); @@ -65,6 +69,7 @@ namespace boost { namespace locale { namespace util { private: void reset(); bool parse_from_lang(const std::string& input); + bool parse_from_script(const std::string& input); bool parse_from_country(const std::string& input); bool parse_from_encoding(const std::string& input); bool parse_from_variant(const std::string& input); diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/time_zone.cpp b/contrib/restricted/boost/locale/src/boost/locale/icu/time_zone.cpp deleted file mode 100644 index 2f11862a59a..00000000000 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/time_zone.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// -// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// -// Distributed under the Boost Software License, Version 1.0. -// https://www.boost.org/LICENSE_1_0.txt - -#include "boost/locale/icu/time_zone.hpp" -#include <boost/locale/hold_ptr.hpp> -#include "boost/locale/icu/icu_util.hpp" -#include <boost/predef/os.h> - -// -// Bug - when ICU tries to find a file that is equivalent to /etc/localtime it finds /usr/share/zoneinfo/localtime -// that is just a symbolic link to /etc/localtime. -// -// It started in 4.0 and was fixed in version 4.6, also the fix was backported to the 4.4 branch so it should be -// available from 4.4.3... So we test if the workaround is required -// -// It is also relevant only for Linux, BSD and Apple (as I see in ICU code) -// - -#if BOOST_LOCALE_ICU_VERSION >= 400 && BOOST_LOCALE_ICU_VERSION <= 406 \ - && (BOOST_LOCALE_ICU_VERSION != 404 || U_ICU_VERSION_PATCHLEVEL_NUM >= 3) -# if BOOST_OS_LINUX || BOOST_OS_BSD_FREE || defined(__APPLE__) -# define BOOST_LOCALE_WORKAROUND_ICU_BUG -# endif -#endif - -#ifdef BOOST_LOCALE_WORKAROUND_ICU_BUG -# include <cstring> -# include <dirent.h> -# include <fstream> -# include <memory> -# include <pthread.h> -# include <sys/stat.h> -# include <sys/types.h> -# include <unistd.h> -#endif - -namespace boost { namespace locale { namespace impl_icu { - -#ifndef BOOST_LOCALE_WORKAROUND_ICU_BUG - - // This is normal behavior - - icu::TimeZone* get_time_zone(const std::string& time_zone) - { - if(time_zone.empty()) - return icu::TimeZone::createDefault(); - else - return icu::TimeZone::createTimeZone(time_zone.c_str()); - } - -#else - - // This is a workaround for an ICU timezone detection bug. - // It is \b very ICU specific and should not be used - // in general. It is also designed to work only on - // specific patforms: Linux, BSD and Apple, where this bug may actually - // occur - namespace { - - // Under BSD, Linux and Mac OS X dirent has normal size - // so no issues with readdir_r - - class directory { - public: - directory(const char* name) : d(0), read_result(0) - { - d = opendir(name); - if(!d) - return; - } - ~directory() - { - if(d) - closedir(d); - } - bool is_open() { return d; } - const char* next() - { - if(d && readdir_r(d, &de, &read_result) == 0 && read_result != 0) - return de.d_name; - return nullptr; - } - - private: - DIR* d; - struct dirent de; - struct dirent* read_result; - }; - - bool files_equal(const std::string& left, const std::string& right) - { - char l[256], r[256]; - std::ifstream ls(left); - if(!ls) - return false; - std::ifstream rs(right); - if(!rs) - return false; - do { - ls.read(l, sizeof(l)); - rs.read(r, sizeof(r)); - size_t n; - if((n = ls.gcount()) != size_t(rs.gcount())) - return false; - if(memcmp(l, r, n) != 0) - return false; - } while(!ls.eof() || !rs.eof()); - if(bool(ls.eof()) != bool(rs.eof())) - return false; - return true; - } - - std::string find_file_in(const std::string& ref, size_t size, const std::string& dir) - { - directory d(dir.c_str()); - if(!d.is_open()) - return std::string(); - - const char* name = nullptr; - while((name = d.next()) != 0) { - std::string file_name = name; - if(file_name == "." || file_name == ".." || file_name == "posixrules" || file_name == "localtime") - continue; - struct stat st; - std::string path = dir + "/" + file_name; - if(stat(path.c_str(), &st) == 0) { - if(S_ISDIR(st.st_mode)) { - std::string res = find_file_in(ref, size, path); - if(!res.empty()) - return file_name + "/" + res; - } else { - if(size_t(st.st_size) == size && files_equal(path, ref)) - return file_name; - } - } - } - return std::string(); - } - - // This actually emulates ICU's search - // algorithm... just it ignores localtime - std::string detect_correct_time_zone() - { - const char* tz_dir = "/usr/share/zoneinfo"; - const char* tz_file = "/etc/localtime"; - - struct stat st; - if(::stat(tz_file, &st) != 0) - return std::string(); - size_t size = st.st_size; - std::string r = find_file_in(tz_file, size, tz_dir); - if(r.empty()) - return r; - if(r.compare(0, 6, "posix/") == 0 || r.compare(0, 6, "right/", 6) == 0) - return r.substr(6); - return r; - } - - // Using pthread as: - // - This bug is relevant for only Linux, BSD, Mac OS X and - // pthreads are native threading API - // - The dependency on boost.thread may be removed when using - // more recent ICU versions (so TLS would not be needed) - // - // This the dependency on Boost.Thread is eliminated - - pthread_once_t init_tz = PTHREAD_ONCE_INIT; - std::string default_time_zone_name; - - extern "C" { - static void init_tz_proc() - { - try { - default_time_zone_name = detect_correct_time_zone(); - } catch(...) { - } - } - } - - std::string get_time_zone_name() - { - pthread_once(&init_tz, init_tz_proc); - return default_time_zone_name; - } - - } // namespace - - icu::TimeZone* get_time_zone(const std::string& time_zone) - { - if(!time_zone.empty()) - return icu::TimeZone::createTimeZone(time_zone.c_str()); - hold_ptr<icu::TimeZone> tz(icu::TimeZone::createDefault()); - icu::UnicodeString id; - tz->getID(id); - // Check if there is a bug? - if(id != icu::UnicodeString("localtime")) - return tz.release(); - // Now let's deal with the bug and run the fixed - // search loop as that of ICU - std::string real_id = get_time_zone_name(); - if(real_id.empty()) { - // if we failed fallback to ICU's time zone - return tz.release(); - } - return icu::TimeZone::createTimeZone(real_id.c_str()); - } -#endif // bug workaround - -}}} // namespace boost::locale::impl_icu diff --git a/contrib/restricted/boost/locale/src/boost/locale/encoding/codepage.cpp b/contrib/restricted/boost/locale/src/encoding/codepage.cpp index 0ac9659ab56..814a8035df2 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/encoding/codepage.cpp +++ b/contrib/restricted/boost/locale/src/encoding/codepage.cpp @@ -1,24 +1,24 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/encoding.hpp> -#include "boost/locale/util/make_std_unique.hpp" +#include "../util/make_std_unique.hpp" #if BOOST_LOCALE_USE_WIN32_API # define BOOST_LOCALE_WITH_WCONV #endif #ifdef BOOST_LOCALE_WITH_ICONV -# include "boost/locale/encoding/iconv_converter.hpp" +# include "iconv_converter.hpp" #endif #ifdef BOOST_LOCALE_WITH_ICU -# include "boost/locale/encoding/uconv_converter.hpp" +# include "uconv_converter.hpp" #endif #ifdef BOOST_LOCALE_WITH_WCONV -# include "boost/locale/encoding/wconv_converter.hpp" +# include "wconv_converter.hpp" #endif namespace boost { namespace locale { namespace conv { @@ -224,7 +224,7 @@ namespace boost { namespace locale { namespace conv { BOOST_LOCALE_INSTANTIATE(char); BOOST_LOCALE_INSTANTIATE_NO_CHAR(wchar_t); -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t BOOST_LOCALE_INSTANTIATE_NO_CHAR(char8_t); #endif diff --git a/contrib/restricted/boost/locale/src/boost/locale/encoding/iconv_converter.hpp b/contrib/restricted/boost/locale/src/encoding/iconv_converter.hpp index 2877dbca5e5..8d26287b564 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/encoding/iconv_converter.hpp +++ b/contrib/restricted/boost/locale/src/encoding/iconv_converter.hpp @@ -8,8 +8,8 @@ #define BOOST_LOCALE_IMPL_ICONV_CODEPAGE_HPP #include <boost/locale/encoding.hpp> -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/iconv.hpp" +#include "../util/encoding.hpp" +#include "../util/iconv.hpp" #include <boost/assert.hpp> #include <cerrno> #include <string> diff --git a/contrib/restricted/boost/locale/src/boost/locale/encoding/uconv_converter.hpp b/contrib/restricted/boost/locale/src/encoding/uconv_converter.hpp index 53a14055322..ae8913764ae 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/encoding/uconv_converter.hpp +++ b/contrib/restricted/boost/locale/src/encoding/uconv_converter.hpp @@ -8,8 +8,8 @@ #define BOOST_LOCALE_IMPL_UCONV_CODEPAGE_HPP #include <boost/locale/encoding.hpp> #include <boost/locale/hold_ptr.hpp> -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/uconv.hpp" +#include "../icu/icu_util.hpp" +#include "../icu/uconv.hpp" #include <unicode/ucnv.h> #include <unicode/ucnv_err.h> diff --git a/contrib/restricted/boost/locale/src/boost/locale/encoding/wconv_converter.hpp b/contrib/restricted/boost/locale/src/encoding/wconv_converter.hpp index 32cd78e21a9..e29b562edfa 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/encoding/wconv_converter.hpp +++ b/contrib/restricted/boost/locale/src/encoding/wconv_converter.hpp @@ -11,7 +11,7 @@ # define NOMINMAX #endif #include <boost/locale/encoding.hpp> -#include "boost/locale/util/encoding.hpp" +#include "../util/encoding.hpp" #include <algorithm> #include <cstddef> #include <cstring> diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/all_generator.hpp b/contrib/restricted/boost/locale/src/icu/all_generator.hpp index b2f8c34a33b..b2f8c34a33b 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/all_generator.hpp +++ b/contrib/restricted/boost/locale/src/icu/all_generator.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/boundary.cpp b/contrib/restricted/boost/locale/src/icu/boundary.cpp index 4adada4f428..339cab50914 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/boundary.cpp +++ b/contrib/restricted/boost/locale/src/icu/boundary.cpp @@ -1,17 +1,17 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2022 Alexander Grund +// Copyright (c) 2021-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/boundary.hpp> #include <boost/locale/generator.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/cdata.hpp" -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/uconv.hpp" -#include "boost/locale/util/encoding.hpp" +#include "../util/encoding.hpp" +#include "all_generator.hpp" +#include "cdata.hpp" +#include "icu_util.hpp" +#include "uconv.hpp" #if BOOST_LOCALE_ICU_VERSION >= 5502 # include <unicode/utext.h> #endif diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/cdata.hpp b/contrib/restricted/boost/locale/src/icu/cdata.hpp index 37ce36888e6..37ce36888e6 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/cdata.hpp +++ b/contrib/restricted/boost/locale/src/icu/cdata.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/codecvt.cpp b/contrib/restricted/boost/locale/src/icu/codecvt.cpp index cdf958ab58f..3e6e24f7743 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/codecvt.cpp +++ b/contrib/restricted/boost/locale/src/icu/codecvt.cpp @@ -1,20 +1,20 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/icu/codecvt.hpp" +#include "codecvt.hpp" #include <boost/locale/encoding.hpp> #include <boost/locale/encoding_errors.hpp> #include <boost/locale/hold_ptr.hpp> #include <boost/locale/util.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/uconv.hpp" -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/make_std_unique.hpp" +#include "../util/encoding.hpp" +#include "../util/make_std_unique.hpp" +#include "all_generator.hpp" +#include "icu_util.hpp" +#include "uconv.hpp" #include <unicode/ucnv.h> #include <unicode/ucnv_err.h> diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/codecvt.hpp b/contrib/restricted/boost/locale/src/icu/codecvt.hpp index f406f7f5335..f406f7f5335 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/codecvt.hpp +++ b/contrib/restricted/boost/locale/src/icu/codecvt.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/collator.cpp b/contrib/restricted/boost/locale/src/icu/collator.cpp index 72ade74fbb7..43d921d5941 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/collator.cpp +++ b/contrib/restricted/boost/locale/src/icu/collator.cpp @@ -1,28 +1,24 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2022-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/collator.hpp> #include <boost/locale/generator.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/cdata.hpp" -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/uconv.hpp" -#include "boost/locale/shared/mo_hash.hpp" -#include "boost/locale/shared/std_collate_adapter.hpp" +#include "../shared/mo_hash.hpp" +#include "../shared/std_collate_adapter.hpp" +#include "all_generator.hpp" +#include "cdata.hpp" +#include "icu_util.hpp" +#include "uconv.hpp" #include <boost/thread.hpp> #include <limits> #include <memory> #include <unicode/coll.h> +#include <unicode/stringpiece.h> #include <vector> -#if BOOST_LOCALE_ICU_VERSION >= 402 -# define BOOST_LOCALE_WITH_STRINGPIECE 1 -# include <unicode/stringpiece.h> -#else -# define BOOST_LOCALE_WITH_STRINGPIECE 0 -#endif #ifdef BOOST_MSVC # pragma warning(disable : 4244) // 'argument' : conversion from 'int' @@ -43,7 +39,6 @@ namespace boost { namespace locale { namespace impl_icu { return res; } -#if BOOST_LOCALE_WITH_STRINGPIECE int do_utf8_compare(collate_level level, const char* b1, const char* e1, @@ -55,7 +50,6 @@ namespace boost { namespace locale { namespace impl_icu { icu::StringPiece right(b2, e2 - b2); return get_collator(level).compareUTF8(left, right, status); } -#endif int do_ustring_compare(collate_level level, const CharType* b1, @@ -159,7 +153,6 @@ namespace boost { namespace locale { namespace impl_icu { bool is_utf8_; }; -#if BOOST_LOCALE_WITH_STRINGPIECE template<> int collate_impl<char>::do_real_compare(collate_level level, const char* b1, @@ -173,7 +166,7 @@ namespace boost { namespace locale { namespace impl_icu { else return do_ustring_compare(level, b1, e1, b2, e2, status); } -#endif + std::locale create_collate(const std::locale& in, const cdata& cd, char_facet_t type) { switch(type) { diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/conversion.cpp b/contrib/restricted/boost/locale/src/icu/conversion.cpp index c619dd94a1e..a7fddb473ab 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/conversion.cpp +++ b/contrib/restricted/boost/locale/src/icu/conversion.cpp @@ -1,23 +1,20 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/conversion.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/cdata.hpp" -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/uconv.hpp" +#include "all_generator.hpp" +#include "cdata.hpp" +#include "icu_util.hpp" +#include "uconv.hpp" #include <limits> #include <unicode/locid.h> #include <unicode/normlzr.h> +#include <unicode/ucasemap.h> #include <unicode/ustring.h> -#if BOOST_LOCALE_ICU_VERSION >= 308 -# include <unicode/ucasemap.h> -# define BOOST_LOCALE_WITH_CASEMAP -#endif #include <vector> namespace boost { namespace locale { namespace impl_icu { @@ -72,7 +69,6 @@ namespace boost { namespace locale { namespace impl_icu { std::string encoding_; }; // converter_impl -#ifdef BOOST_LOCALE_WITH_CASEMAP template<typename T> struct get_casemap_size_type; @@ -193,26 +189,17 @@ namespace boost { namespace locale { namespace impl_icu { raii_casemap<U8Char> map_; }; // converter_impl -#endif // BOOST_LOCALE_WITH_CASEMAP - std::locale create_convert(const std::locale& in, const cdata& cd, char_facet_t type) { switch(type) { case char_facet_t::nochar: break; case char_facet_t::char_f: -#ifdef BOOST_LOCALE_WITH_CASEMAP if(cd.is_utf8()) return std::locale(in, new utf8_converter_impl<char>(cd)); -#endif return std::locale(in, new converter_impl<char>(cd)); case char_facet_t::wchar_f: return std::locale(in, new converter_impl<wchar_t>(cd)); -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 - case char_facet_t::char8_f: -# if defined(BOOST_LOCALE_WITH_CASEMAP) - return std::locale(in, new utf8_converter_impl<char8_t>(cd)); -# else - return std::locale(in, new converter_impl<char8_t>(cd)); -# endif +#ifdef __cpp_lib_char8_t + case char_facet_t::char8_f: return std::locale(in, new utf8_converter_impl<char8_t>(cd)); #elif defined(__cpp_char8_t) case char_facet_t::char8_f: break; #endif diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/date_time.cpp b/contrib/restricted/boost/locale/src/icu/date_time.cpp index 14e21d9f155..76785ec6ce7 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/date_time.cpp +++ b/contrib/restricted/boost/locale/src/icu/date_time.cpp @@ -1,6 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2022 Alexander Grund +// Copyright (c) 2021-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -9,11 +9,11 @@ #include <boost/locale/date_time_facet.hpp> #include <boost/locale/formatting.hpp> #include <boost/locale/hold_ptr.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/cdata.hpp" -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/time_zone.hpp" -#include "boost/locale/icu/uconv.hpp" +#include "all_generator.hpp" +#include "cdata.hpp" +#include "icu_util.hpp" +#include "time_zone.hpp" +#include "uconv.hpp" #include <boost/thread.hpp> #include <cmath> #include <memory> @@ -67,10 +67,6 @@ namespace boost { namespace locale { namespace impl_icu { const double rounded_time = std::floor(calendar_->getTime(err) / U_MILLIS_PER_SECOND) * U_MILLIS_PER_SECOND; calendar_->setTime(rounded_time, err); check_and_throw_dt(err); -#if BOOST_LOCALE_ICU_VERSION < 402 - // workaround old/invalid data, it should be 4 in general - calendar_->setMinimalDaysInFirstWeek(4); -#endif encoding_ = dat.encoding(); } calendar_impl(const calendar_impl& other) @@ -79,15 +75,9 @@ namespace boost { namespace locale { namespace impl_icu { encoding_ = other.encoding_; } - calendar_impl* clone() const override - { - return new calendar_impl(*this); - } + calendar_impl* clone() const override { return new calendar_impl(*this); } - void set_value(period::marks::period_mark p, int value) override - { - calendar_->set(to_icu(p), int32_t(value)); - } + void set_value(period::marks::period_mark p, int value) override { calendar_->set(to_icu(p), int32_t(value)); } int get_value(period::marks::period_mark p, value_type type) const override { @@ -202,10 +192,7 @@ namespace boost { namespace locale { namespace impl_icu { check_and_throw_dt(err); return diff; } - void set_timezone(const std::string& tz) override - { - calendar_->adoptTimeZone(get_time_zone(tz)); - } + void set_timezone(const std::string& tz) override { calendar_->adoptTimeZone(get_time_zone(tz)); } std::string get_timezone() const override { icu::UnicodeString tz; diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/formatter.cpp b/contrib/restricted/boost/locale/src/icu/formatter.cpp index 12cb73632e1..64f8e1e46da 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/formatter.cpp +++ b/contrib/restricted/boost/locale/src/icu/formatter.cpp @@ -1,18 +1,22 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2023 Alexander Grund +// Copyright (c) 2021-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/icu/formatter.hpp" +#include "formatter.hpp" #include <boost/locale/formatting.hpp> #include <boost/locale/info.hpp> -#include "boost/locale/icu/formatters_cache.hpp" -#include "boost/locale/icu/icu_util.hpp" -#include "boost/locale/icu/time_zone.hpp" -#include "boost/locale/icu/uconv.hpp" -#include "boost/locale/util/foreach_char.hpp" +#include "../util/foreach_char.hpp" +#include "../util/numeric_conversion.hpp" +#include "formatters_cache.hpp" +#include "icu_util.hpp" +#include "time_zone.hpp" +#include "uconv.hpp" +#include <boost/assert.hpp> +#include <boost/charconv/limits.hpp> +#include <boost/charconv/to_chars.hpp> #include <limits> #include <memory> #ifdef BOOST_MSVC @@ -20,7 +24,6 @@ # pragma warning(disable : 4251) // "identifier" : class "type" needs to have dll-interface... #endif #include <unicode/datefmt.h> -#include <unicode/decimfmt.h> #include <unicode/numfmt.h> #include <unicode/rbnf.h> #include <unicode/smpdtfmt.h> @@ -54,41 +57,72 @@ namespace boost { namespace locale { namespace impl_icu { public: typedef std::basic_string<CharType> string_type; - number_format(icu::NumberFormat& fmt, std::string codepage) : cvt_(codepage), icu_fmt_(fmt) {} + number_format(icu::NumberFormat& fmt, const std::string& codepage, bool isNumberOnly = false) : + cvt_(codepage), icu_fmt_(fmt), isNumberOnly_(isNumberOnly) + {} string_type format(double value, size_t& code_points) const override { return do_format(value, code_points); } string_type format(int64_t value, size_t& code_points) const override { return do_format(value, code_points); } string_type format(int32_t value, size_t& code_points) const override { return do_format(value, code_points); } size_t parse(const string_type& str, double& value) const override { return do_parse(str, value); } + size_t parse(const string_type& str, uint64_t& value) const override { return do_parse(str, value); } size_t parse(const string_type& str, int64_t& value) const override { return do_parse(str, value); } size_t parse(const string_type& str, int32_t& value) const override { return do_parse(str, value); } + string_type format(const uint64_t value, size_t& code_points) const override + { + // ICU only supports int64_t as the largest integer type + if(value <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) + return format(static_cast<int64_t>(value), code_points); + + // Fallback to using a StringPiece (decimal number) as input + char buffer[boost::charconv::limits<uint64_t>::max_chars10 + 1]; + auto res = boost::charconv::to_chars(buffer, std::end(buffer), value); + BOOST_ASSERT(res); + BOOST_ASSERT(res.ptr < std::end(buffer)); + *res.ptr = '\0'; // ICU expects a NULL-terminated string even for the StringPiece + icu::UnicodeString tmp; + UErrorCode err = U_ZERO_ERROR; + icu_fmt_.format(icu::StringPiece(buffer, res.ptr - buffer), tmp, nullptr, err); + check_and_throw_icu_error(err); + code_points = tmp.countChar32(); + return cvt_.std(tmp); + } + private: bool get_value(double& v, icu::Formattable& fmt) const { UErrorCode err = U_ZERO_ERROR; v = fmt.getDouble(err); - if(U_FAILURE(err)) - return false; - return true; + return U_SUCCESS(err); } bool get_value(int64_t& v, icu::Formattable& fmt) const { UErrorCode err = U_ZERO_ERROR; v = fmt.getInt64(err); - if(U_FAILURE(err)) - return false; - return true; + return U_SUCCESS(err); + } + + bool get_value(uint64_t& v, icu::Formattable& fmt) const + { + UErrorCode err = U_ZERO_ERROR; + // ICU only supports int64_t as the largest integer type + const int64_t tmp = fmt.getInt64(err); + if(U_SUCCESS(err)) { + if(tmp < 0) + return false; + v = static_cast<uint64_t>(tmp); + return true; + } + return util::try_parse_icu(fmt, v); } bool get_value(int32_t& v, icu::Formattable& fmt) const { UErrorCode err = U_ZERO_ERROR; v = fmt.getLong(err); - if(U_FAILURE(err)) - return false; - return true; + return U_SUCCESS(err); } template<typename ValueType> @@ -107,21 +141,22 @@ namespace boost { namespace locale { namespace impl_icu { icu::ParsePosition pp; icu::UnicodeString tmp = cvt_.icu(str.data(), str.data() + str.size()); + // For the plain number parsing (no currency etc) parse "123.456" as 2 ints + // not a float later converted to int + icu_fmt_.setParseIntegerOnly(std::is_integral<ValueType>::value && isNumberOnly_); icu_fmt_.parse(tmp, val, pp); - ValueType tmp_v; - - if(pp.getIndex() == 0 || !get_value(tmp_v, val)) + if(pp.getIndex() == 0 || !get_value(v, val)) return 0; size_t cut = cvt_.cut(tmp, str.data(), str.data() + str.size(), pp.getIndex()); if(cut == 0) return 0; - v = tmp_v; return cut; } icu_std_converter<CharType> cvt_; icu::NumberFormat& icu_fmt_; + const bool isNumberOnly_; }; template<typename CharType> @@ -130,11 +165,11 @@ namespace boost { namespace locale { namespace impl_icu { typedef std::basic_string<CharType> string_type; string_type format(double value, size_t& code_points) const override { return do_format(value, code_points); } + string_type format(uint64_t value, size_t& code_points) const override { return do_format(value, code_points); } string_type format(int64_t value, size_t& code_points) const override { return do_format(value, code_points); } - string_type format(int32_t value, size_t& code_points) const override { return do_format(value, code_points); } - size_t parse(const string_type& str, double& value) const override { return do_parse(str, value); } + size_t parse(const string_type& str, uint64_t& value) const override { return do_parse(str, value); } size_t parse(const string_type& str, int64_t& value) const override { return do_parse(str, value); } size_t parse(const string_type& str, int32_t& value) const override { return do_parse(str, value); } @@ -355,7 +390,7 @@ namespace boost { namespace locale { namespace impl_icu { icu::NumberFormat& nf = cache.number_format((how == std::ios_base::scientific) ? num_fmt_type::sci : num_fmt_type::number); set_fraction_digits(nf, how, ios.precision()); - return ptr_type(new number_format<CharType>(nf, encoding)); + return ptr_type(new number_format<CharType>(nf, encoding, true)); } case currency: { icu::NumberFormat& nf = cache.number_format( diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/formatter.hpp b/contrib/restricted/boost/locale/src/icu/formatter.hpp index 110a031551c..bcda2788ef8 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/formatter.hpp +++ b/contrib/restricted/boost/locale/src/icu/formatter.hpp @@ -1,5 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -31,6 +32,8 @@ namespace boost { namespace locale { namespace impl_icu { /// Format the value and return the number of Unicode code points virtual string_type format(double value, size_t& code_points) const = 0; /// Format the value and return the number of Unicode code points + virtual string_type format(uint64_t value, size_t& code_points) const = 0; + /// Format the value and return the number of Unicode code points virtual string_type format(int64_t value, size_t& code_points) const = 0; /// Format the value and return the number of Unicode code points virtual string_type format(int32_t value, size_t& code_points) const = 0; @@ -40,6 +43,9 @@ namespace boost { namespace locale { namespace impl_icu { virtual size_t parse(const string_type& str, double& value) const = 0; /// Parse the string and return the number of used characters. If it returns 0 /// then parsing failed. + virtual size_t parse(const string_type& str, uint64_t& value) const = 0; + /// Parse the string and return the number of used characters. If it returns 0 + /// then parsing failed. virtual size_t parse(const string_type& str, int64_t& value) const = 0; /// Parse the string and return the number of used characters. If it returns 0 /// then parsing failed. diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/formatters_cache.cpp b/contrib/restricted/boost/locale/src/icu/formatters_cache.cpp index c9a8c46347a..101ffcc6504 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/formatters_cache.cpp +++ b/contrib/restricted/boost/locale/src/icu/formatters_cache.cpp @@ -1,11 +1,11 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2022 Alexander Grund +// Copyright (c) 2021-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/icu/formatters_cache.hpp" +#include "formatters_cache.hpp" #include <boost/assert.hpp> #include <boost/core/ignore_unused.hpp> #include <memory> @@ -87,22 +87,10 @@ namespace boost { namespace locale { namespace impl_icu { switch(type) { case num_fmt_type::number: return icu::NumberFormat::createInstance(locale_, err); break; case num_fmt_type::sci: return icu::NumberFormat::createScientificInstance(locale_, err); break; -#if BOOST_LOCALE_ICU_VERSION >= 408 case num_fmt_type::curr_nat: return icu::NumberFormat::createInstance(locale_, UNUM_CURRENCY, err); break; case num_fmt_type::curr_iso: return icu::NumberFormat::createInstance(locale_, UNUM_CURRENCY_ISO, err); break; -#elif BOOST_LOCALE_ICU_VERSION >= 402 - case num_fmt_type::curr_nat: - return icu::NumberFormat::createInstance(locale_, icu::NumberFormat::kCurrencyStyle, err); - break; - case num_fmt_type::curr_iso: - return icu::NumberFormat::createInstance(locale_, icu::NumberFormat::kIsoCurrencyStyle, err); - break; -#else - case num_fmt_type::curr_nat: - case num_fmt_type::curr_iso: return icu::NumberFormat::createCurrencyInstance(locale_, err); break; -#endif case num_fmt_type::percent: return icu::NumberFormat::createPercentInstance(locale_, err); break; case num_fmt_type::spell: return new icu::RuleBasedNumberFormat(icu::URBNF_SPELLOUT, locale_, err); break; case num_fmt_type::ordinal: return new icu::RuleBasedNumberFormat(icu::URBNF_ORDINAL, locale_, err); break; diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/formatters_cache.hpp b/contrib/restricted/boost/locale/src/icu/formatters_cache.hpp index d0e4978d550..2d4c950c543 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/formatters_cache.hpp +++ b/contrib/restricted/boost/locale/src/icu/formatters_cache.hpp @@ -9,7 +9,7 @@ #define BOOST_LOCALE_PREDEFINED_FORMATTERS_HPP_INCLUDED #include <boost/locale/config.hpp> -#include "boost/locale/icu/icu_util.hpp" +#include "icu_util.hpp" #include <boost/thread/tss.hpp> #include <locale> diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/icu_backend.cpp b/contrib/restricted/boost/locale/src/icu/icu_backend.cpp index ecb78ae45ca..4b70e9750fd 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/icu_backend.cpp +++ b/contrib/restricted/boost/locale/src/icu/icu_backend.cpp @@ -5,14 +5,14 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/icu/icu_backend.hpp" +#include "icu_backend.hpp" #include <boost/locale/gnu_gettext.hpp> #include <boost/locale/localization_backend.hpp> #include <boost/locale/util.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/cdata.hpp" -#include "boost/locale/shared/message.hpp" -#include "boost/locale/util/make_std_unique.hpp" +#include "../shared/message.hpp" +#include "../util/make_std_unique.hpp" +#include "all_generator.hpp" +#include "cdata.hpp" #include <unicode/ucnv.h> diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/icu_backend.hpp b/contrib/restricted/boost/locale/src/icu/icu_backend.hpp index 8266856dc1f..8266856dc1f 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/icu_backend.hpp +++ b/contrib/restricted/boost/locale/src/icu/icu_backend.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/icu_util.hpp b/contrib/restricted/boost/locale/src/icu/icu_util.hpp index 70f4cefa36b..70f4cefa36b 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/icu_util.hpp +++ b/contrib/restricted/boost/locale/src/icu/icu_util.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/numeric.cpp b/contrib/restricted/boost/locale/src/icu/numeric.cpp index d81f55f7baf..e54ab1c498a 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/numeric.cpp +++ b/contrib/restricted/boost/locale/src/icu/numeric.cpp @@ -1,14 +1,15 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/formatting.hpp> -#include "boost/locale/icu/all_generator.hpp" -#include "boost/locale/icu/cdata.hpp" -#include "boost/locale/icu/formatter.hpp" -#include "boost/locale/icu/formatters_cache.hpp" +#include "all_generator.hpp" +#include "cdata.hpp" +#include "formatter.hpp" +#include "formatters_cache.hpp" #include <algorithm> #include <ios> #include <limits> @@ -19,41 +20,31 @@ namespace boost { namespace locale { namespace impl_icu { namespace detail { - template<typename T, bool integer = std::numeric_limits<T>::is_integer> - struct icu_format_type; + template<typename T, typename PreferredType, typename AlternativeType> + struct choose_type_by_digits + : std::conditional<std::numeric_limits<T>::digits <= std::numeric_limits<PreferredType>::digits, + PreferredType, + AlternativeType> {}; - template<typename T> - struct icu_format_type<T, true> { - // ICU supports 32 and 64 bit ints, use the former as long as it fits, else the latter - typedef typename std::conditional<std::numeric_limits<T>::digits <= 31, int32_t, int64_t>::type type; + template<typename T, bool integer = std::numeric_limits<T>::is_integer> + struct icu_format_type { + static_assert(sizeof(T) <= sizeof(int64_t), "Only up to 64 bit integer types are supported by ICU"); + // ICU supports (only) int32_t and int64_t, use the former as long as it fits, else the latter + using large_type = typename choose_type_by_digits<T, int64_t, uint64_t>::type; + using type = typename choose_type_by_digits<T, int32_t, large_type>::type; }; template<typename T> struct icu_format_type<T, false> { // Only float type ICU supports is double - typedef double type; - }; - - // ICU does not support uint64_t values so fall back to the parent/std formatting - // if the number is to large to fit into an int64_t - template<typename T, - bool BigUInt = !std::numeric_limits<T>::is_signed && std::numeric_limits<T>::is_integer - && (sizeof(T) >= sizeof(uint64_t))> - struct use_parent_traits { - static bool use(T /*v*/) { return false; } - }; - template<typename T> - struct use_parent_traits<T, true> { - static bool use(T v) { return v > static_cast<T>(std::numeric_limits<int64_t>::max()); } + using type = double; }; template<typename ValueType> - static bool use_parent(std::ios_base& ios, ValueType v) + static bool use_parent(std::ios_base& ios) { const uint64_t flg = ios_info::get(ios).display_flags(); if(flg == flags::posix) return true; - if(use_parent_traits<ValueType>::use(v)) - return true; if(!std::numeric_limits<ValueType>::is_integer) return false; @@ -105,22 +96,23 @@ namespace boost { namespace locale { namespace impl_icu { template<typename ValueType> iter_type do_real_put(iter_type out, std::ios_base& ios, CharType fill, ValueType val) const { - if(detail::use_parent(ios, val)) + if(detail::use_parent<ValueType>(ios)) return std::num_put<CharType>::do_put(out, ios, fill, val); - const auto formatter = formatter_type::create(ios, loc_, enc_); + const std::unique_ptr<formatter_type> formatter = formatter_type::create(ios, loc_, enc_); if(!formatter) return std::num_put<CharType>::do_put(out, ios, fill, val); + using icu_type = typename detail::icu_format_type<ValueType>::type; size_t code_points; - typedef typename detail::icu_format_type<ValueType>::type icu_type; - const string_type& str = formatter->format(static_cast<icu_type>(val), code_points); + const string_type str = formatter->format(static_cast<icu_type>(val), code_points); + std::streamsize on_left = 0, on_right = 0, points = code_points; if(points < ios.width()) { - std::streamsize n = ios.width() - points; + const std::streamsize n = ios.width() - points; - std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield; + const std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield; // We do not really know internal point, so we assume that it does not // exist. So according to the standard field should be right aligned @@ -239,10 +231,10 @@ namespace boost { namespace locale { namespace impl_icu { do_real_get(iter_type in, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, ValueType& val) const { stream_type* stream_ptr = dynamic_cast<stream_type*>(&ios); - if(!stream_ptr || detail::use_parent(ios, ValueType(0))) + if(!stream_ptr || detail::use_parent<ValueType>(ios)) return std::num_get<CharType>::do_get(in, end, ios, err, val); - const auto formatter = formatter_type::create(ios, loc_, enc_); + const std::unique_ptr<formatter_type> formatter = formatter_type::create(ios, loc_, enc_); if(!formatter) return std::num_get<CharType>::do_get(in, end, ios, err, val); @@ -256,7 +248,7 @@ namespace boost { namespace locale { namespace impl_icu { while(tmp.size() < 4096 && in != end && *in != '\n') tmp += *in++; - typedef typename detail::icu_format_type<ValueType>::type icu_type; + using icu_type = typename detail::icu_format_type<ValueType>::type; icu_type value; size_t parsed_chars; diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/time_zone.hpp b/contrib/restricted/boost/locale/src/icu/time_zone.hpp index 87ab0c44165..d265b1d6e45 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/time_zone.hpp +++ b/contrib/restricted/boost/locale/src/icu/time_zone.hpp @@ -1,5 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2022-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -14,9 +15,14 @@ namespace boost { namespace locale { namespace impl_icu { - // Provides a workaround for an ICU default timezone bug and also - // handles time_zone string correctly - if empty returns default - // otherwise returns the instance created with time_zone - icu::TimeZone* get_time_zone(const std::string& time_zone); + // Return an ICU time zone instance. + // If the argument is empty returns the default timezone. + inline icu::TimeZone* get_time_zone(const std::string& time_zone) + { + if(time_zone.empty()) + return icu::TimeZone::createDefault(); + else + return icu::TimeZone::createTimeZone(time_zone.c_str()); + } }}} // namespace boost::locale::impl_icu #endif diff --git a/contrib/restricted/boost/locale/src/boost/locale/icu/uconv.hpp b/contrib/restricted/boost/locale/src/icu/uconv.hpp index 6563afb627b..f801f10edd7 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/icu/uconv.hpp +++ b/contrib/restricted/boost/locale/src/icu/uconv.hpp @@ -9,7 +9,7 @@ #define BOOST_SRC_LOCALE_ICU_UCONV_HPP #include <boost/locale/encoding.hpp> -#include "boost/locale/icu/icu_util.hpp" +#include "icu_util.hpp" #include <boost/core/exchange.hpp> #include <memory> diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/all_generator.hpp b/contrib/restricted/boost/locale/src/posix/all_generator.hpp index da4d4a82d99..da4d4a82d99 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/all_generator.hpp +++ b/contrib/restricted/boost/locale/src/posix/all_generator.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/codecvt.cpp b/contrib/restricted/boost/locale/src/posix/codecvt.cpp index d2c5acf0065..3f0a0ed43c5 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/codecvt.cpp +++ b/contrib/restricted/boost/locale/src/posix/codecvt.cpp @@ -6,9 +6,9 @@ // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/encoding_errors.hpp> -#include "boost/locale/posix/all_generator.hpp" -#include "boost/locale/shared/iconv_codecvt.hpp" -#include "boost/locale/util/encoding.hpp" +#include "../shared/iconv_codecvt.hpp" +#include "../util/encoding.hpp" +#include "all_generator.hpp" #include <stdexcept> namespace boost { namespace locale { namespace impl_posix { diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/collate.cpp b/contrib/restricted/boost/locale/src/posix/collate.cpp index c9fb0251ff3..bd8ab36053e 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/collate.cpp +++ b/contrib/restricted/boost/locale/src/posix/collate.cpp @@ -8,6 +8,8 @@ #if defined(__FreeBSD__) # include <xlocale.h> #endif +#include "../shared/mo_hash.hpp" +#include "all_generator.hpp" #include <clocale> #include <cstring> #include <ios> @@ -17,9 +19,6 @@ #include <vector> #include <wchar.h> -#include "boost/locale/posix/all_generator.hpp" -#include "boost/locale/shared/mo_hash.hpp" - namespace boost { namespace locale { namespace impl_posix { template<typename CharType> diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/converter.cpp b/contrib/restricted/boost/locale/src/posix/converter.cpp index b787a562c5a..13477aa03bb 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/converter.cpp +++ b/contrib/restricted/boost/locale/src/posix/converter.cpp @@ -7,7 +7,7 @@ #include <boost/locale/conversion.hpp> #include <boost/locale/encoding.hpp> #include <boost/locale/generator.hpp> -#include "boost/locale/util/encoding.hpp" +#include "../util/encoding.hpp" #include <cctype> #include <cstring> #include <langinfo.h> @@ -18,7 +18,7 @@ # include <xlocale.h> #endif -#include "boost/locale/posix/all_generator.hpp" +#include "all_generator.hpp" namespace boost { namespace locale { namespace impl_posix { @@ -125,7 +125,7 @@ namespace boost { namespace locale { namespace impl_posix { return std::locale(in, new std_converter<char>(std::move(lc))); } case char_facet_t::wchar_f: return std::locale(in, new std_converter<wchar_t>(std::move(lc))); -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t case char_facet_t::char8_f: return std::locale(in, new utf8_converter<char8_t>(std::move(lc))); #elif defined(__cpp_char8_t) case char_facet_t::char8_f: break; diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/numeric.cpp b/contrib/restricted/boost/locale/src/posix/numeric.cpp index a3ee2c40551..2810b821af1 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/numeric.cpp +++ b/contrib/restricted/boost/locale/src/posix/numeric.cpp @@ -27,8 +27,8 @@ #include <vector> #include <wctype.h> -#include "boost/locale/posix/all_generator.hpp" -#include "boost/locale/util/numeric.hpp" +#include "../util/numeric.hpp" +#include "all_generator.hpp" namespace boost { namespace locale { namespace impl_posix { diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/posix_backend.cpp b/contrib/restricted/boost/locale/src/posix/posix_backend.cpp index 020d0c77e0f..98aadf211e3 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/posix_backend.cpp +++ b/contrib/restricted/boost/locale/src/posix/posix_backend.cpp @@ -5,7 +5,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/posix/posix_backend.hpp" +#include "posix_backend.hpp" #include <boost/locale/gnu_gettext.hpp> #include <boost/locale/info.hpp> #include <boost/locale/localization_backend.hpp> @@ -19,10 +19,10 @@ # include <xlocale.h> #endif -#include "boost/locale/posix/all_generator.hpp" -#include "boost/locale/shared/message.hpp" -#include "boost/locale/util/gregorian.hpp" -#include "boost/locale/util/make_std_unique.hpp" +#include "../shared/message.hpp" +#include "../util/gregorian.hpp" +#include "../util/make_std_unique.hpp" +#include "all_generator.hpp" namespace boost { namespace locale { namespace impl_posix { diff --git a/contrib/restricted/boost/locale/src/boost/locale/posix/posix_backend.hpp b/contrib/restricted/boost/locale/src/posix/posix_backend.hpp index 925c9580d53..925c9580d53 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/posix/posix_backend.hpp +++ b/contrib/restricted/boost/locale/src/posix/posix_backend.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/date_time.cpp b/contrib/restricted/boost/locale/src/shared/date_time.cpp index c418406d18c..c418406d18c 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/date_time.cpp +++ b/contrib/restricted/boost/locale/src/shared/date_time.cpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/format.cpp b/contrib/restricted/boost/locale/src/shared/format.cpp index 7ee809fe709..9853c7ff622 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/format.cpp +++ b/contrib/restricted/boost/locale/src/shared/format.cpp @@ -1,5 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -7,7 +8,7 @@ #include <boost/locale/format.hpp> #include <boost/locale/generator.hpp> #include <boost/locale/info.hpp> -#include "boost/locale/util/numeric.hpp" +#include "../util/numeric_conversion.hpp" #include <algorithm> #include <iostream> #include <limits> @@ -63,10 +64,9 @@ namespace boost { namespace locale { namespace detail { { if(key.empty()) return; - int position; - if(util::try_to_int(key, position) && position > 0) { - static_assert(sizeof(unsigned) <= sizeof(decltype(d->position)), "Possible lossy conversion"); - d->position = static_cast<unsigned>(position - 1); + decltype(d->position) position; + if(util::try_to_int(key, position) && position > 0u) { + d->position = position - 1u; } else if(key == "num" || key == "number") { as::number(ios_); diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/formatting.cpp b/contrib/restricted/boost/locale/src/shared/formatting.cpp index 457ba782e94..53f436a30e3 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/formatting.cpp +++ b/contrib/restricted/boost/locale/src/shared/formatting.cpp @@ -6,7 +6,7 @@ #include <boost/locale/date_time.hpp> #include <boost/locale/formatting.hpp> -#include "boost/locale/shared/ios_prop.hpp" +#include "ios_prop.hpp" namespace boost { namespace locale { ios_info::ios_info() : flags_(0), domain_id_(0), time_zone_(time_zone::global()) {} @@ -65,7 +65,7 @@ namespace boost { namespace locale { { time_zone_ = tz; } - std::string ios_info::time_zone() const + const std::string& ios_info::time_zone() const { return time_zone_; } diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/generator.cpp b/contrib/restricted/boost/locale/src/shared/generator.cpp index baf424bea8c..ddff3ba655e 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/generator.cpp +++ b/contrib/restricted/boost/locale/src/shared/generator.cpp @@ -1,5 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// Copyright (c) 2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -93,9 +94,7 @@ namespace boost { namespace locale { std::locale generator::generate(const std::string& id) const { - std::locale base = std::locale::classic(); - - return generate(base, id); + return generate(std::locale::classic(), id); } std::locale generator::generate(const std::locale& base, const std::string& id) const @@ -110,8 +109,8 @@ namespace boost { namespace locale { set_all_options(*backend, id); std::locale result = base; - category_t facets = d->cats; - char_facet_t chars = d->chars; + const category_t facets = d->cats; + const char_facet_t chars = d->chars; for(category_t facet = per_character_facet_first; facet <= per_character_facet_last; ++facet) { if(!(facets & facet)) diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/iconv_codecvt.cpp b/contrib/restricted/boost/locale/src/shared/iconv_codecvt.cpp index 2ed618a0ae4..481973079fe 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/iconv_codecvt.cpp +++ b/contrib/restricted/boost/locale/src/shared/iconv_codecvt.cpp @@ -12,9 +12,9 @@ #include <limits> #include <vector> #ifdef BOOST_LOCALE_WITH_ICONV -# include "boost/locale/util/encoding.hpp" -# include "boost/locale/util/iconv.hpp" -# include "boost/locale/util/make_std_unique.hpp" +# include "../util/encoding.hpp" +# include "../util/iconv.hpp" +# include "../util/make_std_unique.hpp" #endif namespace boost { namespace locale { diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/iconv_codecvt.hpp b/contrib/restricted/boost/locale/src/shared/iconv_codecvt.hpp index 51ddc71b683..51ddc71b683 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/iconv_codecvt.hpp +++ b/contrib/restricted/boost/locale/src/shared/iconv_codecvt.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/ids.cpp b/contrib/restricted/boost/locale/src/shared/ids.cpp index 819de7f9935..2d5ef255a39 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/ids.cpp +++ b/contrib/restricted/boost/locale/src/shared/ids.cpp @@ -11,7 +11,7 @@ #include <boost/locale/date_time_facet.hpp> #include <boost/locale/info.hpp> #include <boost/locale/message.hpp> -#include "boost/locale/util/foreach_char.hpp" +#include "../util/foreach_char.hpp" #include <boost/core/ignore_unused.hpp> namespace boost { namespace locale { diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/ios_prop.hpp b/contrib/restricted/boost/locale/src/shared/ios_prop.hpp index d8256592f79..d8256592f79 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/ios_prop.hpp +++ b/contrib/restricted/boost/locale/src/shared/ios_prop.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/localization_backend.cpp b/contrib/restricted/boost/locale/src/shared/localization_backend.cpp index 951cb3beb49..beace3e3afe 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/localization_backend.cpp +++ b/contrib/restricted/boost/locale/src/shared/localization_backend.cpp @@ -12,19 +12,19 @@ #include <vector> #ifdef BOOST_LOCALE_WITH_ICU -# include "boost/locale/icu/icu_backend.hpp" +# include "../icu/icu_backend.hpp" #endif #ifndef BOOST_LOCALE_NO_POSIX_BACKEND -# include "boost/locale/posix/posix_backend.hpp" +# include "../posix/posix_backend.hpp" #endif #ifndef BOOST_LOCALE_NO_STD_BACKEND -# include "boost/locale/std/std_backend.hpp" +# include "../std/std_backend.hpp" #endif #ifndef BOOST_LOCALE_NO_WINAPI_BACKEND -# include "boost/locale/win32/win_backend.hpp" +# include "../win32/win_backend.hpp" #endif namespace boost { namespace locale { diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/message.cpp b/contrib/restricted/boost/locale/src/shared/message.cpp index da8b4b934f7..70eafd22e93 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/message.cpp +++ b/contrib/restricted/boost/locale/src/shared/message.cpp @@ -1,6 +1,6 @@ // // Copyright (c) 2009-2015 Artyom Beilis (Tonkikh) -// Copyright (c) 2021-2023 Alexander Grund +// Copyright (c) 2021-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -20,13 +20,13 @@ #include <boost/locale/encoding.hpp> #include <boost/locale/message.hpp> -#include "boost/locale/shared/message.hpp" -#include "boost/locale/shared/mo_hash.hpp" -#include "boost/locale/shared/mo_lambda.hpp" -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/foreach_char.hpp" +#include "../util/encoding.hpp" +#include "../util/foreach_char.hpp" +#include "message.hpp" +#include "mo_hash.hpp" +#include "mo_lambda.hpp" #include <boost/assert.hpp> -#include <boost/utility/string_view.hpp> +#include <boost/core/detail/string_view.hpp> #include <cstdio> #include <map> #include <memory> @@ -141,7 +141,7 @@ namespace boost { namespace locale { namespace gnu_gettext { hash_offset_ = get(24); } - string_view find(const char* context_in, const char* key_in) const + core::string_view find(const char* context_in, const char* key_in) const { if(!has_hash()) return {}; @@ -192,20 +192,20 @@ namespace boost { namespace locale { namespace gnu_gettext { return data_.data() + off; } - string_view value(unsigned id) const + core::string_view value(unsigned id) const { const uint32_t len = get(translations_offset_ + id * 8); const uint32_t off = get(translations_offset_ + id * 8 + 4); if(len > data_.size() || off > data_.size() - len) throw std::runtime_error("Bad mo-file format"); - return string_view(&data_[off], len); + return core::string_view(&data_[off], len); } bool has_hash() const { return hash_size_ != 0; } size_t size() const { return size_; } - bool empty() { return size_ == 0; } + bool empty() const { return size_ == 0; } private: uint32_t get(unsigned offset) const @@ -233,7 +233,7 @@ namespace boost { namespace locale { namespace gnu_gettext { template<typename CharType> struct mo_file_use_traits { static constexpr bool in_use = false; - using string_view_type = basic_string_view<CharType>; + using string_view_type = core::basic_string_view<CharType>; static string_view_type use(const mo_file&, const CharType*, const CharType*) { throw std::logic_error("Unexpected call"); // LCOV_EXCL_LINE @@ -243,7 +243,7 @@ namespace boost { namespace locale { namespace gnu_gettext { template<> struct mo_file_use_traits<char> { static constexpr bool in_use = true; - using string_view_type = basic_string_view<char>; + using string_view_type = core::basic_string_view<char>; static string_view_type use(const mo_file& mo, const char* context, const char* key) { return mo.find(context, key); @@ -254,10 +254,10 @@ namespace boost { namespace locale { namespace gnu_gettext { template<> struct mo_file_use_traits<char8_t> { static constexpr bool in_use = true; - using string_view_type = basic_string_view<char8_t>; + using string_view_type = core::basic_string_view<char8_t>; static string_view_type use(const mo_file& mo, const char8_t* context, const char8_t* key) { - string_view res = mo.find(reinterpret_cast<const char*>(context), reinterpret_cast<const char*>(key)); + core::string_view res = mo.find(reinterpret_cast<const char*>(context), reinterpret_cast<const char*>(key)); return {reinterpret_cast<const char8_t*>(res.data()), res.size()}; } }; @@ -551,10 +551,10 @@ namespace boost { namespace locale { namespace gnu_gettext { return true; } - static std::string extract(boost::string_view meta, const std::string& key, const boost::string_view separators) + static std::string extract(core::string_view meta, const std::string& key, const core::string_view separators) { const size_t pos = meta.find(key); - if(pos == boost::string_view::npos) + if(pos == core::string_view::npos) return ""; meta.remove_prefix(pos + key.size()); const size_t end_pos = meta.find_first_of(separators); @@ -620,7 +620,7 @@ namespace boost { namespace locale { namespace detail { case char_facet_t::nochar: break; case char_facet_t::char_f: return std::locale(in, gnu_gettext::create_messages_facet<char>(minf)); case char_facet_t::wchar_f: return std::locale(in, gnu_gettext::create_messages_facet<wchar_t>(minf)); -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t case char_facet_t::char8_f: return std::locale(in, gnu_gettext::create_messages_facet<char8_t>(minf)); #elif defined(__cpp_char8_t) case char_facet_t::char8_f: break; diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/message.hpp b/contrib/restricted/boost/locale/src/shared/message.hpp index a68cefcab66..a68cefcab66 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/message.hpp +++ b/contrib/restricted/boost/locale/src/shared/message.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/mo_hash.hpp b/contrib/restricted/boost/locale/src/shared/mo_hash.hpp index 702ea7aece6..702ea7aece6 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/mo_hash.hpp +++ b/contrib/restricted/boost/locale/src/shared/mo_hash.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/mo_lambda.cpp b/contrib/restricted/boost/locale/src/shared/mo_lambda.cpp index 7b37ca91e84..e2a16c8c60e 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/mo_lambda.cpp +++ b/contrib/restricted/boost/locale/src/shared/mo_lambda.cpp @@ -5,7 +5,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/shared/mo_lambda.hpp" +#include "mo_lambda.hpp" #include <boost/assert.hpp> #include <algorithm> #include <cstdlib> diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/mo_lambda.hpp b/contrib/restricted/boost/locale/src/shared/mo_lambda.hpp index ff415175def..ff415175def 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/mo_lambda.hpp +++ b/contrib/restricted/boost/locale/src/shared/mo_lambda.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/shared/std_collate_adapter.hpp b/contrib/restricted/boost/locale/src/shared/std_collate_adapter.hpp index ee4ff43b8c8..ee4ff43b8c8 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/shared/std_collate_adapter.hpp +++ b/contrib/restricted/boost/locale/src/shared/std_collate_adapter.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/all_generator.hpp b/contrib/restricted/boost/locale/src/std/all_generator.hpp index 5dd020815bf..5dd020815bf 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/all_generator.hpp +++ b/contrib/restricted/boost/locale/src/std/all_generator.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/codecvt.cpp b/contrib/restricted/boost/locale/src/std/codecvt.cpp index 22af5d76399..58d4ff8df8e 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/codecvt.cpp +++ b/contrib/restricted/boost/locale/src/std/codecvt.cpp @@ -5,7 +5,7 @@ // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/util.hpp> -#include "boost/locale/std/all_generator.hpp" +#include "all_generator.hpp" #include <locale> namespace boost { namespace locale { namespace impl_std { diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/collate.cpp b/contrib/restricted/boost/locale/src/std/collate.cpp index 48d80bcc972..d7e5e7af5ba 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/collate.cpp +++ b/contrib/restricted/boost/locale/src/std/collate.cpp @@ -5,7 +5,7 @@ // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/encoding.hpp> -#include "boost/locale/std/all_generator.hpp" +#include "all_generator.hpp" #include <boost/assert.hpp> #include <ios> #include <locale> diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/converter.cpp b/contrib/restricted/boost/locale/src/std/converter.cpp index ce08606b06e..ec60a58dc29 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/converter.cpp +++ b/contrib/restricted/boost/locale/src/std/converter.cpp @@ -11,7 +11,7 @@ #include <stdexcept> #include <vector> -#include "boost/locale/std/all_generator.hpp" +#include "all_generator.hpp" namespace boost { namespace locale { namespace impl_std { @@ -104,7 +104,7 @@ namespace boost { namespace locale { namespace impl_std { else return std::locale(in, new std_converter<char>(locale_name)); case char_facet_t::wchar_f: return std::locale(in, new std_converter<wchar_t>(locale_name)); -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t case char_facet_t::char8_f: return std::locale(in, new utf8_converter<char8_t>(locale_name)); #elif defined(__cpp_char8_t) case char_facet_t::char8_f: break; diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/numeric.cpp b/contrib/restricted/boost/locale/src/std/numeric.cpp index fe3dc09515a..b88cbd56530 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/numeric.cpp +++ b/contrib/restricted/boost/locale/src/std/numeric.cpp @@ -14,8 +14,8 @@ #include <sstream> #include <string> -#include "boost/locale/std/all_generator.hpp" -#include "boost/locale/util/numeric.hpp" +#include "../util/numeric.hpp" +#include "all_generator.hpp" namespace boost { namespace locale { namespace impl_std { /// Forwarding time_put facet diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/std_backend.cpp b/contrib/restricted/boost/locale/src/std/std_backend.cpp index 4a134c25840..1eadfd2491c 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/std_backend.cpp +++ b/contrib/restricted/boost/locale/src/std/std_backend.cpp @@ -5,7 +5,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/std/std_backend.hpp" +#include "std_backend.hpp" #include <boost/locale/gnu_gettext.hpp> #include <boost/locale/localization_backend.hpp> #include <boost/locale/util.hpp> @@ -20,15 +20,15 @@ # ifndef NOMINMAX # define NOMINMAX # endif -# include "boost/locale/win32/lcid.hpp" +# include "../win32/lcid.hpp" # include <windows.h> #endif -#include "boost/locale/shared/message.hpp" -#include "boost/locale/std/all_generator.hpp" -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/gregorian.hpp" -#include "boost/locale/util/make_std_unique.hpp" -#include "boost/locale/util/numeric.hpp" +#include "../shared/message.hpp" +#include "../util/encoding.hpp" +#include "../util/gregorian.hpp" +#include "../util/make_std_unique.hpp" +#include "../util/numeric_conversion.hpp" +#include "all_generator.hpp" namespace { struct windows_name { diff --git a/contrib/restricted/boost/locale/src/boost/locale/std/std_backend.hpp b/contrib/restricted/boost/locale/src/std/std_backend.hpp index 4ce6b271e36..4ce6b271e36 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/std/std_backend.hpp +++ b/contrib/restricted/boost/locale/src/std/std_backend.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/codecvt_converter.cpp b/contrib/restricted/boost/locale/src/util/codecvt_converter.cpp index b1cf9df9a9b..26af5005ed5 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/codecvt_converter.cpp +++ b/contrib/restricted/boost/locale/src/util/codecvt_converter.cpp @@ -15,8 +15,8 @@ #include <cstddef> #include <cstring> -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/make_std_unique.hpp" +#include "encoding.hpp" +#include "make_std_unique.hpp" #ifdef BOOST_MSVC # pragma warning(disable : 4244) // loose data diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/default_locale.cpp b/contrib/restricted/boost/locale/src/util/default_locale.cpp index 74cf7705dc8..74cf7705dc8 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/default_locale.cpp +++ b/contrib/restricted/boost/locale/src/util/default_locale.cpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/encoding.cpp b/contrib/restricted/boost/locale/src/util/encoding.cpp index 8a6bf183be0..8b893f1c4a0 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/encoding.cpp +++ b/contrib/restricted/boost/locale/src/util/encoding.cpp @@ -1,14 +1,14 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/string.hpp" +#include "encoding.hpp" +#include <boost/locale/util/string.hpp> #if BOOST_LOCALE_USE_WIN32_API -# include "boost/locale/util/win_codepages.hpp" +# include "win_codepages.hpp" # ifndef NOMINMAX # define NOMINMAX # endif @@ -18,7 +18,7 @@ #include <cstring> namespace boost { namespace locale { namespace util { - std::string normalize_encoding(const string_view encoding) + std::string normalize_encoding(const core::string_view encoding) { std::string result; result.reserve(encoding.length()); @@ -51,7 +51,7 @@ namespace boost { namespace locale { namespace util { return -1; } - int encoding_to_windows_codepage(const string_view encoding) + int encoding_to_windows_codepage(const core::string_view encoding) { return normalized_encoding_to_windows_codepage(normalize_encoding(encoding)); } diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/encoding.hpp b/contrib/restricted/boost/locale/src/util/encoding.hpp index 0f4c3b56e58..2f73d49a339 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/encoding.hpp +++ b/contrib/restricted/boost/locale/src/util/encoding.hpp @@ -1,6 +1,6 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2025 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt @@ -9,7 +9,7 @@ #define BOOST_LOCALE_UTIL_ENCODING_HPP #include <boost/locale/config.hpp> -#include <boost/utility/string_view.hpp> +#include <boost/core/detail/string_view.hpp> #include <cstdint> #include <string> #include <type_traits> @@ -48,7 +48,7 @@ namespace boost { namespace locale { namespace util { #endif /// Make encoding lowercase and remove all non-alphanumeric characters - BOOST_LOCALE_DECL std::string normalize_encoding(string_view encoding); + BOOST_LOCALE_DECL std::string normalize_encoding(core::string_view encoding); /// True if the normalized encodings are equal inline bool are_encodings_equal(const std::string& l, const std::string& r) { @@ -58,10 +58,10 @@ namespace boost { namespace locale { namespace util { BOOST_LOCALE_DECL std::vector<std::string> get_simple_encodings(); #if BOOST_LOCALE_USE_WIN32_API - int encoding_to_windows_codepage(string_view encoding); + int encoding_to_windows_codepage(core::string_view encoding); #else // Requires WinAPI -> Dummy returning invalid - inline int encoding_to_windows_codepage(string_view) // LCOV_EXCL_LINE + inline int encoding_to_windows_codepage(core::string_view) // LCOV_EXCL_LINE { return -1; // LCOV_EXCL_LINE } diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/foreach_char.hpp b/contrib/restricted/boost/locale/src/util/foreach_char.hpp index 37328e12169..1c0dc35ff01 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/foreach_char.hpp +++ b/contrib/restricted/boost/locale/src/util/foreach_char.hpp @@ -9,7 +9,7 @@ #include <boost/locale/config.hpp> -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t # define BOOST_LOCALE_FOREACH_CHAR_I_CHAR8_T(F) F(char8_t) # define BOOST_LOCALE_FOREACH_CHAR_I2_CHAR8_T(F) F(char8_t) #elif defined(__cpp_char8_t) diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/gregorian.cpp b/contrib/restricted/boost/locale/src/util/gregorian.cpp index b0bc6e8a291..3183d4ae6cb 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/gregorian.cpp +++ b/contrib/restricted/boost/locale/src/util/gregorian.cpp @@ -4,11 +4,11 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/util/gregorian.hpp" +#include "gregorian.hpp" #include <boost/locale/date_time.hpp> #include <boost/locale/date_time_facet.hpp> #include <boost/locale/hold_ptr.hpp> -#include "boost/locale/util/timezone.hpp" +#include "timezone.hpp" #include <boost/assert.hpp> #include <algorithm> #include <cstdlib> diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/gregorian.hpp b/contrib/restricted/boost/locale/src/util/gregorian.hpp index e3a3a462385..e3a3a462385 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/gregorian.hpp +++ b/contrib/restricted/boost/locale/src/util/gregorian.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/iconv.hpp b/contrib/restricted/boost/locale/src/util/iconv.hpp index ed8157ba978..ed8157ba978 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/iconv.hpp +++ b/contrib/restricted/boost/locale/src/util/iconv.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/info.cpp b/contrib/restricted/boost/locale/src/util/info.cpp index 2dcbbee1784..2dcbbee1784 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/info.cpp +++ b/contrib/restricted/boost/locale/src/util/info.cpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/locale_data.cpp b/contrib/restricted/boost/locale/src/util/locale_data.cpp index f95d28a5803..1fded47a90b 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/locale_data.cpp +++ b/contrib/restricted/boost/locale/src/util/locale_data.cpp @@ -1,19 +1,39 @@ // // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// Copyright (c) 2022-2023 Alexander Grund +// Copyright (c) 2022-2024 Alexander Grund // // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include <boost/locale/util/locale_data.hpp> -#include "boost/locale/util/encoding.hpp" -#include "boost/locale/util/string.hpp" +#include <boost/locale/util/string.hpp> +#include "encoding.hpp" #include <boost/assert.hpp> #include <algorithm> #include <stdexcept> #include <string> namespace boost { namespace locale { namespace util { + /// Convert uppercase ASCII to lower case, return true if converted + static bool make_lower(char& c) + { + if(is_upper_ascii(c)) { + c += 'a' - 'A'; + return true; + } else + return false; + } + + /// Convert lowercase ASCII to upper case, return true if converted + static bool make_upper(char& c) + { + if(is_lower_ascii(c)) { + c += 'A' - 'a'; + return true; + } else + return false; + } + locale_data::locale_data() { reset(); @@ -28,6 +48,7 @@ namespace boost { namespace locale { namespace util { void locale_data::reset() { language_ = "C"; + script_.clear(); country_.clear(); encoding_ = "US-ASCII"; variant_.clear(); @@ -37,6 +58,8 @@ namespace boost { namespace locale { namespace util { std::string locale_data::to_string() const { std::string result = language_; + if(!script_.empty()) + (result += '_') += script_; if(!country_.empty()) (result += '_') += country_; if(!encoding_.empty() && !util::are_encodings_equal(encoding_, "US-ASCII")) @@ -60,9 +83,7 @@ namespace boost { namespace locale { namespace util { return false; // lowercase ASCII for(char& c : tmp) { - if(is_upper_ascii(c)) - c += 'a' - 'A'; - else if(!is_lower_ascii(c)) + if(!is_lower_ascii(c) && !make_lower(c)) return false; } if(tmp != "c" && tmp != "posix") // Keep default @@ -71,6 +92,33 @@ namespace boost { namespace locale { namespace util { if(end >= input.size()) return true; else if(input[end] == '-' || input[end] == '_') + return parse_from_script(input.substr(end + 1)); + else if(input[end] == '.') + return parse_from_encoding(input.substr(end + 1)); + else { + BOOST_ASSERT_MSG(input[end] == '@', "Unexpected delimiter"); + return parse_from_variant(input.substr(end + 1)); + } + } + + bool locale_data::parse_from_script(const std::string& input) + { + const auto end = input.find_first_of("-_@."); + std::string tmp = input.substr(0, end); + // Script is exactly 4 ASCII characters, otherwise it is not present + if(tmp.length() != 4) + return parse_from_country(input); + + for(char& c : tmp) { + if(!is_lower_ascii(c) && !make_lower(c)) + return parse_from_country(input); + } + make_upper(tmp[0]); // Capitalize first letter only + script_ = tmp; + + if(end >= input.size()) + return true; + else if(input[end] == '-' || input[end] == '_') return parse_from_country(input.substr(end + 1)); else if(input[end] == '.') return parse_from_encoding(input.substr(end + 1)); @@ -91,10 +139,9 @@ namespace boost { namespace locale { namespace util { return false; // Make uppercase - for(char& c : tmp) { - if(util::is_lower_ascii(c)) - c += 'A' - 'a'; - } + for(char& c : tmp) + make_upper(c); + // If it's ALL uppercase ASCII, assume ISO 3166 country id if(std::find_if_not(tmp.begin(), tmp.end(), util::is_upper_ascii) != tmp.end()) { // else handle special cases: @@ -142,20 +189,16 @@ namespace boost { namespace locale { namespace util { return false; variant_ = input; // No assumptions, just make it lowercase - for(char& c : variant_) { - if(util::is_upper_ascii(c)) - c += 'a' - 'A'; - } + for(char& c : variant_) + make_lower(c); return true; } locale_data& locale_data::encoding(std::string new_encoding, const bool uppercase) { if(uppercase) { - for(char& c : new_encoding) { - if(util::is_lower_ascii(c)) - c += 'A' - 'a'; - } + for(char& c : new_encoding) + make_upper(c); } encoding_ = std::move(new_encoding); utf8_ = util::normalize_encoding(encoding_) == "utf8"; diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/make_std_unique.hpp b/contrib/restricted/boost/locale/src/util/make_std_unique.hpp index d7492adc039..d7492adc039 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/make_std_unique.hpp +++ b/contrib/restricted/boost/locale/src/util/make_std_unique.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/numeric.hpp b/contrib/restricted/boost/locale/src/util/numeric.hpp index 146309e3576..e54c95c5580 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/numeric.hpp +++ b/contrib/restricted/boost/locale/src/util/numeric.hpp @@ -10,11 +10,8 @@ #include <boost/locale/info.hpp> #include <boost/predef/os.h> #include <algorithm> -#include <cerrno> -#include <cstdlib> #include <ctime> #include <ios> -#include <limits> #include <locale> #include <sstream> #include <string> @@ -23,22 +20,6 @@ #include "timezone.hpp" namespace boost { namespace locale { namespace util { - - inline bool try_to_int(const std::string& s, int& res) - { - if(s.empty()) - return false; - errno = 0; - char* end_char{}; - const auto v = std::strtol(s.c_str(), &end_char, 10); - if(errno == ERANGE || end_char != s.c_str() + s.size()) - return false; - if(v < std::numeric_limits<int>::min() || v > std::numeric_limits<int>::max()) - return false; - res = v; - return true; - } - template<typename CharType> struct formatting_size_traits { static size_t size(const std::basic_string<CharType>& s, const std::locale& /*l*/) { return s.size(); } @@ -175,11 +156,11 @@ namespace boost { namespace locale { namespace util { iter_type format_time(iter_type out, std::ios_base& ios, CharType fill, std::time_t time, const string_type& format) const { - std::string tz = ios_info::get(ios).time_zone(); - std::tm tm; -#if BOOST_OS_LINUX || BOOST_OS_BSD_FREE || defined(__APPLE__) - std::vector<char> tmp_buf(tz.c_str(), tz.c_str() + tz.size() + 1); + const std::string& tz = ios_info::get(ios).time_zone(); +#if BOOST_OS_BSD_FREE || defined(__APPLE__) + std::vector<char> tz_nonconst; #endif + std::tm tm; if(tz.empty()) { #ifdef BOOST_WINDOWS // Windows uses TLS @@ -200,8 +181,13 @@ namespace boost { namespace locale { namespace util { #if BOOST_OS_LINUX || BOOST_OS_BSD_FREE || defined(__APPLE__) // These have extra fields to specify timezone if(gmtoff != 0) { +# if BOOST_OS_BSD_FREE || defined(__APPLE__) // bsd and apple want tm_zone be non-const - tm.tm_zone = tmp_buf.data(); + tz_nonconst.assign(tz.begin(), tz.end()); + tm.tm_zone = tz_nonconst.data(); +# else + tm.tm_zone = tz.data(); +# endif tm.tm_gmtoff = gmtoff; } #endif diff --git a/contrib/restricted/boost/locale/src/util/numeric_conversion.hpp b/contrib/restricted/boost/locale/src/util/numeric_conversion.hpp new file mode 100644 index 00000000000..5cc15bf9e77 --- /dev/null +++ b/contrib/restricted/boost/locale/src/util/numeric_conversion.hpp @@ -0,0 +1,147 @@ +// +// Copyright (c) 2024-2025 Alexander Grund +// +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_LOCALE_IMPL_UTIL_NUMERIC_CONVERSIONS_HPP +#define BOOST_LOCALE_IMPL_UTIL_NUMERIC_CONVERSIONS_HPP + +#include <boost/locale/config.hpp> +#include <boost/assert.hpp> +#include <boost/charconv/from_chars.hpp> +#include <boost/core/detail/string_view.hpp> +#include <algorithm> +#include <array> +#include <limits> +#include <type_traits> +#ifdef BOOST_LOCALE_WITH_ICU +# include <unicode/fmtable.h> +#endif + +namespace boost { namespace locale { namespace util { + namespace { + + // Create lookup table where: powers_of_10[i] == 10**i + constexpr uint64_t pow10(unsigned exponent) + { + return (exponent == 0) ? 1 : pow10(exponent - 1) * 10u; + } + template<bool condition, std::size_t Length> + using array_if_true = typename std::enable_if<condition, std::array<uint64_t, Length>>::type; + + template<std::size_t Length, typename... Values> + constexpr array_if_true<sizeof...(Values) == Length, Length> make_powers_of_10(Values... values) + { + return {{values...}}; + } + template<std::size_t Length, typename... Values> + constexpr array_if_true<sizeof...(Values) < Length, Length> make_powers_of_10(Values... values) + { + return make_powers_of_10<Length>(values..., pow10(sizeof...(Values))); + } + constexpr auto powers_of_10 = make_powers_of_10<std::numeric_limits<uint64_t>::digits10 + 1>(); +#ifndef BOOST_NO_CXX14_CONSTEXPR + static_assert(powers_of_10[0] == 1u, "!"); + static_assert(powers_of_10[1] == 10u, "!"); + static_assert(powers_of_10[5] == 100000u, "!"); +#endif + } // namespace + + template<typename Integer> + bool try_to_int(core::string_view s, Integer& value) + { + if(s.size() >= 2 && s[0] == '+') { + if(s[1] == '-') // "+-" is not allowed, invalid "+<number>" is detected by parser + return false; + s.remove_prefix(1); + } + const auto res = boost::charconv::from_chars(s, value); + return res && res.ptr == (s.data() + s.size()); + } + + /// Parse a string in scientific format to an integer. + /// In particular the "E notation" is used. + /// I.e. "\d.\d+E\d+", e.g. 5.12E3 == 5120; 5E2 == 500; 2E+1 == 20) + /// Additionally plain integers are recognized. + template<typename Integer> + bool try_scientific_to_int(const core::string_view s, Integer& value) + { + static_assert(std::is_integral<Integer>::value && std::is_unsigned<Integer>::value, + "Must be an unsigned integer"); + if(s.size() < 3) // At least: iEj for E notation + return try_to_int(s, value); + if(s[0] == '-') + return false; + constexpr auto maxDigits = std::numeric_limits<Integer>::digits10 + 1; + + const auto expPos = s.find('E', 1); + if(expPos == core::string_view::npos) + return (s[1] != '.') && try_to_int(s, value); // Shortcut: Regular integer + uint8_t exponent; // Negative exponent would be a fractional + if(BOOST_UNLIKELY(!try_to_int(s.substr(expPos + 1), exponent))) + return false; + + core::string_view significant = s.substr(0, expPos); + Integer significant_value; + if(s[1] == '.') { + const auto numSignificantDigits = significant.size() - 1u; // Exclude dot + const auto numDigits = exponent + 1u; // E0 -> 1 digit + if(BOOST_UNLIKELY(numDigits < numSignificantDigits)) + return false; // Fractional + else if(BOOST_UNLIKELY(numDigits > maxDigits)) + return false; // Too large + // Factor to get from the fractional number to an integer + BOOST_ASSERT(numSignificantDigits - 1u < powers_of_10.size()); + const auto factor = static_cast<Integer>(powers_of_10[numSignificantDigits - 1]); + exponent = static_cast<uint8_t>(numDigits - numSignificantDigits); + + const unsigned firstDigit = significant[0] - '0'; + if(firstDigit > 9u) + return false; // Not a digit + if(numSignificantDigits == maxDigits) { + const auto maxFirstDigit = std::numeric_limits<Integer>::max() / powers_of_10[maxDigits - 1]; + if(firstDigit > maxFirstDigit) + return false; + } + significant.remove_prefix(2); + if(BOOST_UNLIKELY(!try_to_int(significant, significant_value))) + return false; + // firstDigit * factor + significant_value <= max + if(static_cast<Integer>(firstDigit) > (std::numeric_limits<Integer>::max() - significant_value) / factor) + return false; + significant_value += static_cast<Integer>(firstDigit * factor); + } else if(BOOST_UNLIKELY(significant.size() + exponent > maxDigits)) + return false; + else if(BOOST_UNLIKELY(!try_to_int(significant, significant_value))) + return false; + // Add zeros if necessary + if(exponent > 0u) { + BOOST_ASSERT(exponent < powers_of_10.size()); + const auto factor = static_cast<Integer>(powers_of_10[exponent]); + if(significant_value > std::numeric_limits<Integer>::max() / factor) + return false; + value = significant_value * factor; + } else + value = significant_value; + return true; + } + +#ifdef BOOST_LOCALE_WITH_ICU + template<typename Integer> + bool try_parse_icu(icu::Formattable& fmt, Integer& value) + { + if(!fmt.isNumeric()) + return false; + // Get value as a decimal number and parse that + UErrorCode err = U_ZERO_ERROR; + const auto decimals = fmt.getDecimalNumber(err); + if(U_FAILURE(err)) + return false; // Memory error LCOV_EXCL_LINE + const core::string_view s(decimals.data(), decimals.length()); + return try_scientific_to_int(s, value); + } +#endif +}}} // namespace boost::locale::util + +#endif diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/timezone.hpp b/contrib/restricted/boost/locale/src/util/timezone.hpp index 617f40a9772..617f40a9772 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/timezone.hpp +++ b/contrib/restricted/boost/locale/src/util/timezone.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/util/win_codepages.hpp b/contrib/restricted/boost/locale/src/util/win_codepages.hpp index 4c3df668b5d..4c3df668b5d 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/util/win_codepages.hpp +++ b/contrib/restricted/boost/locale/src/util/win_codepages.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/all_generator.hpp b/contrib/restricted/boost/locale/src/win32/all_generator.hpp index 3cf7da94fb0..3cf7da94fb0 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/all_generator.hpp +++ b/contrib/restricted/boost/locale/src/win32/all_generator.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/api.hpp b/contrib/restricted/boost/locale/src/win32/api.hpp index 33791ef9689..e9b95b7ff5a 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/api.hpp +++ b/contrib/restricted/boost/locale/src/win32/api.hpp @@ -15,7 +15,7 @@ #include <string> #include <vector> -#include "boost/locale/win32/lcid.hpp" +#include "lcid.hpp" #ifndef NOMINMAX # define NOMINMAX diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/collate.cpp b/contrib/restricted/boost/locale/src/win32/collate.cpp index 16fe38d1f8d..dcdb2c99ea1 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/collate.cpp +++ b/contrib/restricted/boost/locale/src/win32/collate.cpp @@ -6,9 +6,9 @@ #include <boost/locale/encoding.hpp> #include <boost/locale/generator.hpp> -#include "boost/locale/shared/mo_hash.hpp" -#include "boost/locale/shared/std_collate_adapter.hpp" -#include "boost/locale/win32/api.hpp" +#include "../shared/mo_hash.hpp" +#include "../shared/std_collate_adapter.hpp" +#include "api.hpp" #include <ios> #include <locale> #include <string> diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/converter.cpp b/contrib/restricted/boost/locale/src/win32/converter.cpp index ed29aedc69d..fe168df79d0 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/converter.cpp +++ b/contrib/restricted/boost/locale/src/win32/converter.cpp @@ -7,8 +7,8 @@ #include <boost/locale/conversion.hpp> #include <boost/locale/encoding.hpp> #include <boost/locale/generator.hpp> -#include "boost/locale/win32/all_generator.hpp" -#include "boost/locale/win32/api.hpp" +#include "all_generator.hpp" +#include "api.hpp" #include <cstring> #include <locale> #include <stdexcept> @@ -62,7 +62,7 @@ namespace boost { namespace locale { namespace impl_win { case char_facet_t::nochar: break; case char_facet_t::char_f: return std::locale(in, new utf8_converter<char>(lc)); case char_facet_t::wchar_f: return std::locale(in, new wide_converter(lc)); -#ifndef BOOST_LOCALE_NO_CXX20_STRING8 +#ifdef __cpp_lib_char8_t case char_facet_t::char8_f: return std::locale(in, new utf8_converter<char8_t>(lc)); #elif defined(__cpp_char8_t) case char_facet_t::char8_f: break; diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/lcid.cpp b/contrib/restricted/boost/locale/src/win32/lcid.cpp index 1435455775c..e1b998d66b3 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/lcid.cpp +++ b/contrib/restricted/boost/locale/src/win32/lcid.cpp @@ -8,7 +8,7 @@ # define NOMINMAX #endif -#include "boost/locale/win32/lcid.hpp" +#include "lcid.hpp" #include <boost/locale/util/locale_data.hpp> #include <boost/thread/locks.hpp> #include <boost/thread/mutex.hpp> diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/lcid.hpp b/contrib/restricted/boost/locale/src/win32/lcid.hpp index 19a801d4a87..19a801d4a87 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/lcid.hpp +++ b/contrib/restricted/boost/locale/src/win32/lcid.hpp diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/numeric.cpp b/contrib/restricted/boost/locale/src/win32/numeric.cpp index 556de79a851..3286424e909 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/numeric.cpp +++ b/contrib/restricted/boost/locale/src/win32/numeric.cpp @@ -4,12 +4,12 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/util/numeric.hpp" +#include "../util/numeric.hpp" #include <boost/locale/encoding.hpp> #include <boost/locale/formatting.hpp> #include <boost/locale/generator.hpp> -#include "boost/locale/win32/all_generator.hpp" -#include "boost/locale/win32/api.hpp" +#include "all_generator.hpp" +#include "api.hpp" #include <algorithm> #include <cctype> #include <cstdlib> diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/win_backend.cpp b/contrib/restricted/boost/locale/src/win32/win_backend.cpp index 48155d6c23c..2ce4d460892 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/win_backend.cpp +++ b/contrib/restricted/boost/locale/src/win32/win_backend.cpp @@ -5,17 +5,17 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include "boost/locale/win32/win_backend.hpp" +#include "win_backend.hpp" #include <boost/locale/gnu_gettext.hpp> #include <boost/locale/info.hpp> #include <boost/locale/localization_backend.hpp> #include <boost/locale/util.hpp> #include <boost/locale/util/locale_data.hpp> -#include "boost/locale/shared/message.hpp" -#include "boost/locale/util/gregorian.hpp" -#include "boost/locale/util/make_std_unique.hpp" -#include "boost/locale/win32/all_generator.hpp" -#include "boost/locale/win32/api.hpp" +#include "../shared/message.hpp" +#include "../util/gregorian.hpp" +#include "../util/make_std_unique.hpp" +#include "all_generator.hpp" +#include "api.hpp" #include <algorithm> #include <iterator> #include <vector> diff --git a/contrib/restricted/boost/locale/src/boost/locale/win32/win_backend.hpp b/contrib/restricted/boost/locale/src/win32/win_backend.hpp index 8980535e742..8980535e742 100644 --- a/contrib/restricted/boost/locale/src/boost/locale/win32/win_backend.hpp +++ b/contrib/restricted/boost/locale/src/win32/win_backend.hpp diff --git a/contrib/restricted/boost/locale/ya.make b/contrib/restricted/boost/locale/ya.make index 9576428064a..f2b80c5b7af 100644 --- a/contrib/restricted/boost/locale/ya.make +++ b/contrib/restricted/boost/locale/ya.make @@ -6,19 +6,19 @@ LICENSE(BSL-1.0) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(1.87.0) +VERSION(1.88.0) -ORIGINAL_SOURCE(https://github.com/boostorg/locale/archive/boost-1.87.0.tar.gz) +ORIGINAL_SOURCE(https://github.com/boostorg/locale/archive/boost-1.88.0.tar.gz) PEERDIR( contrib/libs/icu contrib/restricted/boost/assert + contrib/restricted/boost/charconv contrib/restricted/boost/config contrib/restricted/boost/core contrib/restricted/boost/iterator contrib/restricted/boost/predef contrib/restricted/boost/thread - contrib/restricted/boost/utility ) ADDINCL( @@ -50,57 +50,56 @@ ELSEIF (OS_WINDOWS) -DBOOST_LOCALE_NO_POSIX_BACKEND ) SRCS( - src/boost/locale/win32/collate.cpp - src/boost/locale/win32/converter.cpp - src/boost/locale/win32/lcid.cpp - src/boost/locale/win32/numeric.cpp - src/boost/locale/win32/win_backend.cpp + src/win32/collate.cpp + src/win32/converter.cpp + src/win32/lcid.cpp + src/win32/numeric.cpp + src/win32/win_backend.cpp ) ELSE() CFLAGS( -DBOOST_LOCALE_NO_WINAPI_BACKEND ) SRCS( - src/boost/locale/posix/codecvt.cpp - src/boost/locale/posix/collate.cpp - src/boost/locale/posix/converter.cpp - src/boost/locale/posix/numeric.cpp - src/boost/locale/posix/posix_backend.cpp + src/posix/codecvt.cpp + src/posix/collate.cpp + src/posix/converter.cpp + src/posix/numeric.cpp + src/posix/posix_backend.cpp ) ENDIF() SRCS( - src/boost/locale/encoding/codepage.cpp - src/boost/locale/icu/boundary.cpp - src/boost/locale/icu/codecvt.cpp - src/boost/locale/icu/collator.cpp - src/boost/locale/icu/conversion.cpp - src/boost/locale/icu/date_time.cpp - src/boost/locale/icu/formatter.cpp - src/boost/locale/icu/formatters_cache.cpp - src/boost/locale/icu/icu_backend.cpp - src/boost/locale/icu/numeric.cpp - src/boost/locale/icu/time_zone.cpp - src/boost/locale/shared/date_time.cpp - src/boost/locale/shared/format.cpp - src/boost/locale/shared/formatting.cpp - src/boost/locale/shared/generator.cpp - src/boost/locale/shared/iconv_codecvt.cpp - src/boost/locale/shared/ids.cpp - src/boost/locale/shared/localization_backend.cpp - src/boost/locale/shared/message.cpp - src/boost/locale/shared/mo_lambda.cpp - src/boost/locale/std/codecvt.cpp - src/boost/locale/std/collate.cpp - src/boost/locale/std/converter.cpp - src/boost/locale/std/numeric.cpp - src/boost/locale/std/std_backend.cpp - src/boost/locale/util/codecvt_converter.cpp - src/boost/locale/util/default_locale.cpp - src/boost/locale/util/encoding.cpp - src/boost/locale/util/gregorian.cpp - src/boost/locale/util/info.cpp - src/boost/locale/util/locale_data.cpp + src/encoding/codepage.cpp + src/icu/boundary.cpp + src/icu/codecvt.cpp + src/icu/collator.cpp + src/icu/conversion.cpp + src/icu/date_time.cpp + src/icu/formatter.cpp + src/icu/formatters_cache.cpp + src/icu/icu_backend.cpp + src/icu/numeric.cpp + src/shared/date_time.cpp + src/shared/format.cpp + src/shared/formatting.cpp + src/shared/generator.cpp + src/shared/iconv_codecvt.cpp + src/shared/ids.cpp + src/shared/localization_backend.cpp + src/shared/message.cpp + src/shared/mo_lambda.cpp + src/std/codecvt.cpp + src/std/collate.cpp + src/std/converter.cpp + src/std/numeric.cpp + src/std/std_backend.cpp + src/util/codecvt_converter.cpp + src/util/default_locale.cpp + src/util/encoding.cpp + src/util/gregorian.cpp + src/util/info.cpp + src/util/locale_data.cpp ) END() |