Skip to content

Commit

Permalink
bitset: add code and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nikhilgarg28 committed Jul 28, 2015
1 parent 4ec8e4d commit b57da1e
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
55 changes: 55 additions & 0 deletions bitset.go
Original file line number Diff line number Diff line change
@@ -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
}
101 changes: 101 additions & 0 deletions bitset_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}

0 comments on commit b57da1e

Please sign in to comment.