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;
}
}
}