org.plumelib.util.CombinationIterator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plume-util Show documentation
Show all versions of plume-util Show documentation
Utility libraries for Java. Complements Guava, Apache Commons, etc.
package org.plumelib.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.checkerframework.checker.index.qual.LengthOf;
import org.checkerframework.checker.lock.qual.GuardSatisfied;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/**
* Given a set of collections, yield each combination that takes one element from each collection.
* Each tuple has a value from each candidate list. Each combination'slength is the same as the
* number of input lists.
*
* For instance, given {@code [["a1", "a2"], ["b1"], ["c1", "c2", "c3"]]}, this class yields in
* turn:
*
*
* ["a1", "b1", "c1"]
* ["a1", "b1", "c2"]
* ["a1", "b1", "c3"]
* ["a2", "b1", "c1"]
* ["a2", "b1", "c2"]
* ["a2", "b1", "c3"]
*
*
* @param the type of the elements of the collections
*/
public class CombinationIterator implements Iterator> {
/** Lists of candidate values for each position in generated lists. */
private final List[] listsOfCandidates;
/** Iterators for each list of candidate values. */
private final Iterator[] iterators;
/** The size of each returned result; the length of listsOfCandidates. */
private final @LengthOf({"listsOfCandidates", "iterators"}) int combinationSize;
/** The next value to return, or null if to more values. */
private @Nullable List nextValue;
/**
* Creates a {@link CombinationIterator} for lists constructed from the given candidates. Each
* generated list will be the same length as the given list.
*
* @param collectionsOfCandidates lists of candidate values for each position in generated lists
*/
@SuppressWarnings({"rawtypes", "unchecked"}) // for generic array creation
public CombinationIterator(Collection extends Collection> collectionsOfCandidates) {
int size = collectionsOfCandidates.size();
// Just like collectionsOfCandidates, but indexable.
@SuppressWarnings({"nullness:unneeded.suppression", "keyfor:argument"}) // temporary
ArrayList extends Collection> listOfCollectionsOfCanditates =
new ArrayList<>(collectionsOfCandidates);
listsOfCandidates = new ArrayList[size];
iterators = new Iterator[size];
combinationSize = size;
nextValue = (combinationSize == 0 ? null : new ArrayList<>(collectionsOfCandidates.size()));
for (int i = 0; i < combinationSize; i++) {
Collection userSuppliedCandidates = listOfCollectionsOfCanditates.get(i);
List candidates = new ArrayList<>(userSuppliedCandidates);
listsOfCandidates[i] = candidates;
Iterator it = candidates.iterator();
iterators[i] = it;
if (nextValue != null) {
if (it.hasNext()) {
nextValue.add(it.next());
} else {
nextValue = null;
}
}
}
}
@Override
@EnsuresNonNullIf(expression = "nextValue", result = true)
public boolean hasNext(@GuardSatisfied CombinationIterator this) {
return nextValue != null;
}
/** Advance {@code #nextValue} to the next value, or to null if there are no more values. */
@RequiresNonNull("nextValue")
private void advanceNext(@GuardSatisfied CombinationIterator this) {
List nnNextValue = nextValue;
for (int i = combinationSize - 1; i >= 0; i--) {
if (iterators[i].hasNext()) {
nnNextValue.set(i, iterators[i].next());
return;
} else {
iterators[i] = listsOfCandidates[i].iterator();
nnNextValue.set(i, iterators[i].next());
}
}
nextValue = null;
}
@Override
public List next(@GuardSatisfied CombinationIterator this) {
if (!hasNext()) {
throw new NoSuchElementException();
}
List result = new ArrayList(nextValue);
advanceNext();
return result;
}
@Override
public void remove(@GuardSatisfied CombinationIterator this) {
throw new UnsupportedOperationException(
"Remove not implemented for randoop.reflection.SubstitutionEnumerator");
}
}