| 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_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP |
| 9 | #define BOOST_CHARCONV_DETAIL_FASTFLOAT_FLOAT_COMMON_HPP |
| 10 | |
| 11 | #include <boost/charconv/detail/fast_float/constexpr_feature_detect.hpp> |
| 12 | #include <boost/charconv/detail/from_chars_result.hpp> |
| 13 | #include <boost/charconv/detail/config.hpp> |
| 14 | #include <boost/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 charconv { namespace detail { namespace fast_float { |
| 23 | |
| 24 | |
| 25 | template <typename UC> |
| 26 | struct parse_options_t { |
| 27 | constexpr explicit parse_options_t(chars_format fmt = chars_format::general, |
| 28 | UC dot = UC('.')) |
| 29 | : 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 | #if BOOST_CHARCONV_FASTFLOAT_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_CHARCONV_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_CHARCONV_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_CHARCONV_FASTFLOAT_32BIT 1 |
| 62 | #elif SIZE_MAX == 0xffffffffffffffff |
| 63 | #define BOOST_CHARCONV_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_CHARCONV_FASTFLOAT_VISUAL_STUDIO 1 |
| 75 | #endif |
| 76 | |
| 77 | #if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ |
| 78 | #define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
| 79 | #elif defined _WIN32 |
| 80 | #define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 |
| 81 | #else |
| 82 | #if defined(__APPLE__) || defined(__FreeBSD__) |
| 83 | #include <machine/endian.h> |
| 84 | #elif defined(sun) || defined(__sun) |
| 85 | #include <sys/byteorder.h> |
| 86 | #else |
| 87 | #ifdef __has_include |
| 88 | #if __has_include(<endian.h>) |
| 89 | #include <endian.h> |
| 90 | #endif //__has_include(<endian.h>) |
| 91 | #endif //__has_include |
| 92 | #endif |
| 93 | # |
| 94 | #ifndef __BYTE_ORDER__ |
| 95 | // safe choice |
| 96 | #define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 |
| 97 | #endif |
| 98 | # |
| 99 | #ifndef __ORDER_LITTLE_ENDIAN__ |
| 100 | // safe choice |
| 101 | #define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 |
| 102 | #endif |
| 103 | # |
| 104 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| 105 | #define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 0 |
| 106 | #else |
| 107 | #define BOOST_CHARCONV_FASTFLOAT_IS_BIG_ENDIAN 1 |
| 108 | #endif |
| 109 | #endif |
| 110 | |
| 111 | #ifndef BOOST_CHARCONV_FASTFLOAT_ASSERT |
| 112 | #define BOOST_CHARCONV_FASTFLOAT_ASSERT(x) { ((void)(x)); } |
| 113 | #endif |
| 114 | |
| 115 | #ifndef BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT |
| 116 | #define BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(x) { ((void)(x)); } |
| 117 | #endif |
| 118 | |
| 119 | // rust style `try!()` macro, or `?` operator |
| 120 | #define BOOST_CHARCONV_FASTFLOAT_TRY(x) { if (!(x)) return false; } |
| 121 | |
| 122 | namespace boost { namespace charconv { namespace detail { namespace fast_float { |
| 123 | |
| 124 | BOOST_FORCEINLINE constexpr bool cpp20_and_in_constexpr() { |
| 125 | #if BOOST_CHARCONV_FASTFLOAT_HAS_IS_CONSTANT_EVALUATED |
| 126 | return std::is_constant_evaluated(); |
| 127 | #else |
| 128 | return false; |
| 129 | #endif |
| 130 | } |
| 131 | |
| 132 | // Compares two ASCII strings in a case insensitive manner. |
| 133 | template <typename UC> |
| 134 | inline BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 bool |
| 135 | fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) { |
| 136 | char running_diff{0}; |
| 137 | for (size_t i = 0; i < length; ++i) { |
| 138 | running_diff |= (char(input1[i]) ^ char(input2[i])); |
| 139 | } |
| 140 | return (running_diff == 0) || (running_diff == 32); |
| 141 | } |
| 142 | |
| 143 | #ifndef FLT_EVAL_METHOD |
| 144 | #error "FLT_EVAL_METHOD should be defined, please include cfloat." |
| 145 | #endif |
| 146 | |
| 147 | // a pointer and a length to a contiguous block of memory |
| 148 | template <typename T> |
| 149 | struct span { |
| 150 | const T* ptr; |
| 151 | size_t length; |
| 152 | constexpr span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {} |
| 153 | constexpr span() : ptr(nullptr), length(0) {} |
| 154 | |
| 155 | constexpr size_t len() const noexcept { |
| 156 | return length; |
| 157 | } |
| 158 | |
| 159 | BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 const T& operator[](size_t index) const noexcept { |
| 160 | BOOST_CHARCONV_FASTFLOAT_DEBUG_ASSERT(index < length); |
| 161 | return ptr[index]; |
| 162 | } |
| 163 | }; |
| 164 | |
| 165 | struct value128 { |
| 166 | uint64_t low; |
| 167 | uint64_t high; |
| 168 | constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} |
| 169 | constexpr value128() : low(0), high(0) {} |
| 170 | }; |
| 171 | |
| 172 | /* Helper C++11 constexpr generic implementation of leading_zeroes */ |
| 173 | BOOST_FORCEINLINE constexpr |
| 174 | int leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { |
| 175 | return ( |
| 176 | ((input_num & uint64_t(0xffffffff00000000)) && (input_num >>= 32, last_bit |= 32)), |
| 177 | ((input_num & uint64_t( 0xffff0000)) && (input_num >>= 16, last_bit |= 16)), |
| 178 | ((input_num & uint64_t( 0xff00)) && (input_num >>= 8, last_bit |= 8)), |
| 179 | ((input_num & uint64_t( 0xf0)) && (input_num >>= 4, last_bit |= 4)), |
| 180 | ((input_num & uint64_t( 0xc)) && (input_num >>= 2, last_bit |= 2)), |
| 181 | ((input_num & uint64_t( 0x2)) && (input_num >>= 1, last_bit |= 1)), |
| 182 | 63 - last_bit |
| 183 | ); |
| 184 | } |
| 185 | |
| 186 | /* result might be undefined when input_num is zero */ |
| 187 | BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 |
| 188 | int leading_zeroes(uint64_t input_num) { |
| 189 | assert(input_num > 0); |
| 190 | if (cpp20_and_in_constexpr()) { |
| 191 | return leading_zeroes_generic(input_num); |
| 192 | } |
| 193 | #ifdef BOOST_CHARCONV_FASTFLOAT_VISUAL_STUDIO |
| 194 | #if defined(_M_X64) || defined(_M_ARM64) |
| 195 | unsigned long leading_zero = 0; |
| 196 | // Search the mask data from most significant bit (MSB) |
| 197 | // to least significant bit (LSB) for a set bit (1). |
| 198 | _BitScanReverse64(&leading_zero, input_num); |
| 199 | return (int)(63 - leading_zero); |
| 200 | #else |
| 201 | return leading_zeroes_generic(input_num); |
| 202 | #endif |
| 203 | #else |
| 204 | return __builtin_clzll(input_num); |
| 205 | #endif |
| 206 | } |
| 207 | |
| 208 | // slow emulation routine for 32-bit |
| 209 | BOOST_FORCEINLINE constexpr uint64_t emulu(uint32_t x, uint32_t y) { |
| 210 | return x * static_cast<uint64_t>(y); |
| 211 | } |
| 212 | |
| 213 | BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 |
| 214 | uint64_t umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { |
| 215 | uint64_t ad = emulu(x: static_cast<uint32_t>(ab >> 32), y: static_cast<uint32_t>(cd)); |
| 216 | uint64_t bd = emulu(x: static_cast<uint32_t>(ab), y: static_cast<uint32_t>(cd)); |
| 217 | uint64_t adbc = ad + emulu(x: static_cast<uint32_t>(ab), y: static_cast<uint32_t>(cd >> 32)); |
| 218 | uint64_t adbc_carry = !!(adbc < ad); |
| 219 | uint64_t lo = bd + (adbc << 32); |
| 220 | *hi = emulu(x: static_cast<uint32_t>(ab >> 32), y: static_cast<uint32_t>(cd >> 32)) + (adbc >> 32) + |
| 221 | (adbc_carry << 32) + !!(lo < bd); |
| 222 | return lo; |
| 223 | } |
| 224 | |
| 225 | #ifdef BOOST_CHARCONV_FASTFLOAT_32BIT |
| 226 | |
| 227 | // slow emulation routine for 32-bit |
| 228 | #if !defined(__MINGW64__) |
| 229 | BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR14 |
| 230 | uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) { |
| 231 | return umul128_generic(ab, cd, hi); |
| 232 | } |
| 233 | #endif // !__MINGW64__ |
| 234 | |
| 235 | #endif // BOOST_CHARCONV_FASTFLOAT_32BIT |
| 236 | |
| 237 | |
| 238 | // compute 64-bit a*b |
| 239 | BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 |
| 240 | value128 full_multiplication(uint64_t a, uint64_t b) { |
| 241 | if (cpp20_and_in_constexpr()) { |
| 242 | value128 answer; |
| 243 | answer.low = umul128_generic(ab: a, cd: b, hi: &answer.high); |
| 244 | return answer; |
| 245 | } |
| 246 | value128 answer; |
| 247 | #if defined(_M_ARM64) && !defined(__MINGW32__) |
| 248 | // ARM64 has native support for 64-bit multiplications, no need to emulate |
| 249 | // But MinGW on ARM64 doesn't have native support for 64-bit multiplications |
| 250 | answer.high = __umulh(a, b); |
| 251 | answer.low = a * b; |
| 252 | #elif defined(BOOST_CHARCONV_FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__)) |
| 253 | unsigned long long high; |
| 254 | answer.low = _umul128(a, b, &high); // _umul128 not available on ARM64 |
| 255 | answer.high = static_cast<uint64_t>(high); |
| 256 | #elif defined(BOOST_CHARCONV_FASTFLOAT_64BIT) |
| 257 | __uint128_t r = (static_cast<__uint128_t>(a)) * b; |
| 258 | answer.low = uint64_t(r); |
| 259 | answer.high = uint64_t(r >> 64); |
| 260 | #else |
| 261 | answer.low = umul128_generic(a, b, &answer.high); |
| 262 | #endif |
| 263 | return answer; |
| 264 | } |
| 265 | |
| 266 | struct adjusted_mantissa { |
| 267 | uint64_t mantissa{0}; |
| 268 | int32_t power2{0}; // a negative value indicates an invalid result |
| 269 | adjusted_mantissa() = default; |
| 270 | constexpr bool operator==(const adjusted_mantissa &o) const { |
| 271 | return mantissa == o.mantissa && power2 == o.power2; |
| 272 | } |
| 273 | constexpr bool operator!=(const adjusted_mantissa &o) const { |
| 274 | return mantissa != o.mantissa || power2 != o.power2; |
| 275 | } |
| 276 | }; |
| 277 | |
| 278 | // Bias so we can get the real exponent with an invalid adjusted_mantissa. |
| 279 | constexpr static int32_t invalid_am_bias = -0x8000; |
| 280 | |
| 281 | // used for binary_format_lookup_tables<T>::max_mantissa |
| 282 | constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; |
| 283 | |
| 284 | template <typename T, typename U = void> |
| 285 | struct binary_format_lookup_tables; |
| 286 | |
| 287 | template <typename T> struct binary_format : binary_format_lookup_tables<T> { |
| 288 | using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type; |
| 289 | |
| 290 | static inline constexpr int mantissa_explicit_bits(); |
| 291 | static inline constexpr int minimum_exponent(); |
| 292 | static inline constexpr int infinite_power(); |
| 293 | static inline constexpr int sign_index(); |
| 294 | static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST |
| 295 | static inline constexpr int max_exponent_fast_path(); |
| 296 | static inline constexpr int max_exponent_round_to_even(); |
| 297 | static inline constexpr int min_exponent_round_to_even(); |
| 298 | static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); |
| 299 | static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST |
| 300 | static inline constexpr int largest_power_of_ten(); |
| 301 | static inline constexpr int smallest_power_of_ten(); |
| 302 | static inline constexpr T exact_power_of_ten(int64_t power); |
| 303 | static inline constexpr size_t max_digits(); |
| 304 | static inline constexpr equiv_uint exponent_mask(); |
| 305 | static inline constexpr equiv_uint mantissa_mask(); |
| 306 | static inline constexpr equiv_uint hidden_bit_mask(); |
| 307 | }; |
| 308 | |
| 309 | template <typename U> |
| 310 | struct binary_format_lookup_tables<double, U> { |
| 311 | static constexpr double powers_of_ten[] = { |
| 312 | 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, |
| 313 | 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; |
| 314 | |
| 315 | // Largest integer value v so that (5**index * v) <= 1<<53. |
| 316 | // 0x10000000000000 == 1 << 53 |
| 317 | static constexpr std::uint64_t max_mantissa[] = { |
| 318 | UINT64_C(0x10000000000000), |
| 319 | UINT64_C(0x10000000000000) / UINT64_C(5), |
| 320 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5)), |
| 321 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 322 | UINT64_C(0x10000000000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 323 | UINT64_C(0x10000000000000) / (constant_55555), |
| 324 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5)), |
| 325 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), |
| 326 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 327 | UINT64_C(0x10000000000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 328 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555), |
| 329 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5)), |
| 330 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), |
| 331 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 332 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555), |
| 333 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), |
| 334 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), |
| 335 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 336 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 337 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555), |
| 338 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5)), |
| 339 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5)), |
| 340 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 341 | UINT64_C(0x10000000000000) / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5))}; |
| 342 | }; |
| 343 | |
| 344 | template <typename U> |
| 345 | constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[]; |
| 346 | |
| 347 | template <typename U> |
| 348 | constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[]; |
| 349 | |
| 350 | template <typename U> |
| 351 | struct binary_format_lookup_tables<float, U> { |
| 352 | static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, |
| 353 | 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; |
| 354 | |
| 355 | // Largest integer value v so that (5**index * v) <= 1<<24. |
| 356 | // 0x1000000 == 1<<24 |
| 357 | static constexpr uint64_t max_mantissa[] = { |
| 358 | UINT64_C(0x1000000), |
| 359 | UINT64_C(0x1000000) / UINT64_C(5), |
| 360 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5)), |
| 361 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 362 | UINT64_C(0x1000000) / (UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 363 | UINT64_C(0x1000000) / (constant_55555), |
| 364 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5)), |
| 365 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5)), |
| 366 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 367 | UINT64_C(0x1000000) / (constant_55555 * UINT64_C(5) * UINT64_C(5) * UINT64_C(5) * UINT64_C(5)), |
| 368 | UINT64_C(0x1000000) / (constant_55555 * constant_55555), |
| 369 | UINT64_C(0x1000000) / (constant_55555 * constant_55555 * UINT64_C(5))}; |
| 370 | }; |
| 371 | |
| 372 | template <typename U> |
| 373 | constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[]; |
| 374 | |
| 375 | template <typename U> |
| 376 | constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[]; |
| 377 | |
| 378 | template <> inline constexpr int binary_format<double>::min_exponent_fast_path() { |
| 379 | #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) |
| 380 | return 0; |
| 381 | #else |
| 382 | return -22; |
| 383 | #endif |
| 384 | } |
| 385 | |
| 386 | template <> inline constexpr int binary_format<float>::min_exponent_fast_path() { |
| 387 | #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) |
| 388 | return 0; |
| 389 | #else |
| 390 | return -10; |
| 391 | #endif |
| 392 | } |
| 393 | |
| 394 | template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() { |
| 395 | return 52; |
| 396 | } |
| 397 | template <> inline constexpr int binary_format<float>::mantissa_explicit_bits() { |
| 398 | return 23; |
| 399 | } |
| 400 | |
| 401 | template <> inline constexpr int binary_format<double>::max_exponent_round_to_even() { |
| 402 | return 23; |
| 403 | } |
| 404 | |
| 405 | template <> inline constexpr int binary_format<float>::max_exponent_round_to_even() { |
| 406 | return 10; |
| 407 | } |
| 408 | |
| 409 | template <> inline constexpr int binary_format<double>::min_exponent_round_to_even() { |
| 410 | return -4; |
| 411 | } |
| 412 | |
| 413 | template <> inline constexpr int binary_format<float>::min_exponent_round_to_even() { |
| 414 | return -17; |
| 415 | } |
| 416 | |
| 417 | template <> inline constexpr int binary_format<double>::minimum_exponent() { |
| 418 | return -1023; |
| 419 | } |
| 420 | template <> inline constexpr int binary_format<float>::minimum_exponent() { |
| 421 | return -127; |
| 422 | } |
| 423 | |
| 424 | template <> inline constexpr int binary_format<double>::infinite_power() { |
| 425 | return 0x7FF; |
| 426 | } |
| 427 | template <> inline constexpr int binary_format<float>::infinite_power() { |
| 428 | return 0xFF; |
| 429 | } |
| 430 | |
| 431 | template <> inline constexpr int binary_format<double>::sign_index() { return 63; } |
| 432 | template <> inline constexpr int binary_format<float>::sign_index() { return 31; } |
| 433 | |
| 434 | template <> inline constexpr int binary_format<double>::max_exponent_fast_path() { |
| 435 | return 22; |
| 436 | } |
| 437 | template <> inline constexpr int binary_format<float>::max_exponent_fast_path() { |
| 438 | return 10; |
| 439 | } |
| 440 | |
| 441 | template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { |
| 442 | return uint64_t(2) << mantissa_explicit_bits(); |
| 443 | } |
| 444 | template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) { |
| 445 | // caller is responsible to ensure that |
| 446 | // power >= 0 && power <= 22 |
| 447 | // |
| 448 | // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| 449 | return (void)max_mantissa[0], max_mantissa[power]; |
| 450 | } |
| 451 | template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() { |
| 452 | return uint64_t(2) << mantissa_explicit_bits(); |
| 453 | } |
| 454 | template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) { |
| 455 | // caller is responsible to ensure that |
| 456 | // power >= 0 && power <= 10 |
| 457 | // |
| 458 | // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| 459 | return (void)max_mantissa[0], max_mantissa[power]; |
| 460 | } |
| 461 | |
| 462 | template <> |
| 463 | inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) { |
| 464 | // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| 465 | return (void)powers_of_ten[0], powers_of_ten[power]; |
| 466 | } |
| 467 | template <> |
| 468 | inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) { |
| 469 | // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| 470 | return (void)powers_of_ten[0], powers_of_ten[power]; |
| 471 | } |
| 472 | |
| 473 | |
| 474 | template <> |
| 475 | inline constexpr int binary_format<double>::largest_power_of_ten() { |
| 476 | return 308; |
| 477 | } |
| 478 | template <> |
| 479 | inline constexpr int binary_format<float>::largest_power_of_ten() { |
| 480 | return 38; |
| 481 | } |
| 482 | |
| 483 | template <> |
| 484 | inline constexpr int binary_format<double>::smallest_power_of_ten() { |
| 485 | return -342; |
| 486 | } |
| 487 | template <> |
| 488 | inline constexpr int binary_format<float>::smallest_power_of_ten() { |
| 489 | return -65; |
| 490 | } |
| 491 | |
| 492 | template <> inline constexpr size_t binary_format<double>::max_digits() { |
| 493 | return 769; |
| 494 | } |
| 495 | template <> inline constexpr size_t binary_format<float>::max_digits() { |
| 496 | return 114; |
| 497 | } |
| 498 | |
| 499 | template <> inline constexpr binary_format<float>::equiv_uint |
| 500 | binary_format<float>::exponent_mask() { |
| 501 | return 0x7F800000; |
| 502 | } |
| 503 | template <> inline constexpr binary_format<double>::equiv_uint |
| 504 | binary_format<double>::exponent_mask() { |
| 505 | return 0x7FF0000000000000; |
| 506 | } |
| 507 | |
| 508 | template <> inline constexpr binary_format<float>::equiv_uint |
| 509 | binary_format<float>::mantissa_mask() { |
| 510 | return 0x007FFFFF; |
| 511 | } |
| 512 | template <> inline constexpr binary_format<double>::equiv_uint |
| 513 | binary_format<double>::mantissa_mask() { |
| 514 | return 0x000FFFFFFFFFFFFF; |
| 515 | } |
| 516 | |
| 517 | template <> inline constexpr binary_format<float>::equiv_uint |
| 518 | binary_format<float>::hidden_bit_mask() { |
| 519 | return 0x00800000; |
| 520 | } |
| 521 | template <> inline constexpr binary_format<double>::equiv_uint |
| 522 | binary_format<double>::hidden_bit_mask() { |
| 523 | return 0x0010000000000000; |
| 524 | } |
| 525 | |
| 526 | template<typename T> |
| 527 | BOOST_FORCEINLINE BOOST_CHARCONV_FASTFLOAT_CONSTEXPR20 |
| 528 | void to_float(bool negative, adjusted_mantissa am, T &value) { |
| 529 | using uint = typename binary_format<T>::equiv_uint; |
| 530 | uint word = static_cast<uint>(am.mantissa); |
| 531 | word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits(); |
| 532 | word |= uint(negative) << binary_format<T>::sign_index(); |
| 533 | #if BOOST_CHARCONV_FASTFLOAT_HAS_BIT_CAST |
| 534 | value = std::bit_cast<T>(word); |
| 535 | #else |
| 536 | ::memcpy(dest: &value, src: &word, n: sizeof(T)); |
| 537 | #endif |
| 538 | } |
| 539 | |
| 540 | #ifdef BOOST_CHARCONV_FASTFLOAT_SKIP_WHITE_SPACE // disabled by default |
| 541 | template <typename = void> |
| 542 | struct space_lut { |
| 543 | static constexpr bool value[] = { |
| 544 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 545 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 546 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 547 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 548 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 549 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 550 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 551 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 552 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 553 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 554 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| 555 | }; |
| 556 | |
| 557 | template <typename T> |
| 558 | constexpr bool space_lut<T>::value[]; |
| 559 | |
| 560 | inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; } |
| 561 | #endif |
| 562 | |
| 563 | template<typename UC> |
| 564 | static constexpr uint64_t int_cmp_zeros() |
| 565 | { |
| 566 | static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size" ); |
| 567 | 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')); |
| 568 | } |
| 569 | template<typename UC> |
| 570 | static constexpr int int_cmp_len() |
| 571 | { |
| 572 | return sizeof(uint64_t) / sizeof(UC); |
| 573 | } |
| 574 | template<typename UC> |
| 575 | static constexpr UC const * str_const_nan() |
| 576 | { |
| 577 | return nullptr; |
| 578 | } |
| 579 | template<> |
| 580 | constexpr char const * str_const_nan<char>() |
| 581 | { |
| 582 | return "nan" ; |
| 583 | } |
| 584 | template<> |
| 585 | constexpr wchar_t const * str_const_nan<wchar_t>() |
| 586 | { |
| 587 | return L"nan" ; |
| 588 | } |
| 589 | template<> |
| 590 | constexpr char16_t const * str_const_nan<char16_t>() |
| 591 | { |
| 592 | return u"nan" ; |
| 593 | } |
| 594 | template<> |
| 595 | constexpr char32_t const * str_const_nan<char32_t>() |
| 596 | { |
| 597 | return U"nan" ; |
| 598 | } |
| 599 | template<typename UC> |
| 600 | static constexpr UC const * str_const_inf() |
| 601 | { |
| 602 | return nullptr; |
| 603 | } |
| 604 | template<> |
| 605 | constexpr char const * str_const_inf<char>() |
| 606 | { |
| 607 | return "infinity" ; |
| 608 | } |
| 609 | template<> |
| 610 | constexpr wchar_t const * str_const_inf<wchar_t>() |
| 611 | { |
| 612 | return L"infinity" ; |
| 613 | } |
| 614 | template<> |
| 615 | constexpr char16_t const * str_const_inf<char16_t>() |
| 616 | { |
| 617 | return u"infinity" ; |
| 618 | } |
| 619 | template<> |
| 620 | constexpr char32_t const * str_const_inf<char32_t>() |
| 621 | { |
| 622 | return U"infinity" ; |
| 623 | } |
| 624 | |
| 625 | }}}} // namespaces |
| 626 | |
| 627 | #endif |
| 628 | |