static CatchSectionIndices @Nullable [] getCatchSectionIndices(CatchSectionWrapper @NotNull [] sections,
                                                                 boolean[] @NotNull [] canSwap,
                                                                 @NotNull BiPredicate<? super CatchSectionWrapper, ? super CatchSectionWrapper> equals) {
    final CatchSectionIndices[] indices = new CatchSectionIndices[sections.length];
    for (int index = 0; index < sections.length; index++) {
      indices[index] = new CatchSectionIndices(index);
    }

    boolean duplicateFound = false;
    for (int from = 0; from < sections.length - 1; from++) {
      if (indices[from].myHasDuplicate) continue;
      final CatchSectionWrapper section = sections[from];
      if (section == null) continue;

      for (int to = from + 1; to < sections.length; to++) {
        if (indices[to].myHasDuplicate) continue;
        final CatchSectionWrapper otherSection = sections[to];
        if (otherSection == null || !equals.test(section, otherSection)) continue;

        indices[from].addDuplicate(indices[to]);
        duplicateFound = true;
      }
    }
    if (!duplicateFound) return null;

    for (int index = 0; index < sections.length; index++) {
      indices[index].computeInsertionRange(canSwap);
    }

    for (CatchSectionIndices idx : indices) {
      final int[] duplicates = idx.myDuplicates;
      if (duplicates == null) continue;

      for (int from : duplicates) {
        for (int to : duplicates) {
          indices[to].tryCollapseInto(indices[from]);
        }
      }
    }
    return indices;
  }
static CatchSectionIndices @Nullable [] getCatchSectionIndices(CatchSectionWrapper @NotNull [] sections,
                                                                 boolean[] @NotNull [] canSwap,
                                                                 @NotNull BiPredicate<? super CatchSectionWrapper, ? super CatchSectionWrapper> equals)