package org.unicode.cldr.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import com.ibm.icu.lang.CharSequences; import com.ibm.icu.text.Transform; import com.ibm.icu.text.UTF16; /** * Simple cover class for converting iterators, lists of items, arrays, and * CharSequences into forms usable with for loops. Example: * *
 * for (String s : With.in(someIterator)) {
 *     doSomethingWith(s);
 * }
 *
 * for (int codePoint : With.codePointArray("abc\uD800\uDC00")) {
 *     doSomethingWith(codePoint);
 * }
 *
 * for (int integer : With.array(1, 99, 3, 42)) {
 *     doSomethingWith(integer);
 * }
 * 
* * @author markdavis * * @param */ public final class With implements Iterable, Iterator { List> iterators = new ArrayList>(); int current; /** * Interface for an iterator that is simpler to implement, without 'look-ahead'. * Using With.in(), this can be transformed into a regular Java iterator. * The one restriction is that elements cannot be null, since that signals end of the sequence. * * @author markdavis * * @param */ public interface SimpleIterator { /** * Returns null when done * * @return object, or null when done. */ public T next(); } @Override public Iterator iterator() { return this; } @Override public boolean hasNext() { while (current < iterators.size()) { if (iterators.get(current).hasNext()) { return true; } current++; } return false; } @Override public V next() { return iterators.get(current).next(); } @Override public void remove() { throw new UnsupportedOperationException(); } /** * Create a collection from whatever is left in the iterator. For example, myCollection = * With.in(anIterator).toList(); * * @return */ public List toList() { return toCollection(new ArrayList()); } /** * Create a collection from whatever is left in the iterator. For example, myCollection = * With.in(anIterator).toList(); * * @return */ public > C toCollection(C output) { while (hasNext()) { output.add(next()); } return output; } /** * Create a collection from whatever is left in the iterator. For example, myCollection = * With.in(anIterator).toList(); * * @return */ public > C toUnmodifiableCollection(C output) { while (hasNext()) { output.add(next()); } return CldrUtility.protectCollection(output); } /** * Create a collection from whatever is left in the iterator. For example, myCollection = * With.in(anIterator).toList(); * * @return */ public > C toCollection(Transform filter, C output) { while (hasNext()) { W transformedItem = filter.transform(next()); if (transformedItem != null) { output.add(transformedItem); } } return output; } /** * Create an immutable collection from whatever is left in the iterator. For example, myCollection = * With.in(anIterator).toList(); * * @return */ public > C toUnmodifiableCollection(Transform filter, C output) { return CldrUtility.protectCollection(toCollection(filter, output)); } /** * Create a simple object for use in for loops. Example: * *
     * for (int integer : With.in(1, 99, 3, 42)) {
     *     doSomethingWith(integer);
     * }
     * 
* * @param * @param iterator * @return Iterable, for use in for loops, etc. */ @SuppressWarnings("unchecked") public static V[] array(V... values) { return values; } /** * Create a simple object for use in for loops, handling code points * properly. Example: * *
     * for (int codePoint : With.in("abc\uD800\uDC00")) {
     *     doSomethingWith(codePoint);
     * }
     * 
* * Actually returns an array, which avoids boxing/unboxing costs. * * @param iterator * @return Iterable, for use in for loops, etc. */ public static int[] codePointArray(CharSequence source) { return CharSequences.codePoints(source); } /** * An alterative to With.in(CharSequence) that is better when it is likely that only a portion of the text will be * looked at, * such as when an iterator over codepoints is aborted partway. * * @param old * @return */ public static With codePoints(CharSequence... charSequences) { return new With().andCodePoints(charSequences); } /** * Create a simple object for use in for loops. Example: * *
     * for (String s : With.in(someIterator)) {
     *     doSomethingWith(s);
     * }
     * 
* * @param * @param iterator * @return Iterable, for use in for loops, etc. */ @SafeVarargs @SuppressWarnings("unchecked") public static With in(Iterator... iterators) { return new With().and(iterators); } /** * Create a simple object for use in for loops. Example: * *
     * for (String s : With.in(someIterator)) {
     *     doSomethingWith(s);
     * }
     * 
* * @param * @param iterator * @return Iterable, for use in for loops, etc. */ @SuppressWarnings("unchecked") public static With in(Iterable... iterables) { return new With().and(iterables); } /** * Create a simple object for use in for loops. Example: * *
     * for (String s : With.in(someIterator)) {
     *     doSomethingWith(s);
     * }
     * 
* * @param * @param iterator * @return Iterable, for use in for loops, etc. */ @SuppressWarnings("unchecked") public static With in(V... items) { return new With().and(items); } /** * Creates an iterable from a simple iterator. * * @param * @param old * @return */ @SuppressWarnings("unchecked") public static Iterable in(SimpleIterator... sources) { return new With().and(sources); } private With() { } @SuppressWarnings("unchecked") public With and(Iterator... iterators) { for (Iterator iterator : iterators) { this.iterators.add(iterator); } return this; } @SuppressWarnings("unchecked") public With and(V... items) { return and(Arrays.asList(items)); } @SuppressWarnings("unchecked") public With and(Iterable... iterables) { for (Iterable iterable : iterables) { this.iterators.add(iterable.iterator()); } return this; } @SuppressWarnings("unchecked") public With and(SimpleIterator... iterators) { for (SimpleIterator iterator : iterators) { this.iterators.add(new ToIterator(iterator)); } return this; } /** * Will fail if V is not a CharSequence. * * @param sources * @return */ public With andCodePoints(CharSequence... sources) { for (CharSequence charSequence : sources) { this.iterators .add((Iterator) new ToIterator(new CharSequenceSimpleIterator(charSequence))); } return this; } // new CharSequenceSimpleIterator(source) private static class CharSequenceSimpleIterator implements SimpleIterator { private int position; private CharSequence source; public CharSequenceSimpleIterator(CharSequence source) { this.source = source; } @Override public CharSequence next() { // TODO optimize if (position >= source.length()) { return null; } int codePoint = Character.codePointAt(source, position); position += Character.charCount(codePoint); return UTF16.valueOf(codePoint); } } public static Iterator toIterator(SimpleIterator simple) { return new ToIterator(simple); } public static Iterable toIterable(SimpleIterator simple) { return new ToIterator(simple); } public static ToSimpleIterator toSimpleIterator(Iterator iterator) { return new ToSimpleIterator(iterator); } private static class ToIterator implements Iterator, Iterable { private final SimpleIterator simpleIterator; private T current; /** * @param simpleIterator */ public ToIterator(SimpleIterator simpleIterator) { this.simpleIterator = simpleIterator; current = simpleIterator.next(); } @Override public boolean hasNext() { return current != null; } @Override public T next() { T result = current; current = simpleIterator.next(); return result; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public Iterator iterator() { return this; } } private static class ToSimpleIterator implements SimpleIterator { private final Iterator iterator; public ToSimpleIterator(Iterator iterator) { this.iterator = iterator; } @Override public T next() { return iterator.hasNext() ? iterator.next() : null; } } }