in kll/items_sketch.go [707:833]
func (s *ItemsSketch[C]) mergeItemsSketch(other *ItemsSketch[C]) {
if other.IsEmpty() {
return
}
// capture my key mutable fields before doing any merging
myEmpty := s.IsEmpty()
var myMin, myMax C
var err error
if !myEmpty {
myMin, err = s.GetMinItem()
if err != nil {
panic(err)
}
myMax, err = s.GetMaxItem()
if err != nil {
panic(err)
}
}
myMinK := s.minK
finalN := s.n + other.n
// buffers that are referenced multiple times
otherNumLevels := other.numLevels
otherLevelsArr := other.levels
var otherItemsArr []C
// MERGE: update this sketch with level0 items from the other sketch
otherItemsArr = other.GetTotalItemsArray()
for i := otherLevelsArr[0]; i < otherLevelsArr[1]; i++ {
s.updateItem(otherItemsArr[i], s.compareFn)
}
// After the level 0 update, we capture the intermediate state of levels and items arrays...
myCurNumLevels := s.numLevels
myCurLevelsArr := s.levels
myCurItemsArr := s.GetTotalItemsArray()
// then rename them and initialize in case there are no higher levels
myNewNumLevels := myCurNumLevels
myNewLevelsArr := myCurLevelsArr
myNewItemsArr := myCurItemsArr
//merge higher levels if they exist
if otherNumLevels > 1 {
tmpSpaceNeeded := s.GetNumRetained() + getNumRetainedAboveLevelZero(otherNumLevels, otherLevelsArr)
workbuf := make([]C, tmpSpaceNeeded)
ub := ubOnNumLevels(finalN)
worklevels := make([]uint32, ub+2) // ub+1 does not work
outlevels := make([]uint32, ub+2)
provisionalNumLevels := max(myCurNumLevels, otherNumLevels)
populateItemWorkArrays(workbuf, worklevels, provisionalNumLevels,
myCurNumLevels, myCurLevelsArr, myCurItemsArr,
otherNumLevels, otherLevelsArr, otherItemsArr, s.compareFn)
// notice that workbuf is being used as both the input and output
result := generalItemsCompress(s.k, s.m, provisionalNumLevels, workbuf, worklevels, workbuf, outlevels, s.isLevelZeroSorted, s.compareFn, s.deterministicOffsetForTest)
targetItemCount := result[1] //was finalCapacity. Max size given k, m, numLevels
curItemCount := result[2] //was finalPop
// now we need to finalize the results for mySketch
//THE NEW NUM LEVELS
myNewNumLevels = uint8(result[0])
// THE NEW ITEMS ARRAY
if int(targetItemCount) == len(myCurItemsArr) {
myNewItemsArr = myCurItemsArr
} else {
myNewItemsArr = make([]C, targetItemCount)
}
freeSpaceAtBottom := targetItemCount - curItemCount
//shift the new items array create space at bottom
for i := uint32(0); i < uint32(curItemCount); i++ {
myNewItemsArr[uint32(freeSpaceAtBottom)+i] = workbuf[outlevels[0]+i]
}
theShift := uint32(freeSpaceAtBottom) - outlevels[0]
//calculate the new levels array length
var finalLevelsArrLen uint32
if uint32(len(myCurLevelsArr)) < uint32(myNewNumLevels+1) {
finalLevelsArrLen = uint32(myNewNumLevels + 1)
} else {
finalLevelsArrLen = uint32(len(myCurLevelsArr))
}
//THE NEW LEVELS ARRAY
myNewLevelsArr = make([]uint32, finalLevelsArrLen)
for lvl := uint8(0); lvl < myNewNumLevels+1; lvl++ { // includes the "extra" index
myNewLevelsArr[lvl] = outlevels[lvl] + theShift
}
//MEMORY SPACE MANAGEMENT
//not used
}
// Update Preamble:
s.n = finalN
if other.IsEstimationMode() { //otherwise the merge brings over exact items.
s.minK = min(myMinK, other.minK)
}
// Update numLevels, levelsArray, items
s.numLevels = myNewNumLevels
s.levels = myNewLevelsArr
s.items = myNewItemsArr
// Update min, max items
if myEmpty {
s.minItem = other.minItem
s.maxItem = other.maxItem
} else {
if s.compareFn(myMin, *other.minItem) {
s.minItem = &myMin
} else {
s.minItem = other.minItem
}
if s.compareFn(*other.maxItem, myMax) {
s.maxItem = &myMax
} else {
s.maxItem = other.maxItem
}
}
}