1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections.iterators;
18
19 import java.util.ListIterator;
20 import java.util.NoSuchElementException;
21
22 import org.apache.commons.collections.Predicate;
23
24 /**
25 * Decorates another {@link ListIterator} using a predicate to filter elements.
26 * <p>
27 * This iterator decorates the underlying iterator, only allowing through
28 * those elements that match the specified {@link Predicate Predicate}.
29 *
30 * @since 2.0
31 * @version $Id: FilterListIterator.java 1429905 2013-01-07 17:15:14Z ggregory $
32 */
33 public class FilterListIterator<E> implements ListIterator<E> {
34
35 /** The iterator being used */
36 private ListIterator<? extends E> iterator;
37
38 /** The predicate being used */
39 private Predicate<? super E> predicate;
40
41 /**
42 * The value of the next (matching) object, when
43 * {@link #nextObjectSet} is true.
44 */
45 private E nextObject;
46
47 /**
48 * Whether or not the {@link #nextObject} has been set
49 * (possibly to <code>null</code>).
50 */
51 private boolean nextObjectSet = false;
52
53 /**
54 * The value of the previous (matching) object, when
55 * {@link #previousObjectSet} is true.
56 */
57 private E previousObject;
58
59 /**
60 * Whether or not the {@link #previousObject} has been set
61 * (possibly to <code>null</code>).
62 */
63 private boolean previousObjectSet = false;
64
65 /**
66 * The index of the element that would be returned by {@link #next}.
67 */
68 private int nextIndex = 0;
69
70 //-----------------------------------------------------------------------
71 /**
72 * Constructs a new <code>FilterListIterator</code> that will not function
73 * until {@link #setListIterator(ListIterator) setListIterator}
74 * and {@link #setPredicate(Predicate) setPredicate} are invoked.
75 */
76 public FilterListIterator() {
77 super();
78 }
79
80 /**
81 * Constructs a new <code>FilterListIterator</code> that will not
82 * function until {@link #setPredicate(Predicate) setPredicate} is invoked.
83 *
84 * @param iterator the iterator to use
85 */
86 public FilterListIterator(final ListIterator<? extends E> iterator ) {
87 super();
88 this.iterator = iterator;
89 }
90
91 /**
92 * Constructs a new <code>FilterListIterator</code>.
93 *
94 * @param iterator the iterator to use
95 * @param predicate the predicate to use
96 */
97 public FilterListIterator(final ListIterator<? extends E> iterator, final Predicate<? super E> predicate) {
98 super();
99 this.iterator = iterator;
100 this.predicate = predicate;
101 }
102
103 /**
104 * Constructs a new <code>FilterListIterator</code> that will not function
105 * until {@link #setListIterator(ListIterator) setListIterator} is invoked.
106 *
107 * @param predicate the predicate to use.
108 */
109 public FilterListIterator(final Predicate<? super E> predicate) {
110 super();
111 this.predicate = predicate;
112 }
113
114 //-----------------------------------------------------------------------
115 /** Not supported. */
116 public void add(final E o) {
117 throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported.");
118 }
119
120 public boolean hasNext() {
121 return nextObjectSet || setNextObject();
122 }
123
124 public boolean hasPrevious() {
125 return previousObjectSet || setPreviousObject();
126 }
127
128 public E next() {
129 if (!nextObjectSet) {
130 if (!setNextObject()) {
131 throw new NoSuchElementException();
132 }
133 }
134 nextIndex++;
135 final E temp = nextObject;
136 clearNextObject();
137 return temp;
138 }
139
140 public int nextIndex() {
141 return nextIndex;
142 }
143
144 public E previous() {
145 if (!previousObjectSet) {
146 if (!setPreviousObject()) {
147 throw new NoSuchElementException();
148 }
149 }
150 nextIndex--;
151 final E temp = previousObject;
152 clearPreviousObject();
153 return temp;
154 }
155
156 public int previousIndex() {
157 return nextIndex-1;
158 }
159
160 /** Not supported. */
161 public void remove() {
162 throw new UnsupportedOperationException("FilterListIterator.remove() is not supported.");
163 }
164
165 /** Not supported. */
166 public void set(final E o) {
167 throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported.");
168 }
169
170 //-----------------------------------------------------------------------
171 /**
172 * Gets the iterator this iterator is using.
173 *
174 * @return the iterator.
175 */
176 public ListIterator<? extends E> getListIterator() {
177 return iterator;
178 }
179
180 /**
181 * Sets the iterator for this iterator to use.
182 * If iteration has started, this effectively resets the iterator.
183 *
184 * @param iterator the iterator to use
185 */
186 public void setListIterator(final ListIterator<? extends E> iterator) {
187 this.iterator = iterator;
188 }
189
190 //-----------------------------------------------------------------------
191 /**
192 * Gets the predicate this iterator is using.
193 *
194 * @return the predicate.
195 */
196 public Predicate<? super E> getPredicate() {
197 return predicate;
198 }
199
200 /**
201 * Sets the predicate this the iterator to use.
202 *
203 * @param predicate the transformer to use
204 */
205 public void setPredicate(final Predicate<? super E> predicate) {
206 this.predicate = predicate;
207 }
208
209 //-----------------------------------------------------------------------
210 private void clearNextObject() {
211 nextObject = null;
212 nextObjectSet = false;
213 }
214
215 private boolean setNextObject() {
216 // if previousObjectSet,
217 // then we've walked back one step in the
218 // underlying list (due to a hasPrevious() call)
219 // so skip ahead one matching object
220 if (previousObjectSet) {
221 clearPreviousObject();
222 if (!setNextObject()) {
223 return false;
224 }
225 clearNextObject();
226 }
227
228 if (iterator == null) {
229 return false;
230 }
231 while (iterator.hasNext()) {
232 final E object = iterator.next();
233 if (predicate.evaluate(object)) {
234 nextObject = object;
235 nextObjectSet = true;
236 return true;
237 }
238 }
239 return false;
240 }
241
242 private void clearPreviousObject() {
243 previousObject = null;
244 previousObjectSet = false;
245 }
246
247 private boolean setPreviousObject() {
248 // if nextObjectSet,
249 // then we've walked back one step in the
250 // underlying list (due to a hasNext() call)
251 // so skip ahead one matching object
252 if (nextObjectSet) {
253 clearNextObject();
254 if (!setPreviousObject()) {
255 return false;
256 }
257 clearPreviousObject();
258 }
259
260 if (iterator == null) {
261 return false;
262 }
263 while (iterator.hasPrevious()) {
264 final E object = iterator.previous();
265 if (predicate.evaluate(object)) {
266 previousObject = object;
267 previousObjectSet = true;
268 return true;
269 }
270 }
271 return false;
272 }
273
274 }