Add ctz to utils::algorithm
Use CTZ in bitset.forEachBitSet() so we can efficiently go through them in order instead of reverse order.
This commit is contained in:
committed by
Mathias Agopian
parent
0491c65517
commit
5ed80bc616
@@ -50,6 +50,23 @@ constexpr inline T clz(T x) noexcept {
|
||||
}
|
||||
return (sizeof(T) * CHAR_BIT) - details::popcount(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr inline T ctz(T x) noexcept {
|
||||
static_assert(sizeof(T) <= sizeof(uint64_t), "details::ctz() only support up to 64 bits");
|
||||
T c = sizeof(T) * 8;
|
||||
x &= -signed(x);
|
||||
if (x) c--;
|
||||
if (sizeof(T) * 8 > 32) { // if() only needed to quash compiler warnings
|
||||
if (x & 0x00000000FFFFFFFF) c -= 32;
|
||||
}
|
||||
if (x & 0x0000FFFF) c -= 16;
|
||||
if (x & 0x00FF00FF) c -= 8;
|
||||
if (x & 0x0F0F0F0F) c -= 4;
|
||||
if (x & 0x33333333) c -= 2;
|
||||
if (x & 0x55555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
constexpr inline UTILS_PUBLIC UTILS_PURE
|
||||
@@ -79,6 +96,32 @@ unsigned long long UTILS_ALWAYS_INLINE clz(unsigned long long x) noexcept {
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr inline UTILS_PUBLIC UTILS_PURE
|
||||
unsigned int UTILS_ALWAYS_INLINE ctz(unsigned int x) noexcept {
|
||||
#if __has_builtin(__builtin_ctz)
|
||||
return __builtin_ctz(x);
|
||||
#else
|
||||
return details::ctz(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr inline UTILS_PUBLIC UTILS_PURE
|
||||
unsigned long UTILS_ALWAYS_INLINE ctz(unsigned long x) noexcept {
|
||||
#if __has_builtin(__builtin_ctzl)
|
||||
return __builtin_ctzl(x);
|
||||
#else
|
||||
return details::ctz(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr inline UTILS_PUBLIC UTILS_PURE
|
||||
unsigned long long UTILS_ALWAYS_INLINE ctz(unsigned long long x) noexcept {
|
||||
#if __has_builtin(__builtin_ctzll)
|
||||
return __builtin_ctzll(x);
|
||||
#else
|
||||
return details::ctz(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr inline UTILS_PUBLIC UTILS_PURE
|
||||
unsigned int UTILS_ALWAYS_INLINE popcount(unsigned int x) noexcept {
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
T v = storage[i];
|
||||
while (v) {
|
||||
T k = (BITS_PER_WORD - 1) - utils::clz(v);
|
||||
T k = utils::ctz(v);
|
||||
v &= ~(T(1) << k);
|
||||
exec(size_t(k + BITS_PER_WORD * i));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ static inline T count_leading_zeros(T v) noexcept {
|
||||
return utils::clz(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T count_trailing_zeros(T v) noexcept {
|
||||
return utils::ctz(v);
|
||||
}
|
||||
|
||||
TEST(AlgorithmTest, details_clz) {
|
||||
for (uint64_t i = 1, j = 63; i < 64; i *= 2, j--) {
|
||||
EXPECT_EQ(j, details::clz(i));
|
||||
@@ -55,6 +60,28 @@ TEST(AlgorithmTest, clz) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlgorithmTest, details_ctz) {
|
||||
for (uint64_t i = 1, j = 0; i < 64; i *= 2, j++) {
|
||||
EXPECT_EQ(j, details::ctz(i));
|
||||
}
|
||||
for (uint32_t i = 1, j = 0; i < 32; i *= 2, j++) {
|
||||
EXPECT_EQ(j, details::ctz(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlgorithmTest, ctz) {
|
||||
for (uint64_t i = 1, j = 0; i < 64; i *= 2, j++) {
|
||||
EXPECT_EQ(j, ctz(i));
|
||||
EXPECT_EQ(j, details::ctz(i));
|
||||
EXPECT_EQ(j, count_trailing_zeros(i));
|
||||
}
|
||||
for (uint32_t i = 1, j = 0; i < 32; i *= 2, j++) {
|
||||
EXPECT_EQ(j, ctz(i));
|
||||
EXPECT_EQ(j, details::ctz(i));
|
||||
EXPECT_EQ(j, count_trailing_zeros(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlgorithmTest, details_popcount) {
|
||||
EXPECT_EQ(0, details::popcount(0u));
|
||||
EXPECT_EQ(0, details::popcount(0lu));
|
||||
|
||||
Reference in New Issue
Block a user