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(); } }