001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.tools;
003
004 import java.util.AbstractCollection;
005 import java.util.Collection;
006 import java.util.Iterator;
007
008 /**
009 * Filtered view of a collection.
010 * (read-only collection, but elements can be changed, of course)
011 * Lets you iterate through those elements of a given collection that satisfy a
012 * certain condition (imposed by a predicate).
013 * @param <S> element type of the underlying collection
014 * @param <T> element type of filtered collection (and subclass of S). The predicate
015 * must accept only objects of type T.
016 */
017 public class SubclassFilteredCollection<S, T extends S> extends AbstractCollection<T> {
018
019 private final Collection<? extends S> collection;
020 private final Predicate<? super S> predicate;
021 int size = -1;
022
023 private class FilterIterator implements Iterator<T> {
024
025 private final Iterator<? extends S> iterator;
026 private S current;
027
028 public FilterIterator(Iterator<? extends S> iterator) {
029 this.iterator = iterator;
030 }
031
032 private void findNext() {
033 if (current == null) {
034 while (iterator.hasNext()) {
035 current = iterator.next();
036 if (predicate.evaluate(current))
037 return;
038 }
039 current = null;
040 }
041 }
042
043 public boolean hasNext() {
044 findNext();
045 return current != null;
046 }
047
048 public T next() {
049 findNext();
050 S old = current;
051 current = null;
052 // we are save because predicate only accepts objects of type T
053 @SuppressWarnings("unchecked") T res = (T) old;
054 return res;
055 }
056
057 public void remove() {
058 throw new UnsupportedOperationException();
059 }
060 }
061
062 public SubclassFilteredCollection(Collection<? extends S> collection, Predicate<? super S> predicate) {
063 this.collection = collection;
064 this.predicate = predicate;
065 }
066
067 @Override
068 public Iterator<T> iterator() {
069 return new FilterIterator(collection.iterator());
070 }
071
072 @Override
073 public int size() {
074 if (size == -1) {
075 size = 0;
076 Iterator<T> it = iterator();
077 while (it.hasNext()) {
078 size++;
079 it.next();
080 }
081 }
082 return size;
083 }
084
085 @Override
086 public boolean isEmpty() {
087 return !iterator().hasNext();
088 }
089
090 }