Home | History | Annotate | Download | only in util
      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          */
     54         public T next();
     55     }
     56 
     57     @Override
     58     public Iterator<V> iterator() {
     59         return this;
     60     }
     61 
     62     @Override
     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
     74     public V next() {
     75         return iterators.get(current).next();
     76     }
     77 
     78     @Override
     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      */
     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      */
     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      */
    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      */
    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      */
    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")
    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      */
    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      */
    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")
    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")
    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")
    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")
    257     public static <T> Iterable<T> in(SimpleIterator<T>... sources) {
    258         return new With<T>().and(sources);
    259     }
    260 
    261     private With() {
    262     }
    263 
    264     @SuppressWarnings("unchecked")
    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")
    273     public With<V> and(V... items) {
    274         return and(Arrays.asList(items));
    275     }
    276 
    277     @SuppressWarnings("unchecked")
    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")
    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      */
    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 
    313         public CharSequenceSimpleIterator(CharSequence source) {
    314             this.source = source;
    315         }
    316 
    317         @Override
    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 
    329     public static <T> Iterator<T> toIterator(SimpleIterator<T> simple) {
    330         return new ToIterator<T>(simple);
    331     }
    332 
    333     public static <T> Iterable<T> toIterable(SimpleIterator<T> simple) {
    334         return new ToIterator<T>(simple);
    335     }
    336 
    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          */
    348         public ToIterator(SimpleIterator<T> simpleIterator) {
    349             this.simpleIterator = simpleIterator;
    350             current = simpleIterator.next();
    351         }
    352 
    353         @Override
    354         public boolean hasNext() {
    355             return current != null;
    356         }
    357 
    358         @Override
    359         public T next() {
    360             T result = current;
    361             current = simpleIterator.next();
    362             return result;
    363         }
    364 
    365         @Override
    366         public void remove() {
    367             throw new UnsupportedOperationException();
    368         }
    369 
    370         @Override
    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 
    379         public ToSimpleIterator(Iterator<T> iterator) {
    380             this.iterator = iterator;
    381         }
    382 
    383         @Override
    384         public T next() {
    385             return iterator.hasNext() ? iterator.next() : null;
    386         }
    387     }
    388 
    389 }
    390