mirror of
https://github.com/bloeys/nset.git
synced 2025-12-29 06:28:19 +00:00
HasIntersection + GetIntersection + AddMany + Tests
This commit is contained in:
77
nset.go
77
nset.go
@ -53,6 +53,28 @@ func (n *NSet[T]) Add(x T) {
|
|||||||
bucket.Data[unitIndex] |= n.GetBitMask(x)
|
bucket.Data[unitIndex] |= n.GetBitMask(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NSet[T]) AddMany(values ...T) {
|
||||||
|
|
||||||
|
for i := 0; i < len(values); i++ {
|
||||||
|
|
||||||
|
x := values[i]
|
||||||
|
bucket := n.GetBucketFromValue(x)
|
||||||
|
|
||||||
|
unitIndex := n.GetStorageUnitIndex(x)
|
||||||
|
if unitIndex >= bucket.StorageUnitCount {
|
||||||
|
|
||||||
|
storageUnitsToAdd := unitIndex - bucket.StorageUnitCount + 1
|
||||||
|
bucket.Data = append(bucket.Data, make([]StorageType, storageUnitsToAdd)...)
|
||||||
|
|
||||||
|
n.StorageUnitCount += storageUnitsToAdd
|
||||||
|
bucket.StorageUnitCount += storageUnitsToAdd
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket.Data[unitIndex] |= n.GetBitMask(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (n *NSet[T]) Remove(x T) {
|
func (n *NSet[T]) Remove(x T) {
|
||||||
|
|
||||||
b := n.GetBucketFromValue(x)
|
b := n.GetBucketFromValue(x)
|
||||||
@ -118,6 +140,61 @@ func (n *NSet[T]) GetBitMask(x T) StorageType {
|
|||||||
return 1 << (((x << BucketIndexingBits) >> BucketIndexingBits) % StorageTypeBits)
|
return 1 << (((x << BucketIndexingBits) >> BucketIndexingBits) % StorageTypeBits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *NSet[T]) GetIntersection(otherSet *NSet[T]) *NSet[T] {
|
||||||
|
|
||||||
|
outSet := NewNSet[T]()
|
||||||
|
|
||||||
|
for i := 0; i < BucketCount; i++ {
|
||||||
|
|
||||||
|
b1 := &n.Buckets[i]
|
||||||
|
b2 := &otherSet.Buckets[i]
|
||||||
|
|
||||||
|
//bucketIndexBits are the bits removed from the original value to use for bucket indexing.
|
||||||
|
//We will use this to restore the original value 'x' once an intersection is detected
|
||||||
|
bucketIndexBits := T(i << n.shiftAmount)
|
||||||
|
for j := 0; j < len(b1.Data) && j < len(b2.Data); j++ {
|
||||||
|
|
||||||
|
if b1.Data[j]&b2.Data[j] == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
mask := StorageType(1 << 0) //This will be used to check set bits. Numbers will be reconstructed only for set bits
|
||||||
|
commonBits := b1.Data[j] & b2.Data[j] //Bits that are set on both storage units (aka the intersection)
|
||||||
|
firstStorageUnitValue := T(j*StorageTypeBits) | bucketIndexBits //StorageUnitIndex = noBucketBitsX / StorageTypeBits. So: noBucketBitsX = StorageUnitIndex * StorageTypeBits; Then: x = noBucketBitsX | bucketIndexBits
|
||||||
|
for k := T(0); k < StorageTypeBits; k++ {
|
||||||
|
|
||||||
|
if commonBits&mask > 0 {
|
||||||
|
outSet.Add(firstStorageUnitValue + k)
|
||||||
|
// fmt.Printf("Bucket=%d, Storage unit=%d, bitPos=%d, value=%d\n", i, j, k, firstStorageUnitValue+k)
|
||||||
|
}
|
||||||
|
|
||||||
|
mask <<= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NSet[T]) HasIntersection(otherSet *NSet[T]) bool {
|
||||||
|
|
||||||
|
for i := 0; i < len(n.Buckets); i++ {
|
||||||
|
|
||||||
|
b1 := &n.Buckets[i]
|
||||||
|
b2 := &otherSet.Buckets[i]
|
||||||
|
|
||||||
|
for j := 0; j < len(b1.Data) && j < len(b2.Data); j++ {
|
||||||
|
|
||||||
|
if b1.Data[j]&b2.Data[j] > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
//String returns a string of the storage as bytes separated by spaces. A comma is between each storage unit
|
//String returns a string of the storage as bytes separated by spaces. A comma is between each storage unit
|
||||||
func (n *NSet[T]) String() string {
|
func (n *NSet[T]) String() string {
|
||||||
|
|
||||||
|
|||||||
48
nset_test.go
48
nset_test.go
@ -21,28 +21,48 @@ var (
|
|||||||
|
|
||||||
func TestNSet(t *testing.T) {
|
func TestNSet(t *testing.T) {
|
||||||
|
|
||||||
n := nset.NewNSet[uint32]()
|
n1 := nset.NewNSet[uint32]()
|
||||||
n.Add(0)
|
n1.Add(0)
|
||||||
n.Add(1)
|
n1.Add(1)
|
||||||
n.Add(63)
|
n1.Add(63)
|
||||||
n.Add(math.MaxUint32)
|
n1.Add(math.MaxUint32)
|
||||||
|
|
||||||
AllTrue(t, n.Contains(0), n.Contains(1), n.Contains(63), n.Contains(math.MaxUint32), !n.Contains(10), !n.Contains(599))
|
// 4294967295
|
||||||
AllTrue(t, n.ContainsAll(0, 1, 63), !n.ContainsAll(9, 0, 1), !n.ContainsAll(0, 1, 63, 99))
|
// 4294967295
|
||||||
AllTrue(t, n.ContainsAny(0, 1, 63), n.ContainsAny(9, 99, 999, 1), !n.ContainsAny(9, 99, 999))
|
|
||||||
|
|
||||||
IsEq(t, nset.BucketCount-1, n.GetBucketIndex(math.MaxUint32))
|
AllTrue(t, n1.Contains(0), n1.Contains(1), n1.Contains(63), n1.Contains(math.MaxUint32), !n1.Contains(10), !n1.Contains(599))
|
||||||
IsEq(t, math.MaxUint32/64/nset.BucketCount, n.GetStorageUnitIndex(math.MaxUint32))
|
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))
|
||||||
|
|
||||||
nCopy := n.Copy()
|
IsEq(t, nset.BucketCount-1, n1.GetBucketIndex(math.MaxUint32))
|
||||||
n.Remove(1)
|
IsEq(t, math.MaxUint32/64/nset.BucketCount, n1.GetStorageUnitIndex(math.MaxUint32))
|
||||||
|
|
||||||
AllTrue(t, n.Contains(0), n.Contains(63), !n.Contains(1), nCopy.ContainsAll(0, 1, 63, 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) {
|
func TestNSetFullRange(t *testing.T) {
|
||||||
|
return
|
||||||
if fullRangeNSet == nil {
|
if fullRangeNSet == nil {
|
||||||
|
|
||||||
fullRangeNSet = nset.NewNSet[uint32]()
|
fullRangeNSet = nset.NewNSet[uint32]()
|
||||||
|
|||||||
Reference in New Issue
Block a user