diff --git a/src/cmc/bitset.h b/src/cmc/bitset.h index c63b130..5ed5ed9 100644 --- a/src/cmc/bitset.h +++ b/src/cmc/bitset.h @@ -124,10 +124,10 @@ static const char *cmc_string_fmt_bitset = "struct %s<%s> " \ /* Utility Methods */ \ /* Translates a bit index to a word index */ \ - static inline cmc_bitset_word PFX##_bit_to_index(cmc_bitset_word idx) \ + static inline size_t PFX##_bit_to_index(size_t idx) \ { \ /* Calculate how many shifts based on the size of cmc_bitset_word */ \ - static const cmc_bitset_word shift = \ + static const size_t shift = \ ((sizeof(cmc_bitset_word) * 8) >> 6) > 0 \ ? 6 \ : ((sizeof(cmc_bitset_word) * 8) >> 5) > 0 \ @@ -310,11 +310,69 @@ static const char *cmc_string_fmt_bitset = "struct %s<%s> " \ bool PFX##_clear(struct SNAME *_bitset_, size_t bit_index) \ { \ + if (!PFX##_impl_resize(_bitset_, bit_index + 1, false)) \ + return false; \ + \ + /* How many bits in a word */ \ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; \ + \ + size_t i = PFX##_bit_to_index(bit_index); \ + \ + _bitset_->buffer[i] &= ~(((cmc_bitset_word)1) << (bit_index % bits)); \ + \ + _bitset_->flag = cmc_flags.OK; \ + \ + if (_bitset_->callbacks && _bitset_->callbacks->delete) \ + _bitset_->callbacks->delete (); \ + \ return true; \ } \ \ bool PFX##_clear_range(struct SNAME *_bitset_, size_t from, size_t to) \ { \ + if (to < from) \ + { \ + _bitset_->flag = cmc_flags.INVALID; \ + return false; \ + } \ + \ + if (!PFX##_impl_resize(_bitset_, to + 1, false)) \ + return false; \ + \ + size_t start_index = PFX##_bit_to_index(from); \ + size_t end_index = PFX##_bit_to_index(to); \ + \ + /* How many bits in a word */ \ + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT; \ + \ + /* 1111 ... 1111 */ \ + const cmc_bitset_word ones = ~((cmc_bitset_word)0); \ + \ + cmc_bitset_word shift_start = from % bits; \ + cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits; \ + \ + cmc_bitset_word start_mask = ones << shift_start; \ + cmc_bitset_word end_mask = ones >> shift_end; \ + \ + if (start_index == end_index) \ + { \ + _bitset_->buffer[end_index] &= ~(start_mask & end_mask); \ + } \ + else \ + { \ + _bitset_->buffer[start_index] &= ~start_mask; \ + \ + for (size_t i = start_index; i < end_index; i++) \ + _bitset_->buffer[i] = 0; \ + \ + _bitset_->buffer[end_index] &= ~end_mask; \ + } \ + \ + _bitset_->flag = cmc_flags.OK; \ + \ + if (_bitset_->callbacks && _bitset_->callbacks->delete) \ + _bitset_->callbacks->delete (); \ + \ return true; \ } \ \ diff --git a/tests/main/src/bitset.c b/tests/main/src/bitset.c index 61d4b8f..6aefeff 100644 --- a/tests/main/src/bitset.c +++ b/tests/main/src/bitset.c @@ -37,9 +37,9 @@ _Bool bs_fill(struct bitset *_bitset_); _Bool bs_empty(struct bitset *_bitset_); _Bool bs_get(struct bitset *_bitset_, size_t bit_index); _Bool bs_resize(struct bitset *_bitset_, size_t n_bits); -static inline cmc_bitset_word bs_bit_to_index(cmc_bitset_word idx) +static inline size_t bs_bit_to_index(size_t idx) { - static const cmc_bitset_word shift = + static const size_t shift = ((sizeof(cmc_bitset_word) * 8) >> 6) > 0 ? 6 : ((sizeof(cmc_bitset_word) * 8) >> 5) > 0 @@ -163,10 +163,47 @@ _Bool bs_set_range(struct bitset *_bitset_, size_t from, size_t to) } _Bool bs_clear(struct bitset *_bitset_, size_t bit_index) { + if (!bs_impl_resize(_bitset_, bit_index + 1, 0)) + return 0; + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * 8; + size_t i = bs_bit_to_index(bit_index); + _bitset_->buffer[i] &= ~(((cmc_bitset_word)1) << (bit_index % bits)); + _bitset_->flag = cmc_flags.OK; + if (_bitset_->callbacks && _bitset_->callbacks->delete) + _bitset_->callbacks->delete (); return 1; } _Bool bs_clear_range(struct bitset *_bitset_, size_t from, size_t to) { + if (to < from) + { + _bitset_->flag = cmc_flags.INVALID; + return 0; + } + if (!bs_impl_resize(_bitset_, to + 1, 0)) + return 0; + size_t start_index = bs_bit_to_index(from); + size_t end_index = bs_bit_to_index(to); + const cmc_bitset_word bits = sizeof(cmc_bitset_word) * 8; + const cmc_bitset_word ones = ~((cmc_bitset_word)0); + cmc_bitset_word shift_start = from % bits; + cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits; + cmc_bitset_word start_mask = ones << shift_start; + cmc_bitset_word end_mask = ones >> shift_end; + if (start_index == end_index) + { + _bitset_->buffer[end_index] &= ~(start_mask & end_mask); + } + else + { + _bitset_->buffer[start_index] &= ~start_mask; + for (size_t i = start_index; i < end_index; i++) + _bitset_->buffer[i] = 0; + _bitset_->buffer[end_index] &= ~end_mask; + } + _bitset_->flag = cmc_flags.OK; + if (_bitset_->callbacks && _bitset_->callbacks->delete) + _bitset_->callbacks->delete (); return 1; } _Bool bs_flip(struct bitset *_bitset_, size_t bit_index) diff --git a/tests/main/unt/bitset.c b/tests/main/unt/bitset.c index 1f4a517..78314e7 100644 --- a/tests/main/unt/bitset.c +++ b/tests/main/unt/bitset.c @@ -183,9 +183,39 @@ CMC_CREATE_UNIT(BitSet, true, { }); CMC_CREATE_TEST(PFX##_clear(), { - struct bitset *bs = bs_new(64); + struct bitset *bs = bs_new(word_bits * 10 - 1); - // WIP + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert(0 == bs->buffer[0]); + + bs->buffer[0] = 1; // 0001 + cmc_assert(bs_clear(bs, 0)); + cmc_assert(0 == bs->buffer[0]); + + bs->buffer[0] = 10; // 1010 + cmc_assert(bs_clear(bs, 1)); + cmc_assert(bs_clear(bs, 3)); + cmc_assert(0 == bs->buffer[0]); + + cmc_assert(bs_clear(bs, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_clear_range(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert(0 == bs->buffer[0]); + + cmc_assert(bs_clear(bs, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + cmc_assert(bs_set_range(bs, word_bits * 20, word_bits * 21 - 1)); + cmc_assert(bs_clear_range(bs, word_bits * 20, word_bits * 21 - 1)); + + cmc_assert_equals(uint32_t, 0, bs->buffer[bs_bit_to_index(word_bits * 20)]); bs_free(bs); });