All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.emul.java.util.stream.StreamImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package java.util.stream;

import static javaemul.internal.InternalPreconditions.checkNotNull;
import static javaemul.internal.InternalPreconditions.checkState;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.Spliterators.AbstractDoubleSpliterator;
import java.util.Spliterators.AbstractIntSpliterator;
import java.util.Spliterators.AbstractLongSpliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.LongConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;

/**
 * Main implementation of Stream, wrapping a single spliterator and an optional parent stream.
 */
final class StreamImpl extends TerminatableStream> implements Stream {

  /**
   * Represents an empty stream, doing nothing for all methods.
   */
  static class Empty extends TerminatableStream> implements Stream {

    public Empty(TerminatableStream previous) {
      super(previous);
    }

    @Override
    public Stream filter(Predicate predicate) {
      throwIfTerminated();
      return this;
    }

    @Override
    public  Stream map(Function mapper) {
      throwIfTerminated();
      return (Stream) this;
    }

    @Override
    public IntStream mapToInt(ToIntFunction mapper) {
      throwIfTerminated();
      return new IntStreamImpl.Empty(this);
    }

    @Override
    public LongStream mapToLong(ToLongFunction mapper) {
      throwIfTerminated();
      return new LongStreamImpl.Empty(this);
    }

    @Override
    public DoubleStream mapToDouble(ToDoubleFunction mapper) {
      throwIfTerminated();
      return new DoubleStreamImpl.Empty(this);
    }

    @Override
    public  Stream flatMap(Function> mapper) {
      throwIfTerminated();
      return (Stream) this;
    }

    @Override
    public IntStream flatMapToInt(Function mapper) {
      throwIfTerminated();
      return new IntStreamImpl.Empty(this);
    }

    @Override
    public LongStream flatMapToLong(Function mapper) {
      throwIfTerminated();
      return new LongStreamImpl.Empty(this);
    }

    @Override
    public DoubleStream flatMapToDouble(Function mapper) {
      throwIfTerminated();
      return new DoubleStreamImpl.Empty(this);
    }

    @Override
    public Stream distinct() {
      throwIfTerminated();
      return this;
    }

    @Override
    public Stream sorted() {
      throwIfTerminated();
      return this;
    }

    @Override
    public Stream sorted(Comparator comparator) {
      throwIfTerminated();
      return this;
    }

    @Override
    public Stream peek(Consumer action) {
      throwIfTerminated();
      return this;
    }

    @Override
    public Stream limit(long maxSize) {
      throwIfTerminated();
      checkState(maxSize >= 0, "maxSize may not be negative");
      return this;
    }

    @Override
    public Stream skip(long n) {
      throwIfTerminated();
      checkState(n >= 0, "n may not be negative");
      return this;
    }

    @Override
    public void forEach(Consumer action) {
      terminate();
      // nothing to do
    }

    @Override
    public void forEachOrdered(Consumer action) {
      terminate();
      // nothing to do
    }

    @Override
    public Object[] toArray() {
      terminate();
      return new Object[0];
    }

    @Override
    public  A[] toArray(IntFunction generator) {
      terminate();
      return generator.apply(0);
    }

    @Override
    public T reduce(T identity, BinaryOperator accumulator) {
      terminate();
      return identity;
    }

    @Override
    public Optional reduce(BinaryOperator accumulator) {
      terminate();
      return Optional.empty();
    }

    @Override
    public  U reduce(
        U identity, BiFunction accumulator, BinaryOperator combiner) {
      terminate();
      return identity;
    }

    @Override
    public  R collect(
        Supplier supplier, BiConsumer accumulator, BiConsumer combiner) {
      terminate();
      return supplier.get();
    }

    @Override
    public  R collect(Collector collector) {
      terminate();
      return collector.finisher().apply(collector.supplier().get());
    }

    @Override
    public Optional min(Comparator comparator) {
      terminate();
      return Optional.empty();
    }

    @Override
    public Optional max(Comparator comparator) {
      terminate();
      return Optional.empty();
    }

    @Override
    public long count() {
      terminate();
      return 0;
    }

    @Override
    public boolean anyMatch(Predicate predicate) {
      terminate();
      return false;
    }

    @Override
    public boolean allMatch(Predicate predicate) {
      terminate();
      return true;
    }

    @Override
    public boolean noneMatch(Predicate predicate) {
      terminate();
      return true;
    }

    @Override
    public Optional findFirst() {
      terminate();
      return Optional.empty();
    }

    @Override
    public Optional findAny() {
      terminate();
      return Optional.empty();
    }

    @Override
    public Iterator iterator() {
      terminate();
      return Collections.emptyIterator();
    }

    @Override
    public Spliterator spliterator() {
      terminate();
      return Spliterators.emptySpliterator();
    }

    @Override
    public boolean isParallel() {
      throwIfTerminated();
      return false;
    }

    @Override
    public Stream sequential() {
      throwIfTerminated();
      return this;
    }

    @Override
    public Stream parallel() {
      throwIfTerminated();
      return this;
    }

    @Override
    public Stream unordered() {
      throwIfTerminated();
      return this;
    }
  }

  /**
   * Object to Object map spliterator.
   *
   * @param  the input type
   * @param  the output type
   */
  private static final class MapToObjSpliterator extends Spliterators.AbstractSpliterator {
    private final Function map;
    private final Spliterator original;

    public MapToObjSpliterator(Function map, Spliterator original) {
      super(
          original.estimateSize(),
          original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT));
      checkNotNull(map);
      this.map = map;
      this.original = original;
    }

    @Override
    public boolean tryAdvance(final Consumer action) {
      return original.tryAdvance(u -> action.accept(map.apply(u)));
    }
  }

  /**
   * Object to Int map spliterator.
   *
   * @param  the input type
   */
  private static final class MapToIntSpliterator extends Spliterators.AbstractIntSpliterator {
    private final ToIntFunction map;
    private final Spliterator original;

    public MapToIntSpliterator(ToIntFunction map, Spliterator original) {
      super(
          original.estimateSize(),
          original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT));
      checkNotNull(map);
      this.map = map;
      this.original = original;
    }

    @Override
    public boolean tryAdvance(final IntConsumer action) {
      return original.tryAdvance(u -> action.accept(map.applyAsInt(u)));
    }
  }

  /**
   * Object to Long map spliterator.
   *
   * @param  the input type
   */
  private static final class MapToLongSpliterator extends Spliterators.AbstractLongSpliterator {
    private final ToLongFunction map;
    private final Spliterator original;

    public MapToLongSpliterator(ToLongFunction map, Spliterator original) {
      super(
          original.estimateSize(),
          original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT));
      checkNotNull(map);
      this.map = map;
      this.original = original;
    }

    @Override
    public boolean tryAdvance(final LongConsumer action) {
      return original.tryAdvance(u -> action.accept(map.applyAsLong(u)));
    }
  }

  /**
   * Object to Double map spliterator.
   *
   * @param  the input type
   */
  private static final class MapToDoubleSpliterator
      extends Spliterators.AbstractDoubleSpliterator {
    private final ToDoubleFunction map;
    private final Spliterator original;

    public MapToDoubleSpliterator(ToDoubleFunction map, Spliterator original) {
      super(
          original.estimateSize(),
          original.characteristics() & ~(Spliterator.SORTED | Spliterator.DISTINCT));
      checkNotNull(map);
      this.map = map;
      this.original = original;
    }

    @Override
    public boolean tryAdvance(final DoubleConsumer action) {
      return original.tryAdvance(u -> action.accept(map.applyAsDouble(u)));
    }
  }

  /**
   * Object filter spliterator.
   *
   * @param  the type of data to iterate over
   */
  private static final class FilterSpliterator extends Spliterators.AbstractSpliterator {
    private final Predicate filter;
    private final Spliterator original;

    private boolean found;

    public FilterSpliterator(Predicate filter, Spliterator original) {
      super(
          original.estimateSize(),
          original.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED));
      checkNotNull(filter);
      this.filter = filter;
      this.original = original;
    }

    @Override
    public Comparator getComparator() {
      return original.getComparator();
    }

    @Override
    public boolean tryAdvance(final Consumer action) {
      found = false;
      while (!found
          && original.tryAdvance(
              item -> {
                if (filter.test(item)) {
                  found = true;
                  action.accept(item);
                }
              })) {
        // do nothing, work is done in tryAdvance
      }

      return found;
    }
  }

  /**
   * Object skip spliterator.
   *
   * @param  the type of data to iterate over
   */
  private static final class SkipSpliterator extends Spliterators.AbstractSpliterator {
    private long skip;
    private final Spliterator original;

    public SkipSpliterator(long skip, Spliterator original) {
      super(
          original.hasCharacteristics(Spliterator.SIZED)
              ? Math.max(0, original.estimateSize() - skip)
              : Long.MAX_VALUE,
          original.characteristics());
      this.skip = skip;
      this.original = original;
    }

    @Override
    public Comparator getComparator() {
      return original.getComparator();
    }

    @Override
    public boolean tryAdvance(Consumer action) {
      while (skip > 0) {
        if (!original.tryAdvance(ignore -> { })) {
          return false;
        }
        skip--;
      }
      return original.tryAdvance(action);
    }
  }

  /**
   * Object limit spliterator.
   *
   * @param  the type of data to iterate over
   */
  private static final class LimitSpliterator extends Spliterators.AbstractSpliterator {
    private final long limit;
    private final Spliterator original;
    private int position = 0;

    public LimitSpliterator(long limit, Spliterator original) {
      super(
          original.hasCharacteristics(Spliterator.SIZED)
              ? Math.min(original.estimateSize(), limit)
              : Long.MAX_VALUE,
          original.characteristics());
      this.limit = limit;
      this.original = original;
    }

    @Override
    public Comparator getComparator() {
      return original.getComparator();
    }

    @Override
    public boolean tryAdvance(Consumer action) {
      if (position >= limit) {
        return false;
      }
      boolean result = original.tryAdvance(action);
      position++;
      return result;
    }
  }

  /**
   * Value holder for various stream operations.
   */
  private static final class ValueConsumer implements Consumer {
    T value;

    @Override
    public void accept(T value) {
      this.value = value;
    }
  }

  private final Spliterator spliterator;

  public StreamImpl(TerminatableStream prev, Spliterator spliterator) {
    super(prev);
    this.spliterator = spliterator;
  }

  // terminal
  @Override
  public Spliterator spliterator() {
    terminate();
    return spliterator;
  }

  @Override
  public Iterator iterator() {
    return Spliterators.iterator(spliterator());
  }

  @Override
  public long count() {
    terminate();
    long count = 0;
    while (spliterator.tryAdvance(a -> { })) {
      count++;
    }
    return count;
  }

  @Override
  public void forEach(Consumer action) {
    forEachOrdered(action);
  }

  @Override
  public void forEachOrdered(Consumer action) {
    terminate();
    spliterator.forEachRemaining(action);
  }

  @Override
  public Object[] toArray() {
    return toArray(Object[]::new);
  }

  @Override
  public  A[] toArray(IntFunction generator) {
    List collected = collect(Collectors.toList());
    return collected.toArray(generator.apply(collected.size()));
  }

  @Override
  public  R collect(
      Supplier supplier, BiConsumer accumulator, BiConsumer combiner) {
    return collect(
        Collector.of(
            supplier,
            accumulator,
            (a, b) -> {
              combiner.accept(a, b);
              return a;
            }));
  }

  @Override
  public  R collect(final Collector collector) {
    return collector
        .finisher()
        .apply(
            reduce(
                collector.supplier().get(),
                (a, t) -> {
                  collector.accumulator().accept(a, t);
                  return a;
                },
                collector.combiner()));
  }

  @Override
  public Optional findFirst() {
    terminate();
    ValueConsumer holder = new ValueConsumer();
    if (spliterator.tryAdvance(holder)) {
      return Optional.of(holder.value);
    }
    return Optional.empty();
  }

  @Override
  public Optional findAny() {
    return findFirst();
  }

  private static final Consumer NULL_CONSUMER = value -> { };

  @Override
  public boolean anyMatch(Predicate predicate) {
    return filter(predicate).spliterator().tryAdvance(NULL_CONSUMER);
  }

  @Override
  public boolean allMatch(final Predicate predicate) {
    return !anyMatch(predicate.negate());
  }

  @Override
  public boolean noneMatch(final Predicate predicate) {
    return !anyMatch(predicate);
  }

  @Override
  public Optional min(final Comparator comparator) {
    return reduce(BinaryOperator.minBy(comparator));
  }

  @Override
  public Optional max(final Comparator comparator) {
    return reduce(BinaryOperator.maxBy(comparator));
  }

  @Override
  public T reduce(T identity, BinaryOperator accumulator) {
    return reduce(identity, accumulator, accumulator);
  }

  @Override
  public Optional reduce(BinaryOperator accumulator) {
    ValueConsumer consumer = new ValueConsumer();
    if (!spliterator.tryAdvance(consumer)) {
      terminate();
      return Optional.empty();
    }
    return Optional.of(reduce(consumer.value, accumulator));
  }

  // combiner is ignored, since we don't parallelize
  @Override
  public  U reduce(
      U identity, BiFunction accumulator, BinaryOperator combiner) {
    terminate();
    final ValueConsumer consumer = new ValueConsumer();
    consumer.value = identity;
    spliterator.forEachRemaining(
        item -> {
          consumer.accept(accumulator.apply(consumer.value, item));
        });
    return consumer.value;
  }
  // end terminal

  // intermediate
  @Override
  public Stream filter(Predicate predicate) {
    throwIfTerminated();
    return new StreamImpl<>(this, new FilterSpliterator<>(predicate, spliterator));
  }

  @Override
  public  Stream map(Function mapper) {
    throwIfTerminated();
    return new StreamImpl<>(this, new MapToObjSpliterator<>(mapper, spliterator));
  }

  @Override
  public IntStream mapToInt(ToIntFunction mapper) {
    throwIfTerminated();
    return new IntStreamImpl(this, new MapToIntSpliterator<>(mapper, spliterator));
  }

  @Override
  public LongStream mapToLong(ToLongFunction mapper) {
    throwIfTerminated();
    return new LongStreamImpl(this, new MapToLongSpliterator<>(mapper, spliterator));
  }

  @Override
  public DoubleStream mapToDouble(ToDoubleFunction mapper) {
    throwIfTerminated();
    return new DoubleStreamImpl(this, new MapToDoubleSpliterator<>(mapper, spliterator));
  }

  @Override
  public  Stream flatMap(final Function> mapper) {
    throwIfTerminated();
    final Spliterator> spliteratorOfStreams =
        new MapToObjSpliterator<>(mapper, spliterator);

    AbstractSpliterator flatMapSpliterator =
        new Spliterators.AbstractSpliterator(Long.MAX_VALUE, 0) {
          Stream nextStream;
          Spliterator next;

          @Override
          public boolean tryAdvance(Consumer action) {
            // look for a new spliterator
            while (advanceToNextSpliterator()) {
              // if we have one, try to read and use it
              if (next.tryAdvance(action)) {
                return true;
              } else {
                nextStream.close();
                nextStream = null;
                // failed, null it out so we can find another
                next = null;
              }
            }
            return false;
          }

          private boolean advanceToNextSpliterator() {
            while (next == null) {
              if (!spliteratorOfStreams.tryAdvance(
                  n -> {
                    if (n != null) {
                      nextStream = n;
                      next = n.spliterator();
                    }
                  })) {
                return false;
              }
            }
            return true;
          }
        };

    return new StreamImpl(this, flatMapSpliterator);
  }

  @Override
  public IntStream flatMapToInt(Function mapper) {
    throwIfTerminated();
    final Spliterator spliteratorOfStreams =
        new MapToObjSpliterator<>(mapper, spliterator);

    AbstractIntSpliterator flatMapSpliterator =
        new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, 0) {
          IntStream nextStream;
          Spliterator.OfInt next;

          @Override
          public boolean tryAdvance(IntConsumer action) {
            // look for a new spliterator
            while (advanceToNextSpliterator()) {
              // if we have one, try to read and use it
              if (next.tryAdvance(action)) {
                return true;
              } else {
                nextStream.close();
                nextStream = null;
                // failed, null it out so we can find another
                next = null;
              }
            }
            return false;
          }

          private boolean advanceToNextSpliterator() {
            while (next == null) {
              if (!spliteratorOfStreams.tryAdvance(
                  n -> {
                    if (n != null) {
                      nextStream = n;
                      next = n.spliterator();
                    }
                  })) {
                return false;
              }
            }
            return true;
          }
        };

    return new IntStreamImpl(this, flatMapSpliterator);
  }

  @Override
  public LongStream flatMapToLong(Function mapper) {
    throwIfTerminated();
    final Spliterator spliteratorOfStreams =
        new MapToObjSpliterator<>(mapper, spliterator);

    AbstractLongSpliterator flatMapSpliterator =
        new Spliterators.AbstractLongSpliterator(Long.MAX_VALUE, 0) {
          LongStream nextStream;
          Spliterator.OfLong next;

          @Override
          public boolean tryAdvance(LongConsumer action) {
            // look for a new spliterator
            while (advanceToNextSpliterator()) {
              // if we have one, try to read and use it
              if (next.tryAdvance(action)) {
                return true;
              } else {
                nextStream.close();
                nextStream = null;
                // failed, null it out so we can find another
                next = null;
              }
            }
            return false;
          }

          private boolean advanceToNextSpliterator() {
            while (next == null) {
              if (!spliteratorOfStreams.tryAdvance(
                  n -> {
                    if (n != null) {
                      nextStream = n;
                      next = n.spliterator();
                    }
                  })) {
                return false;
              }
            }
            return true;
          }
        };

    return new LongStreamImpl(this, flatMapSpliterator);
  }

  @Override
  public DoubleStream flatMapToDouble(Function mapper) {
    throwIfTerminated();
    final Spliterator spliteratorOfStreams =
        new MapToObjSpliterator<>(mapper, spliterator);

    AbstractDoubleSpliterator flatMapSpliterator =
        new Spliterators.AbstractDoubleSpliterator(Long.MAX_VALUE, 0) {
          DoubleStream nextStream;
          Spliterator.OfDouble next;

          @Override
          public boolean tryAdvance(DoubleConsumer action) {
            // look for a new spliterator
            while (advanceToNextSpliterator()) {
              // if we have one, try to read and use it
              if (next.tryAdvance(action)) {
                return true;
              } else {
                nextStream.close();
                nextStream = null;
                // failed, null it out so we can find another
                next = null;
              }
            }
            return false;
          }

          private boolean advanceToNextSpliterator() {
            while (next == null) {
              if (!spliteratorOfStreams.tryAdvance(
                  n -> {
                    if (n != null) {
                      nextStream = n;
                      next = n.spliterator();
                    }
                  })) {
                return false;
              }
            }
            return true;
          }
        };

    return new DoubleStreamImpl(this, flatMapSpliterator);
  }

  @Override
  public Stream distinct() {
    throwIfTerminated();
    HashSet seen = new HashSet<>();
    return filter(seen::add);
  }

  @Override
  public Stream sorted() {
    throwIfTerminated();
    Comparator c = (Comparator) Comparator.naturalOrder();
    return sorted(c);
  }

  @Override
  public Stream sorted(final Comparator comparator) {
    throwIfTerminated();

    AbstractSpliterator sortedSpliterator =
        new Spliterators.AbstractSpliterator(
            spliterator.estimateSize(), spliterator.characteristics() | Spliterator.SORTED) {
          Spliterator ordered = null;

          @Override
          public Comparator getComparator() {
            return comparator == Comparator.naturalOrder() ? null : comparator;
          }

          @Override
          public boolean tryAdvance(Consumer action) {
            if (ordered == null) {
              List list = new ArrayList<>();
              spliterator.forEachRemaining(list::add);
              Collections.sort(list, comparator);
              ordered = list.spliterator();
            }
            return ordered.tryAdvance(action);
          }
        };

    return new StreamImpl<>(this, sortedSpliterator);
  }

  @Override
  public Stream peek(final Consumer action) {
    checkNotNull(action);
    throwIfTerminated();

    AbstractSpliterator peekSpliterator =
        new Spliterators.AbstractSpliterator(
            spliterator.estimateSize(), spliterator.characteristics()) {
          @Override
          public boolean tryAdvance(final Consumer innerAction) {
            return spliterator.tryAdvance(
                item -> {
                  action.accept(item);
                  innerAction.accept(item);
                });
          }
        };

    return new StreamImpl<>(this, peekSpliterator);
  }

  @Override
  public Stream limit(long maxSize) {
    throwIfTerminated();
    checkState(maxSize >= 0, "maxSize may not be negative");
    return new StreamImpl<>(this, new LimitSpliterator<>(maxSize, spliterator));
  }

  @Override
  public Stream skip(long n) {
    throwIfTerminated();
    checkState(n >= 0, "n may not be negative");
    if (n == 0) {
      return this;
    }
    return new StreamImpl<>(this, new SkipSpliterator<>(n, spliterator));
  }

  @Override
  public boolean isParallel() {
    throwIfTerminated();
    return false;
  }

  @Override
  public Stream sequential() {
    throwIfTerminated();
    return this;
  }

  @Override
  public Stream parallel() {
    throwIfTerminated();
    // do nothing, no such thing as gwt+parallel
    return this;
  }

  @Override
  public Stream unordered() {
    throwIfTerminated();
    return this;
  }
}