blob: 9f00673cd1cf417d4f0cf08ef05016199ee5ae07 [file] [log] [blame]
package annotations.util.coll;
import java.util.*;
/*>>>
import org.checkerframework.checker.nullness.qual.*;
*/
/**
* A simple implementation of {@link KeyedSet} backed by an insertion-order
* {@link java.util.LinkedHashMap} and its
* {@link java.util.LinkedHashMap#values() value collection}.
*/
public class LinkedHashKeyedSet<K, V> extends AbstractSet<V> implements KeyedSet<K, V> {
private final Keyer<? extends K, ? super V> keyer;
private final Map<K, V> theMap = new LinkedHashMap<K, V>();
final Collection<V> theValues = theMap.values();
/**
* Constructs a {@link LinkedHashKeyedSet} that uses the given
* {@link Keyer} to obtain keys for elements.
*/
public LinkedHashKeyedSet(Keyer<? extends K, ? super V> keyer) {
this.keyer = keyer;
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
return theValues.size();
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(Object o) {
return theValues.contains(o);
}
private class KeyedSetIterator implements Iterator<V> {
private final Iterator<V> itr = theValues.iterator();
@Override
public boolean hasNext() {
return itr.hasNext();
}
@Override
public V next() {
return itr.next();
}
@Override
public void remove() {
itr.remove();
}
KeyedSetIterator() {
}
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<V> iterator() {
return new KeyedSetIterator();
}
/**
* {@inheritDoc}
*/
@Override
public Object[] toArray() {
return theValues.toArray();
}
/**
* {@inheritDoc}
*/
@Override
public <T> T[] toArray(T[] a) {
return theValues.toArray(a);
}
private boolean checkAdd(int behavior, V old) {
switch (behavior) {
case REPLACE:
remove(old);
return true;
case IGNORE:
return false;
case THROW_EXCEPTION:
throw new IllegalStateException();
default:
throw new IllegalArgumentException();
}
}
private static boolean eq(Object x, Object y) {
return x == y || (x != null && x.equals(y));
}
/**
* {@inheritDoc}
*/
@Override
public V add(V o, int conflictBehavior, int equalBehavior) {
K key = keyer.getKeyFor(o);
V old = theMap.get(key);
if (old == null
|| (eq(o, old) ? checkAdd(equalBehavior, old) : checkAdd(
conflictBehavior, old)))
theMap.put(key, o);
return old;
}
/**
* {@inheritDoc}
*/
@Override
public boolean add(V o) {
return add(o, THROW_EXCEPTION, IGNORE) == null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean remove(Object o) {
return theValues.remove(o);
}
/**
* {@inheritDoc}
*/
@Override
public boolean addAll(Collection<? extends V> c) {
boolean changed = false;
for (V o : c) {
changed |= add(o);
}
return changed;
}
/**
* {@inheritDoc}
*/
@Override
public void clear() {
theValues.clear();
}
/**
* {@inheritDoc}
*/
@Override
public Keyer<? extends K, ? super V> getKeyer() {
return keyer;
}
/**
* {@inheritDoc}
*/
@Override
public V replace(V v) {
return theMap.put(keyer.getKeyFor(v), v);
}
/**
* {@inheritDoc}
*/
@Override
public V lookup(K k) {
return theMap.get(k);
}
// Use inherited equals and hashCode algorithms because
// those of HashMap.Values are broken!
}