package x10.util; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; public final class SmallSet<K> extends AbstractSet<K> { // elems[0] .. elems[curIndex-1] contains distinct elements, and there might be additional elements in overflow private K[] elems; // we must support null entries private int curIndex; private LinkedHashSet<K> overflow = null; public SmallSet() { this(CollectionFactory.DEFAULT_SIZE); } public SmallSet(int size) { elems = (K[])new Object[size]; } public SmallSet(Collection<K> c) { this(c.size()); addAll(c); } @Override public boolean add(K k) { // X10TypeEnv_c.bounds adds a null entry: if (k==null) throw new RuntimeException("SmallSet doesn't support null entries"); if (contains(k)) return false; if (curIndex<elems.length) { elems[curIndex++] = k; } else { if (overflow==null) overflow = new LinkedHashSet<K>(); overflow.add(k); } return true; } private void removeIndex(int i) { for (int j=i; j<curIndex-1; j++) elems[j] = elems[j+1]; elems[--curIndex] = null; // for garbage collection } @Override public boolean remove(Object o) { for (int i=0; i<curIndex; i++) if (CollectionFactory.equals(elems[i],o)) { removeIndex(i); return true; } return overflow==null ? false : overflow.remove(o); } // no need to override since the implementation in AbstractSet is efficient. @Override public String toString() { return super.toString(); // uses an iterator, and we do not care about efficiency of toString() anyway } @Override public boolean equals(Object o) { return super.equals(o); // uses containsAll } @Override public boolean containsAll(Collection<?> c) { if (c instanceof SmallSet) { SmallSet<K> s = (SmallSet) c; for (int i=0; i<s.curIndex; i++) if (!contains(s.elems[i])) return false; if (s.overflow!=null) for (K o : s.overflow) if (!contains(o)) return false; return true; } return super.containsAll(c); // uses c.iterator() and contains } @Override public boolean addAll(Collection<? extends K> c) { if (c instanceof SmallSet) { boolean modified = false; SmallSet<K> s = (SmallSet) c; for (int i=0; i<s.curIndex; i++) if (add(s.elems[i])) modified = true; if (s.overflow!=null) for (K o : s.overflow) if (add(o)) modified = true; return modified; } return super.addAll(c); // uses c.iterator() and add } @Override public boolean removeAll(Collection<?> c) { return super.removeAll(c); // iterates over the smaller collection } @Override public boolean isEmpty() { return super.isEmpty(); // uses size } @Override public Object[] toArray() { if (overflow==null) { return CollectionFactory.copyOf(elems,curIndex); } return super.toArray(); // uses an iterator } @Override public <T> T[] toArray(T[] a) { if (overflow==null) { if (a.length>=curIndex) { System.arraycopy(elems,0,a,0,curIndex); return a; } return (T[])CollectionFactory.copyOf(elems,curIndex,a.getClass()); } return super.toArray(a); } @Override public boolean retainAll(Collection<?> c) { boolean modified = false; for (int i=0; i<curIndex; i++) if (!c.contains(elems[i])) { modified = true; removeIndex(i); i--; } if (overflow!=null) modified |=overflow.retainAll(c); return modified; } @Override public int hashCode() { int h = 0; for (int i=0; i<curIndex; i++) h += CollectionFactory.hashCode(elems[i]); if (overflow!=null) h+=overflow.hashCode(); return h; } @Override public boolean contains(Object o) { for (int i=0; i<curIndex; i++) if (CollectionFactory.equals(elems[i],o)) return true; return overflow==null ? false : overflow.contains(o); } @Override public void clear() { for (int i=0; i<curIndex; i++) elems[i] = null; overflow = null; curIndex = 0; } public Iterator<K> iterator() { return new Iterator<K>() { int pos; Iterator<K> overflowIt; public boolean hasNext() { return pos<curIndex || ( overflowIt==null ? (overflow!=null && !overflow.isEmpty()) : overflowIt.hasNext()); } public K next() { if (pos<curIndex) { return elems[pos++]; } else { if (overflowIt==null) overflowIt = overflow.iterator(); return overflowIt.next(); } } public void remove() { if (overflowIt==null) { removeIndex(--pos); } else overflowIt.remove(); } }; } public int size() { return curIndex+(overflow==null?0:overflow.size()); } }