From b57da1e6567974f393c24fa24aa119d1e1b254ed Mon Sep 17 00:00:00 2001 From: Nikhil Garg Date: Mon, 27 Jul 2015 22:36:35 -0700 Subject: [PATCH] bitset: add code and tests --- bitset.go | 55 +++++++++++++++++++++++++++ bitset_test.go | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 bitset.go create mode 100644 bitset_test.go diff --git a/bitset.go b/bitset.go new file mode 100644 index 0000000..9f0b2de --- /dev/null +++ b/bitset.go @@ -0,0 +1,55 @@ +package bitset + +const word = uint64(64) +const logword = uint(6) + +type BitSet struct { + length uint64 + bits []uint64 +} + +func getSize(length uint64) uint64 { + return uint64((length + word - 1) / word) +} + +func New(length uint64) *BitSet { + size := getSize(length) + return &BitSet{length, make([]uint64, size)} +} + +func getIndex(pos uint64) (q uint64, r uint) { + q = pos >> logword + r = uint(pos & (word - 1)) + return +} + +func (b *BitSet) Length() uint64 { + return b.length +} + +func (b *BitSet) Get(pos uint64) bool { + q, r := getIndex(pos) + bit := (b.bits[q] >> r) & 1 + return bit != 0 +} + +func (b *BitSet) Set(pos uint64) bool { + current := b.Get(pos) + q, r := getIndex(pos) + b.bits[q] |= (1 << r) + return current +} + +func (b *BitSet) Clear(pos uint64) bool { + current := b.Get(pos) + q, r := getIndex(pos) + b.bits[q] &= ^(1 << r) + return current +} + +func (b *BitSet) Flip(pos uint64) bool { + current := b.Get(pos) + q, r := getIndex(pos) + b.bits[q] ^= (1 << r) + return current +} diff --git a/bitset_test.go b/bitset_test.go new file mode 100644 index 0000000..2a3c75b --- /dev/null +++ b/bitset_test.go @@ -0,0 +1,101 @@ +package bitset + +import ( + "testing" +) + +func TestInit(t *testing.T) { + bs := New(1000) + // initially all bits should be zero + for i := uint64(0); i < 1000; i++ { + if bs.Get(i) { + t.Errorf("Bit %d is set when it should not be", i) + } + } +} + +func TestGetSet(t *testing.T) { + bs := New(1000) + if bs.Set(0) == true { + t.Error("Set on bit %d returned true when it should return false", 0) + } + + if bs.Get(0) == false { + t.Errorf("Bit %d is not set when it should be", 0) + } + + if bs.Set(0) == false { + t.Errorf("Set on bit %d returned false when it should return true", 0) + } +} + +func TestLargeSetGet(t *testing.T) { + size := uint64(1) << 35 + bs := New(size) + + positions := []uint64{0, 1, 10, 1000, 1 << 32, size - 1} + for _, position := range positions { + if bs.Get(position) { + t.Errorf("Bit %d should be false but is true", position) + } + + bs.Set(position) + + if !bs.Get(position) { + t.Errorf("Bit %d should be true but is false", position) + } + } +} + +func TestLength(t *testing.T) { + + sizes := []uint64{0, 1, 10, 1000, 1 << 32, 1 << 33} + for _, size := range sizes { + bs := New(size) + if bs.Length() != size { + t.Errorf("Length should be %d", size) + } + } +} + +func TestClear(t *testing.T) { + bs := New(1000) + pos := uint64(1) + bs.Set(pos) + + if !bs.Get(pos) { + t.Errorf("Bit %d should be set when it is not", pos) + } + + if !bs.Clear(pos) { + t.Error("Clearing bit %d should have returned true", pos) + } + + if bs.Get(pos) { + t.Errorf("Bit %d should have been cleared when it is not", pos) + } +} + +func TestFlip(t *testing.T) { + bs := New(1000) + pos := uint64(1) + + if bs.Get(pos) { + t.Errorf("Bit %d should be clear when it is not", pos) + } + + if bs.Flip(pos) { + t.Error("Flipping bit %d should have returned false, but it did not", pos) + } + + if !bs.Get(pos) { + t.Errorf("Bit %d should have been set when it is not", pos) + } + if !bs.Flip(pos) { + t.Error("Flipping bit %d should have returned true, but it did not", pos) + } + + if bs.Get(pos) { + t.Errorf("Bit %d should have been clear when it is not", pos) + } +}