From a1c7c58f713789c821041231c3b22d04b17c8e71 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Fri, 1 Jun 2018 16:04:41 -0700 Subject: [PATCH] util/bit_array: add functions to count 0/1 bits Change-Id: I7c1ad078982a19c4093e787731974986011f535b Signed-off-by: Daniel Verkamp Reviewed-on: https://review.gerrithub.io/413295 Tested-by: SPDK Automated Test System Reviewed-by: Shuhei Matsumoto Reviewed-by: Jim Harris --- include/spdk/bit_array.h | 18 ++++++ lib/util/bit_array.c | 25 +++++++++ test/unit/lib/util/bit_array.c/bit_array_ut.c | 56 ++++++++++++++++++- 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/include/spdk/bit_array.h b/include/spdk/bit_array.h index b73919b91..fb28a0f93 100644 --- a/include/spdk/bit_array.h +++ b/include/spdk/bit_array.h @@ -155,6 +155,24 @@ uint32_t spdk_bit_array_find_first_set(const struct spdk_bit_array *ba, uint32_t */ uint32_t spdk_bit_array_find_first_clear(const struct spdk_bit_array *ba, uint32_t start_bit_index); +/** + * Count the number of set bits in the array. + * + * \param ba The bit array to search. + * + * \return the number of bits set in the array. + */ +uint32_t spdk_bit_array_count_set(const struct spdk_bit_array *ba); + +/** + * Count the number of cleared bits in the array. + * + * \param ba The bit array to search. + * + * \return the number of bits cleared in the array. + */ +uint32_t spdk_bit_array_count_clear(const struct spdk_bit_array *ba); + #ifdef __cplusplus } #endif diff --git a/lib/util/bit_array.c b/lib/util/bit_array.c index cf5753bbc..394b84bbb 100644 --- a/lib/util/bit_array.c +++ b/lib/util/bit_array.c @@ -41,6 +41,7 @@ typedef uint64_t spdk_bit_array_word; #define SPDK_BIT_ARRAY_WORD_TZCNT(x) (__builtin_ctzll(x)) +#define SPDK_BIT_ARRAY_WORD_POPCNT(x) (__builtin_popcountll(x)) #define SPDK_BIT_ARRAY_WORD_C(x) ((spdk_bit_array_word)(x)) #define SPDK_BIT_ARRAY_WORD_BYTES sizeof(spdk_bit_array_word) #define SPDK_BIT_ARRAY_WORD_BITS (SPDK_BIT_ARRAY_WORD_BYTES * 8) @@ -270,3 +271,27 @@ spdk_bit_array_find_first_clear(const struct spdk_bit_array *ba, uint32_t start_ { return _spdk_bit_array_find_first(ba, start_bit_index, SPDK_BIT_ARRAY_WORD_C(-1)); } + +uint32_t +spdk_bit_array_count_set(const struct spdk_bit_array *ba) +{ + const spdk_bit_array_word *cur_word = ba->words; + uint32_t word_count = spdk_bit_array_word_count(ba->bit_count); + uint32_t set_count = 0; + + while (word_count--) { + /* + * No special treatment is needed for the last (potentially partial) word, since + * spdk_bit_array_resize() makes sure the bits past bit_count are cleared. + */ + set_count += SPDK_BIT_ARRAY_WORD_POPCNT(*cur_word++); + } + + return set_count; +} + +uint32_t +spdk_bit_array_count_clear(const struct spdk_bit_array *ba) +{ + return ba->bit_count - spdk_bit_array_count_set(ba); +} diff --git a/test/unit/lib/util/bit_array.c/bit_array_ut.c b/test/unit/lib/util/bit_array.c/bit_array_ut.c index 65a071db9..682ce3749 100644 --- a/test/unit/lib/util/bit_array.c/bit_array_ut.c +++ b/test/unit/lib/util/bit_array.c/bit_array_ut.c @@ -236,6 +236,59 @@ test_errors(void) spdk_bit_array_free(NULL); } +static void +test_count(void) +{ + struct spdk_bit_array *ba; + uint32_t i; + + /* 0-bit array should have 0 bits set and 0 bits clear */ + ba = spdk_bit_array_create(0); + SPDK_CU_ASSERT_FATAL(ba != NULL); + CU_ASSERT(spdk_bit_array_count_set(ba) == 0); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 0); + spdk_bit_array_free(&ba); + + /* 1-bit array */ + ba = spdk_bit_array_create(1); + SPDK_CU_ASSERT_FATAL(ba != NULL); + CU_ASSERT(spdk_bit_array_count_set(ba) == 0); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 1); + spdk_bit_array_set(ba, 0); + CU_ASSERT(spdk_bit_array_count_set(ba) == 1); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 0); + spdk_bit_array_free(&ba); + + /* 65-bit array */ + ba = spdk_bit_array_create(65); + SPDK_CU_ASSERT_FATAL(ba != NULL); + CU_ASSERT(spdk_bit_array_count_set(ba) == 0); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 65); + spdk_bit_array_set(ba, 0); + CU_ASSERT(spdk_bit_array_count_set(ba) == 1); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 64); + spdk_bit_array_set(ba, 5); + CU_ASSERT(spdk_bit_array_count_set(ba) == 2); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 63); + spdk_bit_array_set(ba, 13); + CU_ASSERT(spdk_bit_array_count_set(ba) == 3); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 62); + spdk_bit_array_clear(ba, 0); + CU_ASSERT(spdk_bit_array_count_set(ba) == 2); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 63); + for (i = 0; i < 65; i++) { + spdk_bit_array_set(ba, i); + } + CU_ASSERT(spdk_bit_array_count_set(ba) == 65); + CU_ASSERT(spdk_bit_array_count_clear(ba) == 0); + for (i = 0; i < 65; i++) { + spdk_bit_array_clear(ba, i); + CU_ASSERT(spdk_bit_array_count_set(ba) == 65 - i - 1); + CU_ASSERT(spdk_bit_array_count_clear(ba) == i + 1); + } + spdk_bit_array_free(&ba); +} + int main(int argc, char **argv) { @@ -257,7 +310,8 @@ main(int argc, char **argv) CU_add_test(suite, "test_64bit", test_64bit) == NULL || CU_add_test(suite, "test_find", test_find) == NULL || CU_add_test(suite, "test_resize", test_resize) == NULL || - CU_add_test(suite, "test_errors", test_errors) == NULL) { + CU_add_test(suite, "test_errors", test_errors) == NULL || + CU_add_test(suite, "test_count", test_count) == NULL) { CU_cleanup_registry(); return CU_get_error(); }