org.plumelib.util.AbstractMostlySingletonSet Maven / Gradle / Ivy
Show all versions of plume-util Show documentation
package org.plumelib.util;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.lock.qual.GuardSatisfied;
import org.checkerframework.checker.nullness.qual.KeyForBottom;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.PolyNull;
import org.checkerframework.checker.signedness.qual.PolySigned;
import org.checkerframework.checker.signedness.qual.Signed;
import org.checkerframework.checker.signedness.qual.UnknownSignedness;
import org.checkerframework.dataflow.qual.SideEffectFree;
/**
* Base class for arbitrary-size sets that is very efficient (more efficient than HashSet) for 0 and
* 1 elements.
*
* Does not support storing {@code null}.
*
*
This class exists because it has multiple subclasses (currently {@link MostlySingletonSet} and
* {@link IdentityMostlySingletonSet}).
*
* @param the type of elements of the set
*/
public abstract class AbstractMostlySingletonSet implements Set {
/** The possible states of this set. */
public enum State {
/** An empty set. */
EMPTY,
/** A singleton set. */
SINGLETON,
/** A set of arbitrary size. */
ANY
}
/** The current state. */
protected State state;
/** The current value, non-null when the state is SINGLETON. */
protected @Nullable T value;
/** The wrapped set, non-null when the state is ANY. */
protected @Nullable Set set;
/**
* Create an AbstractMostlySingletonSet.
*
* @param s the state
*/
protected AbstractMostlySingletonSet(State s) {
this.state = s;
this.value = null;
}
/**
* Create an AbstractMostlySingletonSet.
*
* @param s the state
* @param v the value
*/
protected AbstractMostlySingletonSet(State s, T v) {
this.state = s;
this.value = v;
}
/** Throw an exception if the internal representation is corrupted. */
protected void checkRep() {
if ((state == State.EMPTY && (value != null || set != null))
|| (state == State.SINGLETON && (value == null || set != null))
|| (state == State.ANY && (value != null || set == null))) {
throw new IllegalStateException(
String.format("Bad set: state=%s, value=%s, set=%s", state, value, set));
}
}
@Override
public @NonNegative int size(@GuardSatisfied AbstractMostlySingletonSet this) {
switch (state) {
case EMPTY:
return 0;
case SINGLETON:
return 1;
case ANY:
assert set != null : "@AssumeAssertion(nullness): set initialized before";
return set.size();
default:
throw new IllegalStateException("Unhandled state " + state);
}
}
@Override
public boolean isEmpty(@GuardSatisfied AbstractMostlySingletonSet this) {
return size() == 0;
}
@Override
@SuppressWarnings({
"allcheckers:purity.not.sideeffectfree",
"lock:override.receiver" // cannot specify the anonymous receiver type
})
@SideEffectFree
public Iterator iterator() {
switch (state) {
case EMPTY:
return Collections.emptyIterator();
case SINGLETON:
return new Iterator() {
/** True if the iterator has a next element. */
private boolean hasNext = true;
@Override
public boolean hasNext(/*@GuardedBy Iterator this*/ ) {
return hasNext;
}
@Override
public T next(/*@GuardedBy Iterator this*/ ) {
if (hasNext) {
hasNext = false;
assert value != null : "@AssumeAssertion(nullness): previous add is non-null";
return value;
}
throw new NoSuchElementException();
}
@Override
public void remove(/*@GuardedBy Iterator this*/ ) {
state = State.EMPTY;
value = null;
}
};
case ANY:
assert set != null : "@AssumeAssertion(nullness): set initialized before";
return set.iterator();
default:
throw new IllegalStateException("Unhandled state " + state);
}
}
@Override
public String toString(@GuardSatisfied AbstractMostlySingletonSet this) {
switch (state) {
case EMPTY:
return "[]";
case SINGLETON:
return "[" + value + "]";
case ANY:
assert set != null : "@AssumeAssertion(nullness): set initialized before";
return set.toString();
default:
throw new IllegalStateException("Unhandled state " + state);
}
}
@Override
public boolean addAll(
@GuardSatisfied AbstractMostlySingletonSet this, Collection extends T> c) {
boolean res = false;
for (T elem : c) {
res |= add(elem);
}
return res;
}
@Override
public @PolySigned Object[] toArray() {
throw new UnsupportedOperationException();
}
@SuppressWarnings({"nullness:unneeded.suppression", "keyfor:override.return"}) // temporary
@Override
public <@KeyForBottom S> @Nullable S[] toArray(@PolyNull S[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(
@GuardSatisfied AbstractMostlySingletonSet this, @Nullable @UnknownSignedness Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(
@GuardSatisfied AbstractMostlySingletonSet this, @GuardSatisfied Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(@GuardSatisfied AbstractMostlySingletonSet this, Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(@GuardSatisfied AbstractMostlySingletonSet this, Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear(@GuardSatisfied AbstractMostlySingletonSet this) {
throw new UnsupportedOperationException();
}
}