mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
FP stuff refactored and extended
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user