func()

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
}