DulcetAirman icon

Java 8 ZipperSpliterator from beta

DulcetAirman | PRO | 04/22/14 10:02:19 AM UTC | 0 ⭐ | 1368 👁️ | Never ⏰ | []
Java |

5.22 KB

|

None

|

0 👍

/

0 👎

// use any package you like!
package ch.claude-martin.zip;
 
import java.util.Objects;
import java.util.Spliterator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
 
/**
 * This code is from an early build of Java 8 Beta.
 * 
 * <p>
 * This was removed later and no zip function exists in the final Java 8 release: <a
 * href="http://hg.openjdk.java.net/lambda/lambda/jdk/rev/569088178418">changeset
 * 8789:569088178418.</a>
 * <p>
 * <a href="http://stackoverflow.com/questions/17640754">Discussion on Stackoverflow.</a>
 * 
 */
public final class StreamZipper {
  /** A very simple Pair that can be used to zip two streams. 
   * 
   *  @author Claude Martin */
  public static final class Pair<A, B> {
    /** First element. */
    public final A first;
    /** Second element. */
    public final B second;
 
    public Pair(A first, B second) {
      super();
      this.first = first;
      this.second = second;
    }
 
    /**
     * Scala-style getter for {@link #first}.
     * 
     * @see #first
     * @return the first element.
     */
    public A _1() {
      return this.first;
    }
 
    /**
     * Scala-style getter for {@link #second}.
     * 
     * @see #second
     * @return the second element.
     */
    public B _2() {
      return this.second;
    }
 
    /**
     * Applies the given function to both elements of this pair.
     * 
     * @see #uncurry(BiFunction)
     * @param <R>
     *          return type.
     * @param f
     *          A function on two elements.
     * @throws NullPointerException
     *           if f is null
     * @return The result of applying this pair to f.
     */
    public <R> R applyTo(final BiFunction<? super A, ? super B, R> f) {
      return f.apply(this.first, this.second);
    }
 
    @Override
    public int hashCode() {
      return Objects.hash(this.first, this.second);
    }
 
    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (!(obj instanceof Pair))
        return false;
      final Pair<?, ?> other = (Pair<?, ?>) obj;
      return Objects.equals(this.first, other.first) && Objects.equals(this.second, other.second);
    }
 
    /**
     * Creates an inverted pair.
     * <p>
     * <code>(a, b) &rarr; (b, a)</code>
     * 
     * @return <code>new Pair&lt;&gt;(this.second, this.first)</code>
     */
    public Pair<B, A> swap() {
      return new Pair<>(this.second, this.first);
    }
 
    /**
     * This Pair as an array so that first is on index 0 and second is on index 1.
     * 
     * @return <code>new Object[] { this.first, this.second };</code>
     */
    public Object[] toArray() {
      return new Object[] { this.first, this.second };
    }
 
    /**
     * Returns a string representation of this Pair.
     * 
     * @return "Pair(<i>first</i>, <i>second</i>)"
     */
    @Override
    public String toString() {
      return "Pair(" + this.first + ", " + this.second + ")";
    }
  }
 
  public static <A, B, C> Stream<C> zip(Stream<? extends A> a, Stream<? extends B> b,
      BiFunction<? super A, ? super B, ? extends C> zipper) {
    Objects.requireNonNull(zipper);
    @SuppressWarnings("unchecked")
    Spliterator<A> as = (Spliterator<A>) Objects.requireNonNull(a).spliterator();
    @SuppressWarnings("unchecked")
    Spliterator<B> bs = (Spliterator<B>) Objects.requireNonNull(b).spliterator();
    // Combining loses DISTINCT and SORTED characteristics and for other
    // characteristics the combined stream has a characteristic if both
    // streams to combine have the characteristic
    int characteristics = as.characteristics() & bs.characteristics()
        & ~(Spliterator.DISTINCT | Spliterator.SORTED);
    long size = Math.min(as.estimateSize(), bs.estimateSize());
    Spliterator<C> cs = new ZipperSpliterator<>(as, bs, zipper, size, characteristics);
    return StreamSupport.stream(cs, a.isParallel() || b.isParallel());
  }
 
  final static Object NONE = new Object();
 
  private static final class ZipperSpliterator<A, B, C> extends
      java.util.Spliterators.AbstractSpliterator<C> implements Consumer<Object> {
    final Spliterator<A> as;
    final Spliterator<B> bs;
    final BiFunction<? super A, ? super B, ? extends C> zipper;
    Object a;
    Object b;
 
    ZipperSpliterator(Spliterator<A> as, Spliterator<B> bs,
        BiFunction<? super A, ? super B, ? extends C> zipper, long est,
        int additionalCharacteristics) {
      super(est, additionalCharacteristics);
      this.as = as;
      this.bs = bs;
      this.zipper = zipper;
      this.a = NONE;
    }
 
    @Override
    public void accept(Object aOrB) {
      if (this.a == NONE) {
        this.a = aOrB;
      } else {
        this.b = aOrB;
      }
    }
 
    @Override
    @SuppressWarnings("unchecked")
    public boolean tryAdvance(Consumer<? super C> action) {
      if (this.as.tryAdvance(this) && this.bs.tryAdvance(this)) {
        Object _a = this.a;
        this.a = NONE;
        action.accept(this.zipper.apply((A) _a, (B) this.b));
        return true;
      }
      return false;
    }
  }
}

Comments