From 8b179b4f95342c67c14f8d5af81833c7186b3a5c Mon Sep 17 00:00:00 2001 From: Alexander Lopez Date: Tue, 17 Dec 2024 19:14:02 -0800 Subject: [PATCH] add pop count and capacity --- ccc/bitset.h | 23 +++++++++++++-- ccc/impl/impl_bitset.h | 12 +------- src/bitset.c | 65 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/ccc/bitset.h b/ccc/bitset.h index 4d26bfc2..5218014f 100644 --- a/ccc/bitset.h +++ b/ccc/bitset.h @@ -54,11 +54,10 @@ from the stack or data segment as determined by the user. */ @param [in] cap the number of bits that will be stored in this bit set. @param [in] alloc_fn the allocation function for a dynamic bit set or NULL. @param [in] aux auxiliary data needed for allocation of the bit set. -@param [in] optional_size the number of existing bits set to true, if any. @return the initialized bit set on the right hand side of an equality operator (e.g. ccc_bitset b = ccc_btst_init(...);). */ -#define ccc_btst_init(bitblock_ptr, cap, alloc_fn, aux, optional_size...) \ - ccc_impl_btst_init(bitblock_ptr, cap, alloc_fn, aux, optional_size) +#define ccc_btst_init(bitblock_ptr, cap, alloc_fn, aux) \ + ccc_impl_btst_init(bitblock_ptr, cap, alloc_fn, aux) /**@}*/ @@ -143,4 +142,22 @@ ccc_result ccc_btst_flip_all(ccc_bitset *btst); /**@}*/ +/** @name State Interface +Obtain state from the container. */ +/**@{*/ + +/** @brief Return total number of bits tracked by the set. +@param [in] btst a pointer to the bit set. +@return the total number of bits currently tracked by the set regardless of +true or false state of each. 0 is returned if btst is NULL. */ +size_t ccc_btst_capacity(ccc_bitset const *btst); + +/** @brief Return the number of bits set to CCC_TRUE. O(n). +@param [in] btst a pointer to the bit set. +@return the total number of bits currently set to CCC_TRUE. 0 is returned if +btst is NULL. */ +size_t ccc_btst_popcount(ccc_bitset const *btst); + +/**@}*/ + #endif /* CCC_BITSET */ diff --git a/ccc/impl/impl_bitset.h b/ccc/impl/impl_bitset.h index 08ac089f..4d05ef85 100644 --- a/ccc/impl/impl_bitset.h +++ b/ccc/impl/impl_bitset.h @@ -13,7 +13,6 @@ struct ccc_bitset_ { ccc_bitblock_ *set_; size_t cap_; - size_t sz_; ccc_alloc_fn *alloc_; void *aux_; }; @@ -21,25 +20,16 @@ struct ccc_bitset_ /** @private Number of bits in a block. */ #define CCC_IMPL_BTST_BLOCK_BITS ((size_t)(sizeof(ccc_bitblock_) * CHAR_BIT)) -/** @private */ -#define IMPL_BTST_NON_IMPL_BTST_DEFAULT_SIZE(...) __VA_ARGS__ -/** @private */ -#define IMPL_BTST_DEFAULT_SIZE(...) 0 -/** @private */ -#define IMPL_BTST_OPTIONAL_SIZE(...) \ - __VA_OPT__(IMPL_BTST_NON_)##IMPL_BTST_DEFAULT_SIZE(__VA_ARGS__) - /** @private */ #define ccc_impl_bitblocks(bit_cap) \ ((size_t)((bit_cap) \ + ((CCC_IMPL_BTST_BLOCK_BITS - 1) / CCC_IMPL_BTST_BLOCK_BITS))) /** @private */ -#define ccc_impl_btst_init(bitblock_ptr, cap, alloc_fn, aux, ...) \ +#define ccc_impl_btst_init(bitblock_ptr, cap, alloc_fn, aux) \ { \ .set_ = (bitblock_ptr), \ .cap_ = (cap), \ - .sz_ = IMPL_BST_OPTIONAL_SIZE(__VA_ARGS__), \ .alloc_ = (alloc_fn), \ .aux_ = (aux), \ } diff --git a/src/bitset.c b/src/bitset.c index 57ef745c..f06a7304 100644 --- a/src/bitset.c +++ b/src/bitset.c @@ -1,3 +1,4 @@ +#include #include #include @@ -13,6 +14,7 @@ static ccc_bitblock_ on(size_t bit_i); static ccc_bitblock_ last_on(struct ccc_bitset_ const *); static ccc_tribool status(ccc_bitblock_ const *, size_t bit_i); static size_t blocks(size_t bits); +static unsigned popcount(ccc_bitblock_); /*======================= Public Interface ==============================*/ @@ -24,9 +26,9 @@ ccc_btst_set(ccc_bitset *const btst, size_t const i, ccc_tribool const b) return CCC_BOOL_ERR; } ccc_bitblock_ *const block = &btst->set_[block_i(i)]; - ccc_tribool const res = status(block, i); + ccc_tribool const was = status(block, i); set(block, i, b); - return res; + return was; } ccc_tribool @@ -38,9 +40,9 @@ ccc_btst_set_at(ccc_bitset *const btst, size_t const i, ccc_tribool const b) return CCC_BOOL_ERR; } ccc_bitblock_ *const block = &btst->set_[b_i]; - ccc_tribool const res = status(block, i); + ccc_tribool const was = status(block, i); set(block, i, b); - return res; + return was; } ccc_result @@ -66,9 +68,9 @@ ccc_btst_reset(ccc_bitset *const btst, size_t const i) return CCC_BOOL_ERR; } ccc_bitblock_ *const block = &btst->set_[block_i(i)]; - ccc_tribool const res = status(block, i); + ccc_tribool const was = status(block, i); *block &= ~on(i); - return res; + return was; } ccc_tribool @@ -80,9 +82,9 @@ ccc_btst_reset_at(ccc_bitset *const btst, size_t const i) return CCC_BOOL_ERR; } ccc_bitblock_ *const block = &btst->set_[b_i]; - ccc_tribool const res = status(block, i); + ccc_tribool const was = status(block, i); *block &= ~on(i); - return res; + return was; } ccc_result @@ -108,9 +110,9 @@ ccc_btst_flip(ccc_bitset *const btst, size_t const i) return CCC_BOOL_ERR; } ccc_bitblock_ *const block = &btst->set_[block_i(i)]; - ccc_tribool const res = status(block, i); + ccc_tribool const was = status(block, i); *block ^= on(i); - return res; + return was; } ccc_tribool @@ -122,9 +124,9 @@ ccc_btst_flip_at(ccc_bitset *const btst, size_t const i) return CCC_BOOL_ERR; } ccc_bitblock_ *const block = &btst->set_[b_i]; - ccc_tribool const res = status(block, i); + ccc_tribool const was = status(block, i); *block ^= on(i); - return res; + return was; } ccc_result @@ -147,6 +149,29 @@ ccc_btst_flip_all(ccc_bitset *const btst) return CCC_OK; } +size_t +ccc_btst_capacity(ccc_bitset const *const btst) +{ + if (!btst) + { + return 0; + } + return btst->cap_; +} + +size_t +ccc_btst_popcount(ccc_bitset const *const btst) +{ + if (!btst) + { + return 0; + } + size_t cnt = 0; + for (size_t i = 0; i < btst->cap_; cnt += popcount(btst->set_[i]), ++i) + {} + return cnt; +} + /*======================= Static Helpers ==============================*/ static inline void @@ -202,3 +227,19 @@ blocks(size_t const bits) size_t)((bits) + ((CCC_IMPL_BTST_BLOCK_BITS - 1) / CCC_IMPL_BTST_BLOCK_BITS))); } + +static inline unsigned +popcount(ccc_bitblock_ const b) +{ +#if defined(__GNUC__) || defined(__clang__) + /* There are different pop counts for different integer widths. Be sure to + catch the use of the wrong one by mistake here at compile time. */ + static_assert(sizeof(ccc_bitblock_) == sizeof(unsigned)); + return __builtin_popcount(b); +#else + unsigned cnt = 0; + for (; b; cnt += b & 1U, b >>= 1U) + {} + return cnt; +#endif +}