diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2023-01-03 14:37:09 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2023-01-03 14:37:09 (GMT) |
commit | 7b739f256cb88cb627954d4a1ff04bdb4fc49515 (patch) | |
tree | e0e2ecd90f8004d44f320c78a69edbe37d6169a6 | |
parent | 755acfaa09e08a355b29081b75f9d547d264ce53 (diff) |
Fix some mistakes in bitfield operations.
-rw-r--r-- | src/common/bits.c | 21 | ||||
-rw-r--r-- | tests/common/bitfield.py | 67 |
2 files changed, 79 insertions, 9 deletions
diff --git a/src/common/bits.c b/src/common/bits.c index 590c318..a037078 100644 --- a/src/common/bits.c +++ b/src/common/bits.c @@ -533,34 +533,35 @@ void or_bit_field_at(bitfield_t *dest, const bitfield_t *src, size_t first) size_t start; /* Mot de départ dans le champ */ size_t offset; /* Décalage des mots à basculer*/ size_t remaining; /* Taille du dernier tronçon */ - unsigned long finalcut; /* Limitation du mot final */ + size_t last_iter; /* Dernière itération à mener */ size_t i; /* Boucle de parcours */ unsigned long word; /* Mot reconstituté à tester */ - assert(dest->length <= (first + src->length)); + assert((first + src->length) <= dest->length); start = first / (sizeof(unsigned long) * 8); offset = first % (sizeof(unsigned long) * 8); remaining = (first + src->length) % (sizeof(unsigned long) * 8); - if (remaining == 0) - finalcut = ~0ul; + if ((first + src->length) % (sizeof(unsigned long) * 8) > 0) + last_iter = src->requested; else - finalcut = (1ul << remaining) - 1; + last_iter = src->requested - 1; - for (i = 0; i < (src->requested + 1); i++) + + for (i = 0; i <= last_iter; i++) { if (i < src->requested) word = src->bits[i] << offset; else word = 0; - if (i > 0) + if (i > 0 && offset > 0) word |= src->bits[i - 1] >> (sizeof(unsigned long) * 8 - offset); - if (i == src->requested) - word &= finalcut; + if (i == last_iter && remaining > 0) + word &= (1ul << remaining) - 1; dest->bits[start + i] |= word; @@ -753,6 +754,8 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c test = word ^ bitmask; + test &= bitmask; + if ((i + 1) == mask->requested) { bitmask &= finalcut; diff --git a/tests/common/bitfield.py b/tests/common/bitfield.py index 8c4a470..aff5de6 100644 --- a/tests/common/bitfield.py +++ b/tests/common/bitfield.py @@ -106,6 +106,19 @@ class TestBitFields(ChrysalideTestCase): self.assertFalse(bf_a.test(67)) + bf_a = BitField(75, 0) + + bf_a.or_at(bf_b, 60) + + self.assertFalse(bf_a.test(59)) + + self.assertTrue(bf_a.test(60)) + self.assertTrue(bf_a.test(61)) + self.assertFalse(bf_a.test(62)) + self.assertTrue(bf_a.test(63)) + + self.assertFalse(bf_a.test(64)) + def testBitFieldSwitch(self): """Switch various bits in bitfields.""" @@ -216,3 +229,57 @@ class TestBitFields(ChrysalideTestCase): bf_b = BitField(9, 1) self.assertNotEqual(bf_a, bf_b) + + + def testRealCase00(self): + """Test bits in bitfields against other bitfields in a real case (#02).""" + + bf = BitField(128, 0) + + for b in [ 0, 50, 54, 58, 66, 70, 98 ]: + bf.set(b, 1) + + mask = BitField(128, 0) + + for b in [ 0, 51 ]: + mask.set(b, 1) + + self.assertFalse(bf.test_zeros_with(0, mask)) + + self.assertTrue(bf.test_zeros_with(1, mask)) + + bf = BitField(32, 0) + + mask = BitField(32, 0) + + self.assertTrue(bf.test_zeros_with(0, mask)) + + for b in [ 0, 8, 9, 10 ]: + mask.set(b, 1) + + self.assertTrue(bf.test_zeros_with(0, mask)) + + bf = BitField(32, 1) + + self.assertFalse(bf.test_zeros_with(0, mask)) + + self.assertTrue(bf.test_ones_with(0, mask)) + + + def testRealCase01(self): + """Test bits in bitfields against other bitfields in a real case (#01).""" + + bf = BitField(128, 0) + + mask = BitField(128, 0) + + bits = [ 0, 50, 54, 58, 66, 70, 98 ] + + for b in bits: + mask.set(b, 1) + + bf.or_at(mask, 0) + + self.assertEqual(mask.popcount, len(bits)) + + self.assertEqual(mask.popcount, bf.popcount) |