001package org.biopax.paxtools.util;
002
003import org.apache.commons.logging.Log;
004import org.apache.commons.logging.LogFactory;
005
006import java.util.AbstractSet;
007import java.util.Iterator;
008import java.util.NoSuchElementException;
009import java.util.Set;
010
011/**
012 * Base class for implementing various filter sets.
013 * Filter sets are unmodifiable.
014 * @see ClassFilterSet for an implementation that filters classes.
015 */
016
017public abstract class AbstractFilterSet<F, E> extends AbstractSet<E> implements Filter<F>
018{
019        final Log log = LogFactory.getLog(ClassFilterSet.class);
020
021        int size = -1;
022
023        protected final Set<? extends F> baseSet;
024
025
026        public AbstractFilterSet(Set<? extends F> baseSet)
027        {
028                this.baseSet = baseSet;
029
030        }
031
032        /**
033         * This size operation runs on O(n) and should be avoided for large sets.
034         * It is possible to write a one pass more efficient abstract set but its
035         * initialization cost would be higher.
036         * @return the size of the list
037         */
038        public int size()
039        {
040                if (size == -1)
041                {
042                        int i = 0;
043                        for (E e : this)
044                        {
045                                i++;
046                        }
047                        size = i;
048                }
049                return size;
050        }
051
052        @Override public boolean contains(Object o)
053        {
054
055                return baseSet.contains(o) && filter(((F) o));
056        }
057
058        @Override public Iterator<E> iterator()
059        {
060                return new FilterIterator(baseSet.iterator());
061        }
062
063
064        private class FilterIterator implements Iterator<E>
065        {
066                E next = null;
067
068                final Iterator<? extends F> base;
069
070                public FilterIterator(Iterator<? extends F> base)
071                {
072                        this.base = base;
073                        fetchNext();
074                }
075
076                private void fetchNext()
077                {
078                        F check;
079                        next = null;
080                        while (base.hasNext())
081                        {
082                                check = base.next();
083                                if (filter(check))
084                                {
085                                        try
086                                        {
087                                                next = (E) check;
088                                                break;
089                                        }
090                                        catch (ClassCastException ce)
091                                        {
092                                                log.error("wrong use of filter set. Skipping.", ce);
093                                        }
094                                        return;
095                                }
096                        }
097                }
098
099                public boolean hasNext()
100                {
101                        return next != null;
102                }
103
104                public E next()
105                {
106                        if (hasNext())
107                        {
108                                E value = next;
109                                fetchNext();
110                                return value;
111                        } else
112                        {
113                                throw new NoSuchElementException();
114                        }
115                }
116
117                public void remove()
118                {
119                        throw new UnsupportedOperationException();
120                }
121        }
122}