Skip to main content
summaryrefslogtreecommitdiffstats
blob: dd8230bf26a40f5aa38512c187bfb30f3501511b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*******************************************************************************
 * Copyright (c) 2005, 2008 Oracle. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0, which accompanies this distribution
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *     Oracle - initial API and implementation
 ******************************************************************************/
package org.eclipse.jpt.utility.internal.iterators;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.eclipse.jpt.utility.Filter;
import org.eclipse.jpt.utility.internal.StringTools;

/**
 * A <code>FilteringIterator</code> wraps another <code>Iterator</code>
 * and uses a <code>Filter</code> to determine which elements in the
 * nested iterator are to be returned by calls to <code>next()</code>.
 * <p>
 * As an alternative to building a <code>Filter</code>, a subclass
 * of <code>FilteringIterator</code> can override the
 * <code>accept(Object)</code> method.
 * <p>
 * One, possibly undesirable, side-effect of using this iterator is that
 * the nested iterator's <code>next()</code> method will be invoked
 * <em>before</em> the filtered iterator's <code>next()</code>
 * method is invoked. This is because the "next" element must be
 * checked for whether it is to be accepted before the filtered iterator
 * can determine whether it has a "next" element (i.e. that the
 * <code>hasNext()</code> method should return <code>true</code>).
 * This also prevents a filtered iterator from supporting the optional
 * <code>remove()</code> method.
 */
public class FilteringIterator<E1, E2>
	implements Iterator<E2>
{
	private final Iterator<? extends E1> nestedIterator;
	private final Filter<E1> filter;
	private E2 next;
	private boolean done;


	/**
	 * Construct an iterator with the specified nested
	 * iterator and a disabled filter.
	 * Use this constructor if you want to override the
	 * <code>accept(Object)</code> method instead of building
	 * a <code>Filter</code>.
	 */
	public FilteringIterator(Iterator<? extends E1> nestedIterator) {
		this(nestedIterator, Filter.Disabled.<E1>instance());
	}

	/**
	 * Construct an iterator with the specified nested
	 * iterator and filter.
	 */
	public FilteringIterator(Iterator<? extends E1> nestedIterator, Filter<E1> filter) {
		super();
		this.nestedIterator = nestedIterator;
		this.filter = filter;
		this.loadNext();
	}

	public boolean hasNext() {
		return ! this.done;
	}

	public E2 next() {
		if (this.done) {
			throw new NoSuchElementException();
		}
		E2 result = this.next;
		this.loadNext();
		return result;
	}

	/**
	 * Because we need to pre-load the next element
	 * to be returned, we cannot support the <code>remove()</code>
	 * method.
	 */
	public void remove() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Load next with the next valid entry from the nested
	 * iterator. If there are none, next is set to <code>END</code>.
	 */
	private void loadNext() {
		this.done = true;
		while (this.nestedIterator.hasNext() && (this.done)) {
			E1 temp = this.nestedIterator.next();
			if (this.accept(temp)) {
				// assume that if the object was accepted it is of type E
				this.next = this.cast(temp);
				this.done = false;
			} else {
				this.next = null;
				this.done = true;
			}
		}
	}

	/**
	 * We have to assume the filter will only "accept" objects that can
	 * be cast to E2.
	 */
	@SuppressWarnings("unchecked")
	private E2 cast(E1 o) {
		return (E2) o;
	}

	/**
	 * Return whether the <code>FilteringIterator</code>
	 * should return the specified next element from a call to the
	 * <code>next()</code> method.
	 * <p>
	 * This method can be overridden by a subclass as an
	 * alternative to building a <code>Filter</code>.
	 */
	protected boolean accept(E1 o) {
		return this.filter.accept(o);
	}

	@Override
	public String toString() {
		return StringTools.buildToStringFor(this, this.nestedIterator);
	}

}

Back to the top