static void mergeLongsImpl()

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();
  }