diff --git a/m-bitset.h b/m-bitset.h index fbbc46cf..bb82d353 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -786,6 +786,36 @@ bitset_clz(const bitset_t set) return s; } +// For GCC or CLANG or ICC +#if defined(__GNUC__) +static inline size_t m_b1tset_popcount64(bitset_limb_ct limb) +{ + return (size_t) __builtin_popcountll(limb); +} +#else +// MSVC __popcnt64 may not exist on the target architecture (no emulation layer) +// Use emulation layer: https://en.wikipedia.org/wiki/Hamming_weight +static inline size_t m_b1tset_popcount64(bitset_limb_ct limb) +{ + limb = limb - ((limb >> 1) & 0x5555555555555555ULL); + limb = (limb & 0x3333333333333333ULL) + ((limb >> 2) & 0x3333333333333333ULL); + limb = (limb + (limb >> 4)) & 0x0f0f0f0f0f0f0f0fULL; + return (limb * 0x0101010101010101ULL) >> 56; +} +#endif + +/* Count the number of 1 */ +static inline size_t +bitset_popcount(const bitset_t set) +{ + M_B1TSET_CONTRACT(set); + size_t s = 0; + size_t n = (set->size + M_B1TSET_LIMB_BIT - 1) / M_B1TSET_LIMB_BIT; + for(size_t i = 0 ; i < n; i++) + s += m_b1tset_popcount64(set->ptr[i]); + return s; +} + /* Oplist for a bitset */ #define BITSET_OPLIST \ (INIT(bitset_init) \ diff --git a/tests/test-mbitset.c b/tests/test-mbitset.c index d3488dfc..c65f43d3 100644 --- a/tests/test-mbitset.c +++ b/tests/test-mbitset.c @@ -366,6 +366,17 @@ static void test_clz(void) bitset_set_at(s1, 0, false); assert (bitset_clz(s1) == 64+620+1); } + + M_LET(s1, bitset_t) { + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]"); + assert(bitset_popcount(s1) == 0); + bitset_set_str(s1, "[10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]"); + assert(bitset_popcount(s1) == 1); + bitset_set_str(s1, "[00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]"); + assert(bitset_popcount(s1) == 1); + bitset_set_str(s1, "[10000011100000110010101010110000011111111111111110000001110001110001110001110000]"); + assert(bitset_popcount(s1) == 40); + } } int main(void)