diff --git a/include/fmt/format.h b/include/fmt/format.h index 414d11a3..c60e78a0 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -472,6 +472,16 @@ inline auto bit_cast(const From& from) -> To { return result; } +FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); +#endif + int lz = 0; + constexpr uint32_t msb_mask = 1u << (num_bits() - 1); + for (; (n & msb_mask) == 0; n <<= 1) lz++; + return lz; +} + FMT_INLINE void assume(bool condition) { (void)condition; #if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION @@ -3149,7 +3159,7 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision, const auto leading_mask = carrier_uint(0xF) << leading_shift; const auto leading_xdigit = static_cast((f.f & leading_mask) >> leading_shift); - if (leading_xdigit > 1) f.e -= (32 - FMT_BUILTIN_CLZ(leading_xdigit) - 1); + if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1); int print_xdigits = num_xdigits - 1; if (precision >= 0 && print_xdigits > precision) { diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 46486a6f..7876ba78 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -353,6 +353,16 @@ TEST(format_impl_test, count_digits) { test_count_digits(); } +TEST(format_impl_test, countl_zero) { + constexpr auto num_bits = fmt::detail::num_bits(); + uint32_t n = 1u; + for (int i = 1; i < num_bits - 1; i++) { + n <<= 1; + EXPECT_EQ(fmt::detail::countl_zero(n - 1), num_bits - i); + EXPECT_EQ(fmt::detail::countl_zero(n), num_bits - i - 1); + } +} + #if FMT_USE_FLOAT128 TEST(format_impl_test, write_float128) { auto s = std::string();