in cpc/cpc_union.go [143:230]
func (u *CpcUnion) GetResult() (*CpcSketch, error) {
if err := u.checkUnionState(); err != nil {
return nil, err
}
if u.accumulator != nil {
if u.accumulator.numCoupons == 0 {
result, err := NewCpcSketch(u.lgK, u.accumulator.seed)
if err != nil {
return nil, err
}
result.mergeFlag = true
return result, nil
}
if u.accumulator.getFlavor() != CpcFlavorSparse {
return nil, fmt.Errorf("accumulator must be SPARSE")
}
// Return a copy of the accumulator.
result, err := u.accumulator.Copy()
if err != nil {
return nil, err
}
result.mergeFlag = true
return result, nil
}
// Case: union contains a bitMatrix.
matrix := u.bitMatrix
lgK := u.lgK
result, err := NewCpcSketch(u.lgK, u.seed)
if err != nil {
return nil, err
}
numCoupons := countBitsSetInMatrix(matrix)
result.numCoupons = numCoupons
flavor := determineFlavor(lgK, numCoupons)
if flavor <= CpcFlavorSparse {
return nil, fmt.Errorf("flavor must be greater than SPARSE")
}
offset := determineCorrectOffset(lgK, numCoupons)
result.windowOffset = offset
k := 1 << lgK
window := make([]byte, k)
result.slidingWindow = window
newTableLgSize := max(lgK-4, 2)
table, err := NewPairTable(newTableLgSize, 6+lgK)
if err != nil {
return nil, err
}
result.pairTable = table
maskForClearingWindow := (0xFF << offset) ^ -1
maskForFlippingEarlyZone := (1 << offset) - 1
allSurprisesORed := uint64(0)
for i := 0; i < k; i++ {
pattern := matrix[i]
window[i] = byte((pattern >> offset) & 0xFF)
pattern &= uint64(maskForClearingWindow)
pattern ^= uint64(maskForFlippingEarlyZone)
allSurprisesORed |= pattern
for pattern != 0 {
col := bits.TrailingZeros64(pattern)
pattern ^= 1 << col
rowCol := (i << 6) | col
isNovel, err := table.maybeInsert(rowCol)
if err != nil {
return nil, err
}
if !isNovel {
return nil, fmt.Errorf("isNovel must be true")
}
}
}
result.fiCol = bits.TrailingZeros64(allSurprisesORed)
if result.fiCol > offset {
result.fiCol = offset
}
result.mergeFlag = true
return result, nil
}