diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index d7ef3d9..c870b14 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -72,7 +72,7 @@ to_extended(T value) noexcept { binary_format::minimum_exponent(); equiv_uint bits; #if FASTFLOAT_HAS_BIT_CAST - bits = std::bit_cast(value); + bits = bit_cast(value); #else ::memcpy(&bits, &value, sizeof(T)); #endif diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 0334c64..8267347 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -260,6 +260,88 @@ struct is_supported_char_type > { }; +union float_union { + float f; + uint32_t bits; +}; + +union double_union { + double f; + uint64_t bits; +}; + +template constexpr T bit_cast(const U &u); + +template <> +fastfloat_really_inline constexpr float bit_cast(const uint32_t &u) { + float_union fu; + fu.bits = u; + return fu.f; +} + +template <> +fastfloat_really_inline constexpr double bit_cast(const uint64_t &u) { + double_union fu; + fu.bits = u; + return fu.f; +} + +template <> +fastfloat_really_inline constexpr uint32_t bit_cast(const float &u) { + float_union fu; + fu.f = u; + return fu.bits; +} + +template <> +fastfloat_really_inline constexpr uint64_t bit_cast(const double &u) { + double_union fu; + fu.f = u; + return fu.bits; +} + +#ifdef __STDCPP_FLOAT16_T__ +union float16_union { + std::float16_t f; + uint16_t bits; +}; + +template <> +fastfloat_really_inline constexpr uint16_t bit_cast(const std::float16_t &u) { + float16_union fu; + fu.f = u; + return fu.bits; +} + +template <> +fastfloat_really_inline constexpr std::float16_t bit_cast(const uint16_t &u) { + float16_union fu; + fu.bits = u; + return fu.f; +} +#endif // __STDCPP_FLOAT16_T__ + +#ifdef __STDCPP_BFLOAT16_T__ +union bfloat16_union { + std::bfloat16_t f; + uint16_t bits; +}; + +template <> +fastfloat_really_inline constexpr uint16_t bit_cast(const std::bfloat16_t &u) { + bfloat16_union fu; + fu.f = u; + return fu.bits; +} + +template <> +fastfloat_really_inline constexpr std::bfloat16_t bit_cast(const uint16_t &u) { + bfloat16_union fu; + fu.bits = u; + return fu.f; +} +#endif // __STDCPP_BFLOAT16_T__ + // Compares two ASCII strings in a case insensitive manner. template inline FASTFLOAT_CONSTEXPR14 bool @@ -630,12 +712,13 @@ inline constexpr uint64_t binary_format::max_mantissa_fast_path() { // credit: Jakub Jelínek #ifdef __STDCPP_FLOAT16_T__ - template struct binary_format_lookup_tables { - static constexpr std::float16_t powers_of_ten[] = {}; - static constexpr uint64_t max_mantissa[] = {}; + static constexpr std::float16_t powers_of_ten[] = {1}; // todo: fix this + static constexpr uint64_t max_mantissa[] = {1}; // todo: fix this }; +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + template constexpr std::float16_t binary_format_lookup_tables::powers_of_ten[]; @@ -644,6 +727,33 @@ template constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; +#endif + +template <> +inline constexpr std::float16_t +binary_format::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::equiv_uint +binary_format::exponent_mask() { + return 0x7C00; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x03FF; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x0400; +} + template <> inline constexpr int binary_format::max_exponent_fast_path() { return 0; @@ -655,6 +765,13 @@ binary_format::max_mantissa_fast_path() { return 0; } +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + template <> inline constexpr int binary_format::min_exponent_fast_path() { return 0; @@ -705,13 +822,13 @@ template <> constexpr size_t binary_format::max_digits() { // credit: Jakub Jelínek #ifdef __STDCPP_BFLOAT16_T__ - template struct binary_format_lookup_tables { - static constexpr std::bfloat16_t powers_of_ten[] = {}; - - static constexpr uint64_t max_mantissa[] = {}; + static constexpr std::bfloat16_t powers_of_ten[] = {1}; // todo: fix this + static constexpr uint64_t max_mantissa[] = {1}; // todo: fix this }; +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + template constexpr std::bfloat16_t binary_format_lookup_tables::powers_of_ten[]; @@ -720,17 +837,51 @@ template constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; +#endif + +template <> +inline constexpr std::bfloat16_t +binary_format::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::max_exponent_fast_path() { return 0; } +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7F80; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x007F; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x0080; +} + template <> inline constexpr uint64_t binary_format::max_mantissa_fast_path() { return 0; } +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + template <> inline constexpr int binary_format::min_exponent_fast_path() { return 0; @@ -892,6 +1043,34 @@ to_float(bool negative, adjusted_mantissa am, T &value) { #endif } +#ifdef __STDCPP_FLOAT16_T__ +template <> +fastfloat_really_inline void to_float(bool negative, + adjusted_mantissa am, + std::float16_t &value) { + constexpr int mantissa_bits = + binary_format::mantissa_explicit_bits(); + value = bit_cast( + uint16_t(am.mantissa | (uint16_t(am.power2) << mantissa_bits) | + (negative ? 0x8000 : 0))); +} + +#endif // __STDCPP_FLOAT16_T__ + +#ifdef __STDCPP_BFLOAT16_T__ +template <> +fastfloat_really_inline void to_float(bool negative, + adjusted_mantissa am, + std::bfloat16_t &value) { + constexpr int mantissa_bits = + binary_format::mantissa_explicit_bits(); + value = bit_cast( + uint16_t(am.mantissa | (uint16_t(am.power2) << mantissa_bits) | + (negative ? 0x8000 : 0))); +} + +#endif // __STDCPP_BFLOAT16_T__ + template 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, @@ -944,10 +1123,12 @@ template <> constexpr char16_t const *str_const_nan() { template <> constexpr char32_t const *str_const_nan() { return U"nan"; } + #ifdef __cpp_char8_t template <> constexpr char8_t const *str_const_nan() { return u8"nan"; } + #endif template constexpr UC const *str_const_inf(); @@ -965,10 +1146,12 @@ template <> constexpr char16_t const *str_const_inf() { template <> constexpr char32_t const *str_const_inf() { return U"infinity"; } + #ifdef __cpp_char8_t template <> constexpr char8_t const *str_const_inf() { return u8"infinity"; } + #endif template struct int_luts { @@ -1038,6 +1221,7 @@ fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) { static_assert(std::is_same, uint64_t>::value, "equiv_uint should be uint64_t for double"); + static_assert(std::is_same, uint32_t>::value, "equiv_uint should be uint32_t for float"); @@ -1051,6 +1235,18 @@ static_assert(std::is_same, uint32_t>::value, "equiv_uint should be uint32_t for std::float32_t"); #endif +#ifdef __STDCPP_FLOAT16_T__ +static_assert( + std::is_same::equiv_uint, uint16_t>::value, + "equiv_uint should be uint16_t for std::float16_t"); +#endif + +#ifdef __STDCPP_BFLOAT16_T__ +static_assert( + std::is_same::equiv_uint, uint16_t>::value, + "equiv_uint should be uint16_t for std::bfloat16_t"); +#endif + constexpr chars_format operator~(chars_format rhs) noexcept { using int_type = std::underlying_type::type; return static_cast(~static_cast(rhs)); diff --git a/tests/example_test.cpp b/tests/example_test.cpp index 447eedf..cefaf29 100644 --- a/tests/example_test.cpp +++ b/tests/example_test.cpp @@ -122,6 +122,7 @@ int main() { } std::cout << "parsed the number " << result << std::endl; #ifdef __STDCPP_FLOAT16_T__ + printf("16-bit float\n"); // Parse as 16-bit float std::float16_t parsed_16{}; input = "10000e-1452";