FP stuff refactored and extended

This commit is contained in:
Dmitry Cheryasov
2009-11-29 05:03:33 +02:00
parent d30e10f60f
commit 570d449a23
9 changed files with 733 additions and 41 deletions
@@ -112,10 +112,10 @@ public class PyAssignmentStatementImpl extends PyElementImpl implements PyAssign
}
else if (lhs_tuple != null && rhs_target != null) { // multiple LHS, single RHS: unpacking
//for (PyExpression tuple_elt : lhs_tuple.getElements()) map.add(new Pair<PyExpression, PyExpression>(tuple_elt, rhs_target));
map.addAll(FP.zip(lhs_tuple, new RepeatIterable<PyExpression>(rhs_target)));
map.addAll(FP.zipList(lhs_tuple, new RepeatIterable<PyExpression>(rhs_target)));
}
else if (lhs_tuple != null && rhs_tuple != null) { // multiple both sides: piecewise mapping
map.addAll(FP.zip(lhs_tuple, rhs_tuple, null, null));
map.addAll(FP.zipList(lhs_tuple, rhs_tuple, null, null));
}
}
@@ -0,0 +1,97 @@
package com.jetbrains.python.toolbox;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
/**
* Iterable that splices other iterables and iterates over them sequentially.
* User: dcheryasov
* Date: Nov 20, 2009 8:01:23 AM
*/
public class ChainIterable<T> extends ChainedListBase<Iterable<T>> implements Iterable<T> {
public ChainIterable(@Nullable Iterable<T> initial) {
super(initial);
}
public ChainIterable() {
super(null);
}
public ChainIterable<T> add(Iterable<T> another) {
return (ChainIterable<T>)super.add(another);
}
/**
* Apply wrapper to another and add the result. Convenience to avoid cluttering code with apply() calls.
* @param wrapper
* @param another
* @return
*/
public ChainIterable<T> addWith(FP.Lambda1<Iterable<T>, Iterable<T>> wrapper, Iterable<T> another) {
return (ChainIterable<T>)super.add(wrapper.apply(another));
}
/**
* Convenience: add an item wrapping it into a SingleIterable behind the scenes.
*/
public ChainIterable<T> add(T item) {
return (ChainIterable<T>)super.add(new SingleIterable<T>(item));
}
/**
* Convenience, works without ever touching an iterator.
* @return true if the chain contains at least one iterable (but all iterables in the chain may happen to be empty).
*/
public boolean isEmpty() {
return (myPayload == null);
}
public Iterator<T> iterator() {
class IterMixedIn extends ChainIterationMixin<T, Iterable<T>> {
IterMixedIn(ChainedListBase<Iterable<T>> link) {
super(link);
}
@Override
public Iterator<T> toIterator(Iterable<T> first) {
return first.iterator();
}
}
final IterMixedIn mixin = new IterMixedIn(this);
class Iter extends ChainedListBase<Iterable<T>> implements Iterator<T> {
Iter(ChainedListBase<Iterable<T>> piggybacked) {
super(piggybacked.myPayload);
myNext = piggybacked.myNext;
}
public boolean hasNext() {
return mixin.hasNext();
}
public void remove() {
throw new UnsupportedOperationException(); // we don't remove things
}
public T next() {
return (T)mixin.next();
}
}
return new Iter(this);
}
@Override
public String toString() {
return FP.fold(new FP.StringCollector<T>(), this, new StringBuilder()).toString();
}
}
@@ -0,0 +1,52 @@
package com.jetbrains.python.toolbox;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Common logic of chain iterators.
* User: dcheryasov
* Date: Nov 20, 2009 9:10:39 AM
*/
/* explicitly not public */
abstract class ChainIterationMixin<T, TPayload> {
protected ChainedListBase<TPayload> myLink; // link of the chain we're currently at
protected Iterator<T> myCurrent;
public ChainIterationMixin(ChainedListBase<TPayload> link) {
myLink = link;
}
abstract public Iterator<T> toIterator(TPayload first);
// returns either null or a non-exhausted iterator.
@Nullable
public Iterator<T> getCurrent() {
while ((myCurrent == null || !myCurrent.hasNext()) && myLink.hasPayload()) { // fix myCurrent
if (myCurrent == null) {
myCurrent = toIterator(myLink.myPayload);
assert myCurrent != null;
}
else {
myLink.moveOn();
myCurrent = null;
}
}
return myCurrent;
}
public boolean hasNext() {
Iterator<T> current = getCurrent();
return (current != null);
}
public T next() {
Iterator<T> current = getCurrent();
if (current != null) return current.next();
else throw new NoSuchElementException();
}
}
@@ -0,0 +1,54 @@
package com.jetbrains.python.toolbox;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
/**
* An iterator that combines several other iterators and exhaust them one by one, in chain.
* User: dcheryasov
* Date: Nov 19, 2009 3:49:38 AM
*/
public class ChainIterator<T> extends ChainedListBase<Iterator<T>> implements Iterator<T> {
private ChainIterationMixin<T, Iterator<T>> myMixin;
/**
* Creates new instance.
* @param initial initial iterator. If null, the new iterator is empty, use {@link #add} to add initial content.
*/
public ChainIterator(@Nullable Iterator<T> initial) {
super(initial);
myMixin = new ChainIterationMixin<T, Iterator<T>>(this) {
@Override
public Iterator<T> toIterator(Iterator<T> first) {
return first;
}
};
}
/**
* Adds another iterator to the chain. Values from this iterator will follow the values of the iterator passed to the constructor.
* Adding after the iteration has started is safe.
* @param another iterator to add to the end of the chain.
* @return self, for easy chaining.
*/
public ChainIterator<T> add(Iterator<T> another) {
return (ChainIterator<T>)super.add(another);
}
public boolean hasNext() {
return myMixin.hasNext();
}
public T next() {
return myMixin.next();
}
public void remove() {
throw new UnsupportedOperationException("Cannot remove from ChainIterator");
}
}
@@ -0,0 +1,52 @@
package com.jetbrains.python.toolbox;
/**
* Linked list to base chain iterators an iterables on.
* User: dcheryasov
* Date: Nov 20, 2009 9:43:02 AM
*/
public /*abstract */class ChainedListBase<TPayload> {
protected TPayload myPayload;
protected ChainedListBase<TPayload> myNext;
protected ChainedListBase(TPayload initial) {
myPayload = initial;
}
/**
* Wrap payload into a new linked list element.
* @param payload
* @return
*/
/*
abstract protected ChainedListBase<TPayload> createInstance(TPayload payload);
*/
/**
* Add another element to the end of our linked list
* @param another
* @return
*/
protected ChainedListBase<TPayload> add(TPayload another) {
if (myPayload == null) myPayload = another;
else {
ChainedListBase<TPayload> farthest = this;
while (farthest.myNext != null) farthest = farthest.myNext;
farthest.myNext = /*createInstance*/new ChainedListBase<TPayload>(another);
}
return this;
}
// become to our next
public void moveOn() {
if (myNext != null) {
myPayload = myNext.myPayload;
myNext = myNext.myNext;
}
else myPayload = null; // position 'after the end'
}
public boolean hasPayload() {
return myPayload != null;
}
}
+158 -37
View File
@@ -4,41 +4,81 @@ import com.intellij.openapi.util.Pair;
import com.jetbrains.python.PythonDocumentationProvider;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.*;
/**
* Tools of functional programming, the notorious half of implementation of Lisp.
* Tools of functional programming, the notorious half of implementation of Lisp. (And sometimes a shard or two of Haskell.)
* User: dcheryasov
* Date: Nov 6, 2009 10:06:50 AM
*/
public class FP {
private FP() {
// do not instantiate
}
/**
* [a, b,..] -> [lambda(a), lambda(b),...]
* Action is lazy: function is applied to source items only as soon as values are extracted from the resulting iterable.
* @param lambda function to apply
* @param source list to process
* @param <S> type of source elements
* @param <R> type of result elements
* @return list of mapped values.
*/
@NotNull
public static <S, R> List<R> map(@NotNull Lambda1<S, R> lambda, @NotNull List<S> source) {
List<R> ret = new ArrayList<R>(source.size());
for (S item : source) ret.add(lambda.apply(item));
public static <S, R> Iterable<R> map(@NotNull final Lambda1<S, R> lambda, @NotNull final Iterable<S> source) {
return new Iterable<R>() {
final Iterator<S> feeder = source.iterator();
public Iterator<R> iterator() {
return new Iterator<R>() {
public boolean hasNext() {
return feeder.hasNext();
}
public R next() {
return lambda.apply(feeder.next());
}
public void remove() {
throw new UnsupportedOperationException("Cannot remove from map()");
}
};
}
};
}
/**
* Convenience form of {@link #map(Lambda1, Iterable)}.
*/
@NotNull
public static <S, R> Iterable<R> map(@NotNull final Lambda1<S, R> lambda, @NotNull final S[] source) {
return map(lambda, Arrays.asList(source));
}
/**
* Same as {@link #map}, but non-lazy an returns a modifiable List.
*/
public static <S, R> List<R> mapList(@NotNull final Lambda1<S, R> lambda, @NotNull final Iterable<S> source) {
List<R> ret = new ArrayList<R>(source instanceof Collection? ((Collection)source).size() : 10);
for (R what : map(lambda, source)) ret.add(what);
return ret;
}
/**
* Apply a two-argument lambda to each sequence element and an accumulator.
* @param lambda function to apply; accumulator is the first parameter, sequence item is the second
* @param source sequence to process
* @param unit initial value of the accumulator (like the initial 0 for summing)
* @param <ItemT> type of items in the list
* @param <AccT> 'accumulator' type; can be same as ItemT, or reasonably different (consider ItemT=String and AccT=StringBuilder)
* @return value of the accumulator after all the list is processed.
*/
public static <R> R fold(@NotNull Lambda2<R, R, R> lambda, @NotNull Iterable<R> source, @NotNull final R unit) {
R ret = unit;
for (R item : source) ret = lambda.apply(ret, item);
public static <AccT, ItemT> AccT fold(@NotNull Lambda2<AccT, ItemT, AccT> lambda, @NotNull Iterable<ItemT> source, @NotNull final AccT unit) {
AccT ret = unit;
for (ItemT item : source) ret = lambda.apply(ret, item);
return ret;
}
@@ -47,63 +87,94 @@ public class FP {
* @param lambda function to apply; sequence item is the first parameter, accumulator is the second
* @param source sequence to process
* @param unit initial value of the accumulator (like the initial 0 for summing)
* @return value of the accumulator after all the sequence is processed.
* @param <ItemT> type of items in the list
* @param <AccT> 'accumulator' type
* @return value of the accumulator after all the list is processed.
*/
public static <R> R foldr(@NotNull Lambda2<R, R, R> lambda, @NotNull Iterable<R> source, @NotNull final R unit) {
R ret = unit;
for (R item : source) ret = lambda.apply(item, ret);
public static <AccT, ItemT> AccT foldr(@NotNull Lambda2<ItemT, AccT, AccT> lambda, @NotNull Iterable<ItemT> source, @NotNull final AccT unit) {
AccT ret = unit;
for (ItemT item : source) ret = lambda.apply(item, ret);
return ret;
}
/**
* Zips together two sequences: [a, b,..] + [x, y,..] -> [(a, x), (b, y),..].
* If sequences are of different length, uses up the shortest of the sequences; the rest of the longer sequence is unused.
* The action is lazy: either iterable is only accessed as many times as the result.
* @param one source of first elements
* @param two source of second elements, possibly shorter
* @return list of pairs of elements
*/
public static <R1, R2> List<Pair<R1, R2>> zip(Iterable<R1> one, Iterable<R2> two) {
public static <R1, R2> Iterable<Pair<R1, R2>> zip(Iterable<R1> one, Iterable<R2> two) {
return zipInternal(one, two, null, null, false, false);
}
/**
* Same as {@link #zip(Iterable, Iterable)}, but non-lazy and returns a modifiable List.
*/
public static <R1, R2> List<Pair<R1, R2>> zipList(Iterable<R1> one, Iterable<R2> two) {
List<Pair<R1, R2>> ret = new ArrayList<Pair<R1, R2>>(proposeZippedListLength(one, two, false, false));
for (Pair<R1, R2>what : zipInternal(one, two, null, null, false, false)) ret.add(what);
return ret;
}
/**
* Zips together two sequences: [a, b,..] + [x, y,..] -> [(a, x), (b, y),..]. Fills missing second elements with filler.
* Always uses up entire sequence one; if sequence two is longer, part of it is unused.
* The action is lazy: either iterable is only accessed as many times as the result.
* @param one source of first elements
* @param two source of second elements, possibly shorter
* @param filler value to use instead of elements of sequence two if it is shorter than sequence one
* @return list of pairs of elements
*/
public static <R1, R2> List<Pair<R1, R2>> zip(Iterable<R1> one, Iterable<R2> two, R2 filler) {
public static <R1, R2> Iterable<Pair<R1, R2>> zip(Iterable<R1> one, Iterable<R2> two, R2 filler) {
return zipInternal(one, two, null, filler, false, true);
}
/**
* Same as {@link #zip(Iterable, Iterable, Object)}, but non-lazy and returns a modifiable List.
*/
public static <R1, R2> List<Pair<R1, R2>> zipList(Iterable<R1> one, Iterable<R2> two, R2 filler) {
List<Pair<R1, R2>> ret = new ArrayList<Pair<R1, R2>>(proposeZippedListLength(one, two, false, true));
for (Pair<R1, R2>what : zipInternal(one, two, null, filler, false, true)) ret.add(what);
return ret;
}
/**
* Zips together two sequences: [a, b,..] + [x, y,..] -> [(a, x), (b, y),..]. Fills all missing elements with filler.
* Always uses up both sequences, using the appropriate filler for elements of the shorter sequences.
* The action is lazy: either iterable is only accessed as many times as the result.
* @param one sequences of first elements
* @param two sequences of second elements, possibly shorter
* @param filler1 value to use instead of elements of sequences one if it is shorter than list two
* @param filler2 value to use instead of elements of sequences two if it is shorter than list one
* @return list of pairs of elements
*/
public static <R1, R2> List<Pair<R1, R2>> zip(Iterable<R1> one, Iterable<R2> two, R1 filler1, R2 filler2) {
public static <R1, R2> Iterable<Pair<R1, R2>> zip(Iterable<R1> one, Iterable<R2> two, R1 filler1, R2 filler2) {
return zipInternal(one, two, filler1, filler2, true, true);
}
/**
* Zips two lists.
* @param one first elements
* @param two second elements
* @param filler1 to fill missing first elements
* @param filler2 to fill missing second elements
* @param fill1 use filler1 if list one is too short
* @param fill2 use filler2 if list two is too short
* @return zipped list
* Same as {@link #zip(Iterable, Iterable, Object, Object)}, but non-lazy and returns a modifiable List.
*/
private static <R1, R2> List<Pair<R1, R2>> zipInternal(Iterable<R1> one, Iterable<R2> two, R1 filler1, R2 filler2, boolean fill1, boolean fill2) {
// a boring premature optimization which tries to preallocate an array list of exactly the right size
public static <R1, R2> List<Pair<R1, R2>> zipList(Iterable<R1> one, Iterable<R2> two, R1 filler1, R2 filler2) {
List<Pair<R1, R2>> ret = new ArrayList<Pair<R1, R2>>(proposeZippedListLength(one, two, true, true));
for (Pair<R1, R2>what : zipInternal(one, two, filler1, filler2, true, true)) ret.add(what);
return ret;
}
/**
* Tries to determine the size of an array list of exactly the right size to accommodate
* the result of {@link #zip(Iterable, Iterable, Object, Object)}.
* @param one first iterbale
* @param two second iterable
* @param fill1 true if padding of iterable one is required
* @param fill2 true if padding of iterable two is required
* @return size, if it can be determined, or 10 (which is the default size of ArrayList).
*/
public static int proposeZippedListLength(Iterable one, Iterable two, boolean fill1, boolean fill2) {
int size1 = 0;
int size2 = 0;
int approx_size = 0;
@@ -114,14 +185,53 @@ public class FP {
if (fill1 && !fill2) approx_size = size1;
if (!fill1 && fill2) approx_size = size2;
if (approx_size == 0) approx_size = 10;
List<Pair<R1, R2>> ret = new ArrayList<Pair<R1, R2>>(approx_size);
// the gist
Iterator<R1> one_iter = one.iterator();
Iterator<R2> two_iter = two.iterator();
while (one_iter.hasNext() && two_iter.hasNext()) ret.add(new Pair<R1, R2>(one_iter.next(), two_iter.next()));
while (fill1 && two_iter.hasNext()) ret.add(new Pair<R1, R2>(filler1, two_iter.next()));
while (fill2 && one_iter.hasNext()) ret.add(new Pair<R1, R2>(one_iter.next(), filler2));
return ret;
return approx_size;
}
/**
* Zips two lists.
* @param one first elements
* @param two second elements
* @param filler1 to fill missing first elements
* @param filler2 to fill missing second elements
* @param fill1 use filler1 if list one is too short
* @param fill2 use filler2 if list two is too short
* @return zipped list
*/
private static <R1, R2> Iterable<Pair<R1, R2>> zipInternal(
Iterable<R1> one, Iterable<R2> two, final R1 filler1, final R2 filler2, final boolean fill1, final boolean fill2
) {
final Iterator<R1> one_iter = one.iterator();
final Iterator<R2> two_iter = two.iterator();
return new Iterable<Pair<R1, R2>>() {
public Iterator<Pair<R1, R2>> iterator() {
return new Iterator<Pair<R1, R2>>() {
public void remove() {
throw new UnsupportedOperationException("Cannot remove from zip()");
}
public boolean hasNext() {
final boolean one_has = one_iter.hasNext();
final boolean two_has = two_iter.hasNext();
return (
one_has && two_has ||
fill1 && two_has ||
fill2 && one_has
);
}
public Pair<R1, R2> next() {
if (one_iter.hasNext() && two_iter.hasNext()) return new Pair<R1, R2>(one_iter.next(), two_iter.next());
if (fill1 && two_iter.hasNext()) return new Pair<R1, R2>(filler1, two_iter.next());
if (fill2 && one_iter.hasNext()) return new Pair<R1, R2>(one_iter.next(), filler2);
throw new NoSuchElementException();
}
};
}
};
}
/**
@@ -153,4 +263,15 @@ public class FP {
public interface Lambda2<A1, A2, R> {
R apply(A1 arg1, A2 arg2);
}
/**
* Useful for {@link FP#fold(Lambda2, Iterable, Object) fold}ing into a string. Element's {@code .toString()} is appended to the string builder.
*/
public static class StringCollector<T> implements FP.Lambda2<StringBuilder, T, StringBuilder> {
public StringBuilder apply(StringBuilder builder, T arg2) {
return builder.append(arg2.toString());
}
}
}
@@ -8,12 +8,12 @@ import java.util.NoSuchElementException;
* User: dcheryasov
* Date: Nov 6, 2009 9:57:41 AM
*/
class SingleIterator<T> implements Iterator<T> {
public class SingleIterator<T> implements Iterator<T> {
boolean expired;
private T content;
SingleIterator(T content) {
public SingleIterator(T content) {
this.content = content;
expired = false;
}
@@ -0,0 +1,89 @@
package com.jetbrains.python.toolbox;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* Tests basic FP stuff.
* User: dcheryasov
* Date: Nov 20, 2009 6:46:25 AM
*/
public class FPTest extends TestCase {
public void testMap() {
List<String> sequence = Arrays.asList("a", "b", "c");
FP.Lambda1<String, String> func = new FP.Lambda1<String, String>() {
public String apply(String arg) {
return arg.toUpperCase();
}
};
int count = 0;
for (String what : FP.map(func, sequence)) {
assertEquals(sequence.get(count).toUpperCase(), what);
count += 1;
}
assertEquals(sequence.size(), count);
}
public void testMapEmpty() {
List<String> sequence = Arrays.asList();
FP.Lambda1<String, String> func = new FP.Lambda1<String, String>() {
public String apply(String arg) {
return arg.toUpperCase();
}
};
int count = 0;
for (String what : FP.map(func, sequence)) {
count += 1; // this never happens
}
assertEquals(sequence.size(), count);
}
public void testMapLazy() {
List<Float> sequence = Arrays.asList(1.0f, 2.0f, 3.0f, 0.0f);
FP.Lambda1<Float, Float> func = new FP.Lambda1<Float, Float>() {
public Float apply(Float arg) {
return 1.0f/arg;
}
};
int count = 0;
Iterator<Float> iterator = FP.map(func, sequence).iterator();
while (iterator.hasNext() && count < 3) { // func is applied on the fly and will not be calculated for 4th arg
iterator.next();
count += 1;
}
assertEquals(3, count);
}
public void testFold() {
List<String> sequence = Arrays.asList("a", "b", "c");
FP.Lambda2<StringBuilder, String, StringBuilder> adder = new FP.Lambda2<StringBuilder, String, StringBuilder>() {
public StringBuilder apply(StringBuilder builder, String arg2) {
return builder.append(arg2);
}
};
StringBuilder result = FP.fold(adder, sequence, new StringBuilder());
assertEquals("abc", result.toString());
}
public void testFoldr() {
List<String> sequence = Arrays.asList("a", "b", "c");
FP.Lambda2<String, String, String> adder = new FP.Lambda2<String, String, String>() {
public String apply(String left, String right) {
return left + right;
}
};
String result = FP.foldr(adder, sequence, "");
assertEquals("cba", result);
}
}
@@ -0,0 +1,227 @@
package com.jetbrains.python.toolbox;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Tests all iterators and iterables.
* User: dcheryasov
* Date: Nov 20, 2009 3:42:51 AM
*/
public class IteratorsTest extends TestCase {
public IteratorsTest() {
super();
}
public void testSingleIterable() {
final String value = "foo";
int count = 0;
SingleIterable<String> tested = new SingleIterable<String>(value);
for (String what : tested) {
assertEquals(value, what);
count += 1;
}
assertEquals(1, count);
}
public void testArrayIterable() {
final String[] values = {"foo", "bar", "baz"};
int count = 0;
ArrayIterable<String> tested = new ArrayIterable<String>(values);
for (String what : tested) {
assertEquals(values[count], what);
count += 1;
}
assertEquals(values.length, count);
}
public void testArrayIterableEmpty() {
final String[] values = {};
int count = 0;
ArrayIterable<String> tested = new ArrayIterable<String>(values);
for (String what : tested) {
count += 1;
}
assertEquals(values.length, count);
}
public void testRepeatIterable() {
String value = "foo";
RepeatIterable<String> tested = new RepeatIterable<String>(value);
int count = 0;
int times = 10;
for (String what : tested) {
assertEquals(value, what);
count += 1;
if (count >= times) break;
}
assertEquals(times, count);
}
public void testChainIterableByLists() {
List<String> list1 = Arrays.asList("foo", "bar", "baz");
List<String> list2 = Arrays.asList("ichi", "ni", "san");
List<String> list3 = Arrays.asList("a", "s", "d", "f");
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterable<String> tested = new ChainIterable<String>(list1).add(list2).add(list3);
int count = 0;
for (String what : tested) {
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIterableEmptyFirst() {
List<String> list1 = Arrays.asList();
List<String> list2 = Arrays.asList("ichi", "ni", "san");
List<String> list3 = Arrays.asList("a", "s", "d", "f");
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterable<String> tested = new ChainIterable<String>(list1).add(list2).add(list3);
int count = 0;
for (String what : tested) {
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIterableEmptyLast() {
List<String> list1 = Arrays.asList("foo", "bar", "baz");
List<String> list2 = Arrays.asList("ichi", "ni", "san");
List<String> list3 = Arrays.asList();
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterable<String> tested = new ChainIterable<String>(list1).add(list2).add(list3);
int count = 0;
for (String what : tested) {
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIterableEmptyMiddle() {
List<String> list1 = Arrays.asList("foo", "bar", "baz");
List<String> list2 = Arrays.asList();
List<String> list3 = Arrays.asList("a", "s", "d", "f");
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterable<String> tested = new ChainIterable<String>(list1).add(list2).add(list3);
int count = 0;
for (String what : tested) {
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIteratorBySingles() {
final String[] values = {"foo", "bar", "baz"};
SingleIterator<String> zero = new SingleIterator<String>(values[0]);
SingleIterator<String> one = new SingleIterator<String>(values[1]);
SingleIterator<String> two = new SingleIterator<String>(values[2]);
ChainIterator<String> tested = new ChainIterator<String>(zero).add(one).add(two);
int count = 0;
String what;
while (tested.hasNext()) {
what = tested.next();
assertEquals(values[count], what);
count += 1;
}
assertEquals(values.length, count);
}
public void testChainIteratorByLists() {
List<String> list1 = Arrays.asList("foo", "bar", "baz");
List<String> list2 = Arrays.asList("ichi", "ni", "san");
List<String> list3 = Arrays.asList("a", "s", "d", "f");
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterator<String> tested = new ChainIterator<String>(list1.iterator()).add(list2.iterator()).add(list3.iterator());
int count = 0;
String what;
while (tested.hasNext()) {
what = tested.next();
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIteratorEmptyFirst() {
List<String> list1 = Arrays.asList();
List<String> list2 = Arrays.asList("ichi", "ni", "san");
List<String> list3 = Arrays.asList("a", "s", "d", "f");
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterator<String> tested = new ChainIterator<String>(list1.iterator()).add(list2.iterator()).add(list3.iterator());
int count = 0;
String what;
while (tested.hasNext()) {
what = tested.next();
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIteratorEmptyLast() {
List<String> list1 = Arrays.asList("foo", "bar", "baz");
List<String> list2 = Arrays.asList("ichi", "ni", "san");
List<String> list3 = Arrays.asList();
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterator<String> tested = new ChainIterator<String>(list1.iterator()).add(list2.iterator()).add(list3.iterator());
int count = 0;
String what;
while (tested.hasNext()) {
what = tested.next();
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
public void testChainIteratorEmptyMiddle() {
List<String> list1 = Arrays.asList("foo", "bar", "baz");
List<String> list2 = Arrays.asList();
List<String> list3 = Arrays.asList("a", "s", "d", "f");
List<String> all = new ArrayList<String>();
all.addAll(list1);
all.addAll(list2);
all.addAll(list3);
ChainIterator<String> tested = new ChainIterator<String>(list1.iterator()).add(list2.iterator()).add(list3.iterator());
int count = 0;
String what;
while (tested.hasNext()) {
what = tested.next();
assertEquals(all.get(count), what);
count += 1;
}
assertEquals(all.size(), count);
}
}