lib/uint64set: optimize Set.AddMulti for large sorted sets

This commit is contained in:
Aliaksandr Valialkin 2021-03-15 17:10:40 +02:00
parent 43504ebd14
commit eb103e1527

View file

@ -141,36 +141,32 @@ func (s *Set) AddMulti(a []uint64) {
if len(a) == 0 { if len(a) == 0 {
return return
} }
slowPath := false hiPrev := uint32(a[0] >> 32)
hi := uint32(a[0] >> 32) i := 0
for _, x := range a[1:] { for j, x := range a {
if hi != uint32(x>>32) { hi := uint32(x >> 32)
slowPath = true if hi == hiPrev {
break continue
} }
b32 := s.getOrCreateBucket32(hiPrev)
s.itemsCount += b32.addMulti(a[i:j])
hiPrev = hi
i = j
} }
if slowPath { b32 := s.getOrCreateBucket32(hiPrev)
for _, x := range a { s.itemsCount += b32.addMulti(a[i:])
s.Add(x) }
}
return func (s *Set) getOrCreateBucket32(hi uint32) *bucket32 {
}
// Fast path - all the items in a have identical higher 32 bits.
// Put them in a bulk into the corresponding bucket32.
bs := s.buckets bs := s.buckets
var b32 *bucket32
for i := range bs { for i := range bs {
if bs[i].hi == hi { if bs[i].hi == hi {
b32 = &bs[i] return &bs[i]
break
} }
} }
if b32 == nil { b32 := s.addBucket32()
b32 = s.addBucket32() b32.hi = hi
b32.hi = hi return b32
}
n := b32.addMulti(a)
s.itemsCount += n
} }
func (s *Set) addBucket32() *bucket32 { func (s *Set) addBucket32() *bucket32 {
@ -609,41 +605,32 @@ func (b *bucket32) addMulti(a []uint64) int {
if len(a) == 0 { if len(a) == 0 {
return 0 return 0
} }
hi := uint16(a[0] >> 16) count := 0
slowPath := false hiPrev := uint16(a[0] >> 16)
for _, x := range a[1:] { i := 0
if hi != uint16(x>>16) { for j, x := range a {
slowPath = true hi := uint16(x >> 16)
break if hi == hiPrev {
continue
} }
b16 := b.getOrCreateBucket16(hiPrev)
count += b16.addMulti(a[i:j])
hiPrev = hi
i = j
} }
if slowPath { b16 := b.getOrCreateBucket16(hiPrev)
count := 0 count += b16.addMulti(a[i:])
for _, x := range a { return count
if b.add(uint32(x)) { }
count++
} func (b *bucket32) getOrCreateBucket16(hi uint16) *bucket16 {
}
return count
}
// Fast path - all the items in a have identical higher 32+16 bits.
// Put them to a single bucket16 in a bulk.
var b16 *bucket16
his := b.b16his his := b.b16his
bs := b.buckets bs := b.buckets
if n := b.getHint(); n < uint32(len(his)) && his[n] == hi { n := binarySearch16(his, hi)
b16 = &bs[n] if n < 0 || n >= len(his) || his[n] != hi {
return b.addBucketAtPos(hi, n)
} }
if b16 == nil { return &bs[n]
n := binarySearch16(his, hi)
if n < 0 || n >= len(his) || his[n] != hi {
b16 = b.addBucketAtPos(hi, n)
} else {
b.setHint(n)
b16 = &bs[n]
}
}
return b16.addMulti(a)
} }
func (b *bucket32) addSlow(hi, lo uint16) bool { func (b *bucket32) addSlow(hi, lo uint16) bool {