in src/main/java/org/apache/datasketches/kll/KllLongsHelper.java [123:241]
static void mergeLongsImpl(final KllLongsSketch mySketch, final KllLongsSketch otherLngSk) {
if (otherLngSk.isEmpty()) { return; }
//capture my key mutable fields before doing any merging
final boolean myEmpty = mySketch.isEmpty();
final long myMin = mySketch.getMinItemInternal();
final long myMax = mySketch.getMaxItemInternal();
final int myMinK = mySketch.getMinK();
final long finalN = Math.addExact(mySketch.getN(), otherLngSk.getN());
//buffers that are referenced multiple times
final int otherNumLevels = otherLngSk.getNumLevels();
final int[] otherLevelsArr = otherLngSk.levelsArr;
final long[] otherLongItemsArray;
//MERGE: update this sketch with level0 items from the other sketch
if (otherLngSk.isCompactSingleItem()) {
KllLongsSketch.updateLong(mySketch, otherLngSk.getLongSingleItem());
otherLongItemsArray = new long[0];
} else {
otherLongItemsArray = otherLngSk.getLongItemsArray();
for (int i = otherLevelsArr[0]; i < otherLevelsArr[1]; i++) {
KllLongsSketch.updateLong(mySketch, otherLongItemsArray[i]);
}
}
//After the level 0 update, we capture the intermediate state of my levels and items arrays...
final int myCurNumLevels = mySketch.getNumLevels();
final int[] myCurLevelsArr = mySketch.levelsArr;
final long[] myCurLongItemsArray = mySketch.getLongItemsArray();
// create aliases in case there are no higher levels
int myNewNumLevels = myCurNumLevels;
int[] myNewLevelsArr = myCurLevelsArr;
long[] myNewLongItemsArray = myCurLongItemsArray;
//merge higher levels if they exist
if (otherNumLevels > 1 && !otherLngSk.isCompactSingleItem()) {
final int tmpSpaceNeeded = mySketch.getNumRetained()
+ KllHelper.getNumRetainedAboveLevelZero(otherNumLevels, otherLevelsArr);
final long[] workbuf = new long[tmpSpaceNeeded];
final int provisionalNumLevels = max(myCurNumLevels, otherNumLevels);
final int ub = max(KllHelper.ubOnNumLevels(finalN), provisionalNumLevels);
final int[] worklevels = new int[ub + 2]; // ub+1 does not work
final int[] outlevels = new int[ub + 2];
populateLongWorkArrays(workbuf, worklevels, provisionalNumLevels,
myCurNumLevels, myCurLevelsArr, myCurLongItemsArray,
otherNumLevels, otherLevelsArr, otherLongItemsArray);
// notice that workbuf is being used as both the input and output
final int[] result = generalLongsCompress(mySketch.getK(), mySketch.getM(), provisionalNumLevels,
workbuf, worklevels, workbuf, outlevels, mySketch.isLevelZeroSorted(), KllSketch.random);
final int targetItemCount = result[1]; //was finalCapacity. Max size given k, m, numLevels
final int curItemCount = result[2]; //was finalPop
// now we need to finalize the results for mySketch
//THE NEW NUM LEVELS
myNewNumLevels = result[0];
assert myNewNumLevels <= ub; // ub may be much bigger
// THE NEW ITEMS ARRAY
myNewLongItemsArray = (targetItemCount == myCurLongItemsArray.length)
? myCurLongItemsArray
: new long[targetItemCount];
final int freeSpaceAtBottom = targetItemCount - curItemCount;
//shift the new items array create space at bottom
System.arraycopy(workbuf, outlevels[0], myNewLongItemsArray, freeSpaceAtBottom, curItemCount);
final int theShift = freeSpaceAtBottom - outlevels[0];
//calculate the new levels array length
final int finalLevelsArrLen;
if (myCurLevelsArr.length < myNewNumLevels + 1) { finalLevelsArrLen = myNewNumLevels + 1; }
else { finalLevelsArrLen = myCurLevelsArr.length; }
//THE NEW LEVELS ARRAY
myNewLevelsArr = new int[finalLevelsArrLen];
for (int lvl = 0; lvl < myNewNumLevels + 1; lvl++) { // includes the "extra" index
myNewLevelsArr[lvl] = outlevels[lvl] + theShift;
}
//MEMORY SPACE MANAGEMENT
if (mySketch.getWritableMemory() != null) {
final WritableMemory oldWmem = mySketch.getWritableMemory();
final WritableMemory wmem = KllHelper.memorySpaceMgmt(mySketch, myNewLevelsArr.length, myNewLongItemsArray.length);
if (!wmem.isSameResource(oldWmem)) {
mySketch.getMemoryRequestServer().requestClose(oldWmem);
}
mySketch.setWritableMemory(wmem);
}
} //end of updating levels above level 0
//Update Preamble:
mySketch.setN(finalN);
if (otherLngSk.isEstimationMode()) { //otherwise the merge brings over exact items.
mySketch.setMinK(min(myMinK, otherLngSk.getMinK()));
}
//Update numLevels, levelsArray, items
mySketch.setNumLevels(myNewNumLevels);
mySketch.setLevelsArray(myNewLevelsArr);
mySketch.setLongItemsArray(myNewLongItemsArray);
//Update min, max items
final long otherMin = otherLngSk.getMinItemInternal();
final long otherMax = otherLngSk.getMaxItemInternal();
if (myEmpty) {
mySketch.setMinItem(otherMin);
mySketch.setMaxItem(otherMax);
} else {
mySketch.setMinItem(min(myMin, otherMin));
mySketch.setMaxItem(max(myMax, otherMax));
}
assert KllHelper.sumTheSampleWeights(mySketch.getNumLevels(), mySketch.levelsArr) == mySketch.getN();
}