public static <T> void processSortedListsInOrder(@NotNull List<? extends T> list1,
                                                   @NotNull List<? extends T> list2,
                                                   @NotNull Comparator<? super T> comparator,
                                                   boolean mergeEqualItems,
                                                   // (`element in the result`, `is the element from the list1`)
                                                   @NotNull PairConsumer<? super T, ? super MergeResult> processor) {
    int index1 = 0;
    int index2 = 0;
    while (index1 < list1.size() || index2 < list2.size()) {
      T e;
      if (index1 >= list1.size()) {
        e = list2.get(index2++);
        processor.consume(e, MergeResult.COPIED_FROM_LIST2);
      }
      else if (index2 >= list2.size()) {
        e = list1.get(index1++);
        processor.consume(e, MergeResult.COPIED_FROM_LIST1);
      }
      else {
        T element1 = list1.get(index1);
        T element2 = list2.get(index2);
        int c = comparator.compare(element1, element2);
        if (c == 0) {
          index1++;
          index2++;
          if (mergeEqualItems) {
            e = element1;
            processor.consume(e, MergeResult.MERGED_EQUAL_FROM_BOTH);
          }
          else {
            processor.consume(element1, MergeResult.COPIED_FROM_LIST1);
            e = element2;
            processor.consume(e, MergeResult.COPIED_FROM_LIST2);
          }
        }
        else if (c < 0) {
          e = element1;
          index1++;
          processor.consume(e, MergeResult.COPIED_FROM_LIST1);
        }
        else {
          e = element2;
          index2++;
          processor.consume(e, MergeResult.COPIED_FROM_LIST2);
        }
      }
    }
  }
public static <T> void processSortedListsInOrder(@NotNull List<? extends T> list1,
                                                   @NotNull List<? extends T> list2,
                                                   @NotNull Comparator<? super T> comparator,
                                                   boolean mergeEqualItems,
                                                   // (`element in the result`, `is the element from the list1`)
                                                   @NotNull PairConsumer<? super T, ? super MergeResult> processor)