Skip to content

Commit 3b07818

Browse files
Merge pull request #110 from evanh/master
Add Nand functionality
2 parents c5e9b05 + f1e6d95 commit 3b07818

File tree

9 files changed

+582
-29
lines changed

9 files changed

+582
-29
lines changed

bitarray/and.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func andSparseWithSparseBitArray(sba, other *sparseBitArray) BitArray {
2323

2424
selfIndex := 0
2525
otherIndex := 0
26+
var resultBlock block
2627

2728
// move through the array and compare the blocks if they happen to
2829
// intersect
@@ -52,9 +53,12 @@ func andSparseWithSparseBitArray(sba, other *sparseBitArray) BitArray {
5253
default:
5354
// Here, our indices match for both `sba` and `other`.
5455
// Time to do the bitwise AND operation and add a block
55-
// to our result list.
56-
indices = append(indices, selfValue)
57-
blocks = append(blocks, sba.blocks[selfIndex].and(other.blocks[otherIndex]))
56+
// to our result list if the block has values in it.
57+
resultBlock = sba.blocks[selfIndex].and(other.blocks[otherIndex])
58+
if resultBlock > 0 {
59+
indices = append(indices, selfValue)
60+
blocks = append(blocks, resultBlock)
61+
}
5862
selfIndex++
5963
otherIndex++
6064
}
@@ -92,7 +96,6 @@ func andSparseWithDenseBitArray(sba *sparseBitArray, other *bitArray) BitArray {
9296
// We're ready to return
9397
break
9498
}
95-
9699
ba.blocks[selfIndex] = ba.blocks[selfIndex].and(
97100
other.blocks[selfValue])
98101
}

bitarray/and_test.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ func TestAndSparseWithSparseBitArray(t *testing.T) {
4343
sba.SetBit(280)
4444
other.SetBit(9)
4545
other.SetBit(100)
46+
sba.SetBit(1000)
47+
other.SetBit(1001)
4648

4749
// bits for which both arrays are set
4850
sba.SetBit(1)
@@ -54,15 +56,23 @@ func TestAndSparseWithSparseBitArray(t *testing.T) {
5456

5557
ba := andSparseWithSparseBitArray(sba, other)
5658

59+
// Bits in both
5760
checkBit(t, ba, 1, true)
5861
checkBit(t, ba, 30, true)
5962
checkBit(t, ba, 2680, true)
6063

64+
// Bits in sba but not other
6165
checkBit(t, ba, 3, false)
66+
checkBit(t, ba, 280, false)
67+
checkBit(t, ba, 1000, false)
68+
69+
// Bits in other but not sba
6270
checkBit(t, ba, 9, false)
6371
checkBit(t, ba, 100, false)
6472
checkBit(t, ba, 2, false)
65-
checkBit(t, ba, 280, false)
73+
74+
nums := ba.ToNums()
75+
assert.Equal(t, []uint64{1, 30, 2680}, nums)
6676
}
6777

6878
func TestAndSparseWithDenseBitArray(t *testing.T) {
@@ -80,14 +90,20 @@ func TestAndSparseWithDenseBitArray(t *testing.T) {
8090

8191
ba := andSparseWithDenseBitArray(sba, other)
8292

93+
// Bits in both
8394
checkBit(t, ba, 1, true)
8495
checkBit(t, ba, 150, true)
96+
checkBit(t, ba, 300, true)
97+
98+
// Bits in sba but not other
8599
checkBit(t, ba, 155, false)
100+
101+
// Bits in other but not sba
86102
checkBit(t, ba, 156, false)
87-
checkBit(t, ba, 300, true)
103+
88104
}
89105

90-
// Maks sure that the sparse array is trimmed correctly if compared against a
106+
// Make sure that the sparse array is trimmed correctly if compared against a
91107
// smaller dense bit array.
92108
func TestAndSparseWithSmallerDenseBitArray(t *testing.T) {
93109
sba := newSparseBitArray()
@@ -106,13 +122,18 @@ func TestAndSparseWithSmallerDenseBitArray(t *testing.T) {
106122

107123
ba := andSparseWithDenseBitArray(sba, other)
108124

125+
// Bits in both
109126
checkBit(t, ba, 1, true)
110127
checkBit(t, ba, 150, true)
128+
129+
// Bits in sba but not other
111130
checkBit(t, ba, 155, false)
112-
checkBit(t, ba, 128, false)
113131
checkBit(t, ba, 500, false)
114132
checkBit(t, ba, 1200, false)
115133
checkBit(t, ba, 1500, false)
134+
135+
// Bits in other but not sba
136+
checkBit(t, ba, 128, false)
116137
}
117138

118139
func TestAndDenseWithDenseBitArray(t *testing.T) {
@@ -148,6 +169,7 @@ func TestAndSparseWithEmptySparse(t *testing.T) {
148169
sba.SetBit(5)
149170

150171
ba := andSparseWithSparseBitArray(sba, other)
172+
151173
checkBit(t, ba, 0, false)
152174
checkBit(t, ba, 5, false)
153175
checkBit(t, ba, 100, false)

bitarray/bitarray.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ func (ba *bitArray) And(other BitArray) BitArray {
157157
return andSparseWithDenseBitArray(other.(*sparseBitArray), ba)
158158
}
159159

160+
// Nand will return the result of doing a bitwise and not of the bit array
161+
// with the other bit array on each block.
162+
func (ba *bitArray) Nand(other BitArray) BitArray {
163+
if dba, ok := other.(*bitArray); ok {
164+
return nandDenseWithDenseBitArray(ba, dba)
165+
}
166+
167+
return nandDenseWithSparseBitArray(ba, other.(*sparseBitArray))
168+
}
169+
160170
// Reset clears out the bit array.
161171
func (ba *bitArray) Reset() {
162172
for i := uint64(0); i < uint64(len(ba.blocks)); i++ {
@@ -222,6 +232,10 @@ func (ba *bitArray) Blocks() Iterator {
222232
return newBitArrayIterator(ba)
223233
}
224234

235+
func (ba *bitArray) IsEmpty() bool {
236+
return ba.anyset
237+
}
238+
225239
// complement flips all bits in this array.
226240
func (ba *bitArray) complement() {
227241
for i := uint64(0); i < uint64(len(ba.blocks)); i++ {

bitarray/block.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ func (b block) and(other block) block {
8181
return b & other
8282
}
8383

84+
func (b block) nand(other block) block {
85+
return b &^ other
86+
}
87+
8488
func (b block) get(position uint64) bool {
8589
return b&block(1<<position) != 0
8690
}

bitarray/encoding.go

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,43 +95,64 @@ func (ba *sparseBitArray) Serialize() ([]byte, error) {
9595
return w.Bytes(), nil
9696
}
9797

98+
// This function is a copy from the binary package, with some added error
99+
// checking to avoid panics. The function will return the value, and the number
100+
// of bytes read from the buffer. If the number of bytes is negative, then
101+
// not enough bytes were passed in and the return value will be zero.
102+
func Uint64FromBytes(b []byte) (uint64, int) {
103+
if len(b) < 8 {
104+
return 0, -1
105+
}
106+
107+
val := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
108+
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
109+
return val, 8
110+
}
111+
98112
// Deserialize takes the incoming byte slice, and populates the sparseBitArray
99113
// with data in the bytes. Note that this will overwrite any capacity
100114
// specified when creating the sparseBitArray. Also note that if an error
101115
// is returned, the sparseBitArray this is called on might be populated
102116
// with partial data.
103117
func (ret *sparseBitArray) Deserialize(incoming []byte) error {
104-
r := bytes.NewReader(incoming[1:]) // Discard identifier
118+
var intsize = uint64(s / 8)
119+
var curLoc = uint64(1) // Ignore the identifier byte
105120

106121
var intsToRead uint64
107-
err := binary.Read(r, binary.LittleEndian, &intsToRead)
108-
if err != nil {
109-
return err
110-
}
111-
112-
var nextblock block
113-
for i := intsToRead; i > uint64(0); i-- {
114-
err = binary.Read(r, binary.LittleEndian, &nextblock)
115-
if err != nil {
116-
return err
122+
var bytesRead int
123+
intsToRead, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
124+
if bytesRead < 0 {
125+
return errors.New("Invalid data for BitArray")
126+
}
127+
curLoc += intsize
128+
129+
var nextblock uint64
130+
ret.blocks = make([]block, intsToRead)
131+
for i := uint64(0); i < intsToRead; i++ {
132+
nextblock, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
133+
if bytesRead < 0 {
134+
return errors.New("Invalid data for BitArray")
117135
}
118-
ret.blocks = append(ret.blocks, nextblock)
136+
ret.blocks[i] = block(nextblock)
137+
curLoc += intsize
119138
}
120139

121-
err = binary.Read(r, binary.LittleEndian, &intsToRead)
122-
if err != nil {
123-
return err
140+
intsToRead, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
141+
if bytesRead < 0 {
142+
return errors.New("Invalid data for BitArray")
124143
}
144+
curLoc += intsize
125145

126146
var nextuint uint64
127-
for i := intsToRead; i > uint64(0); i-- {
128-
err = binary.Read(r, binary.LittleEndian, &nextuint)
129-
if err != nil {
130-
return err
147+
ret.indices = make(uintSlice, intsToRead)
148+
for i := uint64(0); i < intsToRead; i++ {
149+
nextuint, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
150+
if bytesRead < 0 {
151+
return errors.New("Invalid data for BitArray")
131152
}
132-
ret.indices = append(ret.indices, nextuint)
153+
ret.indices[i] = nextuint
154+
curLoc += intsize
133155
}
134-
135156
return nil
136157
}
137158

bitarray/interface.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,14 @@ type BitArray interface {
6161
// And will bitwise and the two bitarrays and return a new bitarray
6262
// representing the result.
6363
And(other BitArray) BitArray
64+
// Nand will bitwise nand the two bitarrays and return a new bitarray
65+
// representing the result.
66+
Nand(other BitArray) BitArray
6467
// ToNums converts this bit array to the list of numbers contained
6568
// within it.
6669
ToNums() []uint64
70+
// IsEmpty checks to see if any values are set on the bitarray
71+
IsEmpty() bool
6772
}
6873

6974
// Iterator defines methods used to iterate over a bit array.

0 commit comments

Comments
 (0)