mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-09-14 22:52:47 +08:00
1562 lines
49 KiB
C++
1562 lines
49 KiB
C++
#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 10
|
|
|
|
#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 {
|
|
|
|
// 64 bit integer is used because mantissa can be up to 53 bits for double.
|
|
// An unsigned int avoids signed overflows (which are bad)
|
|
typedef uint_fast64_t am_mant_t;
|
|
|
|
// The number of digits in the mantissa.
|
|
typedef uint_fast16_t am_digits;
|
|
|
|
// The number of bits in the limb.
|
|
typedef uint_fast8_t limb_t;
|
|
|
|
// Size of bits in the mantissa and path and rounding shifts
|
|
typedef int_fast8_t am_bits_t;
|
|
|
|
// 16 bit signed integer is used for power to cover all exponents up to double.
|
|
typedef int_fast16_t am_pow_t;
|
|
// Power bias is signed for handling a denormal float or an invalid mantissa.
|
|
// Bias so we can get the real exponent with an invalid adjusted_mantissa.
|
|
constexpr static am_pow_t invalid_am_bias =
|
|
std::numeric_limits<int16_t>::min() + 1;
|
|
constexpr static am_pow_t am_bias_limit =
|
|
(std::numeric_limits<int16_t>::max() / 16) - 1;
|
|
|
|
// Type for enum chars_format.
|
|
typedef uint_fast8_t chars_format_t;
|
|
|
|
// Type for base, only allowed from 2 to 36.
|
|
typedef uint_fast8_t base_t;
|
|
|
|
enum class chars_format : chars_format_t;
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
namespace detail {
|
|
constexpr chars_format basic_json_fmt = chars_format(1 << 6);
|
|
constexpr chars_format basic_fortran_fmt = chars_format(1 << 7);
|
|
} // namespace detail
|
|
#endif
|
|
|
|
enum class chars_format : chars_format_t {
|
|
scientific = 1 << 0,
|
|
fixed = 1 << 1,
|
|
general = fixed | scientific,
|
|
hex = 1 << 2,
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
no_infnan = 1 << 3,
|
|
allow_leading_plus = 1 << 4,
|
|
skip_white_space = 1 << 5,
|
|
// RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6
|
|
json = chars_format_t(detail::basic_json_fmt) | general | no_infnan,
|
|
// Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed.
|
|
json_or_infnan = chars_format_t(detail::basic_json_fmt) | general,
|
|
fortran = chars_format_t(detail::basic_fortran_fmt) | general,
|
|
#endif
|
|
};
|
|
|
|
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 const fmt = chars_format::general, UC const dot = UC('.'),
|
|
base_t const b = 10) noexcept
|
|
: format(fmt), base(b), decimal_point(dot) {}
|
|
|
|
/** Which number formats are accepted */
|
|
chars_format format;
|
|
/** The base used for integers */
|
|
base_t base;
|
|
/** The character used as decimal point for floats */
|
|
UC decimal_point;
|
|
};
|
|
|
|
using parse_options = parse_options_t<char>;
|
|
|
|
} // namespace fast_float
|
|
|
|
#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(_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
|
|
|
|
#ifdef FASTFLOAT_USE_SIMD
|
|
// user defined
|
|
#elif defined(FASTFLOAT_X86_SIMD)
|
|
// user defined level
|
|
static_assert(FASTFLOAT_X86_SIMD == 20 || FASTFLOAT_X86_SIMD == 42 ||
|
|
FASTFLOAT_X86_SIMD == 52 || FASTFLOAT_ARM_NEON,
|
|
"FASTFLOAT_X86_SIMD should be 20(SSE2), 42(SSE4.2) and 52(AVX2)");
|
|
#elif defined(__AVX2__)
|
|
#define FASTFLOAT_X86_SIMD 52
|
|
#elif defined(__AVX__)
|
|
// On MSVC there's no way to check for SSE4.2 specifically so check AVX.
|
|
#define FASTFLOAT_X86_SIMD 50
|
|
#elif defined(__SSE4_2__)
|
|
#define FASTFLOAT_X86_SIMD 42
|
|
#elif defined(__SSE4_1__)
|
|
#define FASTFLOAT_X86_SIMD 41
|
|
#elif defined(__SSSE3__)
|
|
#define FASTFLOAT_X86_SIMD 31
|
|
#elif defined(__SSE3__)
|
|
#define FASTFLOAT_X86_SIMD 30
|
|
#elif defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \
|
|
(defined(_M_AMD64) || defined(_M_X64) || \
|
|
(defined(_M_IX86_FP) && _M_IX86_FP == 2)))
|
|
#define FASTFLOAT_X86_SIMD 20
|
|
#elif defined(__aarch64__) || defined(_M_ARM64)
|
|
#define FASTFLOAT_ARM_NEON 1
|
|
#endif
|
|
|
|
#if FASTFLOAT_X86_SIMD || FASTFLOAT_ARM_NEON
|
|
#define FASTFLOAT_USE_SIMD 1
|
|
|
|
#if defined(__GNUC__)
|
|
// disable -Wcast-align=strict (GCC only)
|
|
#define FASTFLOAT_SIMD_DISABLE_WARNINGS \
|
|
_Pragma("GCC diagnostic push") \
|
|
_Pragma("GCC diagnostic ignored \"-Wcast-align\"")
|
|
|
|
#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop")
|
|
#else
|
|
#define FASTFLOAT_SIMD_DISABLE_WARNINGS
|
|
#define FASTFLOAT_SIMD_RESTORE_WARNINGS
|
|
#endif
|
|
#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
|
|
// g++-9 hits hits this branch, but then fails to compile
|
|
// [[unlikely]]. This happens only with g++-9.
|
|
#if !defined(__GNUC__) || (__GNUC__ != 9)
|
|
#define FASTFLOAT_USE_UNLIKELY_ATTR
|
|
#endif
|
|
#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
|
|
|
|
// clang-format off
|
|
#ifndef FASTFLOAT_ASSERT
|
|
#define FASTFLOAT_ASSERT(x) \
|
|
{ ((void)(x)); }
|
|
#endif
|
|
|
|
#ifndef FASTFLOAT_DEBUG_ASSERT
|
|
#define FASTFLOAT_DEBUG_ASSERT(x) \
|
|
{ ((void)(x)); }
|
|
#endif
|
|
// clang-format on
|
|
|
|
// 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
|
|
|
|
#if FASTFLOAT_HAS_BIT_CAST
|
|
#include <bit>
|
|
#endif
|
|
|
|
namespace fast_float {
|
|
|
|
#if FASTFLOAT_HAS_BIT_CAST
|
|
using std::bit_cast;
|
|
#else
|
|
template <typename To, typename From>
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) {
|
|
// Implementation of std::bit_cast for pre-C++20.
|
|
auto to = To();
|
|
// The cast suppresses a bogus -Wclass-memaccess on GCC.
|
|
std::memcpy(static_cast<void *>(&to), &from, sizeof(to));
|
|
return to;
|
|
}
|
|
#endif
|
|
|
|
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED
|
|
using std::is_constant_evaluated;
|
|
#else
|
|
fastfloat_really_inline constexpr bool is_constant_evaluated() noexcept {
|
|
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
|
|
> {
|
|
};
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
|
|
template <typename UC>
|
|
inline FASTFLOAT_CONSTEXPR14 bool
|
|
fastfloat_strncasecmp3(UC const *actual_mixedcase,
|
|
UC const *expected_lowercase) {
|
|
if (is_constant_evaluated()) {
|
|
for (uint_fast8_t i = 0; i != 3; ++i) {
|
|
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} else {
|
|
uint64_t val1{0}, val2{0};
|
|
uint64_t mask{0};
|
|
if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 1) {
|
|
mask = 0x2020202020202020;
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 2) {
|
|
mask = 0x0020002000200020;
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 4) {
|
|
mask = 0x0000002000000020;
|
|
}
|
|
if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 1 || sizeof(UC) == 2) {
|
|
std::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC));
|
|
std::memcpy(&val2, expected_lowercase, 3 * sizeof(UC));
|
|
val1 |= mask;
|
|
val2 |= mask;
|
|
return val1 == val2;
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 4) {
|
|
std::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC));
|
|
std::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) noexcept {
|
|
if (is_constant_evaluated()) {
|
|
for (uint_fast8_t i = 0; i != 5; ++i) {
|
|
if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} else {
|
|
uint64_t val1{0}, val2{0};
|
|
if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 1) {
|
|
constexpr uint64_t mask = 0x2020202020202020;
|
|
std::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC));
|
|
std::memcpy(&val2, expected_lowercase, 5 * sizeof(UC));
|
|
val1 |= mask;
|
|
val2 |= mask;
|
|
return val1 == val2;
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 2) {
|
|
constexpr uint64_t mask = 0x0020002000200020;
|
|
std::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC));
|
|
std::memcpy(&val2, expected_lowercase, 4 * sizeof(UC));
|
|
val1 |= mask;
|
|
if (val1 != val2) {
|
|
return false;
|
|
}
|
|
return (actual_mixedcase[4] | 32) == (expected_lowercase[4]);
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 4) {
|
|
constexpr uint64_t mask = 0x0000002000000020;
|
|
std::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC));
|
|
std::memcpy(&val2, expected_lowercase, 2 * sizeof(UC));
|
|
val1 |= mask;
|
|
if (val1 != val2) {
|
|
return false;
|
|
}
|
|
std::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC));
|
|
std::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,
|
|
uint_fast8_t const length) noexcept {
|
|
if (is_constant_evaluated()) {
|
|
for (uint_fast8_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};
|
|
uint64_t mask{0};
|
|
if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 1) {
|
|
mask = 0x2020202020202020;
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 2) {
|
|
mask = 0x0020002000200020;
|
|
} else if FASTFLOAT_CONSTEXPR17 (sizeof(UC) == 4) {
|
|
mask = 0x0000002000000020;
|
|
}
|
|
uint_fast8_t sz = 8 / (sizeof(UC));
|
|
for (uint_fast8_t i = 0; i < length; i += sz) {
|
|
sz = sz < (length - i) ? sz : length - i;
|
|
std::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC));
|
|
std::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC));
|
|
val1 |= mask;
|
|
val2 |= mask;
|
|
if (val1 != val2) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|
|
#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;
|
|
am_digits length;
|
|
|
|
constexpr span(T const *_ptr, am_digits _length) noexcept
|
|
: ptr(_ptr), length(_length) {}
|
|
|
|
constexpr span() noexcept = default;
|
|
|
|
constexpr am_digits len() const noexcept { return length; }
|
|
|
|
FASTFLOAT_CONSTEXPR14 const T &operator[](am_digits index) const noexcept {
|
|
FASTFLOAT_DEBUG_ASSERT(index < length);
|
|
return ptr[index];
|
|
}
|
|
};
|
|
|
|
/* alignas(16) - better data cache usage wo align */
|
|
struct value128 {
|
|
uint64_t low;
|
|
uint64_t high;
|
|
|
|
constexpr value128(uint64_t _low, uint64_t _high) noexcept
|
|
: low(_low), high(_high) {}
|
|
|
|
constexpr value128() noexcept : low(0), high(0) {}
|
|
};
|
|
|
|
/* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t
|
|
leading_zeroes_generic(uint64_t input_num) noexcept {
|
|
assert(input_num > 0);
|
|
FASTFLOAT_ASSUME(input_num > 0);
|
|
uint_fast32_t 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 - static_cast<limb_t>(last_bit);
|
|
}
|
|
|
|
/* result might be undefined when input_num is zero */
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t
|
|
leading_zeroes(uint64_t input_num) noexcept {
|
|
assert(input_num > 0);
|
|
FASTFLOAT_ASSUME(input_num > 0);
|
|
if (is_constant_evaluated()) {
|
|
return leading_zeroes_generic(input_num);
|
|
}
|
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
|
#if FASTFLOAT_X86_SIMD >= 52
|
|
// use lzcnt on MSVC only on AVX2 capable CPU's that all have this BMI
|
|
// instruction
|
|
return __lzcnt64(input_num);
|
|
#elif defined(_M_X64) || defined(_M_ARM64)
|
|
unsigned long leading_zero;
|
|
// 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 static_cast<limb_t>(63 - leading_zero);
|
|
#else
|
|
return static_cast<limb_t>(leading_zeroes_generic(input_num));
|
|
#endif
|
|
#elif __has_builtin(__builtin_clzll)
|
|
return static_cast<limb_t>(__builtin_clzll(input_num));
|
|
#else
|
|
// Unlike MSVC, clang and gcc recognize this implementation and replace
|
|
// it with the assembly instructions which are appropriate for the
|
|
// target (lzcnt or bsr + zero handling).
|
|
int n = 64;
|
|
for (; input_num > 0; input_num >>= 1)
|
|
--n;
|
|
return static_cast<limb_t>(n);
|
|
#endif
|
|
}
|
|
|
|
/* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t
|
|
countr_zero_generic_32(uint32_t input_num) noexcept {
|
|
assert(input_num > 0);
|
|
FASTFLOAT_ASSUME(input_num > 0);
|
|
uint_fast16_t 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 static_cast<limb_t>(last_bit);
|
|
}
|
|
|
|
/* count trailing zeroes for 32-bit integers */
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t
|
|
countr_zero_32(uint32_t input_num) noexcept {
|
|
if (is_constant_evaluated()) {
|
|
return countr_zero_generic_32(input_num);
|
|
}
|
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
|
unsigned long trailing_zero = 0;
|
|
if (_BitScanForward(&trailing_zero, input_num)) {
|
|
return static_cast<limb_t>(trailing_zero);
|
|
}
|
|
return 32;
|
|
#else
|
|
return input_num == 0 ? 32 : static_cast<limb_t>(__builtin_ctz(input_num));
|
|
#endif
|
|
}
|
|
|
|
// For what exactly? It's not only for 32bit.
|
|
fastfloat_really_inline constexpr uint64_t emulu(uint32_t x,
|
|
uint32_t y) noexcept {
|
|
return x * static_cast<uint64_t>(y);
|
|
}
|
|
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
|
|
umul128(uint64_t ab, uint64_t cd, uint64_t &hi) noexcept {
|
|
if (is_constant_evaluated()) {
|
|
auto ab_shifted = static_cast<uint32_t>(ab >> 32);
|
|
auto cd_shifted = static_cast<uint32_t>(cd >> 32);
|
|
|
|
auto ad = emulu(ab_shifted, static_cast<uint32_t>(cd));
|
|
auto bd = emulu(static_cast<uint32_t>(ab), static_cast<uint32_t>(cd));
|
|
auto adbc = ad + emulu(static_cast<uint32_t>(ab), cd_shifted);
|
|
auto adbc_carry = static_cast<uint64_t>(adbc < ad) << 32;
|
|
auto lo = bd + (adbc << 32);
|
|
hi = emulu(ab_shifted, cd_shifted) + static_cast<uint32_t>(adbc >> 32) +
|
|
adbc_carry + static_cast<uint64_t>(lo < bd);
|
|
return lo;
|
|
}
|
|
#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
|
|
hi = __umulh(ab, cd);
|
|
return ab * cd;
|
|
#elif (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64) && \
|
|
!defined(__GNUC__))
|
|
return _umul128(ab, cd, &hi); // _umul128 not available on ARM64
|
|
#endif
|
|
}
|
|
|
|
// compute 64-bit a*b
|
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
|
|
full_multiplication(uint64_t a, uint64_t b) noexcept {
|
|
value128 answer;
|
|
#if defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__)
|
|
__uint128_t r = (static_cast<__uint128_t>(a)) * b;
|
|
answer.low = static_cast<uint64_t>(r);
|
|
answer.high = static_cast<uint64_t>(r >> 64);
|
|
#else
|
|
answer.low = umul128(a, b, answer.high);
|
|
#endif
|
|
return answer;
|
|
}
|
|
|
|
/* alignas(16) - better data cache usage without align */
|
|
struct adjusted_mantissa {
|
|
am_mant_t mantissa;
|
|
am_pow_t power2;
|
|
|
|
constexpr adjusted_mantissa() noexcept : mantissa(0), power2(0) {}
|
|
|
|
constexpr bool operator==(adjusted_mantissa const &o) const noexcept {
|
|
return mantissa == o.mantissa && power2 == o.power2;
|
|
}
|
|
|
|
constexpr bool operator!=(adjusted_mantissa const &o) const noexcept {
|
|
return mantissa != o.mantissa || power2 != o.power2;
|
|
}
|
|
};
|
|
|
|
// used by parse_digits_until_19
|
|
constexpr am_mant_t minimal_nineteen_digit_integer{1000000000000000000ULL};
|
|
|
|
// used for binary_format_lookup_tables<T>::max_mantissa
|
|
constexpr am_mant_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 am_bits_t mantissa_explicit_bits();
|
|
static constexpr am_pow_t minimum_exponent();
|
|
static constexpr am_pow_t infinite_power();
|
|
static constexpr am_bits_t sign_index();
|
|
static constexpr am_bits_t
|
|
min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST
|
|
static constexpr am_bits_t max_exponent_fast_path();
|
|
static constexpr am_pow_t max_exponent_round_to_even();
|
|
static constexpr am_pow_t min_exponent_round_to_even();
|
|
static constexpr am_mant_t max_mantissa_fast_path(am_pow_t const power);
|
|
static constexpr am_mant_t
|
|
max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST
|
|
static constexpr am_pow_t largest_power_of_ten();
|
|
static constexpr am_pow_t smallest_power_of_ten();
|
|
static constexpr T exact_power_of_ten(am_pow_t const power);
|
|
static constexpr am_digits 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 uint32_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 uint32_t binary_format_lookup_tables<float, U>::max_mantissa[];
|
|
|
|
#endif
|
|
|
|
template <>
|
|
inline constexpr am_bits_t 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 am_bits_t 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 am_bits_t binary_format<double>::mantissa_explicit_bits() {
|
|
return 52;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_bits_t binary_format<float>::mantissa_explicit_bits() {
|
|
return 23;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<double>::max_exponent_round_to_even() {
|
|
return 23;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<float>::max_exponent_round_to_even() {
|
|
return 10;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<double>::min_exponent_round_to_even() {
|
|
return -4;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<float>::min_exponent_round_to_even() {
|
|
return -17;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<double>::minimum_exponent() {
|
|
return -1023;
|
|
}
|
|
|
|
template <> inline constexpr am_pow_t binary_format<float>::minimum_exponent() {
|
|
return -127;
|
|
}
|
|
|
|
template <> inline constexpr am_pow_t binary_format<double>::infinite_power() {
|
|
return 0x7FF;
|
|
}
|
|
|
|
template <> inline constexpr am_pow_t binary_format<float>::infinite_power() {
|
|
return 0xFF;
|
|
}
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
|
|
template <> inline constexpr am_bits_t binary_format<double>::sign_index() {
|
|
return 63;
|
|
}
|
|
|
|
template <> inline constexpr am_bits_t binary_format<float>::sign_index() {
|
|
return 31;
|
|
}
|
|
|
|
#endif
|
|
|
|
template <>
|
|
inline constexpr am_bits_t binary_format<double>::max_exponent_fast_path() {
|
|
return 22;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_bits_t binary_format<float>::max_exponent_fast_path() {
|
|
return 10;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t binary_format<double>::max_mantissa_fast_path() {
|
|
return am_mant_t(2) << mantissa_explicit_bits();
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t binary_format<float>::max_mantissa_fast_path() {
|
|
return am_mant_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 uint16_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 uint16_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(am_pow_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 am_bits_t
|
|
binary_format<std::float16_t>::max_exponent_fast_path() {
|
|
return 4;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_bits_t
|
|
binary_format<std::float16_t>::mantissa_explicit_bits() {
|
|
return 10;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t
|
|
binary_format<std::float16_t>::max_mantissa_fast_path() {
|
|
return am_mant_t(2) << mantissa_explicit_bits();
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t
|
|
binary_format<std::float16_t>::max_mantissa_fast_path(am_pow_t power) {
|
|
// caller is responsible to ensure that
|
|
FASTFLOAT_ASSUME(power >= 0 && power <= 4);
|
|
//
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)max_mantissa[0], max_mantissa[power];
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_bits_t
|
|
binary_format<std::float16_t>::min_exponent_fast_path() {
|
|
return 0;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::float16_t>::max_exponent_round_to_even() {
|
|
return 5;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::float16_t>::min_exponent_round_to_even() {
|
|
return -22;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<std::float16_t>::minimum_exponent() {
|
|
return -15;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<std::float16_t>::infinite_power() {
|
|
return 0x1F;
|
|
}
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
|
|
template <>
|
|
inline constexpr am_bits_t binary_format<std::float16_t>::sign_index() {
|
|
return 15;
|
|
}
|
|
|
|
#endif
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::float16_t>::largest_power_of_ten() {
|
|
return 4;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::float16_t>::smallest_power_of_ten() {
|
|
return -27;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_digits 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 uint16_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 uint16_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(am_pow_t power) {
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)powers_of_ten[0], powers_of_ten[power];
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_bits_t
|
|
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 am_bits_t
|
|
binary_format<std::bfloat16_t>::mantissa_explicit_bits() {
|
|
return 7;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t
|
|
binary_format<std::bfloat16_t>::max_mantissa_fast_path() {
|
|
return am_mant_t(2) << mantissa_explicit_bits();
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t
|
|
binary_format<std::bfloat16_t>::max_mantissa_fast_path(am_pow_t power) {
|
|
// caller is responsible to ensure that
|
|
FASTFLOAT_ASSUME(power >= 0 && power <= 3);
|
|
//
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)max_mantissa[0], max_mantissa[power];
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_bits_t
|
|
binary_format<std::bfloat16_t>::min_exponent_fast_path() {
|
|
return 0;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::bfloat16_t>::max_exponent_round_to_even() {
|
|
return 3;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::bfloat16_t>::min_exponent_round_to_even() {
|
|
return -24;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<std::bfloat16_t>::minimum_exponent() {
|
|
return -127;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<std::bfloat16_t>::infinite_power() {
|
|
return 0xFF;
|
|
}
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
|
|
template <>
|
|
inline constexpr am_bits_t binary_format<std::bfloat16_t>::sign_index() {
|
|
return 15;
|
|
}
|
|
|
|
#endif
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::bfloat16_t>::largest_power_of_ten() {
|
|
return 38;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t
|
|
binary_format<std::bfloat16_t>::smallest_power_of_ten() {
|
|
return -60;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_digits binary_format<std::bfloat16_t>::max_digits() {
|
|
return 98;
|
|
}
|
|
#endif // __STDCPP_BFLOAT16_T__
|
|
|
|
template <>
|
|
inline constexpr am_mant_t
|
|
binary_format<double>::max_mantissa_fast_path(am_pow_t power) {
|
|
// caller is responsible to ensure that
|
|
FASTFLOAT_ASSUME(power >= 0 && power <= 22);
|
|
#if defined(__clang__)
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)max_mantissa[0], max_mantissa[power];
|
|
#else
|
|
return max_mantissa[power];
|
|
#endif
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_mant_t
|
|
binary_format<float>::max_mantissa_fast_path(am_pow_t power) {
|
|
// caller is responsible to ensure that
|
|
FASTFLOAT_ASSUME(power >= 0 && power <= 10);
|
|
#if defined(__clang__)
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)max_mantissa[0], max_mantissa[power];
|
|
#else
|
|
return max_mantissa[power];
|
|
#endif
|
|
}
|
|
|
|
template <>
|
|
inline constexpr double
|
|
binary_format<double>::exact_power_of_ten(am_pow_t power) {
|
|
// caller is responsible to ensure that
|
|
FASTFLOAT_ASSUME(power >= 0 && power <= 22);
|
|
#if defined(__clang__)
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)powers_of_ten[0], powers_of_ten[power];
|
|
#else
|
|
return powers_of_ten[power];
|
|
#endif
|
|
}
|
|
|
|
template <>
|
|
inline constexpr float
|
|
binary_format<float>::exact_power_of_ten(am_pow_t power) {
|
|
// caller is responsible to ensure that
|
|
FASTFLOAT_ASSUME(power >= 0 && power <= 10);
|
|
#if defined(__clang__)
|
|
// Work around clang bug https://godbolt.org/z/zedh7rrhc
|
|
return (void)powers_of_ten[0], powers_of_ten[power];
|
|
#else
|
|
return powers_of_ten[power];
|
|
#endif
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<double>::largest_power_of_ten() {
|
|
return 308;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<float>::largest_power_of_ten() {
|
|
return 38;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<double>::smallest_power_of_ten() {
|
|
return -342;
|
|
}
|
|
|
|
template <>
|
|
inline constexpr am_pow_t binary_format<float>::smallest_power_of_ten() {
|
|
return -64;
|
|
}
|
|
|
|
template <> inline constexpr am_digits binary_format<double>::max_digits() {
|
|
return 769;
|
|
}
|
|
|
|
template <> inline constexpr am_digits 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(
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
bool const negative,
|
|
#endif
|
|
adjusted_mantissa const &am, T &value) noexcept {
|
|
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());
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
word =
|
|
equiv_uint(word | equiv_uint(negative) << binary_format<T>::sign_index());
|
|
#endif
|
|
value = bit_cast<T>(word);
|
|
}
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
|
|
template <typename = void> struct space_lut {
|
|
static constexpr uint8_t 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 uint8_t space_lut<T>::value[];
|
|
|
|
#endif
|
|
|
|
template <typename UC> constexpr bool is_space(UC c) {
|
|
// wchar_t and char can be signed, so a negative code unit slips past a plain
|
|
// `c < 256` and then indexes the table by its truncated low byte. Compare as
|
|
// unsigned, matching the care taken in ch_to_digit.
|
|
using UnsignedUC = typename std::make_unsigned<UC>::type;
|
|
return static_cast<UnsignedUC>(c) < 256 && space_lut<>::value[uint8_t(c)];
|
|
}
|
|
|
|
#endif
|
|
|
|
template <typename UC> static constexpr uint64_t int_cmp_zeros() {
|
|
static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4),
|
|
"Unsupported character size");
|
|
return (sizeof(UC) == 1) ? 0x3030303030303030
|
|
: (sizeof(UC) == 2)
|
|
? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 |
|
|
uint64_t(UC('0')) << 16 | UC('0'))
|
|
: (uint64_t(UC('0')) << 32 | UC('0'));
|
|
}
|
|
|
|
template <typename UC> static constexpr int int_cmp_len() {
|
|
return sizeof(uint64_t) / sizeof(UC);
|
|
}
|
|
|
|
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
|
|
|
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
|
|
|
|
#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 limb_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 limb_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) noexcept {
|
|
// 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 limb_t max_digits_u64(base_t base) noexcept {
|
|
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(base_t base) noexcept {
|
|
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 fast_float
|
|
|
|
#endif
|