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:
Mathias Agopian
2018-08-17 16:54:50 -07:00
committed by Mathias Agopian
parent 0491c65517
commit 5ed80bc616
3 changed files with 71 additions and 1 deletions

View File

@@ -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 {