• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Iterator;
7 import java.util.List;
8 
9 import com.ibm.icu.lang.CharSequences;
10 import com.ibm.icu.text.Transform;
11 import com.ibm.icu.text.UTF16;
12 
13 /**
14  * Simple cover class for converting iterators, lists of items, arrays, and
15  * CharSequences into forms usable with for loops. Example:
16  *
17  * <pre>
18  * for (String s : With.in(someIterator)) {
19  *     doSomethingWith(s);
20  * }
21  *
22  * for (int codePoint : With.codePointArray(&quot;abc\uD800\uDC00&quot;)) {
23  *     doSomethingWith(codePoint);
24  * }
25  *
26  * for (int integer : With.array(1, 99, 3, 42)) {
27  *     doSomethingWith(integer);
28  * }
29  * </pre>
30  *
31  * @author markdavis
32  *
33  * @param <V>
34  */
35 public final class With<V> implements Iterable<V>, Iterator<V> {
36     List<Iterator<V>> iterators = new ArrayList<Iterator<V>>();
37     int current;
38 
39     /**
40      * Interface for an iterator that is simpler to implement, without 'look-ahead'.
41      * Using With.in(), this can be transformed into a regular Java iterator.
42      * The one restriction is that elements cannot be null, since that signals end of the sequence.
43      *
44      * @author markdavis
45      *
46      * @param <T>
47      */
48     public interface SimpleIterator<T> {
49         /**
50          * Returns null when done
51          *
52          * @return object, or null when done.
53          */
next()54         public T next();
55     }
56 
57     @Override
iterator()58     public Iterator<V> iterator() {
59         return this;
60     }
61 
62     @Override
hasNext()63     public boolean hasNext() {
64         while (current < iterators.size()) {
65             if (iterators.get(current).hasNext()) {
66                 return true;
67             }
68             current++;
69         }
70         return false;
71     }
72 
73     @Override
next()74     public V next() {
75         return iterators.get(current).next();
76     }
77 
78     @Override
remove()79     public void remove() {
80         throw new UnsupportedOperationException();
81     }
82 
83     /**
84      * Create a collection from whatever is left in the iterator. For example, myCollection =
85      * With.in(anIterator).toList();
86      *
87      * @return
88      */
toList()89     public List<V> toList() {
90         return toCollection(new ArrayList<V>());
91     }
92 
93     /**
94      * Create a collection from whatever is left in the iterator. For example, myCollection =
95      * With.in(anIterator).toList();
96      *
97      * @return
98      */
toCollection(C output)99     public <C extends Collection<V>> C toCollection(C output) {
100         while (hasNext()) {
101             output.add(next());
102         }
103         return output;
104     }
105 
106     /**
107      * Create a collection from whatever is left in the iterator. For example, myCollection =
108      * With.in(anIterator).toList();
109      *
110      * @return
111      */
toUnmodifiableCollection(C output)112     public <C extends Collection<V>> C toUnmodifiableCollection(C output) {
113         while (hasNext()) {
114             output.add(next());
115         }
116         return CldrUtility.protectCollection(output);
117     }
118 
119     /**
120      * Create a collection from whatever is left in the iterator. For example, myCollection =
121      * With.in(anIterator).toList();
122      *
123      * @return
124      */
toCollection(Transform<V, W> filter, C output)125     public <W, C extends Collection<W>> C toCollection(Transform<V, W> filter, C output) {
126         while (hasNext()) {
127             W transformedItem = filter.transform(next());
128             if (transformedItem != null) {
129                 output.add(transformedItem);
130             }
131         }
132         return output;
133     }
134 
135     /**
136      * Create an immutable collection from whatever is left in the iterator. For example, myCollection =
137      * With.in(anIterator).toList();
138      *
139      * @return
140      */
toUnmodifiableCollection(Transform<V, W> filter, C output)141     public <W, C extends Collection<W>> C toUnmodifiableCollection(Transform<V, W> filter, C output) {
142         return CldrUtility.protectCollection(toCollection(filter, output));
143     }
144 
145     /**
146      * Create a simple object for use in for loops. Example:
147      *
148      * <pre>
149      * for (int integer : With.in(1, 99, 3, 42)) {
150      *     doSomethingWith(integer);
151      * }
152      * </pre>
153      *
154      * @param <V>
155      * @param iterator
156      * @return Iterable, for use in for loops, etc.
157      */
158     @SuppressWarnings("unchecked")
array(V... values)159     public static <V> V[] array(V... values) {
160         return values;
161     }
162 
163     /**
164      * Create a simple object for use in for loops, handling code points
165      * properly. Example:
166      *
167      * <pre>
168      * for (int codePoint : With.in(&quot;abc\uD800\uDC00&quot;)) {
169      *     doSomethingWith(codePoint);
170      * }
171      * </pre>
172      *
173      * Actually returns an array, which avoids boxing/unboxing costs.
174      *
175      * @param iterator
176      * @return Iterable, for use in for loops, etc.
177      */
codePointArray(CharSequence source)178     public static int[] codePointArray(CharSequence source) {
179         return CharSequences.codePoints(source);
180     }
181 
182     /**
183      * An alterative to With.in(CharSequence) that is better when it is likely that only a portion of the text will be
184      * looked at,
185      * such as when an iterator over codepoints is aborted partway.
186      *
187      * @param old
188      * @return
189      */
codePoints(CharSequence... charSequences)190     public static With<CharSequence> codePoints(CharSequence... charSequences) {
191         return new With<CharSequence>().andCodePoints(charSequences);
192     }
193 
194     /**
195      * Create a simple object for use in for loops. Example:
196      *
197      * <pre>
198      * for (String s : With.in(someIterator)) {
199      *     doSomethingWith(s);
200      * }
201      * </pre>
202      *
203      * @param <V>
204      * @param iterator
205      * @return Iterable, for use in for loops, etc.
206      */
207     @SafeVarargs
208     @SuppressWarnings("unchecked")
in(Iterator<V>.... iterators)209     public static <V> With<V> in(Iterator<V>... iterators) {
210         return new With<V>().and(iterators);
211     }
212 
213     /**
214      * Create a simple object for use in for loops. Example:
215      *
216      * <pre>
217      * for (String s : With.in(someIterator)) {
218      *     doSomethingWith(s);
219      * }
220      * </pre>
221      *
222      * @param <V>
223      * @param iterator
224      * @return Iterable, for use in for loops, etc.
225      */
226     @SuppressWarnings("unchecked")
in(Iterable<V>.... iterables)227     public static <V> With<V> in(Iterable<V>... iterables) {
228         return new With<V>().and(iterables);
229     }
230 
231     /**
232      * Create a simple object for use in for loops. Example:
233      *
234      * <pre>
235      * for (String s : With.in(someIterator)) {
236      *     doSomethingWith(s);
237      * }
238      * </pre>
239      *
240      * @param <V>
241      * @param iterator
242      * @return Iterable, for use in for loops, etc.
243      */
244     @SuppressWarnings("unchecked")
in(V... items)245     public static <V> With<V> in(V... items) {
246         return new With<V>().and(items);
247     }
248 
249     /**
250      * Creates an iterable from a simple iterator.
251      *
252      * @param <T>
253      * @param old
254      * @return
255      */
256     @SuppressWarnings("unchecked")
in(SimpleIterator<T>.... sources)257     public static <T> Iterable<T> in(SimpleIterator<T>... sources) {
258         return new With<T>().and(sources);
259     }
260 
With()261     private With() {
262     }
263 
264     @SuppressWarnings("unchecked")
and(Iterator<V>.... iterators)265     public With<V> and(Iterator<V>... iterators) {
266         for (Iterator<V> iterator : iterators) {
267             this.iterators.add(iterator);
268         }
269         return this;
270     }
271 
272     @SuppressWarnings("unchecked")
and(V... items)273     public With<V> and(V... items) {
274         return and(Arrays.asList(items));
275     }
276 
277     @SuppressWarnings("unchecked")
and(Iterable<V>.... iterables)278     public With<V> and(Iterable<V>... iterables) {
279         for (Iterable<V> iterable : iterables) {
280             this.iterators.add(iterable.iterator());
281         }
282         return this;
283     }
284 
285     @SuppressWarnings("unchecked")
and(SimpleIterator<V>.... iterators)286     public With<V> and(SimpleIterator<V>... iterators) {
287         for (SimpleIterator<V> iterator : iterators) {
288             this.iterators.add(new ToIterator<V>(iterator));
289         }
290         return this;
291     }
292 
293     /**
294      * Will fail if V is not a CharSequence.
295      *
296      * @param sources
297      * @return
298      */
andCodePoints(CharSequence... sources)299     public With<V> andCodePoints(CharSequence... sources) {
300         for (CharSequence charSequence : sources) {
301             this.iterators
302                 .add((Iterator<V>) new ToIterator<CharSequence>(new CharSequenceSimpleIterator(charSequence)));
303         }
304         return this;
305     }
306 
307     // new CharSequenceSimpleIterator(source)
308 
309     private static class CharSequenceSimpleIterator implements SimpleIterator<CharSequence> {
310         private int position;
311         private CharSequence source;
312 
CharSequenceSimpleIterator(CharSequence source)313         public CharSequenceSimpleIterator(CharSequence source) {
314             this.source = source;
315         }
316 
317         @Override
next()318         public CharSequence next() {
319             // TODO optimize
320             if (position >= source.length()) {
321                 return null;
322             }
323             int codePoint = Character.codePointAt(source, position);
324             position += Character.charCount(codePoint);
325             return UTF16.valueOf(codePoint);
326         }
327     }
328 
toIterator(SimpleIterator<T> simple)329     public static <T> Iterator<T> toIterator(SimpleIterator<T> simple) {
330         return new ToIterator<T>(simple);
331     }
332 
toIterable(SimpleIterator<T> simple)333     public static <T> Iterable<T> toIterable(SimpleIterator<T> simple) {
334         return new ToIterator<T>(simple);
335     }
336 
toSimpleIterator(Iterator<T> iterator)337     public static <T> ToSimpleIterator<T> toSimpleIterator(Iterator<T> iterator) {
338         return new ToSimpleIterator<T>(iterator);
339     }
340 
341     private static class ToIterator<T> implements Iterator<T>, Iterable<T> {
342         private final SimpleIterator<T> simpleIterator;
343         private T current;
344 
345         /**
346          * @param simpleIterator
347          */
ToIterator(SimpleIterator<T> simpleIterator)348         public ToIterator(SimpleIterator<T> simpleIterator) {
349             this.simpleIterator = simpleIterator;
350             current = simpleIterator.next();
351         }
352 
353         @Override
hasNext()354         public boolean hasNext() {
355             return current != null;
356         }
357 
358         @Override
next()359         public T next() {
360             T result = current;
361             current = simpleIterator.next();
362             return result;
363         }
364 
365         @Override
remove()366         public void remove() {
367             throw new UnsupportedOperationException();
368         }
369 
370         @Override
iterator()371         public Iterator<T> iterator() {
372             return this;
373         }
374     }
375 
376     private static class ToSimpleIterator<T> implements SimpleIterator<T> {
377         private final Iterator<T> iterator;
378 
ToSimpleIterator(Iterator<T> iterator)379         public ToSimpleIterator(Iterator<T> iterator) {
380             this.iterator = iterator;
381         }
382 
383         @Override
next()384         public T next() {
385             return iterator.hasNext() ? iterator.next() : null;
386         }
387     }
388 
389 }
390