Files
nset/nset_test.go

367 lines
6.1 KiB
Go
Executable File

package nset_test
import (
"fmt"
"math"
"math/rand"
"testing"
"github.com/bloeys/nset"
)
const (
maxBenchSize = 10_000_000
RandSeed = 9_812_938_704
)
var (
dump int
fullRangeNSet *nset.NSet[uint32]
)
func TestNSet(t *testing.T) {
n1 := nset.NewNSet[uint32]()
n1.Add(0)
n1.Add(1)
n1.Add(63)
n1.Add(math.MaxUint32)
// 4294967295
// 4294967295
AllTrue(t, n1.Contains(0), n1.Contains(1), n1.Contains(63), n1.Contains(math.MaxUint32), !n1.Contains(10), !n1.Contains(599))
AllTrue(t, n1.ContainsAll(0, 1, 63), !n1.ContainsAll(9, 0, 1), !n1.ContainsAll(0, 1, 63, 99))
AllTrue(t, n1.ContainsAny(0, 1, 63), n1.ContainsAny(9, 99, 999, 1), !n1.ContainsAny(9, 99, 999))
IsEq(t, nset.BucketCount-1, n1.GetBucketIndex(math.MaxUint32))
IsEq(t, math.MaxUint32/64/nset.BucketCount, n1.GetStorageUnitIndex(math.MaxUint32))
nCopy := n1.Copy()
n1.Remove(1)
AllTrue(t, n1.Contains(0), n1.Contains(63), !n1.Contains(1), nCopy.ContainsAll(0, 1, 63, math.MaxUint32))
//Intersections
n2 := nset.NewNSet[uint32]()
n2.AddMany(1000, 63, 5, 10)
n3 := nset.NewNSet[uint32]()
n3.AddMany(math.MaxUint32)
AllTrue(t, n1.HasIntersection(n2), n2.HasIntersection(n1), n3.HasIntersection(n1), !n3.HasIntersection(n2))
n4 := nset.NewNSet[uint32]()
n4.AddMany(0, 1, 64, math.MaxUint32)
n5 := nset.NewNSet[uint32]()
n5.AddMany(0, 1, 63, 64, math.MaxUint32)
n4n5 := n4.GetIntersection(n5)
AllTrue(t, n4n5.ContainsAll(0, 1, 64, math.MaxUint32), !n4n5.Contains(63))
}
func TestNSetFullRange(t *testing.T) {
return
if fullRangeNSet == nil {
fullRangeNSet = nset.NewNSet[uint32]()
println("Adding all uint32 to NSet...")
for i := uint32(0); i < math.MaxUint32; i++ {
fullRangeNSet.Add(i)
if i%1_000_000_000 == 0 {
fmt.Printf("i=%d billion\n", i)
}
}
fullRangeNSet.Add(math.MaxUint32)
}
n := fullRangeNSet
IsEq(t, 67_108_864, n.StorageUnitCount)
for i := 0; i < len(n.Buckets); i++ {
b := &n.Buckets[i]
IsEq(t, 524288, b.StorageUnitCount)
for j := 0; j < len(b.Data); j++ {
if b.Data[j] != math.MaxUint64 {
t.Errorf("Error: storage unit is NOT equal to MaxUint64 (i=%d,j=%d)! Expected math.MaxUint64 but got '%08b'\n",
i,
j,
b.Data[j])
}
}
}
}
func AllTrue(t *testing.T, values ...bool) bool {
for i := 0; i < len(values); i++ {
if !values[i] {
t.Errorf("Expected 'true' but got 'false'\n")
}
}
return true
}
func IsEq[T comparable](t *testing.T, expected, val T) bool {
if val == expected {
return true
}
t.Errorf("Expected '%v' but got '%v'\n", expected, val)
return false
}
func BenchmarkNSetAdd(b *testing.B) {
n := nset.NewNSet[uint32]()
for i := uint32(0); i < uint32(b.N); i++ {
n.Add(i % maxBenchSize)
}
}
func BenchmarkMapAdd(b *testing.B) {
hMap := map[uint32]struct{}{}
for i := uint32(0); i < uint32(b.N); i++ {
hMap[i%maxBenchSize] = struct{}{}
}
}
func BenchmarkNSetAddRand(b *testing.B) {
n := nset.NewNSet[uint32]()
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
n.Add(rand.Uint32() % maxBenchSize)
}
}
func BenchmarkNSetAddRandNoSizeLimit(b *testing.B) {
n := nset.NewNSet[uint32]()
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
n.Add(rand.Uint32())
}
}
func BenchmarkMapAddRand(b *testing.B) {
hMap := map[uint32]struct{}{}
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
hMap[rand.Uint32()%maxBenchSize] = struct{}{}
}
}
func BenchmarkNSetContains(b *testing.B) {
//Init
b.StopTimer()
n := nset.NewNSet[uint32]()
for i := uint32(0); i < maxBenchSize; i++ {
n.Add(i)
}
b.StartTimer()
//Work
found := 0
for i := uint32(0); i < uint32(b.N); i++ {
if n.Contains(i) {
found++
}
}
dump = found
}
func BenchmarkMapContains(b *testing.B) {
//Init
b.StopTimer()
hMap := map[uint32]struct{}{}
for i := uint32(0); i < maxBenchSize; i++ {
hMap[i] = struct{}{}
}
b.StartTimer()
//Work
found := 0
for i := uint32(0); i < uint32(b.N); i++ {
if _, ok := hMap[i]; ok {
found++
}
}
dump = found
}
func BenchmarkNSetContainsRand(b *testing.B) {
//Init
b.StopTimer()
n := nset.NewNSet[uint32]()
for i := uint32(0); i < maxBenchSize; i++ {
n.Add(i)
}
b.StartTimer()
//Work
found := 0
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
randVal := rand.Uint32()
if n.Contains(randVal) {
found++
}
}
dump = found
}
func BenchmarkNSetContainsRandFullRange(b *testing.B) {
//Init
if fullRangeNSet == nil {
b.StopTimer()
fullRangeNSet = nset.NewNSet[uint32]()
println("Preparing full range NSet...")
for i := uint32(0); i < math.MaxUint32; i++ {
fullRangeNSet.Add(i)
}
fullRangeNSet.Add(math.MaxUint32)
b.StartTimer()
}
n := fullRangeNSet
//Work
found := 0
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
randVal := rand.Uint32()
if n.Contains(randVal) {
found++
}
}
dump = found
}
func BenchmarkMapContainsRand(b *testing.B) {
//Init
b.StopTimer()
hMap := map[uint32]struct{}{}
for i := uint32(0); i < maxBenchSize; i++ {
hMap[i] = struct{}{}
}
b.StartTimer()
//Work
found := 0
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
randVal := rand.Uint32()
if _, ok := hMap[randVal]; ok {
found++
}
}
dump = found
}
func BenchmarkNSetDelete(b *testing.B) {
//Init
b.StopTimer()
n := nset.NewNSet[uint32]()
for i := uint32(0); i < maxBenchSize; i++ {
n.Add(i)
}
b.StartTimer()
//Work
for i := uint32(0); i < uint32(b.N); i++ {
n.Remove(i)
}
}
func BenchmarkMapDelete(b *testing.B) {
//Init
b.StopTimer()
hMap := map[uint32]struct{}{}
for i := uint32(0); i < maxBenchSize; i++ {
hMap[i] = struct{}{}
}
b.StartTimer()
//Work
for i := uint32(0); i < uint32(b.N); i++ {
delete(hMap, i)
}
}
func BenchmarkNSetDeleteRand(b *testing.B) {
//Init
b.StopTimer()
n := nset.NewNSet[uint32]()
for i := uint32(0); i < maxBenchSize; i++ {
n.Add(i)
}
b.StartTimer()
//Work
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
randVal := rand.Uint32()
n.Remove(randVal)
}
}
func BenchmarkMapDeleteRand(b *testing.B) {
//Init
b.StopTimer()
hMap := map[uint32]struct{}{}
for i := uint32(0); i < maxBenchSize; i++ {
hMap[i] = struct{}{}
}
b.StartTimer()
//Work
rand.Seed(RandSeed)
for i := 0; i < b.N; i++ {
randVal := rand.Uint32()
delete(hMap, randVal)
}
}