blob: 6aa25599f6418f83d4ed8ed2d0c3364d8bb04ce0 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs;
import com.intellij.openapi.util.Pair;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import com.intellij.util.containers.ReadonlyList;
import com.intellij.util.containers.StepList;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
/**
* @author irengrig
*/
public class ReadonlyListsMerger<T> {
private final List<ReadonlyList<T>> myLists;
private final Consumer<CompoundNumber> myConsumer;
private final Comparator<Pair<CompoundNumber, T>> myComparator;
private ReadonlyListsMerger(final List<ReadonlyList<T>> lists, final Consumer<CompoundNumber> consumer, final Comparator<Pair<CompoundNumber, T>> comparator) {
myLists = lists;
myConsumer = consumer;
myComparator = comparator;
}
public static<T extends Comparable<T>> void merge(final List<ReadonlyList<T>> lists, final Consumer<CompoundNumber> consumer) {
new ReadonlyListsMerger<T>(lists, consumer, new MyComparator<T>()).execute();
}
public static<T> void merge(final List<ReadonlyList<T>> lists, final Consumer<CompoundNumber> consumer, final Comparator<Pair<CompoundNumber, T>> comparator) {
new ReadonlyListsMerger<T>(lists, consumer, comparator).execute();
}
public void execute() {
final int[] idxs = new int[myLists.size()];
for (int i = 0; i < myLists.size(); i++) {
final ReadonlyList<T> member = myLists.get(i);
idxs[i] = member.getSize() == 0 ? -1 : 0;
}
while (true) {
CompoundNumber minIdxs = null;
for (int i = 0; i < idxs.length; i++) {
if (idxs[i] == -1) continue; // at end
final ReadonlyList<T> list = myLists.get(i);
if ((minIdxs == null) || (myComparator.compare(Pair.create(new CompoundNumber(i, idxs[i]), list.get(idxs[i])),
Pair.create(minIdxs, myLists.get(minIdxs.getMemberNumber()).get(minIdxs.getIdx()))) <= 0)) {
minIdxs = new CompoundNumber(i, idxs[i]);
}
}
if (minIdxs == null) return;
myConsumer.consume(minIdxs);
final int memberIdx = minIdxs.getMemberNumber();
idxs[memberIdx] = (myLists.get(memberIdx).getSize() == (idxs[memberIdx] + 1) ? -1 : idxs[memberIdx] + 1);
}
}
public static<T> void firstPlusSecond(final StepList<T> first, final ReadonlyList<T> second, final Comparator<T> comparator,
@Nullable final Consumer<T> beforeAddListener, final Processor<T> filter) {
if (second.getSize() == 0) return;
int idx = stolenBinarySearch(first, second.get(0), comparator, 0);
if (idx < 0) {
idx = - (idx + 1);
}
// for group headers to not be left alone without its group
if (idx > 0 && (! filter.process(first.get(idx - 1)))) {
-- idx;
if (idx > 0) --idx;
}
final ReadonlyList<T> remergePart = first.cut(idx);
merge(remergePart, second, comparator, new Consumer<T>() {
@Override
public void consume(T t) {
if (beforeAddListener != null) {
beforeAddListener.consume(t);
}
first.add(t);
}
}, filter);
}
public static<T> void merge(final ReadonlyList<T> one,
final ReadonlyList<T> two,
final Comparator<T> comparator,
final Consumer<T> adder, final Processor<T> filter) {
int idx1 = 0;
int idx2 = 0;
while (idx1 < one.getSize() && idx2 < two.getSize()) {
final T firstOne = one.get(idx1);
if (! filter.process(firstOne)) {
++ idx1;
continue;
}
final int comp = comparator.compare(firstOne, two.get(idx2));
if (comp <= 0) {
adder.consume(firstOne);
++ idx1;
} else {
adder.consume(two.get(idx2));
++ idx2;
}
}
while (idx1 < one.getSize()) {
final T firstOne = one.get(idx1);
if (! filter.process(firstOne)) {
++ idx1;
continue;
}
adder.consume(one.get(idx1));
++ idx1;
}
while (idx2 < two.getSize()) {
adder.consume(two.get(idx2));
++ idx2;
}
}
/*private static<T> int insertIdx(final ReadonlyList<T> first, final int from, final T t, final Comparator<T> comparator) {
int idx = stolenBinarySearch(first, t, comparator, from);
if (idx < 0) {
idx = - (idx + 1);
}
first.
}*/
private static <T> int stolenBinarySearch(ReadonlyList<? extends T> l, T key, Comparator<? super T> c, final int from) {
int low = from;
int high = (l.getSize() - from) -1;
while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = l.get(mid);
int cmp = c.compare(midVal, key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
private static class MyComparator<T extends Comparable<T>> implements Comparator<Pair<CompoundNumber, T>> {
@Override
public int compare(final Pair<CompoundNumber, T> o1, final Pair<CompoundNumber, T> o2) {
return o1.getSecond().compareTo(o2.getSecond());
}
}
}