Skip to content
This repository was archived by the owner on Aug 2, 2021. It is now read-only.

Commit a6e64ae

Browse files
authored
network/bitvector: Multibit set/unset + string rep (#1530)
* network/bitvector: Multibit set/unset + string rep * network/bitvector: Add code comments * network/bitvector: Make Unset -> Set with bool false * network/bitvector: Revert to Set/Unset * network/stream: Update to new bitvector signature
1 parent b3f21dd commit a6e64ae

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

network/bitvector/bitvector.go

+63-1
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,20 @@ import (
2222

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

25+
// BitVector is a convenience object for manipulating and representing bit vectors
2526
type BitVector struct {
2627
len int
2728
b []byte
2829
}
2930

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

36+
// NewFromBytes creates a bit vector from the passed byte slice.
37+
//
38+
// Leftmost bit in byte slice becomes leftmost bit in bit vector
3439
func NewFromBytes(b []byte, l int) (bv *BitVector, err error) {
3540
if l <= 0 {
3641
return nil, errInvalidLength
@@ -44,19 +49,76 @@ func NewFromBytes(b []byte, l int) (bv *BitVector, err error) {
4449
}, nil
4550
}
4651

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

52-
func (bv *BitVector) Set(i int, v bool) {
58+
// Set sets the bit corresponding to the index in the bitvector, counted from left to right
59+
func (bv *BitVector) set(i int, v bool) {
5360
bi := i / 8
5461
cv := bv.Get(i)
5562
if cv != v {
5663
bv.b[bi] ^= 0x1 << uint8(i%8)
5764
}
5865
}
5966

67+
// Set sets the bit corresponding to the index in the bitvector, counted from left to right
68+
func (bv *BitVector) Set(i int) {
69+
bv.set(i, true)
70+
}
71+
72+
// Unset UNSETS the corresponding bit, counted from left to right
73+
func (bv *BitVector) Unset(i int) {
74+
bv.set(i, false)
75+
}
76+
77+
// SetBytes sets all bits in the bitvector that are set in the argument
78+
//
79+
// The argument must be the same as the bitvector length
80+
func (bv *BitVector) SetBytes(bs []byte) error {
81+
if len(bs) != bv.len {
82+
return errors.New("invalid length")
83+
}
84+
for i := 0; i < bv.len*8; i++ {
85+
bi := i / 8
86+
if bs[bi]&(0x01<<uint(i%8)) > 0 {
87+
bv.set(i, true)
88+
}
89+
}
90+
return nil
91+
}
92+
93+
// UnsetBytes UNSETS all bits in the bitvector that are set in the argument
94+
//
95+
// The argument must be the same as the bitvector length
96+
func (bv *BitVector) UnsetBytes(bs []byte) error {
97+
if len(bs) != bv.len {
98+
return errors.New("invalid length")
99+
}
100+
for i := 0; i < bv.len*8; i++ {
101+
bi := i / 8
102+
if bs[bi]&(0x01<<uint(i%8)) > 0 {
103+
bv.set(i, false)
104+
}
105+
}
106+
return nil
107+
}
108+
109+
// String implements Stringer interface
110+
func (bv *BitVector) String() (s string) {
111+
for i := 0; i < bv.len*8; i++ {
112+
if bv.Get(i) {
113+
s += "1"
114+
} else {
115+
s += "0"
116+
}
117+
}
118+
return s
119+
}
120+
121+
// Bytes retrieves the underlying bytes of the bitvector
60122
func (bv *BitVector) Bytes() []byte {
61123
return bv.b
62124
}

network/bitvector/bitvector_test.go

+38-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package bitvector
1818

1919
import "testing"
2020

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

44+
// TestBitvectorGetSet tests correctness of individual Set and Get commands
4345
func TestBitvectorGetSet(t *testing.T) {
4446
for _, length := range []int{
4547
1,
@@ -71,7 +73,7 @@ func TestBitvectorGetSet(t *testing.T) {
7173
}()
7274

7375
for i := 0; i < length; i++ {
74-
bv.Set(i, true)
76+
bv.Set(i)
7577
for j := 0; j < length; j++ {
7678
if j == i {
7779
if !bv.Get(j) {
@@ -84,7 +86,7 @@ func TestBitvectorGetSet(t *testing.T) {
8486
}
8587
}
8688

87-
bv.Set(i, false)
89+
bv.Unset(i)
8890

8991
if bv.Get(i) {
9092
t.Errorf("element on index %v is not set to false", i)
@@ -93,6 +95,7 @@ func TestBitvectorGetSet(t *testing.T) {
9395
}
9496
}
9597

98+
// TestBitvectorNewFromBytesGet tests that bit vector is initialized correctly from underlying byte slice
9699
func TestBitvectorNewFromBytesGet(t *testing.T) {
97100
bv, err := NewFromBytes([]byte{8}, 8)
98101
if err != nil {
@@ -102,3 +105,36 @@ func TestBitvectorNewFromBytesGet(t *testing.T) {
102105
t.Fatalf("element 3 is not set to true: state %08b", bv.b[0])
103106
}
104107
}
108+
109+
// TestBitVectorString tests that string representation of bit vector is correct
110+
func TestBitVectorString(t *testing.T) {
111+
b := []byte{0xa5, 0x81}
112+
expect := "1010010110000001"
113+
bv, err := NewFromBytes(b, 2)
114+
if err != nil {
115+
t.Fatal(err)
116+
}
117+
if bv.String() != expect {
118+
t.Fatalf("bitvector string fail: got %s, expect %s", bv.String(), expect)
119+
}
120+
}
121+
122+
// TestBitVectorSetUnsetBytes tests that setting and unsetting by byte slice modifies the bit vector correctly
123+
func TestBitVectorSetBytes(t *testing.T) {
124+
b := []byte{0xff, 0xff}
125+
cb := []byte{0xa5, 0x81}
126+
expectUnset := "0101101001111110"
127+
expectReset := "1111111111111111"
128+
bv, err := NewFromBytes(b, 2)
129+
if err != nil {
130+
t.Fatal(err)
131+
}
132+
bv.UnsetBytes(cb)
133+
if bv.String() != expectUnset {
134+
t.Fatalf("bitvector unset bytes fail: got %s, expect %s", bv.String(), expectUnset)
135+
}
136+
bv.SetBytes(cb)
137+
if bv.String() != expectReset {
138+
t.Fatalf("bitvector reset bytes fail: got %s, expect %s", bv.String(), expectReset)
139+
}
140+
}

network/stream/messages.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ func (p *Peer) handleOfferedHashesMsg(ctx context.Context, req *OfferedHashesMsg
231231
ctr++
232232

233233
// set the bit, so create a request
234-
want.Set(i/HashSize, true)
234+
want.Set(i / HashSize)
235235
log.Trace("need data", "ref", fmt.Sprintf("%x", hash), "request", true)
236236

237237
// measure how long it takes before we mark chunks for retrieval, and actually send the request

0 commit comments

Comments
 (0)