docs: private static <T> void blockyTandemMergeSortRecursion(final T[] keySrc, final long[] valSrc,
        final T[] keyDst, final long[] valDst, final int grpStart, final int grpLen, // block indices
        final int blkSize, final int arrLim, final Comparator<? super T> comparator) {
      // Important note: grpStart and grpLen do NOT refer to positions in the underlying array.
      // Instead, they refer to the pre-sorted blocks, such as block 0, block 1, etc.
  
      assert (grpLen > 0);
      if (grpLen == 1) { return; }
      final int grpLen1 = grpLen / 2;
      final int grpLen2 = grpLen - grpLen1;
      assert (grpLen1 >= 1);
      assert (grpLen2 >= grpLen1);
  
      final int grpStart1 = grpStart;
      final int grpStart2 = grpStart + grpLen1;
  
      //swap roles of src and dst
      blockyTandemMergeSortRecursion(keyDst, valDst,
                             keySrc, valSrc,
                             grpStart1, grpLen1, blkSize, arrLim, comparator);
  
      //swap roles of src and dst
      blockyTandemMergeSortRecursion(keyDst, valDst,
                             keySrc, valSrc,
                             grpStart2, grpLen2, blkSize, arrLim, comparator);
  
      // here we convert indices of blocks into positions in the underlying array.
      final int arrStart1 = grpStart1 * blkSize;
      final int arrStart2 = grpStart2 * blkSize;
      final int arrLen1   = grpLen1   * blkSize;
      int arrLen2   = grpLen2   * blkSize;
  
      // special case for the final block which might be shorter than blkSize.
      if ((arrStart2 + arrLen2) > arrLim) {
        arrLen2 = arrLim - arrStart2;
      }
  
      tandemMerge(keySrc, valSrc,
                  arrStart1, arrLen1,
                  arrStart2, arrLen2,
                  keyDst, valDst,
                  arrStart1, comparator); // which will be arrStart3
    }