1   /*
2    * RDFpro - An extensible tool for building stream-oriented RDF processing libraries.
3    * 
4    * Written in 2015 by Francesco Corcoglioniti with support by Alessio Palmero Aprosio and Marco
5    * Rospocher. Contact info on http://rdfpro.fbk.eu/
6    * 
7    * To the extent possible under law, the authors have dedicated all copyright and related and
8    * neighboring rights to this software to the public domain worldwide. This software is
9    * distributed without any warranty.
10   * 
11   * You should have received a copy of the CC0 Public Domain Dedication along with this software.
12   * If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
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 }