Skip to content

Commit ed4bdb8

Browse files
[libc][__support][bit] add count_zeros (#82076)
Will be useful for implementing C23 stdbit.h's stdc_count_zeros and stdc_count_ones.
1 parent a468d02 commit ed4bdb8

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

libc/src/__support/CPP/bit.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,35 @@ template <typename T, typename = cpp::enable_if_t<cpp::is_unsigned_v<T>>>
248248
return value == cpp::numeric_limits<T>::max() ? 0 : countr_zero(value) + 1;
249249
}
250250

251+
/// Count number of 1's aka population count or hamming weight.
252+
///
253+
/// Only unsigned integral types are allowed.
254+
template <typename T, typename = cpp::enable_if_t<cpp::is_unsigned_v<T>>>
255+
[[nodiscard]] LIBC_INLINE constexpr int count_ones(T value) {
256+
int count = 0;
257+
for (int i = 0; i != cpp::numeric_limits<T>::digits; ++i)
258+
if ((value >> i) & 0x1)
259+
++count;
260+
return count;
261+
}
262+
#define ADD_SPECIALIZATION(TYPE, BUILTIN) \
263+
template <> \
264+
[[nodiscard]] LIBC_INLINE constexpr int count_ones<TYPE>(TYPE value) { \
265+
return BUILTIN(value); \
266+
}
267+
ADD_SPECIALIZATION(unsigned char, __builtin_popcount)
268+
ADD_SPECIALIZATION(unsigned short, __builtin_popcount)
269+
ADD_SPECIALIZATION(unsigned, __builtin_popcount)
270+
ADD_SPECIALIZATION(unsigned long, __builtin_popcountl)
271+
ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll)
272+
// TODO: 128b specializations?
273+
#undef ADD_SPECIALIZATION
274+
275+
template <typename T, typename = cpp::enable_if_t<cpp::is_unsigned_v<T>>>
276+
[[nodiscard]] LIBC_INLINE constexpr int count_zeros(T value) {
277+
return count_ones<T>(static_cast<T>(~value));
278+
}
279+
251280
} // namespace LIBC_NAMESPACE::cpp
252281

253282
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H

libc/test/src/__support/CPP/bit_test.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,17 @@ TYPED_TEST(LlvmLibcBitTest, FirstTrailingOne, UnsignedTypes) {
232232
EXPECT_EQ(first_trailing_one<T>(T(1) << i), i + 1);
233233
}
234234

235+
TYPED_TEST(LlvmLibcBitTest, CountZeros, UnsignedTypes) {
236+
EXPECT_EQ(count_zeros(T(0)), cpp::numeric_limits<T>::digits);
237+
for (int i = 0; i != cpp::numeric_limits<T>::digits; ++i)
238+
EXPECT_EQ(count_zeros<T>(cpp::numeric_limits<T>::max() >> i), i);
239+
}
240+
241+
TYPED_TEST(LlvmLibcBitTest, CountOnes, UnsignedTypes) {
242+
EXPECT_EQ(count_ones(T(0)), 0);
243+
for (int i = 0; i != cpp::numeric_limits<T>::digits; ++i)
244+
EXPECT_EQ(count_ones<T>(cpp::numeric_limits<T>::max() >> i),
245+
cpp::numeric_limits<T>::digits - i);
246+
}
247+
235248
} // namespace LIBC_NAMESPACE::cpp

0 commit comments

Comments
 (0)