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