From 9d0d90c0304dc52c25a9f4c06af3becdf883d500 Mon Sep 17 00:00:00 2001 From: Steam Powered Taco Date: Wed, 26 Oct 2022 21:43:35 -0600 Subject: [PATCH] Clean last word of target bitset after using Copy. --- bitset.go | 3 +++ bitset_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/bitset.go b/bitset.go index 32d7cfb..83f6e70 100644 --- a/bitset.go +++ b/bitset.go @@ -556,6 +556,9 @@ func (b *BitSet) Copy(c *BitSet) (count uint) { if b.length < c.length { count = b.length } + // Cleaning the last word is needed to keep the invariant that other functions, such as Count, require + // that any bits in the last word that would exceed the length of the bitmask are set to 0. + c.cleanLastWord() return } diff --git a/bitset_test.go b/bitset_test.go index 4bc11d7..b71240d 100644 --- a/bitset_test.go +++ b/bitset_test.go @@ -1486,6 +1486,34 @@ func TestCopy(t *testing.T) { } } +func TestCopyUnaligned(t *testing.T) { + a := New(16) + a.FlipRange(0, 16) + b := New(1) + a.Copy(b) + if b.Count() > b.Len() { + t.Errorf("targets copied set count (%d) should never be larger than target's length (%d)", b.Count(), b.Len()) + } + if !b.Test(0) { + t.Errorf("first bit should still be set in copy: %+v", b) + } + + // Test a more complex scenario with a mix of bits set in the unaligned space to verify no bits are lost. + a = New(32) + a.Set(0).Set(3).Set(4).Set(16).Set(17).Set(29).Set(31) + b = New(19) + a.Copy(b) + + const expectedCount = 5 + if b.Count() != expectedCount { + t.Errorf("targets copied set count: %d, want %d", b.Count(), expectedCount) + } + + if !(b.Test(0) && b.Test(3) && b.Test(4) && b.Test(16) && b.Test(17)) { + t.Errorf("expected set bits are not set: %+v", b) + } +} + func TestCopyFull(t *testing.T) { a := New(10) b := &BitSet{}