package org.infinispan.util;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Function;
import org.infinispan.commons.util.CloseableIterator;
public class DistinctKeyDoubleEntryCloseableIterator<E, K> implements CloseableIterator<E> {
private final CloseableIterator<E> iterator1;
private final CloseableIterator<E> iterator2;
private final Function<? super E, K> function;
private final Set<K> keysSeenInFirst;
private boolean completedFirst = false;
private E iterator2Next;
public DistinctKeyDoubleEntryCloseableIterator(CloseableIterator<E> first,
CloseableIterator<E> second,
Function<? super E, K> function,
Set<K> seenKeys) {
this.iterator1 = first;
this.iterator2 = second;
this.function = function;
this.keysSeenInFirst = seenKeys;
}
@Override
public void close() {
try {
iterator1.close();
} catch (Throwable t1) {
try {
iterator2.close();
} catch (Throwable t2) {
t1.addSuppressed(t2);
}
throw t1;
}
iterator2.close();
}
@Override
public boolean hasNext() {
boolean hasNext;
if (!completedFirst) {
hasNext = iterator1.hasNext();
if (hasNext) {
return hasNext;
} else {
completedFirst = true;
}
}
while (iterator2.hasNext()) {
E e = iterator2.next();
if (!keysSeenInFirst.remove(function.apply(e))) {
iterator2Next = e;
break;
}
}
return iterator2Next != null;
}
@Override
public E next() {
E next;
if (!completedFirst) {
// We have to double check hasNext in case if they are calling next without hasNext
if (iterator1.hasNext()) {
next = iterator1.next();
keysSeenInFirst.add(function.apply(next));
return next;
} else {
completedFirst = true;
}
}
E e;
if (iterator2Next != null) {
e = iterator2Next;
iterator2Next = null;
return e;
}
while(iterator2.hasNext()) {
e = iterator2.next();
if (!keysSeenInFirst.remove(function.apply(e))) {
return e;
}
}
throw new NoSuchElementException();
}
}