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