Skip to content

Commit

Permalink
Merge pull request #110 from evanh/master
Browse files Browse the repository at this point in the history
Add Nand functionality
  • Loading branch information
dustinhiatt-wf committed Aug 18, 2015
2 parents c5e9b05 + f1e6d95 commit 3b07818
Show file tree
Hide file tree
Showing 9 changed files with 582 additions and 29 deletions.
11 changes: 7 additions & 4 deletions bitarray/and.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func andSparseWithSparseBitArray(sba, other *sparseBitArray) BitArray {

selfIndex := 0
otherIndex := 0
var resultBlock block

// move through the array and compare the blocks if they happen to
// intersect
Expand Down Expand Up @@ -52,9 +53,12 @@ func andSparseWithSparseBitArray(sba, other *sparseBitArray) BitArray {
default:
// Here, our indices match for both `sba` and `other`.
// Time to do the bitwise AND operation and add a block
// to our result list.
indices = append(indices, selfValue)
blocks = append(blocks, sba.blocks[selfIndex].and(other.blocks[otherIndex]))
// to our result list if the block has values in it.
resultBlock = sba.blocks[selfIndex].and(other.blocks[otherIndex])
if resultBlock > 0 {
indices = append(indices, selfValue)
blocks = append(blocks, resultBlock)
}
selfIndex++
otherIndex++
}
Expand Down Expand Up @@ -92,7 +96,6 @@ func andSparseWithDenseBitArray(sba *sparseBitArray, other *bitArray) BitArray {
// We're ready to return
break
}

ba.blocks[selfIndex] = ba.blocks[selfIndex].and(
other.blocks[selfValue])
}
Expand Down
30 changes: 26 additions & 4 deletions bitarray/and_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ func TestAndSparseWithSparseBitArray(t *testing.T) {
sba.SetBit(280)
other.SetBit(9)
other.SetBit(100)
sba.SetBit(1000)
other.SetBit(1001)

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

ba := andSparseWithSparseBitArray(sba, other)

// Bits in both
checkBit(t, ba, 1, true)
checkBit(t, ba, 30, true)
checkBit(t, ba, 2680, true)

// Bits in sba but not other
checkBit(t, ba, 3, false)
checkBit(t, ba, 280, false)
checkBit(t, ba, 1000, false)

// Bits in other but not sba
checkBit(t, ba, 9, false)
checkBit(t, ba, 100, false)
checkBit(t, ba, 2, false)
checkBit(t, ba, 280, false)

nums := ba.ToNums()
assert.Equal(t, []uint64{1, 30, 2680}, nums)
}

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

ba := andSparseWithDenseBitArray(sba, other)

// Bits in both
checkBit(t, ba, 1, true)
checkBit(t, ba, 150, true)
checkBit(t, ba, 300, true)

// Bits in sba but not other
checkBit(t, ba, 155, false)

// Bits in other but not sba
checkBit(t, ba, 156, false)
checkBit(t, ba, 300, true)

}

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

ba := andSparseWithDenseBitArray(sba, other)

// Bits in both
checkBit(t, ba, 1, true)
checkBit(t, ba, 150, true)

// Bits in sba but not other
checkBit(t, ba, 155, false)
checkBit(t, ba, 128, false)
checkBit(t, ba, 500, false)
checkBit(t, ba, 1200, false)
checkBit(t, ba, 1500, false)

// Bits in other but not sba
checkBit(t, ba, 128, false)
}

func TestAndDenseWithDenseBitArray(t *testing.T) {
Expand Down Expand Up @@ -148,6 +169,7 @@ func TestAndSparseWithEmptySparse(t *testing.T) {
sba.SetBit(5)

ba := andSparseWithSparseBitArray(sba, other)

checkBit(t, ba, 0, false)
checkBit(t, ba, 5, false)
checkBit(t, ba, 100, false)
Expand Down
14 changes: 14 additions & 0 deletions bitarray/bitarray.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ func (ba *bitArray) And(other BitArray) BitArray {
return andSparseWithDenseBitArray(other.(*sparseBitArray), ba)
}

// Nand will return the result of doing a bitwise and not of the bit array
// with the other bit array on each block.
func (ba *bitArray) Nand(other BitArray) BitArray {
if dba, ok := other.(*bitArray); ok {
return nandDenseWithDenseBitArray(ba, dba)
}

return nandDenseWithSparseBitArray(ba, other.(*sparseBitArray))
}

// Reset clears out the bit array.
func (ba *bitArray) Reset() {
for i := uint64(0); i < uint64(len(ba.blocks)); i++ {
Expand Down Expand Up @@ -222,6 +232,10 @@ func (ba *bitArray) Blocks() Iterator {
return newBitArrayIterator(ba)
}

func (ba *bitArray) IsEmpty() bool {
return ba.anyset
}

// complement flips all bits in this array.
func (ba *bitArray) complement() {
for i := uint64(0); i < uint64(len(ba.blocks)); i++ {
Expand Down
4 changes: 4 additions & 0 deletions bitarray/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ func (b block) and(other block) block {
return b & other
}

func (b block) nand(other block) block {
return b &^ other
}

func (b block) get(position uint64) bool {
return b&block(1<<position) != 0
}
Expand Down
63 changes: 42 additions & 21 deletions bitarray/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,43 +95,64 @@ func (ba *sparseBitArray) Serialize() ([]byte, error) {
return w.Bytes(), nil
}

// This function is a copy from the binary package, with some added error
// checking to avoid panics. The function will return the value, and the number
// of bytes read from the buffer. If the number of bytes is negative, then
// not enough bytes were passed in and the return value will be zero.
func Uint64FromBytes(b []byte) (uint64, int) {
if len(b) < 8 {
return 0, -1
}

val := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
return val, 8
}

// Deserialize takes the incoming byte slice, and populates the sparseBitArray
// with data in the bytes. Note that this will overwrite any capacity
// specified when creating the sparseBitArray. Also note that if an error
// is returned, the sparseBitArray this is called on might be populated
// with partial data.
func (ret *sparseBitArray) Deserialize(incoming []byte) error {
r := bytes.NewReader(incoming[1:]) // Discard identifier
var intsize = uint64(s / 8)
var curLoc = uint64(1) // Ignore the identifier byte

var intsToRead uint64
err := binary.Read(r, binary.LittleEndian, &intsToRead)
if err != nil {
return err
}

var nextblock block
for i := intsToRead; i > uint64(0); i-- {
err = binary.Read(r, binary.LittleEndian, &nextblock)
if err != nil {
return err
var bytesRead int
intsToRead, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
if bytesRead < 0 {
return errors.New("Invalid data for BitArray")
}
curLoc += intsize

var nextblock uint64
ret.blocks = make([]block, intsToRead)
for i := uint64(0); i < intsToRead; i++ {
nextblock, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
if bytesRead < 0 {
return errors.New("Invalid data for BitArray")
}
ret.blocks = append(ret.blocks, nextblock)
ret.blocks[i] = block(nextblock)
curLoc += intsize
}

err = binary.Read(r, binary.LittleEndian, &intsToRead)
if err != nil {
return err
intsToRead, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
if bytesRead < 0 {
return errors.New("Invalid data for BitArray")
}
curLoc += intsize

var nextuint uint64
for i := intsToRead; i > uint64(0); i-- {
err = binary.Read(r, binary.LittleEndian, &nextuint)
if err != nil {
return err
ret.indices = make(uintSlice, intsToRead)
for i := uint64(0); i < intsToRead; i++ {
nextuint, bytesRead = Uint64FromBytes(incoming[curLoc : curLoc+intsize])
if bytesRead < 0 {
return errors.New("Invalid data for BitArray")
}
ret.indices = append(ret.indices, nextuint)
ret.indices[i] = nextuint
curLoc += intsize
}

return nil
}

Expand Down
5 changes: 5 additions & 0 deletions bitarray/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,14 @@ type BitArray interface {
// And will bitwise and the two bitarrays and return a new bitarray
// representing the result.
And(other BitArray) BitArray
// Nand will bitwise nand the two bitarrays and return a new bitarray
// representing the result.
Nand(other BitArray) BitArray
// ToNums converts this bit array to the list of numbers contained
// within it.
ToNums() []uint64
// IsEmpty checks to see if any values are set on the bitarray
IsEmpty() bool
}

// Iterator defines methods used to iterate over a bit array.
Expand Down
Loading

0 comments on commit 3b07818

Please sign in to comment.