JBIterable: stateful filters/transforms/generators clion/142.3917
authorGregory.Shrago <gregory.shrago@jetbrains.com>
Mon, 10 Aug 2015 12:58:06 +0000 (15:58 +0300)
committerGregory.Shrago <gregory.shrago@jetbrains.com>
Mon, 10 Aug 2015 13:20:23 +0000 (16:20 +0300)
JBIterator: ability to introspect operations

platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java
platform/util/src/com/intellij/util/containers/JBIterable.java
platform/util/src/com/intellij/util/containers/JBIterator.java

index c8896ad222e25389ca0726b70fd249e748383bea..0911b7c74fbbacb3a6aa4c274f6f80d48d771bc2 100644 (file)
@@ -68,6 +68,16 @@ public class TreeTraverserTest extends TestCase {
     }
   };
 
+  private static final Function<Integer, Integer> FIBONACCI2 = new JBIterable.StatefulTransform<Integer, Integer>() {
+    int k0;
+    @Override
+    public Integer fun(Integer k) {
+      int t = k0;
+      k0 = k;
+      return t + k;
+    }
+  };
+
   @NotNull
   private static Condition<Integer> LESS_THAN(final int max) {
     return new Condition<Integer>() {
@@ -90,6 +100,13 @@ public class TreeTraverserTest extends TestCase {
 
   // JBIterable ----------------------------------------------
 
+  public void testAppend() {
+    JBIterable<Integer> 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<Integer> 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<Integer> it = JBIterable.generate(1, INCREMENT).take(5).filter(new JBIterable.StatefulFilter<Integer>() {
+      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<Integer> 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
index c2d34b994d58d273756b57f1aab71794f775e4d7..f9d9c816d5ab4f83ff3bb190d6c1d57dfc4fdc4f 100644 (file)
@@ -108,6 +108,7 @@ public abstract class JBIterable<E> implements Iterable<E> {
     return new JBIterable<E>() {
       @Override
       public Iterator<E> iterator() {
+        final Function<? super E, ? extends E> fun = Stateful.copy(generator);
         return new JBIterator<E>() {
           E cur = first;
 
@@ -115,7 +116,7 @@ public abstract class JBIterable<E> implements Iterable<E> {
           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<E> implements Iterable<E> {
    * {@code Iterator} supports it.
    */
   public final JBIterable<E> append(@Nullable Iterable<? extends E> 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<?>, Iterable<E>>identity());
   }
 
   public final <T> JBIterable<E> append(@Nullable Iterable<T> other, @NotNull Function<? super T, ? extends Iterable<? extends E>> fun) {
     return other == null ? this : this == EMPTY ? from(other).flatten(fun) : append(from(other).flatten(fun));
   }
 
-  public final JBIterable<E> repeat(final int count) {
+  public final JBIterable<E> repeat(int count) {
     Function<JBIterable<E>, JBIterable<E>> fun = Functions.identity();
     return generate(this, fun).take(count).flatten(fun);
   }
@@ -259,7 +260,7 @@ public abstract class JBIterable<E> implements Iterable<E> {
     return intercept(new Function<Iterator<E>, Iterator<E>>() {
       @Override
       public Iterator<E> fun(Iterator<E> iterator) {
-        return JBIterator.from(iterator).filter(condition);
+        return JBIterator.from(iterator).filter(Stateful.copy(condition));
       }
     });
   }
@@ -288,7 +289,7 @@ public abstract class JBIterable<E> implements Iterable<E> {
     return intercept(new Function<Iterator<E>, Iterator<E>>() {
       @Override
       public Iterator<E> fun(Iterator<E> iterator) {
-        return JBIterator.from(iterator).takeWhile(condition);
+        return JBIterator.from(iterator).takeWhile(Stateful.copy(condition));
       }
     });
   }
@@ -308,7 +309,7 @@ public abstract class JBIterable<E> implements Iterable<E> {
     return intercept(new Function<Iterator<E>, Iterator<E>>() {
       @Override
       public Iterator<E> fun(Iterator<E> iterator) {
-        return JBIterator.from(iterator).skipWhile(condition);
+        return JBIterator.from(iterator).skipWhile(Stateful.copy(condition));
       }
     });
   }
@@ -326,7 +327,7 @@ public abstract class JBIterable<E> implements Iterable<E> {
     return intercept(new Function<Iterator<E>, Iterator<T>>() {
       @Override
       public Iterator<T> fun(Iterator<E> iterator) {
-        return JBIterator.from(iterator).transform(function);
+        return JBIterator.from(iterator).transform(Stateful.copy(function));
       }
     });
   }
@@ -344,13 +345,14 @@ public abstract class JBIterable<E> implements Iterable<E> {
     return intercept(new Function<Iterator<E>, Iterator<T>>() {
       @Override
       public Iterator<T> fun(final Iterator<E> iterator) {
+        final Function<? super E, ? extends Iterable<? extends T>> fun = Stateful.copy(function);
         return new JBIterator<T>() {
           Iterator<? extends T> 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<E> implements Iterable<E> {
     }
     return collection;
   }
+
+  @SuppressWarnings("unchecked")
+  public abstract static class Stateful<Self extends Stateful> implements Cloneable {
+
+    @NotNull
+    static <T> 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<T> extends Stateful<StatefulFilter> implements Condition<T> {
+
+  }
+
+  public abstract static class StatefulTransform<S, T> extends Stateful<StatefulTransform> implements Function<S, T> {
+
+  }
 }
index 1eee5d9898ae30d21296c8f35ab99e12d8a04039..ababafdf6474f845e812077e5c276ba462e6bc4a 100644 (file)
@@ -68,7 +68,7 @@ public abstract class JBIterator<E> implements Iterator<E> {
   }
 
   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<E> implements Iterator<E> {
   }
 
   @NotNull
-  public final <T> JBIterator<T> transform(@NotNull final Function<? super E, T> function) {
-    return addOp(new Op() {
+  public final <T> JBIterator<T> transform(@NotNull Function<? super E, T> function) {
+    return addOp(new Op<Function<? super E, T>>(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<E> filter(@NotNull final Condition<? super E> condition) {
-    return addOp(new Op() {
+  public final JBIterator<E> filter(@NotNull Condition<? super E> condition) {
+    return addOp(new Op<Condition<? super E>>(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<E> implements Iterator<E> {
   }
 
   @NotNull
-  public final JBIterator<E> takeWhile(@NotNull final Condition<? super E> condition) {
-    return addOp(new Op() {
+  public final JBIterator<E> takeWhile(@NotNull Condition<? super E> condition) {
+    return addOp(new Op<Condition<? super E>>(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<E> implements Iterator<E> {
 
   @NotNull
   public final JBIterator<E> skipWhile(@NotNull final Condition<? super E> condition) {
-    return addOp(new Op() {
+    return addOp(new Op<Condition<? super E>>(condition) {
 
       boolean active = true;
 
@@ -194,7 +184,7 @@ public abstract class JBIterator<E> implements Iterator<E> {
 
       @Override
       public String toString() {
-        return "skip:" + toShortString(condition);
+        return "skipWhile:" + super.toString();
       }
     });
   }
@@ -218,13 +208,28 @@ public abstract class JBIterator<E> implements Iterator<E> {
 
   @Override
   public String toString() {
-    JBIterable<Op> ops = JBIterable.generate(firstOp.nextOp, new Function<Op, Op>() {
+    JBIterable<Op> ops = operationsImpl();
+    return "{cur=" + cur + "; ops[" + ops.size() + "]=" + ops + "}";
+  }
+
+  @NotNull
+  public JBIterable<Object> operations() {
+    return operationsImpl().transform(new Function<Op, Object>() {
+      @Override
+      public Object fun(Op op) {
+        return op.impl;
+      }
+    });
+  }
+
+  @NotNull
+  private JBIterable<Op> operationsImpl() {
+    return JBIterable.generate(firstOp.nextOp, new Function<Op, Op>() {
       @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<E> implements Iterator<E> {
     }
   };
 
-  private static class Op {
+  private static class Op<T> {
+    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<A> implements Condition<A> {