summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2023-01-03 14:37:09 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2023-01-03 14:37:09 (GMT)
commit7b739f256cb88cb627954d4a1ff04bdb4fc49515 (patch)
treee0e2ecd90f8004d44f320c78a69edbe37d6169a6
parent755acfaa09e08a355b29081b75f9d547d264ce53 (diff)
Fix some mistakes in bitfield operations.
-rw-r--r--src/common/bits.c21
-rw-r--r--tests/common/bitfield.py67
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)