1
2
3
4
5
6
7
8
9
10
11
12
13
14 package eu.fbk.rdfpro.util;
15
16 import java.util.Iterator;
17 import java.util.NoSuchElementException;
18 import java.util.Objects;
19 import java.util.function.Function;
20 import java.util.function.Predicate;
21
22 import javax.annotation.Nullable;
23
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import info.aduna.iteration.CloseableIteration;
28 import info.aduna.iteration.Iteration;
29
30 final class Iterators {
31
32 private static final Logger LOGGER = LoggerFactory.getLogger(Iterators.class);
33
34 @Nullable
35 public static <T> Iterator<T> unmodifiable(@Nullable final Iterator<T> iterator) {
36 return iterator == null ? null : new UnmodifiableIterator<T>(iterator);
37 }
38
39 public static <T> Iterator<T> concat(
40 final Iterator<? extends Iterator<? extends T>> iteratorSupplier) {
41 return new ConcatIterator<T>(Objects.requireNonNull(iteratorSupplier));
42 }
43
44 public static <T> Iterator<T> filter(final Iterator<T> iterator,
45 final Predicate<? super T> predicate) {
46 return new FilterIterator<T>(Objects.requireNonNull(iterator),
47 Objects.requireNonNull(predicate));
48 }
49
50 public static <T, R> Iterator<R> transform(final Iterator<T> iterator,
51 final Function<? super T, ? extends R> transformer) {
52 return new TransformIterator<T, R>(Objects.requireNonNull(iterator),
53 Objects.requireNonNull(transformer));
54 }
55
56 public static <T> Iterator<T> forIteration(final Iteration<? extends T, ?> iteration) {
57 return new IterationIterator<T>(iteration);
58 }
59
60 public static <T, E extends Exception> CloseableIteration<T, E> toIteration(
61 final Iterator<T> iterator) {
62 return new IteratorIteration<T, E>(iterator);
63 }
64
65 private static final class UnmodifiableIterator<T> implements Iterator<T>, AutoCloseable {
66
67 private final Iterator<T> iterator;
68
69 UnmodifiableIterator(final Iterator<T> iterator) {
70 this.iterator = iterator;
71 }
72
73 @Override
74 public boolean hasNext() {
75 return this.iterator.hasNext();
76 }
77
78 @Override
79 public T next() {
80 return this.iterator.next();
81 }
82
83 @Override
84 public void close() {
85 if (this.iterator instanceof AutoCloseable) {
86 try {
87 ((AutoCloseable) this.iterator).close();
88 } catch (final Throwable ex) {
89 LOGGER.error("Could not close iterator", ex);
90 }
91 }
92 }
93
94 }
95
96 private static final class ConcatIterator<T> implements Iterator<T>, AutoCloseable {
97
98 private final Iterator<? extends Iterator<? extends T>> iteratorSupplier;
99
100 @Nullable
101 private Iterator<? extends T> currentIterator;
102
103 @Nullable
104 private Iterator<? extends T> removeIterator;
105
106 private boolean eof;
107
108 ConcatIterator(final Iterator<? extends Iterator<? extends T>> iteratorSupplier) {
109 this.iteratorSupplier = iteratorSupplier;
110 this.currentIterator = null;
111 this.removeIterator = null;
112 this.eof = false;
113 }
114
115 @Override
116 public boolean hasNext() {
117 if (this.eof) {
118 return false;
119 }
120 while (true) {
121 if (this.currentIterator != null) {
122 if (this.currentIterator.hasNext()) {
123 return true;
124 } else if (this.currentIterator != this.removeIterator) {
125 IO.closeQuietly(this.currentIterator);
126 }
127 }
128 if (!this.iteratorSupplier.hasNext()) {
129 this.eof = true;
130 return false;
131 }
132 this.currentIterator = this.iteratorSupplier.next();
133 }
134 }
135
136 @Override
137 public T next() {
138 if (!hasNext()) {
139 throw new NoSuchElementException();
140 }
141 final T element = this.currentIterator.next();
142 if (this.removeIterator != this.currentIterator) {
143 IO.closeQuietly(this.removeIterator);
144 }
145 this.removeIterator = this.currentIterator;
146 return element;
147 }
148
149 @Override
150 public void remove() {
151 if (this.removeIterator == null) {
152 throw new NoSuchElementException();
153 }
154 this.removeIterator.remove();
155 this.removeIterator = null;
156 }
157
158 @Override
159 public void close() throws Exception {
160 this.eof = true;
161 IO.closeQuietly(this.removeIterator);
162 IO.closeQuietly(this.currentIterator);
163 IO.closeQuietly(this.iteratorSupplier);
164 }
165
166 }
167
168 private static final class FilterIterator<T> implements Iterator<T>, AutoCloseable {
169
170 private final Iterator<? extends T> iterator;
171
172 private final Predicate<? super T> predicate;
173
174 private T next;
175
176 private boolean eof;
177
178 private boolean removable;
179
180 FilterIterator(final Iterator<? extends T> iterator, final Predicate<? super T> predicate) {
181 this.iterator = iterator;
182 this.predicate = predicate;
183 this.next = null;
184 this.eof = false;
185 this.removable = false;
186 }
187
188 @Override
189 public boolean hasNext() {
190 if (!this.eof) {
191 if (this.next != null) {
192 return true;
193 }
194 while (this.next == null && this.iterator.hasNext()) {
195 final T element = this.iterator.next();
196 this.removable = false;
197 if (this.predicate.test(element)) {
198 this.next = element;
199 return true;
200 }
201 }
202 this.eof = true;
203 }
204 return false;
205 }
206
207 @Override
208 public T next() {
209 if (!hasNext()) {
210 throw new NoSuchElementException();
211 }
212 final T result = this.next;
213 this.next = null;
214 this.removable = true;
215 return result;
216 }
217
218 @Override
219 public void remove() {
220 if (!this.removable) {
221 throw new NoSuchElementException();
222 }
223 this.iterator.remove();
224 this.removable = false;
225 }
226
227 @Override
228 public void close() throws Exception {
229 IO.closeQuietly(this.iterator);
230 }
231
232 }
233
234 private static final class TransformIterator<T, R> implements Iterator<R>, AutoCloseable {
235
236 private final Iterator<T> iterator;
237
238 private final Function<? super T, ? extends R> transformer;
239
240 TransformIterator(final Iterator<T> iterator,
241 final Function<? super T, ? extends R> transformer) {
242 this.iterator = iterator;
243 this.transformer = transformer;
244 }
245
246 @Override
247 public boolean hasNext() {
248 return this.iterator.hasNext();
249 }
250
251 @Override
252 public R next() {
253 return this.transformer.apply(this.iterator.next());
254 }
255
256 @Override
257 public void remove() {
258 this.iterator.remove();
259 }
260
261 @Override
262 public void close() throws Exception {
263 IO.closeQuietly(this.iterator);
264 }
265
266 }
267
268 private static final class IterationIterator<T> implements Iterator<T>, AutoCloseable {
269
270 private final Iteration<? extends T, ?> iteration;
271
272 IterationIterator(final Iteration<? extends T, ?> iteration) {
273 this.iteration = iteration;
274 }
275
276 @Override
277 public boolean hasNext() {
278 try {
279 return this.iteration.hasNext();
280 } catch (RuntimeException | Error ex) {
281 close();
282 throw ex;
283 } catch (final Throwable ex) {
284 close();
285 throw new RuntimeException(ex);
286 }
287 }
288
289 @Override
290 public T next() {
291 try {
292 return this.iteration.next();
293 } catch (RuntimeException | Error ex) {
294 close();
295 throw ex;
296 } catch (final Throwable ex) {
297 close();
298 throw new RuntimeException(ex);
299 }
300 }
301
302 @Override
303 public void close() {
304 if (this.iteration instanceof CloseableIteration<?, ?>) {
305 try {
306 ((CloseableIteration<? extends T, ?>) this.iteration).close();
307 } catch (final Throwable ex) {
308 LOGGER.error("Could not close iteration", ex);
309 }
310 }
311 }
312
313 }
314
315 private static final class IteratorIteration<T, E extends Exception> implements
316 CloseableIteration<T, E> {
317
318 private final Iterator<T> iterator;
319
320 IteratorIteration(final Iterator<T> iterator) {
321 this.iterator = iterator;
322 }
323
324 @Override
325 public boolean hasNext() throws E {
326 return this.iterator.hasNext();
327 }
328
329 @Override
330 public T next() throws E {
331 return this.iterator.next();
332 }
333
334 @Override
335 public void remove() throws E {
336 this.iterator.remove();
337 }
338
339 @Override
340 public void close() throws E {
341 IO.closeQuietly(this.iterator);
342 }
343
344 }
345
346 }