| #ifndef FASTFLOAT_FLOAT_COMMON_H |
| #define FASTFLOAT_FLOAT_COMMON_H |
| |
| #include <cfloat> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cassert> |
| #include <cstring> |
| #include <limits> |
| #include <type_traits> |
| #include <system_error> |
| #ifdef __has_include |
| #if __has_include(<stdfloat>) && (__cplusplus > 202002L || (defined(_MSVC_LANG) && (_MSVC_LANG > 202002L))) |
| #include <stdfloat> |
| #endif |
| #endif |
| #include "constexpr_feature_detect.h" |
| |
| #define FASTFLOAT_VERSION_MAJOR 8 |
| #define FASTFLOAT_VERSION_MINOR 2 |
| #define FASTFLOAT_VERSION_PATCH 6 |
| |
| #define FASTFLOAT_STRINGIZE_IMPL(x) #x |
| #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) |
| |
| #define FASTFLOAT_VERSION_STR \ |
| FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MAJOR) \ |
| "." FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MINOR) "." FASTFLOAT_STRINGIZE( \ |
| FASTFLOAT_VERSION_PATCH) |
| |
| #define FASTFLOAT_VERSION \ |
| (FASTFLOAT_VERSION_MAJOR * 10000 + FASTFLOAT_VERSION_MINOR * 100 + \ |
| FASTFLOAT_VERSION_PATCH) |
| |
| namespace fast_float { |
| |
| enum class chars_format : uint64_t; |
| |
| namespace detail { |
| constexpr chars_format basic_json_fmt = chars_format(1 << 5); |
| constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); |
| } // namespace detail |
| |
| enum class chars_format : uint64_t { |
| scientific = 1 << 0, |
| fixed = 1 << 2, |
| hex = 1 << 3, |
| no_infnan = 1 << 4, |
| // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 |
| json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan, |
| // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. |
| json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific, |
| fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific, |
| general = fixed | scientific, |
| allow_leading_plus = 1 << 7, |
| skip_white_space = 1 << 8, |
| }; |
| |
| template <typename UC> struct from_chars_result_t { |
| UC const *ptr; |
| std::errc ec; |
| |
| // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2497r0.html |
| constexpr explicit operator bool() const noexcept { |
| return ec == std::errc(); |
| } |
| }; |
| |
| using from_chars_result = from_chars_result_t<char>; |
| |
| template <typename UC> struct parse_options_t { |
| constexpr explicit parse_options_t(chars_format fmt = chars_format::general, |
| UC dot = UC('.'), int b = 10) |
| : format(fmt), decimal_point(dot), base(b) {} |
| |
| /** Which number formats are accepted */ |
| chars_format format; |
| /** The character used as decimal point */ |
| UC decimal_point; |
| /** The base used for integers */ |
| int base; |
| }; |
| |
| using parse_options = parse_options_t<char>; |
| |
| } // namespace fast_float |
| |
| #if FASTFLOAT_HAS_BIT_CAST |
| #include <bit> |
| #endif |
| |
| #if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ |
| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \ |
| defined(__MINGW64__) || defined(__s390x__) || \ |
| (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ |
| defined(__PPC64LE__)) || \ |
| defined(__loongarch64) || (defined(__riscv) && __riscv_xlen == 64)) |
| #define FASTFLOAT_64BIT 1 |
| #elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ |
| defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \ |
| defined(__MINGW32__) || defined(__EMSCRIPTEN__) || \ |
| (defined(__riscv) && __riscv_xlen == 32)) |
| #define FASTFLOAT_32BIT 1 |
| #else |
| // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. |
| // We can never tell the register width, but the SIZE_MAX is a good |
| // approximation. UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max |
| // portability. |
| #if SIZE_MAX == 0xffff |
| #error Unknown platform (16-bit, unsupported) |
| #elif SIZE_MAX == 0xffffffff |
| #define FASTFLOAT_32BIT 1 |
| #elif SIZE_MAX == 0xffffffffffffffff |
| #define FASTFLOAT_64BIT 1 |
| #else |
| #error Unknown platform (not 32-bit, not 64-bit?) |
| #endif |
| #endif |
| |
| #if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) || \ |
| (defined(_M_ARM64) && !defined(__MINGW32__)) |
| #include <intrin.h> |
| #endif |
| |
| #if defined(_MSC_VER) && !defined(__clang__) |
| #define FASTFLOAT_VISUAL_STUDIO 1 |
| #endif |
| |
| #if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ |
| #define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
| #elif defined _WIN32 |
| #define FASTFLOAT_IS_BIG_ENDIAN 0 |
| #else |
| #if defined(__APPLE__) || defined(__FreeBSD__) |
| #include <machine/endian.h> |
| #elif defined(sun) || defined(__sun) |
| #include <sys/byteorder.h> |
| #elif defined(__MVS__) |
| #include <sys/endian.h> |
| #else |
| #ifdef __has_include |
| #if __has_include(<endian.h>) |
| #include <endian.h> |
| #endif //__has_include(<endian.h>) |
| #endif //__has_include |
| #endif |
| # |
| #ifndef __BYTE_ORDER__ |
| // safe choice |
| #define FASTFLOAT_IS_BIG_ENDIAN 0 |
| #endif |
| # |
| #ifndef __ORDER_LITTLE_ENDIAN__ |
| // safe choice |
| #define FASTFLOAT_IS_BIG_ENDIAN 0 |
| #endif |
| # |
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| #define FASTFLOAT_IS_BIG_ENDIAN 0 |
| #else |
| #define FASTFLOAT_IS_BIG_ENDIAN 1 |
| #endif |
| #endif |
| |
| #if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ |
| (defined(_M_AMD64) || defined(_M_X64) || \ |
| (defined(_M_IX86_FP) && _M_IX86_FP == 2))) |
| #define FASTFLOAT_SSE2 1 |
| #endif |
| |
| #if defined(__aarch64__) || defined(_M_ARM64) |
| #define FASTFLOAT_NEON 1 |
| #endif |
| |
| #if defined(FASTFLOAT_SSE2) || defined(FASTFLOAT_NEON) |
| #define FASTFLOAT_HAS_SIMD 1 |
| #endif |
| |
| #if defined(__GNUC__) |
| // disable -Wcast-align=strict (GCC only) |
| #define FASTFLOAT_SIMD_DISABLE_WARNINGS \ |
| _Pragma("GCC diagnostic push") \ |
| _Pragma("GCC diagnostic ignored \"-Wcast-align\"") |
| #else |
| #define FASTFLOAT_SIMD_DISABLE_WARNINGS |
| #endif |
| |
| #if defined(__GNUC__) |
| #define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") |
| #else |
| #define FASTFLOAT_SIMD_RESTORE_WARNINGS |
| #endif |
| |
| #ifdef FASTFLOAT_VISUAL_STUDIO |
| #define fastfloat_really_inline __forceinline |
| #else |
| #define fastfloat_really_inline inline __attribute__((always_inline)) |
| #endif |
| |
| // Branch-probability hint marking the rare slow-path branches as cold, so the |
| // optimizer keeps the out-of-line slow-path re-parse off the hot path (and does |
| // not duplicate the force-inlined hot scanner into the caller, which bloated |
| // the hot frame and hurt ILP on some targets). Used at the call site as |
| // if fastfloat_unlikely(cond) { ... } |
| // (the macro supplies the parentheses). It expands to the standard [[unlikely]] |
| // attribute when supported, otherwise to __builtin_expect on GCC/Clang, or |
| // to a no-op elsewhere (e.g. pre-C++20 MSVC, which has no equivalent hint). |
| #ifdef __has_cpp_attribute |
| #if __has_cpp_attribute(unlikely) >= 201803L |
| #define FASTFLOAT_USE_UNLIKELY_ATTR 1 |
| #endif |
| #endif |
| |
| #ifdef FASTFLOAT_USE_UNLIKELY_ATTR |
| #define fastfloat_unlikely(x) (x) [[unlikely]] |
| #elif defined(__GNUC__) || defined(__clang__) |
| #define fastfloat_unlikely(x) (__builtin_expect(!!(x), 0)) |
| #else |
| #define fastfloat_unlikely(x) (x) |
| #endif |
| |
| #ifndef FASTFLOAT_ASSERT |
| #define FASTFLOAT_ASSERT(x) \ |
| { ((void)(x)); } |
| #endif |
| |
| #ifndef FASTFLOAT_DEBUG_ASSERT |
| #define FASTFLOAT_DEBUG_ASSERT(x) \ |
| { ((void)(x)); } |
| #endif |
| |
| // rust style `try!()` macro, or `?` operator |
| #define FASTFLOAT_TRY(x) \ |
| { \ |
| if (!(x)) \ |
| return false; \ |
| } |
| |
| #define FASTFLOAT_ENABLE_IF(...) \ |
| typename std::enable_if<(__VA_ARGS__), int>::type |
| |
| namespace fast_float { |
| |
| fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() { |
| #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED |
| return std::is_constant_evaluated(); |
| #else |
| return false; |
| #endif |
| } |
| |
| template <typename T> |
| struct is_supported_float_type |
| : std::integral_constant< |
| bool, std::is_same<T, double>::value || std::is_same<T, float>::value |
| #ifdef __STDCPP_FLOAT64_T__ |
| || std::is_same<T, std::float64_t>::value |
| #endif |
| #ifdef __STDCPP_FLOAT32_T__ |
| || std::is_same<T, std::float32_t>::value |
| #endif |
| #ifdef __STDCPP_FLOAT16_T__ |
| || std::is_same<T, std::float16_t>::value |
| #endif |
| #ifdef __STDCPP_BFLOAT16_T__ |
| || std::is_same<T, std::bfloat16_t>::value |
| #endif |
| > { |
| }; |
| |
| template <typename T> |
| using equiv_uint_t = typename std::conditional< |
| sizeof(T) == 1, uint8_t, |
| typename std::conditional< |
| sizeof(T) == 2, uint16_t, |
| typename std::conditional<sizeof(T) == 4, uint32_t, |
| uint64_t>::type>::type>::type; |
| |
| template <typename T> struct is_supported_integer_type : std::is_integral<T> {}; |
| |
| template <typename UC> |
| struct is_supported_char_type |
| : std::integral_constant<bool, std::is_same<UC, char>::value || |
| std::is_same<UC, wchar_t>::value || |
| std::is_same<UC, char16_t>::value || |
| std::is_same<UC, char32_t>::value |
| #ifdef __cpp_char8_t |
| || std::is_same<UC, char8_t>::value |
| #endif |
| > { |
| }; |
| |
| template <typename UC> |
| inline FASTFLOAT_CONSTEXPR14 bool |
| fastfloat_strncasecmp3(UC const *actual_mixedcase, |
| UC const *expected_lowercase) { |
| uint64_t mask{0}; |
| FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { |
| mask = 0x0020002000200020; |
| } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { |
| mask = 0x0000002000000020; |
| } |
| else { |
| return false; |
| } |
| |
| uint64_t val1{0}, val2{0}; |
| if (cpp20_and_in_constexpr()) { |
| for (size_t i = 0; i < 3; i++) { |
| if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { |
| return false; |
| } |
| } |
| return true; |
| } else { |
| FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) { |
| ::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase, 3 * sizeof(UC)); |
| val1 |= mask; |
| val2 |= mask; |
| return val1 == val2; |
| } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { |
| ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); |
| val1 |= mask; |
| if (val1 != val2) { |
| return false; |
| } |
| return (actual_mixedcase[2] | 32) == (expected_lowercase[2]); |
| } |
| else { |
| return false; |
| } |
| } |
| } |
| |
| template <typename UC> |
| inline FASTFLOAT_CONSTEXPR14 bool |
| fastfloat_strncasecmp5(UC const *actual_mixedcase, |
| UC const *expected_lowercase) { |
| uint64_t mask{0}; |
| uint64_t val1{0}, val2{0}; |
| if (cpp20_and_in_constexpr()) { |
| for (size_t i = 0; i < 5; i++) { |
| if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { |
| return false; |
| } |
| } |
| return true; |
| } else { |
| FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { |
| mask = 0x2020202020202020; |
| ::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase, 5 * sizeof(UC)); |
| val1 |= mask; |
| val2 |= mask; |
| return val1 == val2; |
| } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { |
| mask = 0x0020002000200020; |
| ::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase, 4 * sizeof(UC)); |
| val1 |= mask; |
| if (val1 != val2) { |
| return false; |
| } |
| return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); |
| } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { |
| mask = 0x0000002000000020; |
| ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); |
| val1 |= mask; |
| if (val1 != val2) { |
| return false; |
| } |
| ::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase + 2, 2 * sizeof(UC)); |
| val1 |= mask; |
| if (val1 != val2) { |
| return false; |
| } |
| return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); |
| } |
| else { |
| return false; |
| } |
| } |
| } |
| |
| // Compares two ASCII strings in a case insensitive manner. |
| template <typename UC> |
| inline FASTFLOAT_CONSTEXPR14 bool |
| fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, |
| size_t length) { |
| uint64_t mask{0}; |
| FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { |
| mask = 0x0020002000200020; |
| } |
| else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { |
| mask = 0x0000002000000020; |
| } |
| else { |
| return false; |
| } |
| |
| if (cpp20_and_in_constexpr()) { |
| for (size_t i = 0; i < length; i++) { |
| if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { |
| return false; |
| } |
| } |
| return true; |
| } else { |
| uint64_t val1{0}, val2{0}; |
| size_t sz{8 / (sizeof(UC))}; |
| for (size_t i = 0; i < length; i += sz) { |
| val1 = val2 = 0; |
| sz = sz < (length - i) ? sz : length - i; |
| ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); |
| ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); |
| val1 |= mask; |
| val2 |= mask; |
| if (val1 != val2) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| #ifndef FLT_EVAL_METHOD |
| #error "FLT_EVAL_METHOD should be defined, please include cfloat." |
| #endif |
| |
| // a pointer and a length to a contiguous block of memory |
| template <typename T> struct span { |
| T const *ptr; |
| size_t length; |
| |
| constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {} |
| |
| constexpr span() : ptr(nullptr), length(0) {} |
| |
| constexpr size_t len() const noexcept { return length; } |
| |
| FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept { |
| FASTFLOAT_DEBUG_ASSERT(index < length); |
| return ptr[index]; |
| } |
| }; |
| |
| struct value128 { |
| uint64_t low; |
| uint64_t high; |
| |
| constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} |
| |
| constexpr value128() : low(0), high(0) {} |
| }; |
| |
| /* Helper C++14 constexpr generic implementation of leading_zeroes */ |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int |
| leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { |
| if (input_num & uint64_t(0xffffffff00000000)) { |
| input_num >>= 32; |
| last_bit |= 32; |
| } |
| if (input_num & uint64_t(0xffff0000)) { |
| input_num >>= 16; |
| last_bit |= 16; |
| } |
| if (input_num & uint64_t(0xff00)) { |
| input_num >>= 8; |
| last_bit |= 8; |
| } |
| if (input_num & uint64_t(0xf0)) { |
| input_num >>= 4; |
| last_bit |= 4; |
| } |
| if (input_num & uint64_t(0xc)) { |
| input_num >>= 2; |
| last_bit |= 2; |
| } |
| if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ |
| last_bit |= 1; |
| } |
| return 63 - last_bit; |
| } |
| |
| /* result might be undefined when input_num is zero */ |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int |
| leading_zeroes(uint64_t input_num) { |
| assert(input_num > 0); |
| if (cpp20_and_in_constexpr()) { |
| return leading_zeroes_generic(input_num); |
| } |
| #ifdef FASTFLOAT_VISUAL_STUDIO |
| #if defined(_M_X64) || defined(_M_ARM64) |
| unsigned long leading_zero = 0; |
| // Search the mask data from most significant bit (MSB) |
| // to least significant bit (LSB) for a set bit (1). |
| _BitScanReverse64(&leading_zero, input_num); |
| return (int)(63 - leading_zero); |
| #else |
| return leading_zeroes_generic(input_num); |
| #endif |
| #else |
| return __builtin_clzll(input_num); |
| #endif |
| } |
| |
| /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int |
| countr_zero_generic_32(uint32_t input_num) { |
| if (input_num == 0) { |
| return 32; |
| } |
| int last_bit = 0; |
| if (!(input_num & 0x0000FFFF)) { |
| input_num >>= 16; |
| last_bit |= 16; |
| } |
| if (!(input_num & 0x00FF)) { |
| input_num >>= 8; |
| last_bit |= 8; |
| } |
| if (!(input_num & 0x0F)) { |
| input_num >>= 4; |
| last_bit |= 4; |
| } |
| if (!(input_num & 0x3)) { |
| input_num >>= 2; |
| last_bit |= 2; |
| } |
| if (!(input_num & 0x1)) { |
| last_bit |= 1; |
| } |
| return last_bit; |
| } |
| |
| /* count trailing zeroes for 32-bit integers */ |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int |
| countr_zero_32(uint32_t input_num) { |
| if (cpp20_and_in_constexpr()) { |
| return countr_zero_generic_32(input_num); |
| } |
| #ifdef FASTFLOAT_VISUAL_STUDIO |
| unsigned long trailing_zero = 0; |
| if (_BitScanForward(&trailing_zero, input_num)) { |
| return (int)trailing_zero; |
| } |
| return 32; |
| #else |
| return input_num == 0 ? 32 : __builtin_ctz(input_num); |
| #endif |
| } |
| |
| // slow emulation routine for 32-bit |
| fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) { |
| return x * (uint64_t)y; |
| } |
| |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t |
| umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { |
| uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); |
| uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); |
| uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); |
| uint64_t adbc_carry = (uint64_t)(adbc < ad); |
| uint64_t lo = bd + (adbc << 32); |
| *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + |
| (adbc_carry << 32) + (uint64_t)(lo < bd); |
| return lo; |
| } |
| |
| #ifdef FASTFLOAT_32BIT |
| |
| // slow emulation routine for 32-bit |
| #if !defined(__MINGW64__) |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, |
| uint64_t cd, |
| uint64_t *hi) { |
| return umul128_generic(ab, cd, hi); |
| } |
| #endif // !__MINGW64__ |
| |
| #endif // FASTFLOAT_32BIT |
| |
| // compute 64-bit a*b |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 |
| full_multiplication(uint64_t a, uint64_t b) { |
| if (cpp20_and_in_constexpr()) { |
| value128 answer; |
| answer.low = umul128_generic(a, b, &answer.high); |
| return answer; |
| } |
| value128 answer; |
| #if defined(_M_ARM64) && !defined(__MINGW32__) |
| // ARM64 has native support for 64-bit multiplications, no need to emulate |
| // But MinGW on ARM64 doesn't have native support for 64-bit multiplications |
| answer.high = __umulh(a, b); |
| answer.low = a * b; |
| #elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__) && \ |
| !defined(_M_ARM64) && !defined(__GNUC__)) |
| answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64 |
| #elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__) |
| __uint128_t r = ((__uint128_t)a) * b; |
| answer.low = uint64_t(r); |
| answer.high = uint64_t(r >> 64); |
| #else |
| answer.low = umul128_generic(a, b, &answer.high); |
| #endif |
| return answer; |
| } |
| |
| struct adjusted_mantissa { |
| uint64_t mantissa{0}; |
| int32_t power2{0}; // a negative value indicates an invalid result |
| adjusted_mantissa() = default; |
| |
| constexpr bool operator==(adjusted_mantissa const &o) const { |
| return mantissa == o.mantissa && power2 == o.power2; |
| } |
| |
| constexpr bool operator!=(adjusted_mantissa const &o) const { |
| return mantissa != o.mantissa || power2 != o.power2; |
| } |
| }; |
| |
| // Bias so we can get the real exponent with an invalid adjusted_mantissa. |
| constexpr static int32_t invalid_am_bias = -0x8000; |
| |
| // used for binary_format_lookup_tables<T>::max_mantissa |
| constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; |
| |
| template <typename T, typename U = void> struct binary_format_lookup_tables; |
| |
| template <typename T> struct binary_format : binary_format_lookup_tables<T> { |
| using equiv_uint = equiv_uint_t<T>; |
| |
| static constexpr int mantissa_explicit_bits(); |
| static constexpr int minimum_exponent(); |
| static constexpr int infinite_power(); |
| static constexpr int sign_index(); |
| static constexpr int |
| min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST |
| static constexpr int max_exponent_fast_path(); |
| static constexpr int max_exponent_round_to_even(); |
| static constexpr int min_exponent_round_to_even(); |
| static constexpr uint64_t max_mantissa_fast_path(int64_t power); |
| static constexpr uint64_t |
| max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST |
| static constexpr int largest_power_of_ten(); |
| static constexpr int smallest_power_of_ten(); |
| static constexpr T exact_power_of_ten(int64_t power); |
| static constexpr size_t max_digits(); |
| static constexpr equiv_uint exponent_mask(); |
| static constexpr equiv_uint mantissa_mask(); |
| static constexpr equiv_uint hidden_bit_mask(); |
| }; |
| |
| template <typename U> struct binary_format_lookup_tables<double, U> { |
| static constexpr double powers_of_ten[] = { |
| 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, |
| 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; |
| |
| // Largest integer value v so that (5**index * v) <= 1<<53. |
| // 0x20000000000000 == 1 << 53 |
| static constexpr uint64_t max_mantissa[] = { |
| 0x20000000000000, |
| 0x20000000000000 / 5, |
| 0x20000000000000 / (5 * 5), |
| 0x20000000000000 / (5 * 5 * 5), |
| 0x20000000000000 / (5 * 5 * 5 * 5), |
| 0x20000000000000 / (constant_55555), |
| 0x20000000000000 / (constant_55555 * 5), |
| 0x20000000000000 / (constant_55555 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * 5 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * 5 * 5 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555), |
| 0x20000000000000 / (constant_55555 * constant_55555 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555), |
| 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5), |
| 0x20000000000000 / |
| (constant_55555 * constant_55555 * constant_55555 * 5 * 5), |
| 0x20000000000000 / |
| (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5), |
| 0x20000000000000 / |
| (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5), |
| 0x20000000000000 / |
| (constant_55555 * constant_55555 * constant_55555 * constant_55555), |
| 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * |
| constant_55555 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * |
| constant_55555 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * |
| constant_55555 * 5 * 5 * 5), |
| 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * |
| constant_55555 * 5 * 5 * 5 * 5)}; |
| }; |
| |
| #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE |
| |
| template <typename U> |
| constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[]; |
| |
| template <typename U> |
| constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[]; |
| |
| #endif |
| |
| template <typename U> struct binary_format_lookup_tables<float, U> { |
| static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, |
| 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; |
| |
| // Largest integer value v so that (5**index * v) <= 1<<24. |
| // 0x1000000 == 1<<24 |
| static constexpr uint64_t max_mantissa[] = { |
| 0x1000000, |
| 0x1000000 / 5, |
| 0x1000000 / (5 * 5), |
| 0x1000000 / (5 * 5 * 5), |
| 0x1000000 / (5 * 5 * 5 * 5), |
| 0x1000000 / (constant_55555), |
| 0x1000000 / (constant_55555 * 5), |
| 0x1000000 / (constant_55555 * 5 * 5), |
| 0x1000000 / (constant_55555 * 5 * 5 * 5), |
| 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5), |
| 0x1000000 / (constant_55555 * constant_55555), |
| 0x1000000 / (constant_55555 * constant_55555 * 5)}; |
| }; |
| |
| #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE |
| |
| template <typename U> |
| constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[]; |
| |
| template <typename U> |
| constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[]; |
| |
| #endif |
| |
| template <> |
| inline constexpr int binary_format<double>::min_exponent_fast_path() { |
| #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) |
| return 0; |
| #else |
| return -22; |
| #endif |
| } |
| |
| template <> |
| inline constexpr int binary_format<float>::min_exponent_fast_path() { |
| #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) |
| return 0; |
| #else |
| return -10; |
| #endif |
| } |
| |
| template <> |
| inline constexpr int binary_format<double>::mantissa_explicit_bits() { |
| return 52; |
| } |
| |
| template <> |
| inline constexpr int binary_format<float>::mantissa_explicit_bits() { |
| return 23; |
| } |
| |
| template <> |
| inline constexpr int binary_format<double>::max_exponent_round_to_even() { |
| return 23; |
| } |
| |
| template <> |
| inline constexpr int binary_format<float>::max_exponent_round_to_even() { |
| return 10; |
| } |
| |
| template <> |
| inline constexpr int binary_format<double>::min_exponent_round_to_even() { |
| return -4; |
| } |
| |
| template <> |
| inline constexpr int binary_format<float>::min_exponent_round_to_even() { |
| return -17; |
| } |
| |
| template <> inline constexpr int binary_format<double>::minimum_exponent() { |
| return -1023; |
| } |
| |
| template <> inline constexpr int binary_format<float>::minimum_exponent() { |
| return -127; |
| } |
| |
| template <> inline constexpr int binary_format<double>::infinite_power() { |
| return 0x7FF; |
| } |
| |
| template <> inline constexpr int binary_format<float>::infinite_power() { |
| return 0xFF; |
| } |
| |
| template <> inline constexpr int binary_format<double>::sign_index() { |
| return 63; |
| } |
| |
| template <> inline constexpr int binary_format<float>::sign_index() { |
| return 31; |
| } |
| |
| template <> |
| inline constexpr int binary_format<double>::max_exponent_fast_path() { |
| return 22; |
| } |
| |
| template <> |
| inline constexpr int binary_format<float>::max_exponent_fast_path() { |
| return 10; |
| } |
| |
| template <> |
| inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { |
| return uint64_t(2) << mantissa_explicit_bits(); |
| } |
| |
| template <> |
| inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() { |
| return uint64_t(2) << mantissa_explicit_bits(); |
| } |
| |
| // credit: Jakub JelÃnek |
| #ifdef __STDCPP_FLOAT16_T__ |
| template <typename U> struct binary_format_lookup_tables<std::float16_t, U> { |
| static constexpr std::float16_t powers_of_ten[] = {1e0f16, 1e1f16, 1e2f16, |
| 1e3f16, 1e4f16}; |
| |
| // Largest integer value v so that (5**index * v) <= 1<<11. |
| // 0x800 == 1<<11 |
| static constexpr uint64_t max_mantissa[] = {0x800, |
| 0x800 / 5, |
| 0x800 / (5 * 5), |
| 0x800 / (5 * 5 * 5), |
| 0x800 / (5 * 5 * 5 * 5), |
| 0x800 / (constant_55555)}; |
| }; |
| |
| #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE |
| |
| template <typename U> |
| constexpr std::float16_t |
| binary_format_lookup_tables<std::float16_t, U>::powers_of_ten[]; |
| |
| template <typename U> |
| constexpr uint64_t |
| binary_format_lookup_tables<std::float16_t, U>::max_mantissa[]; |
| |
| #endif |
| |
| template <> |
| inline constexpr std::float16_t |
| binary_format<std::float16_t>::exact_power_of_ten(int64_t power) { |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)powers_of_ten[0], powers_of_ten[power]; |
| } |
| |
| template <> |
| inline constexpr binary_format<std::float16_t>::equiv_uint |
| binary_format<std::float16_t>::exponent_mask() { |
| return 0x7C00; |
| } |
| |
| template <> |
| inline constexpr binary_format<std::float16_t>::equiv_uint |
| binary_format<std::float16_t>::mantissa_mask() { |
| return 0x03FF; |
| } |
| |
| template <> |
| inline constexpr binary_format<std::float16_t>::equiv_uint |
| binary_format<std::float16_t>::hidden_bit_mask() { |
| return 0x0400; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::max_exponent_fast_path() { |
| return 4; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::mantissa_explicit_bits() { |
| return 10; |
| } |
| |
| template <> |
| inline constexpr uint64_t |
| binary_format<std::float16_t>::max_mantissa_fast_path() { |
| return uint64_t(2) << mantissa_explicit_bits(); |
| } |
| |
| template <> |
| inline constexpr uint64_t |
| binary_format<std::float16_t>::max_mantissa_fast_path(int64_t power) { |
| // caller is responsible to ensure that |
| // power >= 0 && power <= 4 |
| // |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)max_mantissa[0], max_mantissa[power]; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::min_exponent_fast_path() { |
| return 0; |
| } |
| |
| template <> |
| inline constexpr int |
| binary_format<std::float16_t>::max_exponent_round_to_even() { |
| return 5; |
| } |
| |
| template <> |
| inline constexpr int |
| binary_format<std::float16_t>::min_exponent_round_to_even() { |
| return -22; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::minimum_exponent() { |
| return -15; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::infinite_power() { |
| return 0x1F; |
| } |
| |
| template <> inline constexpr int binary_format<std::float16_t>::sign_index() { |
| return 15; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::largest_power_of_ten() { |
| return 4; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::float16_t>::smallest_power_of_ten() { |
| return -27; |
| } |
| |
| template <> |
| inline constexpr size_t binary_format<std::float16_t>::max_digits() { |
| return 22; |
| } |
| #endif // __STDCPP_FLOAT16_T__ |
| |
| // credit: Jakub JelÃnek |
| #ifdef __STDCPP_BFLOAT16_T__ |
| template <typename U> struct binary_format_lookup_tables<std::bfloat16_t, U> { |
| static constexpr std::bfloat16_t powers_of_ten[] = {1e0bf16, 1e1bf16, 1e2bf16, |
| 1e3bf16}; |
| |
| // Largest integer value v so that (5**index * v) <= 1<<8. |
| // 0x100 == 1<<8 |
| static constexpr uint64_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5), |
| 0x100 / (5 * 5 * 5), |
| 0x100 / (5 * 5 * 5 * 5)}; |
| }; |
| |
| #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE |
| |
| template <typename U> |
| constexpr std::bfloat16_t |
| binary_format_lookup_tables<std::bfloat16_t, U>::powers_of_ten[]; |
| |
| template <typename U> |
| constexpr uint64_t |
| binary_format_lookup_tables<std::bfloat16_t, U>::max_mantissa[]; |
| |
| #endif |
| |
| template <> |
| inline constexpr std::bfloat16_t |
| binary_format<std::bfloat16_t>::exact_power_of_ten(int64_t power) { |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)powers_of_ten[0], powers_of_ten[power]; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::max_exponent_fast_path() { |
| return 3; |
| } |
| |
| template <> |
| inline constexpr binary_format<std::bfloat16_t>::equiv_uint |
| binary_format<std::bfloat16_t>::exponent_mask() { |
| return 0x7F80; |
| } |
| |
| template <> |
| inline constexpr binary_format<std::bfloat16_t>::equiv_uint |
| binary_format<std::bfloat16_t>::mantissa_mask() { |
| return 0x007F; |
| } |
| |
| template <> |
| inline constexpr binary_format<std::bfloat16_t>::equiv_uint |
| binary_format<std::bfloat16_t>::hidden_bit_mask() { |
| return 0x0080; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::mantissa_explicit_bits() { |
| return 7; |
| } |
| |
| template <> |
| inline constexpr uint64_t |
| binary_format<std::bfloat16_t>::max_mantissa_fast_path() { |
| return uint64_t(2) << mantissa_explicit_bits(); |
| } |
| |
| template <> |
| inline constexpr uint64_t |
| binary_format<std::bfloat16_t>::max_mantissa_fast_path(int64_t power) { |
| // caller is responsible to ensure that |
| // power >= 0 && power <= 3 |
| // |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)max_mantissa[0], max_mantissa[power]; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::min_exponent_fast_path() { |
| return 0; |
| } |
| |
| template <> |
| inline constexpr int |
| binary_format<std::bfloat16_t>::max_exponent_round_to_even() { |
| return 3; |
| } |
| |
| template <> |
| inline constexpr int |
| binary_format<std::bfloat16_t>::min_exponent_round_to_even() { |
| return -24; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::minimum_exponent() { |
| return -127; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::infinite_power() { |
| return 0xFF; |
| } |
| |
| template <> inline constexpr int binary_format<std::bfloat16_t>::sign_index() { |
| return 15; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::largest_power_of_ten() { |
| return 38; |
| } |
| |
| template <> |
| inline constexpr int binary_format<std::bfloat16_t>::smallest_power_of_ten() { |
| return -60; |
| } |
| |
| template <> |
| inline constexpr size_t binary_format<std::bfloat16_t>::max_digits() { |
| return 98; |
| } |
| #endif // __STDCPP_BFLOAT16_T__ |
| |
| template <> |
| inline constexpr uint64_t |
| binary_format<double>::max_mantissa_fast_path(int64_t power) { |
| // caller is responsible to ensure that |
| // power >= 0 && power <= 22 |
| // |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)max_mantissa[0], max_mantissa[power]; |
| } |
| |
| template <> |
| inline constexpr uint64_t |
| binary_format<float>::max_mantissa_fast_path(int64_t power) { |
| // caller is responsible to ensure that |
| // power >= 0 && power <= 10 |
| // |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)max_mantissa[0], max_mantissa[power]; |
| } |
| |
| template <> |
| inline constexpr double |
| binary_format<double>::exact_power_of_ten(int64_t power) { |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)powers_of_ten[0], powers_of_ten[power]; |
| } |
| |
| template <> |
| inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) { |
| // Work around clang bug https://godbolt.org/z/zedh7rrhc |
| return (void)powers_of_ten[0], powers_of_ten[power]; |
| } |
| |
| template <> inline constexpr int binary_format<double>::largest_power_of_ten() { |
| return 308; |
| } |
| |
| template <> inline constexpr int binary_format<float>::largest_power_of_ten() { |
| return 38; |
| } |
| |
| template <> |
| inline constexpr int binary_format<double>::smallest_power_of_ten() { |
| return -342; |
| } |
| |
| template <> inline constexpr int binary_format<float>::smallest_power_of_ten() { |
| return -64; |
| } |
| |
| template <> inline constexpr size_t binary_format<double>::max_digits() { |
| return 769; |
| } |
| |
| template <> inline constexpr size_t binary_format<float>::max_digits() { |
| return 114; |
| } |
| |
| template <> |
| inline constexpr binary_format<float>::equiv_uint |
| binary_format<float>::exponent_mask() { |
| return 0x7F800000; |
| } |
| |
| template <> |
| inline constexpr binary_format<double>::equiv_uint |
| binary_format<double>::exponent_mask() { |
| return 0x7FF0000000000000; |
| } |
| |
| template <> |
| inline constexpr binary_format<float>::equiv_uint |
| binary_format<float>::mantissa_mask() { |
| return 0x007FFFFF; |
| } |
| |
| template <> |
| inline constexpr binary_format<double>::equiv_uint |
| binary_format<double>::mantissa_mask() { |
| return 0x000FFFFFFFFFFFFF; |
| } |
| |
| template <> |
| inline constexpr binary_format<float>::equiv_uint |
| binary_format<float>::hidden_bit_mask() { |
| return 0x00800000; |
| } |
| |
| template <> |
| inline constexpr binary_format<double>::equiv_uint |
| binary_format<double>::hidden_bit_mask() { |
| return 0x0010000000000000; |
| } |
| |
| template <typename T> |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void |
| to_float(bool negative, adjusted_mantissa am, T &value) { |
| using equiv_uint = equiv_uint_t<T>; |
| equiv_uint word = equiv_uint(am.mantissa); |
| word = equiv_uint(word | equiv_uint(am.power2) |
| << binary_format<T>::mantissa_explicit_bits()); |
| word = |
| equiv_uint(word | equiv_uint(negative) << binary_format<T>::sign_index()); |
| #if FASTFLOAT_HAS_BIT_CAST |
| value = std::bit_cast<T>(word); |
| #else |
| ::memcpy(&value, &word, sizeof(T)); |
| #endif |
| } |
| |
| template <typename = void> struct space_lut { |
| static constexpr bool value[] = { |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
| }; |
| |
| #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE |
| |
| template <typename T> constexpr bool space_lut<T>::value[]; |
| |
| #endif |
| |
| template <typename UC> constexpr bool is_space(UC c) { |
| return c < 256 && space_lut<>::value[uint8_t(c)]; |
| } |
| |
| template <typename UC> static constexpr uint64_t int_cmp_zeros() { |
| static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), |
| "Unsupported character size"); |
| return (sizeof(UC) == 1) ? 0x3030303030303030 |
| : (sizeof(UC) == 2) |
| ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | |
| uint64_t(UC('0')) << 16 | UC('0')) |
| : (uint64_t(UC('0')) << 32 | UC('0')); |
| } |
| |
| template <typename UC> static constexpr int int_cmp_len() { |
| return sizeof(uint64_t) / sizeof(UC); |
| } |
| |
| template <typename UC> constexpr UC const *str_const_nan(); |
| |
| template <> constexpr char const *str_const_nan<char>() { return "nan"; } |
| |
| template <> constexpr wchar_t const *str_const_nan<wchar_t>() { return L"nan"; } |
| |
| template <> constexpr char16_t const *str_const_nan<char16_t>() { |
| return u"nan"; |
| } |
| |
| template <> constexpr char32_t const *str_const_nan<char32_t>() { |
| return U"nan"; |
| } |
| |
| #ifdef __cpp_char8_t |
| template <> constexpr char8_t const *str_const_nan<char8_t>() { |
| return u8"nan"; |
| } |
| #endif |
| |
| template <typename UC> constexpr UC const *str_const_inf(); |
| |
| template <> constexpr char const *str_const_inf<char>() { return "infinity"; } |
| |
| template <> constexpr wchar_t const *str_const_inf<wchar_t>() { |
| return L"infinity"; |
| } |
| |
| template <> constexpr char16_t const *str_const_inf<char16_t>() { |
| return u"infinity"; |
| } |
| |
| template <> constexpr char32_t const *str_const_inf<char32_t>() { |
| return U"infinity"; |
| } |
| |
| #ifdef __cpp_char8_t |
| template <> constexpr char8_t const *str_const_inf<char8_t>() { |
| return u8"infinity"; |
| } |
| #endif |
| |
| template <typename = void> struct int_luts { |
| static constexpr uint8_t chdigit[] = { |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, |
| 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, |
| 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
| 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, |
| 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, |
| 33, 34, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
| 255}; |
| |
| static constexpr size_t maxdigits_u64[] = { |
| 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, |
| 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; |
| |
| static constexpr uint64_t min_safe_u64[] = { |
| 9223372036854775808ull, 12157665459056928801ull, 4611686018427387904, |
| 7450580596923828125, 4738381338321616896, 3909821048582988049, |
| 9223372036854775808ull, 12157665459056928801ull, 10000000000000000000ull, |
| 5559917313492231481, 2218611106740436992, 8650415919381337933, |
| 2177953337809371136, 6568408355712890625, 1152921504606846976, |
| 2862423051509815793, 6746640616477458432, 15181127029874798299ull, |
| 1638400000000000000, 3243919932521508681, 6221821273427820544, |
| 11592836324538749809ull, 876488338465357824, 1490116119384765625, |
| 2481152873203736576, 4052555153018976267, 6502111422497947648, |
| 10260628712958602189ull, 15943230000000000000ull, 787662783788549761, |
| 1152921504606846976, 1667889514952984961, 2386420683693101056, |
| 3379220508056640625, 4738381338321616896}; |
| }; |
| |
| #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE |
| |
| template <typename T> constexpr uint8_t int_luts<T>::chdigit[]; |
| |
| template <typename T> constexpr size_t int_luts<T>::maxdigits_u64[]; |
| |
| template <typename T> constexpr uint64_t int_luts<T>::min_safe_u64[]; |
| |
| #endif |
| |
| template <typename UC> |
| fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { |
| // wchar_t and char can be signed, so we need to be careful. |
| using UnsignedUC = typename std::make_unsigned<UC>::type; |
| return int_luts<>::chdigit[static_cast<unsigned char>( |
| static_cast<UnsignedUC>(c) & |
| static_cast<UnsignedUC>( |
| -((static_cast<UnsignedUC>(c) & ~0xFFull) == 0)))]; |
| } |
| |
| fastfloat_really_inline constexpr size_t max_digits_u64(int base) { |
| return int_luts<>::maxdigits_u64[base - 2]; |
| } |
| |
| // If a u64 is exactly max_digits_u64() in length, this is |
| // the value below which it has definitely overflowed. |
| fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) { |
| return int_luts<>::min_safe_u64[base - 2]; |
| } |
| |
| static_assert(std::is_same<equiv_uint_t<double>, uint64_t>::value, |
| "equiv_uint should be uint64_t for double"); |
| static_assert(std::numeric_limits<double>::is_iec559, |
| "double must fulfill the requirements of IEC 559 (IEEE 754)"); |
| |
| static_assert(std::is_same<equiv_uint_t<float>, uint32_t>::value, |
| "equiv_uint should be uint32_t for float"); |
| static_assert(std::numeric_limits<float>::is_iec559, |
| "float must fulfill the requirements of IEC 559 (IEEE 754)"); |
| |
| #ifdef __STDCPP_FLOAT64_T__ |
| static_assert(std::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value, |
| "equiv_uint should be uint64_t for std::float64_t"); |
| static_assert( |
| std::numeric_limits<std::float64_t>::is_iec559, |
| "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)"); |
| |
| template <> |
| struct binary_format<std::float64_t> : public binary_format<double> {}; |
| #endif // __STDCPP_FLOAT64_T__ |
| |
| #ifdef __STDCPP_FLOAT32_T__ |
| static_assert(std::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value, |
| "equiv_uint should be uint32_t for std::float32_t"); |
| static_assert( |
| std::numeric_limits<std::float32_t>::is_iec559, |
| "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)"); |
| |
| template <> |
| struct binary_format<std::float32_t> : public binary_format<float> {}; |
| #endif // __STDCPP_FLOAT32_T__ |
| |
| #ifdef __STDCPP_FLOAT16_T__ |
| static_assert( |
| std::is_same<binary_format<std::float16_t>::equiv_uint, uint16_t>::value, |
| "equiv_uint should be uint16_t for std::float16_t"); |
| static_assert( |
| std::numeric_limits<std::float16_t>::is_iec559, |
| "std::float16_t must fulfill the requirements of IEC 559 (IEEE 754)"); |
| #endif // __STDCPP_FLOAT16_T__ |
| |
| #ifdef __STDCPP_BFLOAT16_T__ |
| static_assert( |
| std::is_same<binary_format<std::bfloat16_t>::equiv_uint, uint16_t>::value, |
| "equiv_uint should be uint16_t for std::bfloat16_t"); |
| static_assert( |
| std::numeric_limits<std::bfloat16_t>::is_iec559, |
| "std::bfloat16_t must fulfill the requirements of IEC 559 (IEEE 754)"); |
| #endif // __STDCPP_BFLOAT16_T__ |
| |
| constexpr chars_format operator~(chars_format rhs) noexcept { |
| using int_type = std::underlying_type<chars_format>::type; |
| return static_cast<chars_format>(~static_cast<int_type>(rhs)); |
| } |
| |
| constexpr chars_format operator&(chars_format lhs, chars_format rhs) noexcept { |
| using int_type = std::underlying_type<chars_format>::type; |
| return static_cast<chars_format>(static_cast<int_type>(lhs) & |
| static_cast<int_type>(rhs)); |
| } |
| |
| constexpr chars_format operator|(chars_format lhs, chars_format rhs) noexcept { |
| using int_type = std::underlying_type<chars_format>::type; |
| return static_cast<chars_format>(static_cast<int_type>(lhs) | |
| static_cast<int_type>(rhs)); |
| } |
| |
| constexpr chars_format operator^(chars_format lhs, chars_format rhs) noexcept { |
| using int_type = std::underlying_type<chars_format>::type; |
| return static_cast<chars_format>(static_cast<int_type>(lhs) ^ |
| static_cast<int_type>(rhs)); |
| } |
| |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & |
| operator&=(chars_format &lhs, chars_format rhs) noexcept { |
| return lhs = (lhs & rhs); |
| } |
| |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & |
| operator|=(chars_format &lhs, chars_format rhs) noexcept { |
| return lhs = (lhs | rhs); |
| } |
| |
| fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & |
| operator^=(chars_format &lhs, chars_format rhs) noexcept { |
| return lhs = (lhs ^ rhs); |
| } |
| |
| namespace detail { |
| // adjust for deprecated feature macros |
| constexpr chars_format adjust_for_feature_macros(chars_format fmt) { |
| return fmt |
| #ifdef FASTFLOAT_ALLOWS_LEADING_PLUS |
| | chars_format::allow_leading_plus |
| #endif |
| #ifdef FASTFLOAT_SKIP_WHITE_SPACE |
| | chars_format::skip_white_space |
| #endif |
| ; |
| } |
| } // namespace detail |
| } // namespace fast_float |
| |
| #endif |