diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index feb7815d..9baf2ca1 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -216,11 +216,10 @@ template struct basic_fp { template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } // Assigns n to this and return true iff predecessor is closer than successor. - template FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert((std::numeric_limits::is_iec559 && - std::numeric_limits::digits <= 113) || - is_float128::value, - "unsupported FP"); + template ::is_iec559)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); // Assume Float is in the format [sign][exponent][significand]. using carrier_uint = typename dragonbox::float_info::carrier_uint; const auto num_float_significand_bits = @@ -231,8 +230,8 @@ template struct basic_fp { f = static_cast(u & significand_mask); auto biased_e = static_cast((u & exponent_mask()) >> num_float_significand_bits); - // The predecessor is closer if n is a normalized power of 2 (f == 0) other - // than the smallest normalized number (biased_e > 1). + // The predecessor is closer if n is a normalized power of 2 (f == 0) + // other than the smallest normalized number (biased_e > 1). auto is_predecessor_closer = f == 0 && biased_e > 1; if (biased_e == 0) biased_e = 1; // Subnormals use biased exponent 1 (min exponent). @@ -242,6 +241,13 @@ template struct basic_fp { if (!has_implicit_bit()) ++e; return is_predecessor_closer; } + + template ::is_iec559)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } }; using fp = basic_fp; diff --git a/include/fmt/format.h b/include/fmt/format.h index fe74db64..d6a77cc2 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -990,11 +990,12 @@ constexpr auto is_negative(T) -> bool { return false; } -template constexpr auto is_supported_floating_point(T) -> bool { - return (std::is_same() && FMT_USE_FLOAT) || - (std::is_same() && FMT_USE_DOUBLE) || - (std::is_same() && FMT_USE_LONG_DOUBLE) || - is_float128(); +template +FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { + if (std::is_same()) return FMT_USE_FLOAT; + if (std::is_same()) return FMT_USE_DOUBLE; + if (std::is_same()) return FMT_USE_LONG_DOUBLE; + return true; } // Smallest of uint32_t, uint64_t, uint128_t that is large enough to @@ -2345,14 +2346,14 @@ template ::value&& FMT_CONSTEXPR20 bool isfinite(T value) { constexpr T inf = T(std::numeric_limits::infinity()); if (is_constant_evaluated()) - return !isnan(value) && value != inf && value != -inf; + return !detail::isnan(value) && value != inf && value != -inf; return std::isfinite(value); } template ::value)> FMT_CONSTEXPR bool isfinite(T value) { T inf = T(std::numeric_limits::infinity()); // std::isfinite doesn't support __float128. - return !isnan(value) && value != inf && value != -inf; + return !detail::isnan(value) && value != inf && value != -inf; } template ::value)> diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index f6f2860d..bea9bd67 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -361,6 +361,37 @@ TEST(format_impl_test, write_float128) { } #endif +struct double_double { + double a; + double b; + + explicit constexpr double_double(double a_val = 0, double b_val = 0) + : a(a_val), b(b_val) {} + + operator double() const { return a + b; } + auto operator-() const -> double_double { return double_double(-a, -b); } +}; + +bool operator>=(const double_double& lhs, const double_double& rhs) { + return lhs.a + lhs.b >= rhs.a + rhs.b; +} + +namespace std { +template <> struct is_floating_point : std::true_type {}; +template <> struct numeric_limits { + static constexpr bool is_iec559 = false; + static constexpr int digits = 106; +}; +} // namespace std + +TEST(format_impl_test, write_double_double) { + auto s = std::string(); + fmt::detail::write(std::back_inserter(s), double_double(42), {}); +#ifndef _MSC_VER // MSVC has an issue with specializing is_floating_point. + EXPECT_EQ(s, "42"); +#endif +} + #ifdef _WIN32 # include