diff --git a/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java b/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java index c8896ad222e2..0911b7c74fbb 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java @@ -68,6 +68,16 @@ public class TreeTraverserTest extends TestCase { } }; + private static final Function FIBONACCI2 = new JBIterable.StatefulTransform() { + int k0; + @Override + public Integer fun(Integer k) { + int t = k0; + k0 = k; + return t + k; + } + }; + @NotNull private static Condition LESS_THAN(final int max) { return new Condition() { @@ -90,6 +100,13 @@ public class TreeTraverserTest extends TestCase { // JBIterable ---------------------------------------------- + public void testAppend() { + JBIterable it = JBIterable.of(1, 2, 3).append(JBIterable.of(4, 5, 6)).append(7); + assertEquals(7, it.size()); + assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7), it.toList()); + assertTrue(it.contains(5)); + } + public void testGenerateRepeat() { JBIterable it = JBIterable.generate(1, INCREMENT).take(3).repeat(3); assertEquals(9, it.size()); @@ -137,6 +154,26 @@ public class TreeTraverserTest extends TestCase { } } + public void testStatefulFilter() { + JBIterable it = JBIterable.generate(1, INCREMENT).take(5).filter(new JBIterable.StatefulFilter() { + int prev; + @Override + public boolean value(Integer integer) { + boolean b = integer > prev; + if (b) prev = integer; + return b; + } + }); + assertEquals(Arrays.asList(1, 2, 3, 4, 5), it.toList()); + assertEquals(Arrays.asList(1, 2, 3, 4, 5), it.toList()); + } + + public void testStatefulGenerator() { + JBIterable it = JBIterable.generate(1, FIBONACCI2).take(8); + assertEquals(Arrays.asList(1, 1, 2, 3, 5, 8, 13, 21), it.toList()); + assertEquals(Arrays.asList(1, 1, 2, 3, 5, 8, 13, 21), it.toList()); + } + // TreeTraversal ---------------------------------------------- @NotNull diff --git a/platform/util/src/com/intellij/util/containers/JBIterable.java b/platform/util/src/com/intellij/util/containers/JBIterable.java index c2d34b994d58..f9d9c816d5ab 100644 --- a/platform/util/src/com/intellij/util/containers/JBIterable.java +++ b/platform/util/src/com/intellij/util/containers/JBIterable.java @@ -108,6 +108,7 @@ public abstract class JBIterable implements Iterable { return new JBIterable() { @Override public Iterator iterator() { + final Function fun = Stateful.copy(generator); return new JBIterator() { E cur = first; @@ -115,7 +116,7 @@ public abstract class JBIterable implements Iterable { public E nextImpl() { E result = cur; if (result == null) return stop(); - cur = generator.fun(cur); + cur = fun.fun(cur); return result; } }; @@ -228,14 +229,14 @@ public abstract class JBIterable implements Iterable { * {@code Iterator} supports it. */ public final JBIterable append(@Nullable Iterable other) { - return other == null ? this : this == EMPTY ? from(other) : from(ContainerUtil.concat(myIterable, other)); + return other == null ? this : this == EMPTY ? from(other) : of(myIterable, other).flatten(Functions., Iterable>identity()); } public final JBIterable append(@Nullable Iterable other, @NotNull Function> fun) { return other == null ? this : this == EMPTY ? from(other).flatten(fun) : append(from(other).flatten(fun)); } - public final JBIterable repeat(final int count) { + public final JBIterable repeat(int count) { Function, JBIterable> fun = Functions.identity(); return generate(this, fun).take(count).flatten(fun); } @@ -259,7 +260,7 @@ public abstract class JBIterable implements Iterable { return intercept(new Function, Iterator>() { @Override public Iterator fun(Iterator iterator) { - return JBIterator.from(iterator).filter(condition); + return JBIterator.from(iterator).filter(Stateful.copy(condition)); } }); } @@ -288,7 +289,7 @@ public abstract class JBIterable implements Iterable { return intercept(new Function, Iterator>() { @Override public Iterator fun(Iterator iterator) { - return JBIterator.from(iterator).takeWhile(condition); + return JBIterator.from(iterator).takeWhile(Stateful.copy(condition)); } }); } @@ -308,7 +309,7 @@ public abstract class JBIterable implements Iterable { return intercept(new Function, Iterator>() { @Override public Iterator fun(Iterator iterator) { - return JBIterator.from(iterator).skipWhile(condition); + return JBIterator.from(iterator).skipWhile(Stateful.copy(condition)); } }); } @@ -326,7 +327,7 @@ public abstract class JBIterable implements Iterable { return intercept(new Function, Iterator>() { @Override public Iterator fun(Iterator iterator) { - return JBIterator.from(iterator).transform(function); + return JBIterator.from(iterator).transform(Stateful.copy(function)); } }); } @@ -344,13 +345,14 @@ public abstract class JBIterable implements Iterable { return intercept(new Function, Iterator>() { @Override public Iterator fun(final Iterator iterator) { + final Function> fun = Stateful.copy(function); return new JBIterator() { Iterator cur; @Override public T nextImpl() { while ((cur == null || !cur.hasNext()) && iterator.hasNext()) { - cur = function.fun(iterator.next()).iterator(); + cur = fun.fun(iterator.next()).iterator(); } if (cur == null || !cur.hasNext()) return stop(); return cur.next(); @@ -456,4 +458,33 @@ public abstract class JBIterable implements Iterable { } return collection; } + + @SuppressWarnings("unchecked") + public abstract static class Stateful implements Cloneable { + + @NotNull + static T copy(@NotNull T o) { + if (!(o instanceof Stateful)) { + return o; + } + return (T)((Stateful)o).clone(); + } + + public Self clone() { + try { + return (Self)super.clone(); + } + catch (CloneNotSupportedException e) { + throw new AssertionError(e); + } + } + } + + public abstract static class StatefulFilter extends Stateful implements Condition { + + } + + public abstract static class StatefulTransform extends Stateful implements Function { + + } } diff --git a/platform/util/src/com/intellij/util/containers/JBIterator.java b/platform/util/src/com/intellij/util/containers/JBIterator.java index 1eee5d9898ae..ababafdf6474 100644 --- a/platform/util/src/com/intellij/util/containers/JBIterator.java +++ b/platform/util/src/com/intellij/util/containers/JBIterator.java @@ -68,7 +68,7 @@ public abstract class JBIterator implements Iterator { } private Object cur = INIT; - private final Op firstOp = new Op(); + private final Op firstOp = new Op(null); private Op lastOp = firstOp; protected abstract E nextImpl(); @@ -125,31 +125,21 @@ public abstract class JBIterator implements Iterator { } @NotNull - public final JBIterator transform(@NotNull final Function function) { - return addOp(new Op() { + public final JBIterator transform(@NotNull Function function) { + return addOp(new Op>(function) { @Override public Object apply(Object o) { - return function.fun((E)o); - } - - @Override - public String toString() { - return toShortString(function); + return impl.fun((E)o); } }); } @NotNull - public final JBIterator filter(@NotNull final Condition condition) { - return addOp(new Op() { + public final JBIterator filter(@NotNull Condition condition) { + return addOp(new Op>(condition) { @Override public Object apply(Object o) { - return condition.value((E)o) ? o : SKIP; - } - - @Override - public String toString() { - return toShortString(condition); + return impl.value((E)o) ? o : SKIP; } }); } @@ -160,16 +150,16 @@ public abstract class JBIterator implements Iterator { } @NotNull - public final JBIterator takeWhile(@NotNull final Condition condition) { - return addOp(new Op() { + public final JBIterator takeWhile(@NotNull Condition condition) { + return addOp(new Op>(condition) { @Override public Object apply(Object o) { - return condition.value((E)o) ? o : stop(); + return impl.value((E)o) ? o : stop(); } @Override public String toString() { - return "while:" + toShortString(condition); + return "takeWhile:" + super.toString(); } }); } @@ -181,7 +171,7 @@ public abstract class JBIterator implements Iterator { @NotNull public final JBIterator skipWhile(@NotNull final Condition condition) { - return addOp(new Op() { + return addOp(new Op>(condition) { boolean active = true; @@ -194,7 +184,7 @@ public abstract class JBIterator implements Iterator { @Override public String toString() { - return "skip:" + toShortString(condition); + return "skipWhile:" + super.toString(); } }); } @@ -218,13 +208,28 @@ public abstract class JBIterator implements Iterator { @Override public String toString() { - JBIterable ops = JBIterable.generate(firstOp.nextOp, new Function() { + JBIterable ops = operationsImpl(); + return "{cur=" + cur + "; ops[" + ops.size() + "]=" + ops + "}"; + } + + @NotNull + public JBIterable operations() { + return operationsImpl().transform(new Function() { + @Override + public Object fun(Op op) { + return op.impl; + } + }); + } + + @NotNull + private JBIterable operationsImpl() { + return JBIterable.generate(firstOp.nextOp, new Function() { @Override public Op fun(Op op) { return op.nextOp; } }); - return "{cur=" + cur + "; ops[" + ops.size() + "]=" + ops + "}"; } private static String toShortString(@NotNull Object o) { @@ -239,12 +244,22 @@ public abstract class JBIterator implements Iterator { } }; - private static class Op { + private static class Op { + final T impl; Op nextOp; + public Op(T impl) { + this.impl = impl; + } + Object apply(Object o) { throw new UnsupportedOperationException(); } + + @Override + public String toString() { + return impl == null ? "" : toShortString(impl); + } } private static class CountDown implements Condition {