62.65% Lines (52/83)
82.61% Functions (19/23)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // Copyright 2020-2023 Daniel Lemire | 1 | // Copyright 2020-2023 Daniel Lemire | |||||
| 2 | // Copyright 2023 Matt Borland | 2 | // Copyright 2023 Matt Borland | |||||
| 3 | // Distributed under the Boost Software License, Version 1.0. | 3 | // Distributed under the Boost Software License, Version 1.0. | |||||
| 4 | // https://www.boost.org/LICENSE_1_0.txt | 4 | // https://www.boost.org/LICENSE_1_0.txt | |||||
| 5 | // | 5 | // | |||||
| 6 | // Derivative of: https://github.com/fastfloat/fast_float | 6 | // Derivative of: https://github.com/fastfloat/fast_float | |||||
| 7 | 7 | |||||||
| 8 | #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP | 8 | #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP | |||||
| 9 | #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP | 9 | #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP | |||||
| 10 | 10 | |||||||
| 11 | #include <boost/json/detail/charconv/detail/fast_float/constexpr_feature_detect.hpp> | 11 | #include <boost/json/detail/charconv/detail/fast_float/constexpr_feature_detect.hpp> | |||||
| 12 | #include <boost/json/detail/charconv/detail/from_chars_result.hpp> | 12 | #include <boost/json/detail/charconv/detail/from_chars_result.hpp> | |||||
| 13 | #include <boost/json/detail/charconv/detail/config.hpp> | 13 | #include <boost/json/detail/charconv/detail/config.hpp> | |||||
| 14 | #include <boost/json/detail/charconv/chars_format.hpp> | 14 | #include <boost/json/detail/charconv/chars_format.hpp> | |||||
| 15 | #include <cfloat> | 15 | #include <cfloat> | |||||
| 16 | #include <cstdint> | 16 | #include <cstdint> | |||||
| 17 | #include <cassert> | 17 | #include <cassert> | |||||
| 18 | #include <cstring> | 18 | #include <cstring> | |||||
| 19 | #include <type_traits> | 19 | #include <type_traits> | |||||
| 20 | #include <system_error> | 20 | #include <system_error> | |||||
| 21 | 21 | |||||||
| 22 | namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float { | 22 | namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float { | |||||
| 23 | 23 | |||||||
| 24 | 24 | |||||||
| 25 | template <typename UC> | 25 | template <typename UC> | |||||
| 26 | struct parse_options_t { | 26 | struct parse_options_t { | |||||
| HITCBC | 27 | 1009310 | constexpr explicit parse_options_t(chars_format fmt = chars_format::general, | 27 | 1009310 | constexpr explicit parse_options_t(chars_format fmt = chars_format::general, | ||
| 28 | UC dot = UC('.')) | 28 | UC dot = UC('.')) | |||||
| HITCBC | 29 | 1009310 | : format(fmt), decimal_point(dot) {} | 29 | 1009310 | : format(fmt), decimal_point(dot) {} | ||
| 30 | 30 | |||||||
| 31 | /** Which number formats are accepted */ | 31 | /** Which number formats are accepted */ | |||||
| 32 | chars_format format; | 32 | chars_format format; | |||||
| 33 | /** The character used as decimal point */ | 33 | /** The character used as decimal point */ | |||||
| 34 | UC decimal_point; | 34 | UC decimal_point; | |||||
| 35 | }; | 35 | }; | |||||
| 36 | using parse_options = parse_options_t<char>; | 36 | using parse_options = parse_options_t<char>; | |||||
| 37 | 37 | |||||||
| 38 | }}}}}} | 38 | }}}}}} | |||||
| 39 | 39 | |||||||
| 40 | #ifdef BOOST_JSON_HAS_BIT_CAST | 40 | #ifdef BOOST_JSON_HAS_BIT_CAST | |||||
| 41 | #include <bit> | 41 | #include <bit> | |||||
| 42 | #endif | 42 | #endif | |||||
| 43 | 43 | |||||||
| 44 | #if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \ | 44 | #if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \ | |||||
| 45 | || defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \ | 45 | || defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \ | |||||
| 46 | || defined(__MINGW64__) \ | 46 | || defined(__MINGW64__) \ | |||||
| 47 | || defined(__s390x__) \ | 47 | || defined(__s390x__) \ | |||||
| 48 | || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) ) | 48 | || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) ) | |||||
| 49 | #define BOOST_JSON_FASTFLOAT_64BIT 1 | 49 | #define BOOST_JSON_FASTFLOAT_64BIT 1 | |||||
| 50 | #elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) \ | 50 | #elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) \ | |||||
| 51 | || defined(__arm__) || defined(_M_ARM) || defined(__ppc__) \ | 51 | || defined(__arm__) || defined(_M_ARM) || defined(__ppc__) \ | |||||
| 52 | || defined(__MINGW32__) || defined(__EMSCRIPTEN__)) | 52 | || defined(__MINGW32__) || defined(__EMSCRIPTEN__)) | |||||
| 53 | #define BOOST_JSON_FASTFLOAT_32BIT 1 | 53 | #define BOOST_JSON_FASTFLOAT_32BIT 1 | |||||
| 54 | #else | 54 | #else | |||||
| 55 | // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. | 55 | // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. | |||||
| 56 | // We can never tell the register width, but the SIZE_MAX is a good approximation. | 56 | // We can never tell the register width, but the SIZE_MAX is a good approximation. | |||||
| 57 | // UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max portability. | 57 | // UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max portability. | |||||
| 58 | #if SIZE_MAX == 0xffff | 58 | #if SIZE_MAX == 0xffff | |||||
| 59 | #error Unknown platform (16-bit, unsupported) | 59 | #error Unknown platform (16-bit, unsupported) | |||||
| 60 | #elif SIZE_MAX == 0xffffffff | 60 | #elif SIZE_MAX == 0xffffffff | |||||
| 61 | #define BOOST_JSON_FASTFLOAT_32BIT 1 | 61 | #define BOOST_JSON_FASTFLOAT_32BIT 1 | |||||
| 62 | #elif SIZE_MAX == 0xffffffffffffffff | 62 | #elif SIZE_MAX == 0xffffffffffffffff | |||||
| 63 | #define BOOST_JSON_FASTFLOAT_64BIT 1 | 63 | #define BOOST_JSON_FASTFLOAT_64BIT 1 | |||||
| 64 | #else | 64 | #else | |||||
| 65 | #error Unknown platform (not 32-bit, not 64-bit?) | 65 | #error Unknown platform (not 32-bit, not 64-bit?) | |||||
| 66 | #endif | 66 | #endif | |||||
| 67 | #endif | 67 | #endif | |||||
| 68 | 68 | |||||||
| 69 | #if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) | 69 | #if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) | |||||
| 70 | #include <intrin.h> | 70 | #include <intrin.h> | |||||
| 71 | #endif | 71 | #endif | |||||
| 72 | 72 | |||||||
| 73 | #if defined(_MSC_VER) && !defined(__clang__) | 73 | #if defined(_MSC_VER) && !defined(__clang__) | |||||
| 74 | #define BOOST_JSON_FASTFLOAT_VISUAL_STUDIO 1 | 74 | #define BOOST_JSON_FASTFLOAT_VISUAL_STUDIO 1 | |||||
| 75 | #endif | 75 | #endif | |||||
| 76 | 76 | |||||||
| 77 | // rust style `try!()` macro, or `?` operator | 77 | // rust style `try!()` macro, or `?` operator | |||||
| 78 | #define BOOST_JSON_FASTFLOAT_TRY(x) { if (!(x)) return false; } | 78 | #define BOOST_JSON_FASTFLOAT_TRY(x) { if (!(x)) return false; } | |||||
| 79 | 79 | |||||||
| 80 | namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float { | 80 | namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float { | |||||
| 81 | 81 | |||||||
| 82 | BOOST_FORCEINLINE constexpr bool cpp20_and_in_constexpr() { | 82 | BOOST_FORCEINLINE constexpr bool cpp20_and_in_constexpr() { | |||||
| 83 | #ifdef BOOST_JSON_HAS_IS_CONSTANT_EVALUATED | 83 | #ifdef BOOST_JSON_HAS_IS_CONSTANT_EVALUATED | |||||
| 84 | return std::is_constant_evaluated(); | 84 | return std::is_constant_evaluated(); | |||||
| 85 | #else | 85 | #else | |||||
| HITCBC | 86 | 8902634 | return false; | 86 | 8902634 | return false; | ||
| 87 | #endif | 87 | #endif | |||||
| 88 | } | 88 | } | |||||
| 89 | 89 | |||||||
| 90 | // Compares two ASCII strings in a case insensitive manner. | 90 | // Compares two ASCII strings in a case insensitive manner. | |||||
| 91 | template <typename UC> | 91 | template <typename UC> | |||||
| 92 | inline BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE bool | 92 | inline BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE bool | |||||
| MISUBC | 93 | ✗ | fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) { | 93 | ✗ | fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) { | ||
| MISUBC | 94 | ✗ | char running_diff{0}; | 94 | ✗ | char running_diff{0}; | ||
| MISUBC | 95 | ✗ | for (size_t i = 0; i < length; ++i) { | 95 | ✗ | for (size_t i = 0; i < length; ++i) { | ||
| MISUBC | 96 | ✗ | running_diff |= (char(input1[i]) ^ char(input2[i])); | 96 | ✗ | running_diff |= (char(input1[i]) ^ char(input2[i])); | ||
| 97 | } | 97 | } | |||||
| MISUBC | 98 | ✗ | return (running_diff == 0) || (running_diff == 32); | 98 | ✗ | return (running_diff == 0) || (running_diff == 32); | ||
| 99 | } | 99 | } | |||||
| 100 | 100 | |||||||
| 101 | #ifndef FLT_EVAL_METHOD | 101 | #ifndef FLT_EVAL_METHOD | |||||
| 102 | #error "FLT_EVAL_METHOD should be defined, please include cfloat." | 102 | #error "FLT_EVAL_METHOD should be defined, please include cfloat." | |||||
| 103 | #endif | 103 | #endif | |||||
| 104 | 104 | |||||||
| 105 | // a pointer and a length to a contiguous block of memory | 105 | // a pointer and a length to a contiguous block of memory | |||||
| 106 | template <typename T> | 106 | template <typename T> | |||||
| 107 | struct span { | 107 | struct span { | |||||
| 108 | const T* ptr; | 108 | const T* ptr; | |||||
| 109 | size_t length; | 109 | size_t length; | |||||
| HITCBC | 110 | 2028274 | constexpr span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {} | 110 | 2028274 | constexpr span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {} | ||
| 111 | constexpr span() : ptr(nullptr), length(0) {} | 111 | constexpr span() : ptr(nullptr), length(0) {} | |||||
| 112 | 112 | |||||||
| HITCBC | 113 | 1155768 | constexpr size_t len() const noexcept { | 113 | 1155768 | constexpr size_t len() const noexcept { | ||
| HITCBC | 114 | 1155768 | return length; | 114 | 1155768 | return length; | ||
| 115 | } | 115 | } | |||||
| 116 | 116 | |||||||
| HITCBC | 117 | 36365 | BOOST_JSON_CXX14_CONSTEXPR const T& operator[](size_t index) const noexcept { | 117 | 36365 | BOOST_JSON_CXX14_CONSTEXPR const T& operator[](size_t index) const noexcept { | ||
| HITCBC | 118 | 36365 | BOOST_ASSERT(index < length); | 118 | 36365 | BOOST_ASSERT(index < length); | ||
| HITCBC | 119 | 36365 | return ptr[index]; | 119 | 36365 | return ptr[index]; | ||
| 120 | } | 120 | } | |||||
| 121 | }; | 121 | }; | |||||
| 122 | 122 | |||||||
| 123 | struct value128 { | 123 | struct value128 { | |||||
| 124 | uint64_t low; | 124 | uint64_t low; | |||||
| 125 | uint64_t high; | 125 | uint64_t high; | |||||
| 126 | constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} | 126 | constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} | |||||
| 127 | constexpr value128() : low(0), high(0) {} | 127 | constexpr value128() : low(0), high(0) {} | |||||
| 128 | }; | 128 | }; | |||||
| 129 | 129 | |||||||
| 130 | /* Helper C++11 constexpr generic implementation of leading_zeroes */ | 130 | /* Helper C++11 constexpr generic implementation of leading_zeroes */ | |||||
| 131 | BOOST_FORCEINLINE constexpr | 131 | BOOST_FORCEINLINE constexpr | |||||
| 132 | int leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { | 132 | int leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { | |||||
| 133 | return ( | 133 | return ( | |||||
| MISUBC | 134 | ✗ | ((input_num & uint64_t(0xffffffff00000000)) && (input_num >>= 32, last_bit |= 32)), | 134 | ✗ | ((input_num & uint64_t(0xffffffff00000000)) && (input_num >>= 32, last_bit |= 32)), | ||
| MISUBC | 135 | ✗ | ((input_num & uint64_t( 0xffff0000)) && (input_num >>= 16, last_bit |= 16)), | 135 | ✗ | ((input_num & uint64_t( 0xffff0000)) && (input_num >>= 16, last_bit |= 16)), | ||
| MISUBC | 136 | ✗ | ((input_num & uint64_t( 0xff00)) && (input_num >>= 8, last_bit |= 8)), | 136 | ✗ | ((input_num & uint64_t( 0xff00)) && (input_num >>= 8, last_bit |= 8)), | ||
| MISUBC | 137 | ✗ | ((input_num & uint64_t( 0xf0)) && (input_num >>= 4, last_bit |= 4)), | 137 | ✗ | ((input_num & uint64_t( 0xf0)) && (input_num >>= 4, last_bit |= 4)), | ||
| MISUBC | 138 | ✗ | ((input_num & uint64_t( 0xc)) && (input_num >>= 2, last_bit |= 2)), | 138 | ✗ | ((input_num & uint64_t( 0xc)) && (input_num >>= 2, last_bit |= 2)), | ||
| MISUBC | 139 | ✗ | ((input_num & uint64_t( 0x2)) && (input_num >>= 1, last_bit |= 1)), | 139 | ✗ | ((input_num & uint64_t( 0x2)) && (input_num >>= 1, last_bit |= 1)), | ||
| 140 | 63 - last_bit | 140 | 63 - last_bit | |||||
| MISUBC | 141 | ✗ | ); | 141 | ✗ | ); | ||
| 142 | } | 142 | } | |||||
| 143 | 143 | |||||||
| 144 | /* result might be undefined when input_num is zero */ | 144 | /* result might be undefined when input_num is zero */ | |||||
| 145 | BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 | 145 | BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 | |||||
| 146 | int leading_zeroes(uint64_t input_num) { | 146 | int leading_zeroes(uint64_t input_num) { | |||||
| HITCBC | 147 | 2008629 | assert(input_num > 0); | 147 | 2008629 | assert(input_num > 0); | ||
| HITCBC | 148 | 2008629 | if (cpp20_and_in_constexpr()) { | 148 | 2008629 | if (cpp20_and_in_constexpr()) { | ||
| MISUBC | 149 | ✗ | return leading_zeroes_generic(input_num); | 149 | ✗ | return leading_zeroes_generic(input_num); | ||
| 150 | } | 150 | } | |||||
| 151 | #ifdef BOOST_JSON_FASTFLOAT_VISUAL_STUDIO | 151 | #ifdef BOOST_JSON_FASTFLOAT_VISUAL_STUDIO | |||||
| 152 | #if defined(_M_X64) || defined(_M_ARM64) | 152 | #if defined(_M_X64) || defined(_M_ARM64) | |||||
| 153 | unsigned long leading_zero = 0; | 153 | unsigned long leading_zero = 0; | |||||
| 154 | // Search the mask data from most significant bit (MSB) | 154 | // Search the mask data from most significant bit (MSB) | |||||
| 155 | // to least significant bit (LSB) for a set bit (1). | 155 | // to least significant bit (LSB) for a set bit (1). | |||||
| 156 | _BitScanReverse64(&leading_zero, input_num); | 156 | _BitScanReverse64(&leading_zero, input_num); | |||||
| 157 | return (int)(63 - leading_zero); | 157 | return (int)(63 - leading_zero); | |||||
| 158 | #else | 158 | #else | |||||
| 159 | return leading_zeroes_generic(input_num); | 159 | return leading_zeroes_generic(input_num); | |||||
| 160 | #endif | 160 | #endif | |||||
| 161 | #else | 161 | #else | |||||
| HITCBC | 162 | 2008629 | return __builtin_clzll(input_num); | 162 | 2008629 | return __builtin_clzll(input_num); | ||
| 163 | #endif | 163 | #endif | |||||
| 164 | } | 164 | } | |||||
| 165 | 165 | |||||||
| 166 | // slow emulation routine for 32-bit | 166 | // slow emulation routine for 32-bit | |||||
| 167 | BOOST_FORCEINLINE constexpr uint64_t emulu(uint32_t x, uint32_t y) { | 167 | BOOST_FORCEINLINE constexpr uint64_t emulu(uint32_t x, uint32_t y) { | |||||
| MISUBC | 168 | ✗ | return x * (uint64_t)y; | 168 | ✗ | return x * (uint64_t)y; | ||
| 169 | } | 169 | } | |||||
| 170 | 170 | |||||||
| 171 | BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE | 171 | BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE | |||||
| 172 | uint64_t umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { | 172 | uint64_t umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { | |||||
| MISUBC | 173 | ✗ | uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); | 173 | ✗ | uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); | ||
| MISUBC | 174 | ✗ | uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); | 174 | ✗ | uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); | ||
| MISUBC | 175 | ✗ | uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); | 175 | ✗ | uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); | ||
| MISUBC | 176 | ✗ | uint64_t adbc_carry = !!(adbc < ad); | 176 | ✗ | uint64_t adbc_carry = !!(adbc < ad); | ||
| MISUBC | 177 | ✗ | uint64_t lo = bd + (adbc << 32); | 177 | ✗ | uint64_t lo = bd + (adbc << 32); | ||
| MISUBC | 178 | ✗ | *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + | 178 | ✗ | *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + | ||
| MISUBC | 179 | ✗ | (adbc_carry << 32) + !!(lo < bd); | 179 | ✗ | (adbc_carry << 32) + !!(lo < bd); | ||
| MISUBC | 180 | ✗ | return lo; | 180 | ✗ | return lo; | ||
| 181 | } | 181 | } | |||||
| 182 | 182 | |||||||
| 183 | #ifdef BOOST_JSON_FASTFLOAT_32BIT | 183 | #ifdef BOOST_JSON_FASTFLOAT_32BIT | |||||
| 184 | 184 | |||||||
| 185 | // slow emulation routine for 32-bit | 185 | // slow emulation routine for 32-bit | |||||
| 186 | #if !defined(__MINGW64__) | 186 | #if !defined(__MINGW64__) | |||||
| 187 | BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE | 187 | BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE | |||||
| 188 | uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { | 188 | uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { | |||||
| 189 | return umul128_generic(ab, cd, hi); | 189 | return umul128_generic(ab, cd, hi); | |||||
| 190 | } | 190 | } | |||||
| 191 | #endif // !__MINGW64__ | 191 | #endif // !__MINGW64__ | |||||
| 192 | 192 | |||||||
| 193 | #endif // BOOST_JSON_FASTFLOAT_32BIT | 193 | #endif // BOOST_JSON_FASTFLOAT_32BIT | |||||
| 194 | 194 | |||||||
| 195 | 195 | |||||||
| 196 | // compute 64-bit a*b | 196 | // compute 64-bit a*b | |||||
| 197 | BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 | 197 | BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 | |||||
| 198 | value128 full_multiplication(uint64_t a, uint64_t b) { | 198 | value128 full_multiplication(uint64_t a, uint64_t b) { | |||||
| HITCBC | 199 | 2010874 | if (cpp20_and_in_constexpr()) { | 199 | 2010874 | if (cpp20_and_in_constexpr()) { | ||
| MISUBC | 200 | ✗ | value128 answer; | 200 | ✗ | value128 answer; | ||
| MISUBC | 201 | ✗ | answer.low = umul128_generic(a, b, &answer.high); | 201 | ✗ | answer.low = umul128_generic(a, b, &answer.high); | ||
| MISUBC | 202 | ✗ | return answer; | 202 | ✗ | return answer; | ||
| 203 | } | 203 | } | |||||
| HITCBC | 204 | 2010874 | value128 answer; | 204 | 2010874 | value128 answer; | ||
| 205 | #if defined(_M_ARM64) && !defined(__MINGW32__) | 205 | #if defined(_M_ARM64) && !defined(__MINGW32__) | |||||
| 206 | // ARM64 has native support for 64-bit multiplications, no need to emulate | 206 | // ARM64 has native support for 64-bit multiplications, no need to emulate | |||||
| 207 | // But MinGW on ARM64 doesn't have native support for 64-bit multiplications | 207 | // But MinGW on ARM64 doesn't have native support for 64-bit multiplications | |||||
| 208 | answer.high = __umulh(a, b); | 208 | answer.high = __umulh(a, b); | |||||
| 209 | answer.low = a * b; | 209 | answer.low = a * b; | |||||
| 210 | #elif defined(BOOST_JSON_FASTFLOAT_32BIT) || \ | 210 | #elif defined(BOOST_JSON_FASTFLOAT_32BIT) || \ | |||||
| 211 | (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64)) | 211 | (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64)) | |||||
| 212 | unsigned long long high; | 212 | unsigned long long high; | |||||
| 213 | answer.low = _umul128(a, b, &high); // _umul128 not available on ARM64 | 213 | answer.low = _umul128(a, b, &high); // _umul128 not available on ARM64 | |||||
| 214 | answer.high = static_cast<uint64_t>(high); | 214 | answer.high = static_cast<uint64_t>(high); | |||||
| 215 | #elif defined(BOOST_JSON_FASTFLOAT_64BIT) | 215 | #elif defined(BOOST_JSON_FASTFLOAT_64BIT) | |||||
| HITCBC | 216 | 2010874 | __uint128_t r = ((__uint128_t)a) * b; | 216 | 2010874 | __uint128_t r = ((__uint128_t)a) * b; | ||
| HITCBC | 217 | 2010874 | answer.low = uint64_t(r); | 217 | 2010874 | answer.low = uint64_t(r); | ||
| HITCBC | 218 | 2010874 | answer.high = uint64_t(r >> 64); | 218 | 2010874 | answer.high = uint64_t(r >> 64); | ||
| 219 | #else | 219 | #else | |||||
| 220 | answer.low = umul128_generic(a, b, &answer.high); | 220 | answer.low = umul128_generic(a, b, &answer.high); | |||||
| 221 | #endif | 221 | #endif | |||||
| HITCBC | 222 | 2010874 | return answer; | 222 | 2010874 | return answer; | ||
| 223 | } | 223 | } | |||||
| 224 | 224 | |||||||
| 225 | struct adjusted_mantissa { | 225 | struct adjusted_mantissa { | |||||
| 226 | uint64_t mantissa{0}; | 226 | uint64_t mantissa{0}; | |||||
| 227 | int32_t power2{0}; // a negative value indicates an invalid result | 227 | int32_t power2{0}; // a negative value indicates an invalid result | |||||
| 228 | adjusted_mantissa() = default; | 228 | adjusted_mantissa() = default; | |||||
| 229 | constexpr bool operator==(const adjusted_mantissa &o) const { | 229 | constexpr bool operator==(const adjusted_mantissa &o) const { | |||||
| 230 | return mantissa == o.mantissa && power2 == o.power2; | 230 | return mantissa == o.mantissa && power2 == o.power2; | |||||
| 231 | } | 231 | } | |||||
| HITCBC | 232 | 1000712 | constexpr bool operator!=(const adjusted_mantissa &o) const { | 232 | 1000712 | constexpr bool operator!=(const adjusted_mantissa &o) const { | ||
| HITCBC | 233 | 1000712 | return mantissa != o.mantissa || power2 != o.power2; | 233 | 1000712 | return mantissa != o.mantissa || power2 != o.power2; | ||
| 234 | } | 234 | } | |||||
| 235 | }; | 235 | }; | |||||
| 236 | 236 | |||||||
| 237 | // Bias so we can get the real exponent with an invalid adjusted_mantissa. | 237 | // Bias so we can get the real exponent with an invalid adjusted_mantissa. | |||||
| 238 | constexpr static int32_t invalid_am_bias = -0x8000; | 238 | constexpr static int32_t invalid_am_bias = -0x8000; | |||||
| 239 | 239 | |||||||
| 240 | // used for binary_format_lookup_tables<T>::max_mantissa | 240 | // used for binary_format_lookup_tables<T>::max_mantissa | |||||
| 241 | constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; | 241 | constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; | |||||
| 242 | 242 | |||||||
| 243 | template <typename T, typename U = void> | 243 | template <typename T, typename U = void> | |||||
| 244 | struct binary_format_lookup_tables; | 244 | struct binary_format_lookup_tables; | |||||
| 245 | 245 | |||||||
| 246 | template <typename T> struct binary_format : binary_format_lookup_tables<T> { | 246 | template <typename T> struct binary_format : binary_format_lookup_tables<T> { | |||||
| 247 | using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type; | 247 | using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type; | |||||
| 248 | 248 | |||||||
| 249 | static inline constexpr int mantissa_explicit_bits(); | 249 | static inline constexpr int mantissa_explicit_bits(); | |||||
| 250 | static inline constexpr int minimum_exponent(); | 250 | static inline constexpr int minimum_exponent(); | |||||
| 251 | static inline constexpr int infinite_power(); | 251 | static inline constexpr int infinite_power(); | |||||
| 252 | static inline constexpr int sign_index(); | 252 | static inline constexpr int sign_index(); | |||||
| 253 | static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST | 253 | static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST | |||||
| 254 | static inline constexpr int max_exponent_fast_path(); | 254 | static inline constexpr int max_exponent_fast_path(); | |||||
| 255 | static inline constexpr int max_exponent_round_to_even(); | 255 | static inline constexpr int max_exponent_round_to_even(); | |||||
| 256 | static inline constexpr int min_exponent_round_to_even(); | 256 | static inline constexpr int min_exponent_round_to_even(); | |||||
| 257 | static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); | 257 | static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); | |||||
| 258 | static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST | 258 | static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST | |||||
| 259 | static inline constexpr int largest_power_of_ten(); | 259 | static inline constexpr int largest_power_of_ten(); | |||||
| 260 | static inline constexpr int smallest_power_of_ten(); | 260 | static inline constexpr int smallest_power_of_ten(); | |||||
| 261 | static inline constexpr T exact_power_of_ten(int64_t power); | 261 | static inline constexpr T exact_power_of_ten(int64_t power); | |||||
| 262 | static inline constexpr size_t max_digits(); | 262 | static inline constexpr size_t max_digits(); | |||||
| 263 | static inline constexpr equiv_uint exponent_mask(); | 263 | static inline constexpr equiv_uint exponent_mask(); | |||||
| 264 | static inline constexpr equiv_uint mantissa_mask(); | 264 | static inline constexpr equiv_uint mantissa_mask(); | |||||
| 265 | static inline constexpr equiv_uint hidden_bit_mask(); | 265 | static inline constexpr equiv_uint hidden_bit_mask(); | |||||
| 266 | }; | 266 | }; | |||||
| 267 | 267 | |||||||
| 268 | template <typename U> | 268 | template <typename U> | |||||
| 269 | struct binary_format_lookup_tables<double, U> { | 269 | struct binary_format_lookup_tables<double, U> { | |||||
| 270 | static constexpr double powers_of_ten[] = { | 270 | static constexpr double powers_of_ten[] = { | |||||
| 271 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, | 271 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, | |||||
| 272 | 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; | 272 | 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; | |||||
| 273 | 273 | |||||||
| 274 | // Largest integer value v so that (5**index * v) <= 1<<53. | 274 | // Largest integer value v so that (5**index * v) <= 1<<53. | |||||
| 275 | // 0x10000000000000 == 1 << 53 | 275 | // 0x10000000000000 == 1 << 53 | |||||
| 276 | static constexpr std::uint64_t max_mantissa[] = { | 276 | static constexpr std::uint64_t max_mantissa[] = { | |||||
| 277 | UINT64_C(0x10000000000000), | 277 | UINT64_C(0x10000000000000), | |||||
| 278 | UINT64_C(0x10000000000000) / UINT64_C(5), | 278 | UINT64_C(0x10000000000000) / UINT64_C(5), | |||||
| 279 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5)), | 279 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5)), | |||||
| 280 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 280 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 281 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 281 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 282 | UINT64_C(0x10000000000000) / (constant_55555), | 282 | UINT64_C(0x10000000000000) / (constant_55555), | |||||
| 283 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5)), | 283 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5)), | |||||
| 284 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), | 284 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), | |||||
| 285 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 285 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 286 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 286 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 287 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555), | 287 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555), | |||||
| 288 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5)), | 288 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5)), | |||||
| 289 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), | 289 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), | |||||
| 290 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 290 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 291 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555), | 291 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555), | |||||
| 292 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), | 292 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), | |||||
| 293 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), | 293 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), | |||||
| 294 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 294 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 295 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 295 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 296 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555), | 296 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555), | |||||
| 297 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), | 297 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), | |||||
| 298 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), | 298 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), | |||||
| 299 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 299 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 300 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5))}; | 300 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5))}; | |||||
| 301 | }; | 301 | }; | |||||
| 302 | 302 | |||||||
| 303 | template <typename U> | 303 | template <typename U> | |||||
| 304 | constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[]; | 304 | constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[]; | |||||
| 305 | 305 | |||||||
| 306 | template <typename U> | 306 | template <typename U> | |||||
| 307 | constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[]; | 307 | constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[]; | |||||
| 308 | 308 | |||||||
| 309 | template <typename U> | 309 | template <typename U> | |||||
| 310 | struct binary_format_lookup_tables<float, U> { | 310 | struct binary_format_lookup_tables<float, U> { | |||||
| 311 | static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, | 311 | static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, | |||||
| 312 | 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; | 312 | 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; | |||||
| 313 | 313 | |||||||
| 314 | // Largest integer value v so that (5**index * v) <= 1<<24. | 314 | // Largest integer value v so that (5**index * v) <= 1<<24. | |||||
| 315 | // 0x1000000 == 1<<24 | 315 | // 0x1000000 == 1<<24 | |||||
| 316 | static constexpr uint64_t max_mantissa[] = { | 316 | static constexpr uint64_t max_mantissa[] = { | |||||
| 317 | UINT64_C(0x1000000), | 317 | UINT64_C(0x1000000), | |||||
| 318 | UINT64_C(0x1000000) / UINT64_C(5), | 318 | UINT64_C(0x1000000) / UINT64_C(5), | |||||
| 319 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5)), | 319 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5)), | |||||
| 320 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 320 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 321 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 321 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 322 | UINT64_C(0x1000000) / (constant_55555), | 322 | UINT64_C(0x1000000) / (constant_55555), | |||||
| 323 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5)), | 323 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5)), | |||||
| 324 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), | 324 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), | |||||
| 325 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 325 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 326 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | 326 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), | |||||
| 327 | UINT64_C(0x1000000) / (constant_55555 * constant_55555), | 327 | UINT64_C(0x1000000) / (constant_55555 * constant_55555), | |||||
| 328 | UINT64_C(0x1000000) / (constant_55555 * constant_55555 * UINT64_C(5))}; | 328 | UINT64_C(0x1000000) / (constant_55555 * constant_55555 * UINT64_C(5))}; | |||||
| 329 | }; | 329 | }; | |||||
| 330 | 330 | |||||||
| 331 | template <typename U> | 331 | template <typename U> | |||||
| 332 | constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[]; | 332 | constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[]; | |||||
| 333 | 333 | |||||||
| 334 | template <typename U> | 334 | template <typename U> | |||||
| 335 | constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[]; | 335 | constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[]; | |||||
| 336 | 336 | |||||||
| HITCBC | 337 | 1009310 | template <> inline constexpr int binary_format<double>::min_exponent_fast_path() { | 337 | 1009310 | template <> inline constexpr int binary_format<double>::min_exponent_fast_path() { | ||
| 338 | #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) | 338 | #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) | |||||
| 339 | return 0; | 339 | return 0; | |||||
| 340 | #else | 340 | #else | |||||
| HITCBC | 341 | 1009310 | return -22; | 341 | 1009310 | return -22; | ||
| 342 | #endif | 342 | #endif | |||||
| 343 | } | 343 | } | |||||
| 344 | 344 | |||||||
| 345 | template <> inline constexpr int binary_format<float>::min_exponent_fast_path() { | 345 | template <> inline constexpr int binary_format<float>::min_exponent_fast_path() { | |||||
| 346 | #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) | 346 | #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) | |||||
| 347 | return 0; | 347 | return 0; | |||||
| 348 | #else | 348 | #else | |||||
| 349 | return -10; | 349 | return -10; | |||||
| 350 | #endif | 350 | #endif | |||||
| 351 | } | 351 | } | |||||
| 352 | 352 | |||||||
| HITCBC | 353 | 7032865 | template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() { | 353 | 7032865 | template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() { | ||
| HITCBC | 354 | 7032865 | return 52; | 354 | 7032865 | return 52; | ||
| 355 | } | 355 | } | |||||
| 356 | template <> inline constexpr int binary_format<float>::mantissa_explicit_bits() { | 356 | template <> inline constexpr int binary_format<float>::mantissa_explicit_bits() { | |||||
| 357 | return 23; | 357 | return 23; | |||||
| 358 | } | 358 | } | |||||
| 359 | 359 | |||||||
| HITCBC | 360 | 8893 | template <> inline constexpr int binary_format<double>::max_exponent_round_to_even() { | 360 | 8893 | template <> inline constexpr int binary_format<double>::max_exponent_round_to_even() { | ||
| HITCBC | 361 | 8893 | return 23; | 361 | 8893 | return 23; | ||
| 362 | } | 362 | } | |||||
| 363 | 363 | |||||||
| 364 | template <> inline constexpr int binary_format<float>::max_exponent_round_to_even() { | 364 | template <> inline constexpr int binary_format<float>::max_exponent_round_to_even() { | |||||
| 365 | return 10; | 365 | return 10; | |||||
| 366 | } | 366 | } | |||||
| 367 | 367 | |||||||
| HITCBC | 368 | 9255 | template <> inline constexpr int binary_format<double>::min_exponent_round_to_even() { | 368 | 9255 | template <> inline constexpr int binary_format<double>::min_exponent_round_to_even() { | ||
| HITCBC | 369 | 9255 | return -4; | 369 | 9255 | return -4; | ||
| 370 | } | 370 | } | |||||
| 371 | 371 | |||||||
| 372 | template <> inline constexpr int binary_format<float>::min_exponent_round_to_even() { | 372 | template <> inline constexpr int binary_format<float>::min_exponent_round_to_even() { | |||||
| 373 | return -17; | 373 | return -17; | |||||
| 374 | } | 374 | } | |||||
| 375 | 375 | |||||||
| HITCBC | 376 | 2002893 | template <> inline constexpr int binary_format<double>::minimum_exponent() { | 376 | 2002893 | template <> inline constexpr int binary_format<double>::minimum_exponent() { | ||
| HITCBC | 377 | 2002893 | return -1023; | 377 | 2002893 | return -1023; | ||
| 378 | } | 378 | } | |||||
| 379 | template <> inline constexpr int binary_format<float>::minimum_exponent() { | 379 | template <> inline constexpr int binary_format<float>::minimum_exponent() { | |||||
| 380 | return -127; | 380 | return -127; | |||||
| 381 | } | 381 | } | |||||
| 382 | 382 | |||||||
| HITCBC | 383 | 3072364 | template <> inline constexpr int binary_format<double>::infinite_power() { | 383 | 3072364 | template <> inline constexpr int binary_format<double>::infinite_power() { | ||
| HITCBC | 384 | 3072364 | return 0x7FF; | 384 | 3072364 | return 0x7FF; | ||
| 385 | } | 385 | } | |||||
| 386 | template <> inline constexpr int binary_format<float>::infinite_power() { | 386 | template <> inline constexpr int binary_format<float>::infinite_power() { | |||||
| 387 | return 0xFF; | 387 | return 0xFF; | |||||
| 388 | } | 388 | } | |||||
| 389 | 389 | |||||||
| HITCBC | 390 | 1005351 | template <> inline constexpr int binary_format<double>::sign_index() { return 63; } | 390 | 1005351 | template <> inline constexpr int binary_format<double>::sign_index() { return 63; } | ||
| 391 | template <> inline constexpr int binary_format<float>::sign_index() { return 31; } | 391 | template <> inline constexpr int binary_format<float>::sign_index() { return 31; } | |||||
| 392 | 392 | |||||||
| HITCBC | 393 | 546058 | template <> inline constexpr int binary_format<double>::max_exponent_fast_path() { | 393 | 546058 | template <> inline constexpr int binary_format<double>::max_exponent_fast_path() { | ||
| HITCBC | 394 | 546058 | return 22; | 394 | 546058 | return 22; | ||
| 395 | } | 395 | } | |||||
| 396 | template <> inline constexpr int binary_format<float>::max_exponent_fast_path() { | 396 | template <> inline constexpr int binary_format<float>::max_exponent_fast_path() { | |||||
| 397 | return 10; | 397 | return 10; | |||||
| 398 | } | 398 | } | |||||
| 399 | 399 | |||||||
| HITCBC | 400 | 5895 | template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { | 400 | 5895 | template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { | ||
| HITCBC | 401 | 5895 | return uint64_t(2) << mantissa_explicit_bits(); | 401 | 5895 | return uint64_t(2) << mantissa_explicit_bits(); | ||
| 402 | } | 402 | } | |||||
| MISUBC | 403 | ✗ | template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) { | 403 | ✗ | template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) { | ||
| 404 | // caller is responsible to ensure that | 404 | // caller is responsible to ensure that | |||||
| 405 | // power >= 0 && power <= 22 | 405 | // power >= 0 && power <= 22 | |||||
| 406 | // | 406 | // | |||||
| 407 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | 407 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | |||||
| MISUBC | 408 | ✗ | return (void)max_mantissa[0], max_mantissa[power]; | 408 | ✗ | return (void)max_mantissa[0], max_mantissa[power]; | ||
| 409 | } | 409 | } | |||||
| 410 | template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() { | 410 | template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() { | |||||
| 411 | return uint64_t(2) << mantissa_explicit_bits(); | 411 | return uint64_t(2) << mantissa_explicit_bits(); | |||||
| 412 | } | 412 | } | |||||
| 413 | template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) { | 413 | template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) { | |||||
| 414 | // caller is responsible to ensure that | 414 | // caller is responsible to ensure that | |||||
| 415 | // power >= 0 && power <= 10 | 415 | // power >= 0 && power <= 10 | |||||
| 416 | // | 416 | // | |||||
| 417 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | 417 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | |||||
| 418 | return (void)max_mantissa[0], max_mantissa[power]; | 418 | return (void)max_mantissa[0], max_mantissa[power]; | |||||
| 419 | } | 419 | } | |||||
| 420 | 420 | |||||||
| 421 | template <> | 421 | template <> | |||||
| HITCBC | 422 | 5570 | inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) { | 422 | 5570 | inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) { | ||
| 423 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | 423 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | |||||
| HITCBC | 424 | 5570 | return (void)powers_of_ten[0], powers_of_ten[power]; | 424 | 5570 | return (void)powers_of_ten[0], powers_of_ten[power]; | ||
| 425 | } | 425 | } | |||||
| 426 | template <> | 426 | template <> | |||||
| 427 | inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) { | 427 | inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) { | |||||
| 428 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | 428 | // Work around clang bug https://godbolt.org/z/zedh7rrhc | |||||
| 429 | return (void)powers_of_ten[0], powers_of_ten[power]; | 429 | return (void)powers_of_ten[0], powers_of_ten[power]; | |||||
| 430 | } | 430 | } | |||||
| 431 | 431 | |||||||
| 432 | 432 | |||||||
| 433 | template <> | 433 | template <> | |||||
| HITCBC | 434 | 2004451 | inline constexpr int binary_format<double>::largest_power_of_ten() { | 434 | 2004451 | inline constexpr int binary_format<double>::largest_power_of_ten() { | ||
| HITCBC | 435 | 2004451 | return 308; | 435 | 2004451 | return 308; | ||
| 436 | } | 436 | } | |||||
| 437 | template <> | 437 | template <> | |||||
| 438 | inline constexpr int binary_format<float>::largest_power_of_ten() { | 438 | inline constexpr int binary_format<float>::largest_power_of_ten() { | |||||
| 439 | return 38; | 439 | return 38; | |||||
| 440 | } | 440 | } | |||||
| 441 | 441 | |||||||
| 442 | template <> | 442 | template <> | |||||
| HITCBC | 443 | 2004451 | inline constexpr int binary_format<double>::smallest_power_of_ten() { | 443 | 2004451 | inline constexpr int binary_format<double>::smallest_power_of_ten() { | ||
| HITCBC | 444 | 2004451 | return -342; | 444 | 2004451 | return -342; | ||
| 445 | } | 445 | } | |||||
| 446 | template <> | 446 | template <> | |||||
| 447 | inline constexpr int binary_format<float>::smallest_power_of_ten() { | 447 | inline constexpr int binary_format<float>::smallest_power_of_ten() { | |||||
| 448 | return -65; | 448 | return -65; | |||||
| 449 | } | 449 | } | |||||
| 450 | 450 | |||||||
| 451 | template <> inline constexpr size_t binary_format<double>::max_digits() { | 451 | template <> inline constexpr size_t binary_format<double>::max_digits() { | |||||
| 452 | return 769; | 452 | return 769; | |||||
| 453 | } | 453 | } | |||||
| 454 | template <> inline constexpr size_t binary_format<float>::max_digits() { | 454 | template <> inline constexpr size_t binary_format<float>::max_digits() { | |||||
| 455 | return 114; | 455 | return 114; | |||||
| 456 | } | 456 | } | |||||
| 457 | 457 | |||||||
| 458 | template <> inline constexpr binary_format<float>::equiv_uint | 458 | template <> inline constexpr binary_format<float>::equiv_uint | |||||
| 459 | binary_format<float>::exponent_mask() { | 459 | binary_format<float>::exponent_mask() { | |||||
| 460 | return 0x7F800000; | 460 | return 0x7F800000; | |||||
| 461 | } | 461 | } | |||||
| 462 | template <> inline constexpr binary_format<double>::equiv_uint | 462 | template <> inline constexpr binary_format<double>::equiv_uint | |||||
| 463 | binary_format<double>::exponent_mask() { | 463 | binary_format<double>::exponent_mask() { | |||||
| 464 | return 0x7FF0000000000000; | 464 | return 0x7FF0000000000000; | |||||
| 465 | } | 465 | } | |||||
| 466 | 466 | |||||||
| 467 | template <> inline constexpr binary_format<float>::equiv_uint | 467 | template <> inline constexpr binary_format<float>::equiv_uint | |||||
| 468 | binary_format<float>::mantissa_mask() { | 468 | binary_format<float>::mantissa_mask() { | |||||
| 469 | return 0x007FFFFF; | 469 | return 0x007FFFFF; | |||||
| 470 | } | 470 | } | |||||
| 471 | template <> inline constexpr binary_format<double>::equiv_uint | 471 | template <> inline constexpr binary_format<double>::equiv_uint | |||||
| 472 | binary_format<double>::mantissa_mask() { | 472 | binary_format<double>::mantissa_mask() { | |||||
| 473 | return 0x000FFFFFFFFFFFFF; | 473 | return 0x000FFFFFFFFFFFFF; | |||||
| 474 | } | 474 | } | |||||
| 475 | 475 | |||||||
| 476 | template <> inline constexpr binary_format<float>::equiv_uint | 476 | template <> inline constexpr binary_format<float>::equiv_uint | |||||
| 477 | binary_format<float>::hidden_bit_mask() { | 477 | binary_format<float>::hidden_bit_mask() { | |||||
| 478 | return 0x00800000; | 478 | return 0x00800000; | |||||
| 479 | } | 479 | } | |||||
| 480 | template <> inline constexpr binary_format<double>::equiv_uint | 480 | template <> inline constexpr binary_format<double>::equiv_uint | |||||
| 481 | binary_format<double>::hidden_bit_mask() { | 481 | binary_format<double>::hidden_bit_mask() { | |||||
| 482 | return 0x0010000000000000; | 482 | return 0x0010000000000000; | |||||
| 483 | } | 483 | } | |||||
| 484 | 484 | |||||||
| 485 | template<typename T> | 485 | template<typename T> | |||||
| 486 | BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 | 486 | BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 | |||||
| 487 | void to_float(bool negative, adjusted_mantissa am, T &value) { | 487 | void to_float(bool negative, adjusted_mantissa am, T &value) { | |||||
| 488 | using uint = typename binary_format<T>::equiv_uint; | 488 | using uint = typename binary_format<T>::equiv_uint; | |||||
| HITCBC | 489 | 1005351 | uint word = (uint)am.mantissa; | 489 | 1005351 | uint word = (uint)am.mantissa; | ||
| HITCBC | 490 | 1005351 | word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits(); | 490 | 1005351 | word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits(); | ||
| HITCBC | 491 | 1005351 | word |= uint(negative) << binary_format<T>::sign_index(); | 491 | 1005351 | word |= uint(negative) << binary_format<T>::sign_index(); | ||
| 492 | #ifdef BOOST_JSON_HAS_BIT_CAST | 492 | #ifdef BOOST_JSON_HAS_BIT_CAST | |||||
| 493 | value = std::bit_cast<T>(word); | 493 | value = std::bit_cast<T>(word); | |||||
| 494 | #else | 494 | #else | |||||
| HITCBC | 495 | 1005351 | ::memcpy(&value, &word, sizeof(T)); | 495 | 1005351 | ::memcpy(&value, &word, sizeof(T)); | ||
| 496 | #endif | 496 | #endif | |||||
| HITCBC | 497 | 1005351 | } | 497 | 1005351 | } | ||
| 498 | 498 | |||||||
| 499 | template<typename UC> | 499 | template<typename UC> | |||||
| HITCBC | 500 | 2986 | static constexpr uint64_t int_cmp_zeros() | 500 | 2986 | static constexpr uint64_t int_cmp_zeros() | ||
| 501 | { | 501 | { | |||||
| 502 | static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size"); | 502 | static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size"); | |||||
| HITCBC | 503 | 2986 | 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')); | 503 | 2986 | 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')); | ||
| 504 | } | 504 | } | |||||
| 505 | template<typename UC> | 505 | template<typename UC> | |||||
| HITCBC | 506 | 2986 | static constexpr int int_cmp_len() | 506 | 2986 | static constexpr int int_cmp_len() | ||
| 507 | { | 507 | { | |||||
| HITCBC | 508 | 2986 | return sizeof(uint64_t) / sizeof(UC); | 508 | 2986 | return sizeof(uint64_t) / sizeof(UC); | ||
| 509 | } | 509 | } | |||||
| 510 | template<typename UC> | 510 | template<typename UC> | |||||
| 511 | static constexpr UC const * str_const_nan() | 511 | static constexpr UC const * str_const_nan() | |||||
| 512 | { | 512 | { | |||||
| 513 | return nullptr; | 513 | return nullptr; | |||||
| 514 | } | 514 | } | |||||
| 515 | template<> | 515 | template<> | |||||
| MISUBC | 516 | ✗ | constexpr char const * str_const_nan<char>() | 516 | ✗ | constexpr char const * str_const_nan<char>() | ||
| 517 | { | 517 | { | |||||
| MISUBC | 518 | ✗ | return "nan"; | 518 | ✗ | return "nan"; | ||
| 519 | } | 519 | } | |||||
| 520 | template<> | 520 | template<> | |||||
| 521 | constexpr wchar_t const * str_const_nan<wchar_t>() | 521 | constexpr wchar_t const * str_const_nan<wchar_t>() | |||||
| 522 | { | 522 | { | |||||
| 523 | return L"nan"; | 523 | return L"nan"; | |||||
| 524 | } | 524 | } | |||||
| 525 | template<> | 525 | template<> | |||||
| 526 | constexpr char16_t const * str_const_nan<char16_t>() | 526 | constexpr char16_t const * str_const_nan<char16_t>() | |||||
| 527 | { | 527 | { | |||||
| 528 | return u"nan"; | 528 | return u"nan"; | |||||
| 529 | } | 529 | } | |||||
| 530 | template<> | 530 | template<> | |||||
| 531 | constexpr char32_t const * str_const_nan<char32_t>() | 531 | constexpr char32_t const * str_const_nan<char32_t>() | |||||
| 532 | { | 532 | { | |||||
| 533 | return U"nan"; | 533 | return U"nan"; | |||||
| 534 | } | 534 | } | |||||
| 535 | template<typename UC> | 535 | template<typename UC> | |||||
| 536 | static constexpr UC const * str_const_inf() | 536 | static constexpr UC const * str_const_inf() | |||||
| 537 | { | 537 | { | |||||
| 538 | return nullptr; | 538 | return nullptr; | |||||
| 539 | } | 539 | } | |||||
| 540 | template<> | 540 | template<> | |||||
| MISUBC | 541 | ✗ | constexpr char const * str_const_inf<char>() | 541 | ✗ | constexpr char const * str_const_inf<char>() | ||
| 542 | { | 542 | { | |||||
| MISUBC | 543 | ✗ | return "infinity"; | 543 | ✗ | return "infinity"; | ||
| 544 | } | 544 | } | |||||
| 545 | template<> | 545 | template<> | |||||
| 546 | constexpr wchar_t const * str_const_inf<wchar_t>() | 546 | constexpr wchar_t const * str_const_inf<wchar_t>() | |||||
| 547 | { | 547 | { | |||||
| 548 | return L"infinity"; | 548 | return L"infinity"; | |||||
| 549 | } | 549 | } | |||||
| 550 | template<> | 550 | template<> | |||||
| 551 | constexpr char16_t const * str_const_inf<char16_t>() | 551 | constexpr char16_t const * str_const_inf<char16_t>() | |||||
| 552 | { | 552 | { | |||||
| 553 | return u"infinity"; | 553 | return u"infinity"; | |||||
| 554 | } | 554 | } | |||||
| 555 | template<> | 555 | template<> | |||||
| 556 | constexpr char32_t const * str_const_inf<char32_t>() | 556 | constexpr char32_t const * str_const_inf<char32_t>() | |||||
| 557 | { | 557 | { | |||||
| 558 | return U"infinity"; | 558 | return U"infinity"; | |||||
| 559 | } | 559 | } | |||||
| 560 | 560 | |||||||
| 561 | }}}}}} // namespaces | 561 | }}}}}} // namespaces | |||||
| 562 | 562 | |||||||
| 563 | #endif | 563 | #endif | |||||