/* Copyright (C) 2006 Christian Schneider
*
* This file is part of Nomad.
*
* Nomad is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Nomad is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Nomad; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sf.nmedit.nmutils.collections;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Subset<T> extends AbstractCollection<T>
{
private Collection<T> superSet;
private Filter<T> filter;
private transient int size = 0;
private transient int modCount;
public Subset(Collection<T> superSet, Filter<T> filter)
{
this.superSet = superSet;
this.filter = filter;
}
public boolean add(T e)
{
if (!filter.contains(e))
throw new IllegalArgumentException("filter rejects element: "+e);
if (superSet.add(e))
{
modCount++;
return true;
}
return false;
}
@Override
public Iterator<T> iterator()
{
return new FilterIterator<T>(this);
}
@Override
public int size()
{
if (size <= 0)
size = Counter.countIterable(this);
return size;
}
public boolean isEmpty()
{
return (size>0) ? false : !iterator().hasNext();
}
// the filter
public static interface Filter<T>
{
boolean contains(T element);
}
// the filter iterator
protected static class FilterIterator<T> implements Iterator<T>
{
private Subset<T> set;
private Iterator<T> iter;
private T element;
private int knownMod;
public FilterIterator(Subset<T> set)
{
this.set = set;
this.iter = set.superSet.iterator();
knownMod = set.modCount;
}
private T trynext()
{
if (element == null)
{
T e;
while (iter.hasNext())
{
e = iter.next();
if (set.filter.contains(e))
{
element = e;
break;
}
}
}
return element;
}
public boolean hasNext()
{
return trynext() != null;
}
public T next()
{
T n = trynext();
if (n == null)
throw new NoSuchElementException();
element = null;
return n;
}
public void remove()
{
if (knownMod != set.modCount)
throw new ConcurrentModificationException();
iter.remove();
}
}
}