From cc7fc66899087bb28177dfd6e2c8bd2cfac41190 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 29 Aug 2022 19:31:19 +0200 Subject: [PATCH] Add bitset_ctz function --- m-bitset.h | 27 +++++++++++++++++++++++++++ tests/test-mbitset.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/m-bitset.h b/m-bitset.h index 24c43ed7..3d9a1827 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -786,6 +786,32 @@ m_bitset_clz(const m_bitset_t set) return s; } +/* Count the number of trailing zero */ +static inline size_t +m_bitset_ctz(const m_bitset_t set) +{ + M_B1TSET_CONTRACT(set); + size_t s = set->size; + if (M_UNLIKELY (s == 0)) { + return 0; + } + size_t i = 0, n = (s -1) / M_B1TSET_LIMB_BIT; + size_t m = s % M_B1TSET_LIMB_BIT; + m_b1tset_limb_ct limb = set->ptr[0]; + s = 0; + while (limb == 0 && i < n) { + s += M_B1TSET_LIMB_BIT; + limb = set->ptr[++i]; + } + if (i == n && m != 0) { + m_b1tset_limb_ct mask = (((m_b1tset_limb_ct)1) << m) - 1; + limb &= mask; + } + unsigned ctz = m_core_ctz64(limb); + s += (ctz == 64) ? m : ctz; + return s; +} + // For GCC or CLANG or ICC #if defined(__GNUC__) static inline size_t m_b1tset_popcount64(m_b1tset_limb_ct limb) @@ -910,6 +936,7 @@ m_bitset_popcount(const m_bitset_t set) #define bitset_not m_bitset_not #define bitset_hash m_bitset_hash #define bitset_clz m_bitset_clz +#define bitset_ctz m_bitset_ctz #define bitset_popcount m_bitset_popcount #define bitset_get_str m_bitset_get_str diff --git a/tests/test-mbitset.c b/tests/test-mbitset.c index 2b902ab0..3570b575 100644 --- a/tests/test-mbitset.c +++ b/tests/test-mbitset.c @@ -377,6 +377,47 @@ static void test_clz(void) bitset_set_str(s1, "[10000011100000110010101010110000011111111111111110000001110001110001110001110000]"); assert(bitset_popcount(s1) == 40); } + + M_LET(s1, bitset_t) { + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]"); + assert(bitset_ctz(s1) == 116); + bitset_set_str(s1, "[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]"); + assert(bitset_ctz(s1) == 0); + bitset_set_str(s1, "[01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]"); + assert(bitset_ctz(s1) == 1); + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 115); + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010]"); + assert(bitset_ctz(s1) == 114); + bitset_set_str(s1, "[000001]"); + assert(bitset_ctz(s1) == 5); + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 64); + bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000010000]"); + assert(bitset_ctz(s1) == 64); + bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 63); + bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000001000]"); + assert(bitset_ctz(s1) == 63); + bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 65); + bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000010000]"); + assert(bitset_ctz(s1) == 65); + bitset_set_str(s1, "[00001000001110000011001010101011000001111111111111111000000111000111000111000111000]"); + assert(bitset_ctz(s1) == 4); + bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 128); + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 127); + bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_ctz(s1) == 129); + bitset_set_str(s1, "[0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000000000000000001]"); + assert(bitset_ctz(s1) == 128); + bitset_set_str(s1, "[000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000000001000]"); + assert(bitset_ctz(s1) == 127); + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000011000000000000000000000000]"); + assert(bitset_ctz(s1) == 129); + } } int main(void)