diff --git a/src/cmc/bitset.h b/src/cmc/bitset.h index 6dac081..f34fb91 100644 --- a/src/cmc/bitset.h +++ b/src/cmc/bitset.h @@ -379,7 +379,7 @@ static const char *cmc_string_fmt_bitset = "struct %s " { \ _bitset_->buffer[start_index] &= ~start_mask; \ \ - for (size_t i = start_index; i < end_index; i++) \ + for (size_t i = start_index + 1; i < end_index; i++) \ _bitset_->buffer[i] = 0; \ \ _bitset_->buffer[end_index] &= ~end_mask; \ @@ -395,11 +395,69 @@ static const char *cmc_string_fmt_bitset = "struct %s " \ bool PFX##_flip(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->update) \ + _bitset_->callbacks->update(); \ + \ return true; \ } \ \ bool PFX##_flip_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 + 1; i < end_index; i++) \ + _bitset_->buffer[i] ^= ones; \ + \ + _bitset_->buffer[end_index] ^= end_mask; \ + } \ + \ + _bitset_->flag = cmc_flags.OK; \ + \ + if (_bitset_->callbacks && _bitset_->callbacks->update) \ + _bitset_->callbacks->update (); \ + \ return true; \ } \ \ diff --git a/tests/main/src/bitset.c b/tests/main/src/bitset.c index 6aefeff..fbad19e 100644 --- a/tests/main/src/bitset.c +++ b/tests/main/src/bitset.c @@ -197,7 +197,7 @@ _Bool bs_clear_range(struct bitset *_bitset_, size_t from, size_t to) else { _bitset_->buffer[start_index] &= ~start_mask; - for (size_t i = start_index; i < end_index; i++) + for (size_t i = start_index + 1; i < end_index; i++) _bitset_->buffer[i] = 0; _bitset_->buffer[end_index] &= ~end_mask; } @@ -208,10 +208,47 @@ _Bool bs_clear_range(struct bitset *_bitset_, size_t from, size_t to) } _Bool bs_flip(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->update) + _bitset_->callbacks->update(); return 1; } _Bool bs_flip_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 + 1; i < end_index; i++) + _bitset_->buffer[i] ^= ones; + _bitset_->buffer[end_index] ^= end_mask; + } + _bitset_->flag = cmc_flags.OK; + if (_bitset_->callbacks && _bitset_->callbacks->delete) + _bitset_->callbacks->delete (); return 1; } _Bool bs_put(struct bitset *_bitset_, size_t bit_index) diff --git a/tests/main/unt/bitset.c b/tests/main/unt/bitset.c index 02ed05b..3888b1c 100644 --- a/tests/main/unt/bitset.c +++ b/tests/main/unt/bitset.c @@ -13,7 +13,7 @@ CMC_CREATE_UNIT(BitSet, true, { const size_t word_bits = sizeof(cmc_bitset_word) * CHAR_BIT; printf("%s", cmc_test_color(5)); - printf(" BitSet<"CMC_TO_STRING(CMC_BITSET_WORD_TYPE)">\n"); + printf(" BitSet<" CMC_TO_STRING(CMC_BITSET_WORD_TYPE) ">\n"); printf("%s", cmc_test_color(0)); CMC_CREATE_TEST(PFX##_new(), { @@ -137,15 +137,19 @@ CMC_CREATE_UNIT(BitSet, true, { bs->buffer[0] = 0; cmc_assert(bs_set(bs, word_bits - 1)); - cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 1)), bs->buffer[0]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, + ((cmc_bitset_word)1 << (word_bits - 1)), + bs->buffer[0]); cmc_assert(bs_set(bs, word_bits * 8 - 1)); - cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 1)), - bs->buffer[bs_bit_to_index(word_bits * 8 - 1)]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, + ((cmc_bitset_word)1 << (word_bits - 1)), + bs->buffer[bs_bit_to_index(word_bits * 8 - 1)]); cmc_assert(bs_set(bs, word_bits * 18 - 2)); - cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 2)), - bs->buffer[bs_bit_to_index(word_bits * 18 - 2)]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, + ((cmc_bitset_word)1 << (word_bits - 2)), + bs->buffer[bs_bit_to_index(word_bits * 18 - 2)]); bs_free(bs); }); @@ -161,6 +165,9 @@ CMC_CREATE_UNIT(BitSet, true, { cmc_assert_equals(uint8_t, 1, bs->buffer[0]); cmc_assert_equals(int32_t, cmc_flags.OK, bs->flag); + cmc_assert(!bs_set_range(bs, 1, 0)); + cmc_assert_equals(int32_t, cmc_flags.INVALID, bs->flag); + bs->buffer[0] = 0; cmc_assert(bs_set_range(bs, 4, 7)); /* 1111 0000 */ @@ -170,24 +177,28 @@ CMC_CREATE_UNIT(BitSet, true, { cmc_assert_equals(uint8_t, 244, bs->buffer[0]); cmc_assert(bs_set_range(bs, word_bits * 6 - 2, word_bits * 6 - 2)); - cmc_assert_equals(CMC_BITSET_WORD_TYPE, ((cmc_bitset_word)1 << (word_bits - 2)), - bs->buffer[bs_bit_to_index(word_bits * 6 - 2)]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, + ((cmc_bitset_word)1 << (word_bits - 2)), + bs->buffer[bs_bit_to_index(word_bits * 6 - 2)]); // Make sure we have at least word_bits * 40 slots bs_set(bs, word_bits * 40); cmc_assert(bs_set_range(bs, word_bits * 20, word_bits * 21 - 1)); cmc_assert_equals(CMC_BITSET_WORD_TYPE, (~(cmc_bitset_word)0), - bs->buffer[bs_bit_to_index(word_bits * 20)]); + bs->buffer[bs_bit_to_index(word_bits * 20)]); - cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[bs_bit_to_index(word_bits * 20 - 1)]); - cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[bs_bit_to_index(word_bits * 21 + 1)]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, + bs->buffer[bs_bit_to_index(word_bits * 20 - 1)]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, + bs->buffer[bs_bit_to_index(word_bits * 21 + 1)]); cmc_assert(bs_set_range(bs, 0, word_bits * 100 - 1)); cmc_assert_equals(size_t, 100, bs->capacity); for (size_t i = 0; i < bs->capacity; i++) - cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), bs->buffer[i]); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), + bs->buffer[i]); bs_free(bs); }); @@ -219,6 +230,9 @@ CMC_CREATE_UNIT(BitSet, true, { cmc_assert_not_equals(ptr, NULL, bs); cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + cmc_assert(!bs_clear_range(bs, 1, 0)); + cmc_assert_equals(int32_t, cmc_flags.INVALID, bs->flag); + cmc_assert(bs_clear_range(bs, 0, word_bits * 100 - 1)); cmc_assert_equals(size_t, 100, bs->capacity); @@ -231,13 +245,73 @@ CMC_CREATE_UNIT(BitSet, true, { for (size_t i = 0; i < bs->capacity; i++) bs->buffer[i] = ~((cmc_bitset_word)0); - cmc_assert(bs_clear_range(bs, 0, word_bits * 200 - 1)); + cmc_assert(bs_set_range(bs, 0, word_bits * 100 - 1)); + cmc_assert(bs_clear_range(bs, 0, word_bits * 100 - 1)); - cmc_assert_equals(size_t, 200, bs->capacity); + cmc_assert_equals(size_t, 100, bs->capacity); for (size_t i = 0; i < bs->capacity; i++) cmc_assert_equals(size_t, 0, bs->buffer[0]); + cmc_assert(bs_clear_range(bs, 0, word_bits * 200 - 1)); + cmc_assert_equals(size_t, 200, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_flip(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_flip(bs, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 1, bs->buffer[0]); + + cmc_assert(bs_flip(bs, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_set_range(bs, 0, 2)); // 0111 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 7, bs->buffer[0]); + cmc_assert(bs_flip(bs, 1)); // 0101 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 5, bs->buffer[0]); + + cmc_assert(bs_flip(bs, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + bs_free(bs); + }); + + CMC_CREATE_TEST(PFX##_flip_range(), { + struct bitset *bs = bs_new(word_bits * 10 - 1); + + cmc_assert_not_equals(ptr, NULL, bs); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 0, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 1, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 0, 0)); + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 0, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 1, 4)); // 0001 1110 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 30, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 2, 3)); // 0001 0010 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 18, bs->buffer[0]); + + cmc_assert(bs_flip_range(bs, 0, 2)); // 0001 0101 + cmc_assert_equals(CMC_BITSET_WORD_TYPE, 21, bs->buffer[0]); + + bs->buffer[0] = 0; + + cmc_assert(bs_flip_range(bs, 0, word_bits * 100 - 1)); + cmc_assert_equals(size_t, 100, bs->capacity); + + for (size_t i = 0; i < bs->capacity; i++) + cmc_assert_equals(CMC_BITSET_WORD_TYPE, ~((cmc_bitset_word)0), + bs->buffer[i]); + bs_free(bs); }); @@ -267,7 +341,7 @@ CMC_CREATE_UNIT(BitSetIter, true, { const size_t word_bits = sizeof(cmc_bitset_word) * CHAR_BIT; printf("%s", cmc_test_color(5)); - printf(" BitSet<"CMC_TO_STRING(CMC_BITSET_WORD_TYPE)">\n"); + printf(" BitSet<" CMC_TO_STRING(CMC_BITSET_WORD_TYPE) ">\n"); printf("%s", cmc_test_color(0)); CMC_CREATE_TEST(PFX##_iter_start(), { @@ -284,10 +358,12 @@ int main(void) { int result = BitSet() + BitSetIter(); - printf(" +---------------------------------------------------------------+"); + printf( + " +---------------------------------------------------------------+"); printf("\n"); printf(" | BitSet Suit : %-47s |\n", result == 0 ? "PASSED" : "FAILED"); - printf(" +---------------------------------------------------------------+"); + printf( + " +---------------------------------------------------------------+"); printf("\n\n\n"); return result;