From 0d51657278f88d2fb17b3ca65bfe72c406e3f888 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov <vladislav@shchapov.ru> Date: Wed, 30 Nov 2022 22:32:32 +0500 Subject: [PATCH] Add countl_zero function Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> --- include/fmt/format.h | 12 +++++++++++- test/format-impl-test.cc | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 414d11a370527..c60e78a0fbc6f 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<uint32_t>() - 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<uint32_t>((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 46486a6f4a8d0..fb109b56db661 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -353,6 +353,19 @@ TEST(format_impl_test, count_digits) { test_count_digits<uint64_t>(); } +// Tests fmt::detail::countl_zero for unsigned type UInt. +template <typename UInt> void test_countl_zero() { + constexpr auto num_bits = fmt::detail::num_bits<UInt>(); + UInt 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); + } +} + +TEST(format_impl_test, countl_zero) { test_countl_zero<uint32_t>(); } + #if FMT_USE_FLOAT128 TEST(format_impl_test, write_float128) { auto s = std::string();