Skip to content
This repository was archived by the owner on Aug 2, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions network/bitvector/bitvector.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,20 @@ import (

var errInvalidLength = errors.New("invalid length")

// BitVector is a convenience object for manipulating and representing bit vectors
type BitVector struct {
len int
b []byte
}

// New creates a new bit vector with the given length
func New(l int) (bv *BitVector, err error) {
return NewFromBytes(make([]byte, l/8+1), l)
}

// NewFromBytes creates a bit vector from the passed byte slice.
//
// Leftmost bit in byte slice becomes leftmost bit in bit vector
func NewFromBytes(b []byte, l int) (bv *BitVector, err error) {
if l <= 0 {
return nil, errInvalidLength
Expand All @@ -44,11 +49,13 @@ func NewFromBytes(b []byte, l int) (bv *BitVector, err error) {
}, nil
}

// Get gets the corresponding bit, counted from left to right
func (bv *BitVector) Get(i int) bool {
bi := i / 8
return bv.b[bi]&(0x1<<uint(i%8)) != 0
}

// Set sets the corresponding bit, counted from left to right, to the corresponding state of v
func (bv *BitVector) Set(i int, v bool) {
bi := i / 8
cv := bv.Get(i)
Expand All @@ -57,6 +64,38 @@ func (bv *BitVector) Set(i int, v bool) {
}
}

// SetBytes modifies all bits in the bitvector that are set in the argument
//
// If v is true, it sets all bits in the bitvector that are set in the argument
// If v is false, it unsets all bites in the bitvector that are set in the argument

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo - bites -> bits.

Unset 1010101001 is easier to reason about than SetBytes 1010101001 false IMO.

@nolash nolash Jul 2, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it because the corresponding one for individual bits is Set(int, bool) - should we change that too, then? I think they should be the same.

And yes I agree Unset is better.

//
// The argument must be the same as the bitvector length
func (bv *BitVector) SetBytes(bs []byte, v bool) error {
if len(bs) != bv.len {
return errors.New("invalid length")
}
for i := 0; i < bv.len*8; i++ {
bi := i / 8
if bs[bi]&(0x01<<uint(i%8)) > 0 {
bv.Set(i, v)
}
}
return nil
}

// String implements Stringer interface
func (bv *BitVector) String() (s string) {
for i := 0; i < bv.len*8; i++ {
if bv.Get(i) {
s += "1"
} else {
s += "0"
}
}
return s
}

// Bytes retrieves the underlying bytes of the bitvector
func (bv *BitVector) Bytes() []byte {
return bv.b
}
36 changes: 36 additions & 0 deletions network/bitvector/bitvector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package bitvector

import "testing"

// TestBitvectorNew checks that enforcements of argument length works in the constructors
func TestBitvectorNew(t *testing.T) {
_, err := New(0)
if err != errInvalidLength {
Expand All @@ -40,6 +41,7 @@ func TestBitvectorNew(t *testing.T) {
}
}

// TestBitvectorGetSet tests correctness of individual Set and Get commands
func TestBitvectorGetSet(t *testing.T) {
for _, length := range []int{
1,
Expand Down Expand Up @@ -93,6 +95,7 @@ func TestBitvectorGetSet(t *testing.T) {
}
}

// TestBitvectorNewFromBytesGet tests that bit vector is initialized correctly from underlying byte slice
func TestBitvectorNewFromBytesGet(t *testing.T) {
bv, err := NewFromBytes([]byte{8}, 8)
if err != nil {
Expand All @@ -102,3 +105,36 @@ func TestBitvectorNewFromBytesGet(t *testing.T) {
t.Fatalf("element 3 is not set to true: state %08b", bv.b[0])
}
}

// TestBitVectorString tests that string representation of bit vector is correct
func TestBitVectorString(t *testing.T) {
b := []byte{0xa5, 0x81}
expect := "1010010110000001"
bv, err := NewFromBytes(b, 2)
if err != nil {
t.Fatal(err)
}
if bv.String() != expect {
t.Fatalf("bitvector string fail: got %s, expect %s", bv.String(), expect)
}
}

// TestBitVectorSetUnsetBytes tests that setting and unsetting by byte slice modifies the bit vector correctly
func TestBitVectorSetBytes(t *testing.T) {
b := []byte{0xff, 0xff}
cb := []byte{0xa5, 0x81}
expectUnset := "0101101001111110"
expectReset := "1111111111111111"
bv, err := NewFromBytes(b, 2)
if err != nil {
t.Fatal(err)
}
bv.SetBytes(cb, false)
if bv.String() != expectUnset {
t.Fatalf("bitvector unset bytes fail: got %s, expect %s", bv.String(), expectUnset)
}
bv.SetBytes(cb, true)
if bv.String() != expectReset {
t.Fatalf("bitvector reset bytes fail: got %s, expect %s", bv.String(), expectReset)
}
}