mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
1078 lines
21 KiB
Go
1078 lines
21 KiB
Go
package bintrie
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"math/bits"
|
|
"testing"
|
|
)
|
|
|
|
const (
|
|
ones63 = 0x7FFFFFFFFFFFFFFF // 63 bits of 1
|
|
)
|
|
|
|
func TestBytes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
ba BitArray
|
|
want [32]byte
|
|
}{
|
|
{
|
|
name: "length == 0",
|
|
ba: BitArray{len: 0, words: [4]uint64{0, 0, 0, 0}},
|
|
want: [32]byte{},
|
|
},
|
|
{
|
|
name: "length < 64",
|
|
ba: BitArray{len: 38, words: [4]uint64{0x3FFFFFFFFF, 0, 0, 0}},
|
|
want: func() [32]byte {
|
|
var b [32]byte
|
|
binary.BigEndian.PutUint64(b[24:32], 0x3FFFFFFFFF)
|
|
return b
|
|
}(),
|
|
},
|
|
{
|
|
name: "64 <= length < 128",
|
|
ba: BitArray{len: 100, words: [4]uint64{maxUint64, 0xFFFFFFFFF, 0, 0}},
|
|
want: func() [32]byte {
|
|
var b [32]byte
|
|
binary.BigEndian.PutUint64(b[16:24], 0xFFFFFFFFF)
|
|
binary.BigEndian.PutUint64(b[24:32], maxUint64)
|
|
return b
|
|
}(),
|
|
},
|
|
{
|
|
name: "128 <= length < 192",
|
|
ba: BitArray{len: 130, words: [4]uint64{maxUint64, maxUint64, 0x3, 0}},
|
|
want: func() [32]byte {
|
|
var b [32]byte
|
|
binary.BigEndian.PutUint64(b[8:16], 0x3)
|
|
binary.BigEndian.PutUint64(b[16:24], maxUint64)
|
|
binary.BigEndian.PutUint64(b[24:32], maxUint64)
|
|
return b
|
|
}(),
|
|
},
|
|
{
|
|
name: "192 <= length < 255",
|
|
ba: BitArray{len: 201, words: [4]uint64{maxUint64, maxUint64, maxUint64, 0x1FF}},
|
|
want: func() [32]byte {
|
|
var b [32]byte
|
|
binary.BigEndian.PutUint64(b[0:8], 0x1FF)
|
|
binary.BigEndian.PutUint64(b[8:16], maxUint64)
|
|
binary.BigEndian.PutUint64(b[16:24], maxUint64)
|
|
binary.BigEndian.PutUint64(b[24:32], maxUint64)
|
|
return b
|
|
}(),
|
|
},
|
|
{
|
|
name: "length == 254",
|
|
ba: BitArray{len: 254, words: [4]uint64{maxUint64, maxUint64, maxUint64, 0x3FFFFFFFFFFFFFFF}},
|
|
want: func() [32]byte {
|
|
var b [32]byte
|
|
binary.BigEndian.PutUint64(b[0:8], 0x3FFFFFFFFFFFFFFF)
|
|
binary.BigEndian.PutUint64(b[8:16], maxUint64)
|
|
binary.BigEndian.PutUint64(b[16:24], maxUint64)
|
|
binary.BigEndian.PutUint64(b[24:32], maxUint64)
|
|
return b
|
|
}(),
|
|
},
|
|
{
|
|
name: "length == 255",
|
|
ba: BitArray{len: 255, words: [4]uint64{maxUint64, maxUint64, maxUint64, ones63}},
|
|
want: func() [32]byte {
|
|
var b [32]byte
|
|
binary.BigEndian.PutUint64(b[0:8], ones63)
|
|
binary.BigEndian.PutUint64(b[8:16], maxUint64)
|
|
binary.BigEndian.PutUint64(b[16:24], maxUint64)
|
|
binary.BigEndian.PutUint64(b[24:32], maxUint64)
|
|
return b
|
|
}(),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.ba.Bytes()
|
|
if !bytes.Equal(got[:], tt.want[:]) {
|
|
t.Errorf("BitArray.Bytes() = %v, want %v", got, tt.want)
|
|
}
|
|
|
|
// check if the received bytes has the same bit count as the BitArray.len
|
|
count := 0
|
|
for _, b := range got {
|
|
count += bits.OnesCount8(b)
|
|
}
|
|
if count != int(tt.ba.len) {
|
|
t.Errorf("BitArray.Bytes() bit count = %v, want %v", count, tt.ba.len)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRsh(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initial *BitArray
|
|
shiftBy uint8
|
|
expected *BitArray
|
|
}{
|
|
{
|
|
name: "zero length array",
|
|
initial: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
shiftBy: 5,
|
|
expected: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 0",
|
|
initial: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
shiftBy: 0,
|
|
expected: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by more than length",
|
|
initial: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
shiftBy: 65,
|
|
expected: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by less than 64",
|
|
initial: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
shiftBy: 32,
|
|
expected: &BitArray{
|
|
len: 96,
|
|
words: [4]uint64{maxUint64, 0x00000000FFFFFFFF, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by exactly 64",
|
|
initial: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
shiftBy: 64,
|
|
expected: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 127",
|
|
initial: &BitArray{
|
|
len: 255,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, ones63},
|
|
},
|
|
shiftBy: 127,
|
|
expected: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 128",
|
|
initial: &BitArray{
|
|
len: 251,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, maxUint64},
|
|
},
|
|
shiftBy: 128,
|
|
expected: &BitArray{
|
|
len: 123,
|
|
words: [4]uint64{maxUint64, 0x7FFFFFFFFFFFFFF, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 192",
|
|
initial: &BitArray{
|
|
len: 251,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, maxUint64},
|
|
},
|
|
shiftBy: 192,
|
|
expected: &BitArray{
|
|
len: 59,
|
|
words: [4]uint64{0x7FFFFFFFFFFFFFF, 0, 0, 0},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := new(BitArray).rsh(tt.initial, tt.shiftBy)
|
|
if !result.Equal(tt.expected) {
|
|
t.Errorf("rsh() got = %+v, want %+v", result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLsh(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
x *BitArray
|
|
n uint8
|
|
want *BitArray
|
|
}{
|
|
{
|
|
name: "empty array",
|
|
x: emptyBitArray,
|
|
n: 5,
|
|
want: emptyBitArray,
|
|
},
|
|
{
|
|
name: "shift by 0",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
n: 0,
|
|
want: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift within first word",
|
|
x: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
n: 4,
|
|
want: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xF0, 0, 0, 0}, // 11110000
|
|
},
|
|
},
|
|
{
|
|
name: "shift across word boundary",
|
|
x: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
n: 62,
|
|
want: &BitArray{
|
|
len: 66,
|
|
words: [4]uint64{0xC000000000000000, 0x3, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 64 (full word)",
|
|
x: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xFF, 0, 0, 0}, // 11111111
|
|
},
|
|
n: 64,
|
|
want: &BitArray{
|
|
len: 72,
|
|
words: [4]uint64{0, 0xFF, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 128",
|
|
x: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xFF, 0, 0, 0}, // 11111111
|
|
},
|
|
n: 128,
|
|
want: &BitArray{
|
|
len: 136,
|
|
words: [4]uint64{0, 0, 0xFF, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "shift by 192",
|
|
x: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xFF, 0, 0, 0}, // 11111111
|
|
},
|
|
n: 192,
|
|
want: &BitArray{
|
|
len: 200,
|
|
words: [4]uint64{0, 0, 0, 0xFF},
|
|
},
|
|
},
|
|
{
|
|
name: "shift causing length overflow",
|
|
x: &BitArray{
|
|
len: 200,
|
|
words: [4]uint64{0xFF, 0, 0, 0},
|
|
},
|
|
n: 60,
|
|
want: &BitArray{
|
|
len: 255, // capped at maxUint8
|
|
words: [4]uint64{
|
|
0xF000000000000000,
|
|
0xF,
|
|
0,
|
|
0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "shift sparse bits",
|
|
x: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xAA, 0, 0, 0}, // 10101010
|
|
},
|
|
n: 4,
|
|
want: &BitArray{
|
|
len: 12,
|
|
words: [4]uint64{0xAA0, 0, 0, 0}, // 101010100000
|
|
},
|
|
},
|
|
{
|
|
name: "shift partial word across boundary",
|
|
x: &BitArray{
|
|
len: 100,
|
|
words: [4]uint64{0xFF, 0xFF, 0, 0},
|
|
},
|
|
n: 60,
|
|
want: &BitArray{
|
|
len: 160,
|
|
words: [4]uint64{
|
|
0xF000000000000000,
|
|
0xF00000000000000F,
|
|
0xF,
|
|
0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "near maximum length shift",
|
|
x: &BitArray{
|
|
len: 251,
|
|
words: [4]uint64{0xFF, 0, 0, 0},
|
|
},
|
|
n: 4,
|
|
want: &BitArray{
|
|
len: 255, // capped at maxUint8
|
|
words: [4]uint64{0xFF0, 0, 0, 0},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := new(BitArray).lsh(tt.x, tt.n)
|
|
if !got.Equal(tt.want) {
|
|
t.Errorf("Lsh() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAppend(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
x *BitArray
|
|
y *BitArray
|
|
want *BitArray
|
|
}{
|
|
{
|
|
name: "both empty arrays",
|
|
x: emptyBitArray,
|
|
y: emptyBitArray,
|
|
want: emptyBitArray,
|
|
},
|
|
{
|
|
name: "first array empty",
|
|
x: emptyBitArray,
|
|
y: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
want: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
},
|
|
{
|
|
name: "second array empty",
|
|
x: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
y: emptyBitArray,
|
|
want: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
},
|
|
{
|
|
name: "within first word",
|
|
x: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
y: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
want: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xFF, 0, 0, 0}, // 11111111
|
|
},
|
|
},
|
|
{
|
|
name: "different lengths within word",
|
|
x: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
y: &BitArray{
|
|
len: 2,
|
|
words: [4]uint64{0x3, 0, 0, 0}, // 11
|
|
},
|
|
want: &BitArray{
|
|
len: 6,
|
|
words: [4]uint64{0x3F, 0, 0, 0}, // 111111
|
|
},
|
|
},
|
|
{
|
|
name: "across word boundary",
|
|
x: &BitArray{
|
|
len: 62,
|
|
words: [4]uint64{0x3FFFFFFFFFFFFFFF, 0, 0, 0},
|
|
},
|
|
y: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0}, // 1111
|
|
},
|
|
want: &BitArray{
|
|
len: 66,
|
|
words: [4]uint64{maxUint64, 0x3, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "across multiple words",
|
|
x: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
y: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
want: &BitArray{
|
|
len: 192,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "sparse bits",
|
|
x: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xAA, 0, 0, 0}, // 10101010
|
|
},
|
|
y: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0x55, 0, 0, 0}, // 01010101
|
|
},
|
|
want: &BitArray{
|
|
len: 16,
|
|
words: [4]uint64{0xAA55, 0, 0, 0}, // 1010101001010101
|
|
},
|
|
},
|
|
{
|
|
name: "result exactly at length limit",
|
|
x: &BitArray{
|
|
len: 251,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0x7FFFFFFFFFFFFFFF},
|
|
},
|
|
y: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0},
|
|
},
|
|
want: &BitArray{
|
|
len: 255,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0x7FFFFFFFFFFFFFFF},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := new(BitArray).Append(tt.x, tt.y)
|
|
if !got.Equal(tt.want) {
|
|
t.Errorf("Append() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLSBs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
x *BitArray
|
|
pos uint8
|
|
want *BitArray
|
|
}{
|
|
{
|
|
name: "zero position",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
pos: 0,
|
|
want: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "position beyond length",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
pos: 65,
|
|
want: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get last 4 bits",
|
|
x: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xFF, 0, 0, 0}, // 11111111
|
|
},
|
|
pos: 4,
|
|
want: &BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0x0F, 0, 0, 0}, // 1111
|
|
},
|
|
},
|
|
{
|
|
name: "get bits across word boundary",
|
|
x: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
pos: 64,
|
|
want: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get bits from max length array",
|
|
x: &BitArray{
|
|
len: 251,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0x7FFFFFFFFFFFFFF},
|
|
},
|
|
pos: 200,
|
|
want: &BitArray{
|
|
len: 51,
|
|
words: [4]uint64{0x7FFFFFFFFFFFF, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "empty array",
|
|
x: emptyBitArray,
|
|
pos: 1,
|
|
want: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "sparse bits",
|
|
x: &BitArray{
|
|
len: 16,
|
|
words: [4]uint64{0xAAAA, 0, 0, 0}, // 1010101010101010
|
|
},
|
|
pos: 8,
|
|
want: &BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xAA, 0, 0, 0}, // 10101010
|
|
},
|
|
},
|
|
{
|
|
name: "position equals length",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
pos: 64,
|
|
want: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := new(BitArray).lsb(tt.x, tt.pos)
|
|
if !got.Equal(tt.want) {
|
|
t.Errorf("LSBs() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLSBsFromLSB(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initial BitArray
|
|
length uint8
|
|
expected BitArray
|
|
}{
|
|
{
|
|
name: "zero",
|
|
initial: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
length: 0,
|
|
expected: BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 32 LSBs",
|
|
initial: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
length: 32,
|
|
expected: BitArray{
|
|
len: 32,
|
|
words: [4]uint64{0x00000000FFFFFFFF, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 1 LSB",
|
|
initial: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
length: 1,
|
|
expected: BitArray{
|
|
len: 1,
|
|
words: [4]uint64{0x1, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 100 LSBs across words",
|
|
initial: BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
length: 100,
|
|
expected: BitArray{
|
|
len: 100,
|
|
words: [4]uint64{maxUint64, 0x0000000FFFFFFFFF, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 64 LSBs at word boundary",
|
|
initial: BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
length: 64,
|
|
expected: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 128 LSBs at word boundary",
|
|
initial: BitArray{
|
|
len: 192,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0},
|
|
},
|
|
length: 128,
|
|
expected: BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 150 LSBs in third word",
|
|
initial: BitArray{
|
|
len: 192,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0},
|
|
},
|
|
length: 150,
|
|
expected: BitArray{
|
|
len: 150,
|
|
words: [4]uint64{maxUint64, maxUint64, 0x3FFFFF, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get 220 LSBs in fourth word",
|
|
initial: BitArray{
|
|
len: 255,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, maxUint64},
|
|
},
|
|
length: 220,
|
|
expected: BitArray{
|
|
len: 220,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0xFFFFFFF},
|
|
},
|
|
},
|
|
{
|
|
name: "get 251 LSBs",
|
|
initial: BitArray{
|
|
len: 255,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, maxUint64},
|
|
},
|
|
length: 251,
|
|
expected: BitArray{
|
|
len: 251,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, 0x7FFFFFFFFFFFFFF},
|
|
},
|
|
},
|
|
{
|
|
name: "get 100 LSBs from sparse bits",
|
|
initial: BitArray{
|
|
len: 128,
|
|
words: [4]uint64{0xAAAAAAAAAAAAAAAA, 0x5555555555555555, 0, 0},
|
|
},
|
|
length: 100,
|
|
expected: BitArray{
|
|
len: 100,
|
|
words: [4]uint64{0xAAAAAAAAAAAAAAAA, 0x0000000555555555, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "no change when new length equals current length",
|
|
initial: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
length: 64,
|
|
expected: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "no change when new length greater than current length",
|
|
initial: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
length: 128,
|
|
expected: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := new(BitArray).copyLsb(&tt.initial, tt.length)
|
|
if !result.Equal(&tt.expected) {
|
|
t.Errorf("Truncate() got = %+v, want %+v", result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMSBs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
x *BitArray
|
|
n uint8
|
|
want *BitArray
|
|
}{
|
|
{
|
|
name: "empty array",
|
|
x: emptyBitArray,
|
|
n: 0,
|
|
want: emptyBitArray,
|
|
},
|
|
{
|
|
name: "get all bits",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
n: 64,
|
|
want: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get more bits than available",
|
|
x: &BitArray{
|
|
len: 32,
|
|
words: [4]uint64{0xFFFFFFFF, 0, 0, 0},
|
|
},
|
|
n: 64,
|
|
want: &BitArray{
|
|
len: 32,
|
|
words: [4]uint64{0xFFFFFFFF, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get half of available bits",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
n: 32,
|
|
want: &BitArray{
|
|
len: 32,
|
|
words: [4]uint64{0xFFFFFFFF00000000 >> 32, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get MSBs across word boundary",
|
|
x: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{maxUint64, maxUint64, 0, 0},
|
|
},
|
|
n: 100,
|
|
want: &BitArray{
|
|
len: 100,
|
|
words: [4]uint64{maxUint64, maxUint64 >> 28, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get MSBs from max length array",
|
|
x: &BitArray{
|
|
len: 255,
|
|
words: [4]uint64{maxUint64, maxUint64, maxUint64, ones63},
|
|
},
|
|
n: 64,
|
|
want: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "get zero bits",
|
|
x: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
n: 0,
|
|
want: &BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "sparse bits",
|
|
x: &BitArray{
|
|
len: 128,
|
|
words: [4]uint64{0xAAAAAAAAAAAAAAAA, 0x5555555555555555, 0, 0},
|
|
},
|
|
n: 64,
|
|
want: &BitArray{
|
|
len: 64,
|
|
words: [4]uint64{0x5555555555555555, 0, 0, 0},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := new(BitArray).MSBs(tt.x, tt.n)
|
|
if !got.Equal(tt.want) {
|
|
t.Errorf("MSBs() = %v, want %v", got, tt.want)
|
|
}
|
|
|
|
if got.len != tt.want.len {
|
|
t.Errorf("MSBs() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSetBit(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
bit uint8
|
|
want BitArray
|
|
}{
|
|
{
|
|
name: "set bit 0",
|
|
bit: 0,
|
|
want: BitArray{
|
|
len: 1,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "set bit 1",
|
|
bit: 1,
|
|
want: BitArray{
|
|
len: 1,
|
|
words: [4]uint64{1, 0, 0, 0},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := new(BitArray).SetBit(tt.bit)
|
|
if !got.Equal(&tt.want) {
|
|
t.Errorf("SetBit(%v) = %v, want %v", tt.bit, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSetBytes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
length uint8
|
|
data []byte
|
|
want BitArray
|
|
}{
|
|
{
|
|
name: "empty data",
|
|
length: 0,
|
|
data: []byte{},
|
|
want: BitArray{
|
|
len: 0,
|
|
words: [4]uint64{0, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "single byte",
|
|
length: 8,
|
|
data: []byte{0xFF},
|
|
want: BitArray{
|
|
len: 8,
|
|
words: [4]uint64{0xFF, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "two bytes",
|
|
length: 16,
|
|
data: []byte{0xAA, 0xFF},
|
|
want: BitArray{
|
|
len: 16,
|
|
words: [4]uint64{0xAAFF, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "three bytes",
|
|
length: 24,
|
|
data: []byte{0xAA, 0xBB, 0xCC},
|
|
want: BitArray{
|
|
len: 24,
|
|
words: [4]uint64{0xAABBCC, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "four bytes",
|
|
length: 32,
|
|
data: []byte{0xAA, 0xBB, 0xCC, 0xDD},
|
|
want: BitArray{
|
|
len: 32,
|
|
words: [4]uint64{0xAABBCCDD, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "eight bytes (full word)",
|
|
length: 64,
|
|
data: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
|
want: BitArray{
|
|
len: 64,
|
|
words: [4]uint64{maxUint64, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "sixteen bytes (two words)",
|
|
length: 128,
|
|
data: []byte{
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
|
},
|
|
want: BitArray{
|
|
len: 128,
|
|
words: [4]uint64{
|
|
0xAAAAAAAAAAAAAAAA,
|
|
0xFFFFFFFFFFFFFFFF,
|
|
0, 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "thirty-two bytes (full array)",
|
|
length: 251,
|
|
data: []byte{
|
|
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
},
|
|
want: BitArray{
|
|
len: 251,
|
|
words: [4]uint64{
|
|
maxUint64,
|
|
maxUint64,
|
|
maxUint64,
|
|
0x7FFFFFFFFFFFFFF,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "truncate to length",
|
|
length: 4,
|
|
data: []byte{0xFF},
|
|
want: BitArray{
|
|
len: 4,
|
|
words: [4]uint64{0xF, 0, 0, 0},
|
|
},
|
|
},
|
|
{
|
|
name: "data larger than 32 bytes",
|
|
length: 251,
|
|
data: []byte{
|
|
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, // extra bytes should be ignored
|
|
},
|
|
want: BitArray{
|
|
len: 251,
|
|
words: [4]uint64{
|
|
maxUint64,
|
|
maxUint64,
|
|
maxUint64,
|
|
0x7FFFFFFFFFFFFFF,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := new(BitArray).SetBytes(tt.length, tt.data)
|
|
if !got.Equal(&tt.want) {
|
|
t.Errorf("SetBytes(%d, %v) = %v, want %v", tt.length, tt.data, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|