/** * */ package vroom.common.utilities; import java.util.AbstractSet; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; /** * <code>IntegerSet</code> is an implementation of {@link Set} to store integers. It is backed up by an array of * booleans and requires the maximum value to be known. * <p> * {@link #add(Integer)}, {@link #remove(Object)}, and {@link #contains(Object)} are executed in constant time, while * iterating over the set is done in O({@code maxValue}) * </p> * <p> * Creation date: Oct 14, 2011 - 1:55:53 PM * </p> * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 1.0 */ public class IntegerSet extends AbstractSet<Integer> { private final Boolean[] mMask; private int mSize; private int mMinIdx; /** * Creates a new <code>IntegerSet</code> with an initial set of values. * <p> * Note that the set will not be able to handle values that are higher than the maximum value stored in * {@code values} * </p> * * @param values * an initial set of values */ public IntegerSet(Collection<Integer> values) { int maxValue = -1; for (Integer i : values) if (i > maxValue) maxValue = i; mMask = new Boolean[maxValue + 1]; mMinIdx = mMask.length - 1; Arrays.fill(mMask, Boolean.FALSE); addAll(values); } /** * Creates a new <code>IntegerSet</code> with an initial set of values * * @param values * an initial set of values * @param maxValue * the maximum value that will ever be contained in this set */ public IntegerSet(Collection<Integer> values, int maxValue) { this(maxValue); addAll(values); } /** * Creates a new empty <code>IntegerSet</code> * * @param maxValue * the maximum value that will ever be contained in this set */ public IntegerSet(int maxValue) { mMask = new Boolean[maxValue + 1]; mMinIdx = mMask.length - 1; Arrays.fill(mMask, Boolean.FALSE); mSize = 0; } @Override public boolean contains(Object o) { if (o instanceof Integer) { int e = (Integer) o; return contains(e); } else { return false; } } /** * Special implementation of {@link #contains(Object)} to prevent additional wrapping of integers * * @param e * the element to remove * @return <code>true</code> if this set contains the specified element * @see #contains(Integer) */ public boolean contains(int e) { if (e < 0 || e >= mMask.length) return false; return mMask[e]; } @Override public boolean add(Integer e) { return add(e.intValue()); } /** * Special implementation of {@link #add(Integer)} to prevent additional wrapping of integers * * @param e * the element to add * @return <code>true</code> if this set did not already contain the specified element * @see #add(Integer) */ public boolean add(int e) { boolean prev = mMask[e]; if (!prev) { mMask[e] = Boolean.TRUE; if (e < mMinIdx) mMinIdx = e; mSize++; } return !prev; } @Override public boolean remove(Object o) { if (o instanceof Integer) { int e = (Integer) o; return remove(e); } else { return false; } } /** * Special implementation of {@link #remove(Object)} to prevent additional wrapping of integers * * @param e * the element to remove * @return <code>true</code> if this set contained the specified element * @see #remove(Integer) */ public boolean remove(int e) { if (e < 0 || e >= mMask.length) return false; boolean prev = mMask[e]; if (prev) { mMask[e] = Boolean.FALSE; if (e == mMinIdx) mMinIdx++; mSize--; } return prev; } @Override public boolean removeAll(Collection<?> c) { boolean changed = false; for (Object o : c) changed |= remove(o); return changed; } /* * (non-Javadoc) * @see java.util.AbstractCollection#iterator() */ @Override public IntegerSetIterator iterator() { return new IntegerSetIterator(); } /* * (non-Javadoc) * @see java.util.AbstractCollection#size() */ @Override public int size() { return mSize; } /** * Return the maximum value that can be stored in this set * * @return the maximum value that can be stored in this set */ public int maxValue() { return mMask.length - 1; } @Override public void clear() { Arrays.fill(mMask, Boolean.FALSE); mSize = 0; } /** * <code>IntegerSetIterator</code> is an implementation of {@link Iterator} that iterates over an instance of * {@link IntegerSet}. This implementation iterates over the whole set in {@link IntegerSet#maxValue() maxId} steps. * <p> * Creation date: Oct 14, 2011 - 2:15:50 PM * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 1.0 */ public class IntegerSetIterator implements Iterator<Integer> { private int mCurrent; private int mNext; /** * Creates a new <code>IntegerSetIterator</code> */ public IntegerSetIterator() { super(); mNext = mMinIdx - 1; moveToNextElement(); mMinIdx = mNext; } private void moveToNextElement() { mNext++; while (mNext < IntegerSet.this.mMask.length && !IntegerSet.this.mMask[mNext].booleanValue()) mNext++; } @Override public boolean hasNext() { return mNext < IntegerSet.this.mMask.length; } @Override public Integer next() { if (!hasNext()) throw new NoSuchElementException(); mCurrent = mNext; moveToNextElement(); return mCurrent; } @Override public void remove() { if (mCurrent < 0) throw new IllegalStateException(); IntegerSet.this.remove(mCurrent); mCurrent = -1; } } }