From 7408c48dff1e7679ec0adb73d370ca66e6407caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 20 Jul 2025 21:44:11 +0200 Subject: [PATCH] Add uc_bv_find_first_zero --- include/ucore/bitvec.h | 7 ++++++- src/bitvec.c | 18 ++++++++++++++++++ test/test_bitvec.c | 27 +++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/include/ucore/bitvec.h b/include/ucore/bitvec.h index bb5dfe1..a141bdc 100644 --- a/include/ucore/bitvec.h +++ b/include/ucore/bitvec.h @@ -68,11 +68,16 @@ void uc_bv_set_all(struct UCBitVec *v); /** Initialize bits from a array of ints, each array element maps to one bit. * The bits are initialized from the int array so zero maps to zero and non-zero maps to one. * e..g to set the 5 first bits, to 01110: - * int a[] = {0,1,1,1,0}; + * int a[] = {0,1,1,1,0}; * set_bits_from_array(v,a,5); * */ void uc_bv_set_bits_from_array(struct UCBitVec *v,const char *array,size_t array_len); +/** Find the index of the first zero bit in the bitvec. + * @param v The bitvec to search + * @return The index of the first zero bit, or -1 if all bits are set + */ +int uc_bv_find_first_zero(const struct UCBitVec *v); #ifdef __cplusplus } diff --git a/src/bitvec.c b/src/bitvec.c index 6fb5892..d168f84 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -2,6 +2,7 @@ #include #include #include +#include "ucore/utils.h" #include "ucore/bitvec.h" #ifdef __GNUC__ @@ -12,6 +13,8 @@ #define unlikely(expr) (expr) #endif +UC_STATIC_ASSERT(CHAR_BIT % 8 == 0); + static inline int bit_index(int b) { return b / (sizeof(uc_bv_integer) * CHAR_BIT); @@ -88,3 +91,18 @@ void uc_bv_set_all(struct UCBitVec *v) memset(v->vec,0xff,v->vec_len * sizeof(uc_bv_integer)); } +int uc_bv_find_first_zero(const struct UCBitVec *v) +{ + const size_t bits_per_word = sizeof(uc_bv_integer) * CHAR_BIT; + + for (size_t i = 0; i < v->vec_len; i++) { + uc_bv_integer inverted = ~v->vec[i]; + + if (inverted != 0) { + int bit_pos = __builtin_ffsl(inverted) - 1; // ffsl returns 1-based index + return (int)(i * bits_per_word + bit_pos); + } + } + + return -1; +} diff --git a/test/test_bitvec.c b/test/test_bitvec.c index 4676114..a3ec81c 100644 --- a/test/test_bitvec.c +++ b/test/test_bitvec.c @@ -79,6 +79,31 @@ START_TEST (test_bitvec_setall_clearall) uc_bv_free(v); +} +END_TEST +START_TEST (test_bitvec_find_first_zero) +{ + uc_bv_integer buf[8]; + struct UCBitVec v = UC_BV_STATIC_INIT(buf); + uc_bv_set_all(&v); + + int bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, -1); + + uc_bv_clr_bit(&v, 0); + bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, 0); + + uc_bv_set_bit(&v, 0); + uc_bv_clr_bit(&v, 63); + bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, 63); + + uc_bv_set_bit(&v, 63); + uc_bv_clr_bit(&v, sizeof buf * CHAR_BIT - 1); + bit = uc_bv_find_first_zero(&v); + ck_assert_int_eq(bit, sizeof buf * CHAR_BIT - 1); + } END_TEST @@ -91,6 +116,8 @@ Suite *bitvec_suite(void) tcase_add_test(tc, test_bitvec_set_bits_from_array); tcase_add_test(tc, test_bitvec_clearbit); tcase_add_test(tc, test_bitvec_setall_clearall); + tcase_add_test(tc, test_bitvec_find_first_zero); + suite_add_tcase(s, tc); return s;