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! }