001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.tools; 003 004import java.util.AbstractCollection; 005import java.util.Collection; 006import 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 * @since 3147 017 */ 018public class SubclassFilteredCollection<S, T extends S> extends AbstractCollection<T> { 019 020 private final Collection<? extends S> collection; 021 private final Predicate<? super S> predicate; 022 int size = -1; 023 024 private class FilterIterator implements Iterator<T> { 025 026 private final Iterator<? extends S> iterator; 027 private S current; 028 029 public FilterIterator(Iterator<? extends S> iterator) { 030 this.iterator = iterator; 031 } 032 033 private void findNext() { 034 if (current == null) { 035 while (iterator.hasNext()) { 036 current = iterator.next(); 037 if (predicate.evaluate(current)) 038 return; 039 } 040 current = null; 041 } 042 } 043 044 @Override 045 public boolean hasNext() { 046 findNext(); 047 return current != null; 048 } 049 050 @SuppressWarnings("unchecked") 051 @Override 052 public T next() { 053 findNext(); 054 S old = current; 055 current = null; 056 // we are save because predicate only accepts objects of type T 057 return (T) old; 058 } 059 060 @Override 061 public void remove() { 062 throw new UnsupportedOperationException(); 063 } 064 } 065 066 /** 067 * Constructs a new {@code SubclassFilteredCollection}. 068 * @param collection The base collection to filter 069 * @param predicate The predicate to use as filter 070 */ 071 public SubclassFilteredCollection(Collection<? extends S> collection, Predicate<? super S> predicate) { 072 this.collection = collection; 073 this.predicate = predicate; 074 } 075 076 @Override 077 public Iterator<T> iterator() { 078 return new FilterIterator(collection.iterator()); 079 } 080 081 @Override 082 public int size() { 083 if (size == -1) { 084 size = 0; 085 Iterator<T> it = iterator(); 086 while (it.hasNext()) { 087 size++; 088 it.next(); 089 } 090 } 091 return size; 092 } 093 094 @Override 095 public boolean isEmpty() { 096 return !iterator().hasNext(); 097 } 098}