docs: static int[] generalCompress(final int k, final int m, final int numLevelsIn, final float[] inBuf,
        final int[] inLevels, final float[] outBuf, final int[] outLevels, final boolean isLevelZeroSorted) {
      assert numLevelsIn > 0; // things are too weird if zero levels are allowed
      int numLevels = numLevelsIn;
      int currentItemCount = inLevels[numLevels] - inLevels[0]; // decreases with each compaction
      int targetItemCount = computeTotalCapacity(k, m, numLevels); // increases if we add levels
      boolean doneYet = false;
      outLevels[0] = 0;
      int curLevel = -1;
      while (!doneYet) {
        curLevel++; // start out at level 0
  
        // If we are at the current top level, add an empty level above it for convenience,
        // but do not increment numLevels until later
        if (curLevel == (numLevels - 1)) {
          inLevels[curLevel + 2] = inLevels[curLevel + 1];
        }
  
        final int rawBeg = inLevels[curLevel];
        final int rawLim = inLevels[curLevel + 1];
        final int rawPop = rawLim - rawBeg;
  
        if ((currentItemCount < targetItemCount) || (rawPop < levelCapacity(k, numLevels, curLevel, m))) {
          // copy level over as is
          // because inBuf and outBuf could be the same, make sure we are not moving data upwards!
          assert (rawBeg >= outLevels[curLevel]);
          System.arraycopy(inBuf, rawBeg, outBuf, outLevels[curLevel], rawPop);
          outLevels[curLevel + 1] = outLevels[curLevel] + rawPop;
        }
        else {
          // The sketch is too full AND this level is too full, so we compact it
          // Note: this can add a level and thus change the sketches capacities
  
          final int popAbove = inLevels[curLevel + 2] - rawLim;
          final boolean oddPop = isOdd(rawPop);
          final int adjBeg = oddPop ? 1 + rawBeg : rawBeg;
          final int adjPop = oddPop ? rawPop - 1 : rawPop;
          final int halfAdjPop = adjPop / 2;
  
          if (oddPop) { // copy one guy over
            outBuf[outLevels[curLevel]] = inBuf[rawBeg];
            outLevels[curLevel + 1] = outLevels[curLevel] + 1;
          } else { // copy zero guys over
            outLevels[curLevel + 1] = outLevels[curLevel];
          }
  
          // level zero might not be sorted, so we must sort it if we wish to compact it
          if ((curLevel == 0) && !isLevelZeroSorted) {
            Arrays.sort(inBuf, adjBeg, adjBeg + adjPop);
          }
  
          if (popAbove == 0) { // Level above is empty, so halve up
            randomlyHalveUp(inBuf, adjBeg, adjPop);
          } else { // Level above is nonempty, so halve down, then merge up
            randomlyHalveDown(inBuf, adjBeg, adjPop);
            mergeSortedArrays(inBuf, adjBeg, halfAdjPop, inBuf, rawLim, popAbove, inBuf, adjBeg + halfAdjPop);
          }
  
          // track the fact that we just eliminated some data
          currentItemCount -= halfAdjPop;
  
          // Adjust the boundaries of the level above
          inLevels[curLevel + 1] = inLevels[curLevel + 1] - halfAdjPop;
  
          // Increment numLevels if we just compacted the old top level
          // This creates some more capacity (the size of the new bottom level)
          if (curLevel == (numLevels - 1)) {
            numLevels++;
            targetItemCount += levelCapacity(k, numLevels, 0, m);
          }
  
        } // end of code for compacting a level
  
        // determine whether we have processed all levels yet (including any new levels that we created)
  
        if (curLevel == (numLevels - 1)) { doneYet = true; }
  
      } // end of loop over levels
  
      assert (outLevels[numLevels] - outLevels[0]) == currentItemCount;
  
      return new int[] {numLevels, targetItemCount, currentItemCount};
    }