001/*
002 * Copyright (C) 2015 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you
005 * may not use this file except in compliance with the License.  You may
006 * obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.  See the License for the specific language governing
014 * permissions and limitations under the License.
015 */
016
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.base.Preconditions.checkState;
021
022import com.google.common.annotations.Beta;
023import com.google.common.annotations.GwtCompatible;
024import com.google.common.math.LongMath;
025import java.util.ArrayDeque;
026import java.util.Collection;
027import java.util.Deque;
028import java.util.Iterator;
029import java.util.OptionalDouble;
030import java.util.OptionalInt;
031import java.util.OptionalLong;
032import java.util.PrimitiveIterator;
033import java.util.Spliterator;
034import java.util.Spliterators;
035import java.util.Spliterators.AbstractSpliterator;
036import java.util.function.BiConsumer;
037import java.util.function.BiFunction;
038import java.util.function.Consumer;
039import java.util.function.DoubleConsumer;
040import java.util.function.IntConsumer;
041import java.util.function.LongConsumer;
042import java.util.stream.DoubleStream;
043import java.util.stream.IntStream;
044import java.util.stream.LongStream;
045import java.util.stream.Stream;
046import java.util.stream.StreamSupport;
047import org.checkerframework.checker.nullness.compatqual.NullableDecl;
048
049/**
050 * Static utility methods related to {@code Stream} instances.
051 *
052 * @since 21.0
053 */
054@Beta
055@GwtCompatible
056public final class Streams {
057  /**
058   * Returns a sequential {@link Stream} of the contents of {@code iterable}, delegating to {@link
059   * Collection#stream} if possible.
060   */
061  public static <T> Stream<T> stream(Iterable<T> iterable) {
062    return (iterable instanceof Collection)
063        ? ((Collection<T>) iterable).stream()
064        : StreamSupport.stream(iterable.spliterator(), false);
065  }
066
067  /**
068   * Returns {@link Collection#stream}.
069   *
070   * @deprecated There is no reason to use this; just invoke {@code collection.stream()} directly.
071   */
072  @Deprecated
073  public static <T> Stream<T> stream(Collection<T> collection) {
074    return collection.stream();
075  }
076
077  /**
078   * Returns a sequential {@link Stream} of the remaining contents of {@code iterator}. Do not use
079   * {@code iterator} directly after passing it to this method.
080   */
081  public static <T> Stream<T> stream(Iterator<T> iterator) {
082    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
083  }
084
085  /**
086   * If a value is present in {@code optional}, returns a stream containing only that element,
087   * otherwise returns an empty stream.
088   */
089  public static <T> Stream<T> stream(com.google.common.base.Optional<T> optional) {
090    return optional.isPresent() ? Stream.of(optional.get()) : Stream.of();
091  }
092
093  /**
094   * If a value is present in {@code optional}, returns a stream containing only that element,
095   * otherwise returns an empty stream.
096   *
097   * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
098   */
099  public static <T> Stream<T> stream(java.util.Optional<T> optional) {
100    return optional.isPresent() ? Stream.of(optional.get()) : Stream.of();
101  }
102
103  /**
104   * If a value is present in {@code optional}, returns a stream containing only that element,
105   * otherwise returns an empty stream.
106   *
107   * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
108   */
109  public static IntStream stream(OptionalInt optional) {
110    return optional.isPresent() ? IntStream.of(optional.getAsInt()) : IntStream.empty();
111  }
112
113  /**
114   * If a value is present in {@code optional}, returns a stream containing only that element,
115   * otherwise returns an empty stream.
116   *
117   * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
118   */
119  public static LongStream stream(OptionalLong optional) {
120    return optional.isPresent() ? LongStream.of(optional.getAsLong()) : LongStream.empty();
121  }
122
123  /**
124   * If a value is present in {@code optional}, returns a stream containing only that element,
125   * otherwise returns an empty stream.
126   *
127   * <p><b>Java 9 users:</b> use {@code optional.stream()} instead.
128   */
129  public static DoubleStream stream(OptionalDouble optional) {
130    return optional.isPresent() ? DoubleStream.of(optional.getAsDouble()) : DoubleStream.empty();
131  }
132
133  /**
134   * Returns a {@link Stream} containing the elements of the first stream, followed by the elements
135   * of the second stream, and so on.
136   *
137   * <p>This is equivalent to {@code Stream.of(streams).flatMap(stream -> stream)}, but the returned
138   * stream may perform better.
139   *
140   * @see Stream#concat(Stream, Stream)
141   */
142  @SafeVarargs
143  public static <T> Stream<T> concat(Stream<? extends T>... streams) {
144    // TODO(lowasser): consider an implementation that can support SUBSIZED
145    boolean isParallel = false;
146    int characteristics = Spliterator.ORDERED | Spliterator.SIZED | Spliterator.NONNULL;
147    long estimatedSize = 0L;
148    ImmutableList.Builder<Spliterator<? extends T>> splitrsBuilder =
149        new ImmutableList.Builder<>(streams.length);
150    for (Stream<? extends T> stream : streams) {
151      isParallel |= stream.isParallel();
152      Spliterator<? extends T> splitr = stream.spliterator();
153      splitrsBuilder.add(splitr);
154      characteristics &= splitr.characteristics();
155      estimatedSize = LongMath.saturatedAdd(estimatedSize, splitr.estimateSize());
156    }
157    return StreamSupport.stream(
158            CollectSpliterators.flatMap(
159                splitrsBuilder.build().spliterator(),
160                splitr -> (Spliterator<T>) splitr,
161                characteristics,
162                estimatedSize),
163            isParallel)
164        .onClose(
165            () -> {
166              for (Stream<? extends T> stream : streams) {
167                stream.close();
168              }
169            });
170  }
171
172  /**
173   * Returns an {@link IntStream} containing the elements of the first stream, followed by the
174   * elements of the second stream, and so on.
175   *
176   * <p>This is equivalent to {@code Stream.of(streams).flatMapToInt(stream -> stream)}, but the
177   * returned stream may perform better.
178   *
179   * @see IntStream#concat(IntStream, IntStream)
180   */
181  public static IntStream concat(IntStream... streams) {
182    // TODO(lowasser): optimize this later
183    return Stream.of(streams).flatMapToInt(stream -> stream);
184  }
185
186  /**
187   * Returns a {@link LongStream} containing the elements of the first stream, followed by the
188   * elements of the second stream, and so on.
189   *
190   * <p>This is equivalent to {@code Stream.of(streams).flatMapToLong(stream -> stream)}, but the
191   * returned stream may perform better.
192   *
193   * @see LongStream#concat(LongStream, LongStream)
194   */
195  public static LongStream concat(LongStream... streams) {
196    // TODO(lowasser): optimize this later
197    return Stream.of(streams).flatMapToLong(stream -> stream);
198  }
199
200  /**
201   * Returns a {@link DoubleStream} containing the elements of the first stream, followed by the
202   * elements of the second stream, and so on.
203   *
204   * <p>This is equivalent to {@code Stream.of(streams).flatMapToDouble(stream -> stream)}, but the
205   * returned stream may perform better.
206   *
207   * @see DoubleStream#concat(DoubleStream, DoubleStream)
208   */
209  public static DoubleStream concat(DoubleStream... streams) {
210    // TODO(lowasser): optimize this later
211    return Stream.of(streams).flatMapToDouble(stream -> stream);
212  }
213
214  /**
215   * Returns a stream in which each element is the result of passing the corresponding elementY of
216   * each of {@code streamA} and {@code streamB} to {@code function}.
217   *
218   * <p>For example:
219   *
220   * <pre>{@code
221   * Streams.zip(
222   *   Stream.of("foo1", "foo2", "foo3"),
223   *   Stream.of("bar1", "bar2"),
224   *   (arg1, arg2) -> arg1 + ":" + arg2)
225   * }</pre>
226   *
227   * <p>will return {@code Stream.of("foo1:bar1", "foo2:bar2")}.
228   *
229   * <p>The resulting stream will only be as long as the shorter of the two input streams; if one
230   * stream is longer, its extra elements will be ignored.
231   *
232   * <p>Note that if you are calling {@link Stream#forEach} on the resulting stream, you might want
233   * to consider using {@link #forEachPair} instead of this method.
234   *
235   * <p><b>Performance note:</b> The resulting stream is not <a
236   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>.
237   * This may harm parallel performance.
238   */
239  public static <A, B, R> Stream<R> zip(
240      Stream<A> streamA, Stream<B> streamB, BiFunction<? super A, ? super B, R> function) {
241    checkNotNull(streamA);
242    checkNotNull(streamB);
243    checkNotNull(function);
244    boolean isParallel = streamA.isParallel() || streamB.isParallel(); // same as Stream.concat
245    Spliterator<A> splitrA = streamA.spliterator();
246    Spliterator<B> splitrB = streamB.spliterator();
247    int characteristics =
248        splitrA.characteristics()
249            & splitrB.characteristics()
250            & (Spliterator.SIZED | Spliterator.ORDERED);
251    Iterator<A> itrA = Spliterators.iterator(splitrA);
252    Iterator<B> itrB = Spliterators.iterator(splitrB);
253    return StreamSupport.stream(
254            new AbstractSpliterator<R>(
255                Math.min(splitrA.estimateSize(), splitrB.estimateSize()), characteristics) {
256              @Override
257              public boolean tryAdvance(Consumer<? super R> action) {
258                if (itrA.hasNext() && itrB.hasNext()) {
259                  action.accept(function.apply(itrA.next(), itrB.next()));
260                  return true;
261                }
262                return false;
263              }
264            },
265            isParallel)
266        .onClose(streamA::close)
267        .onClose(streamB::close);
268  }
269
270  /**
271   * Invokes {@code consumer} once for each pair of <i>corresponding</i> elements in {@code streamA}
272   * and {@code streamB}. If one stream is longer than the other, the extra elements are silently
273   * ignored. Elements passed to the consumer are guaranteed to come from the same position in their
274   * respective source streams. For example:
275   *
276   * <pre>{@code
277   * Streams.forEachPair(
278   *   Stream.of("foo1", "foo2", "foo3"),
279   *   Stream.of("bar1", "bar2"),
280   *   (arg1, arg2) -> System.out.println(arg1 + ":" + arg2)
281   * }</pre>
282   *
283   * <p>will print:
284   *
285   * <pre>{@code
286   * foo1:bar1
287   * foo2:bar2
288   * }</pre>
289   *
290   * <p><b>Warning:</b> If either supplied stream is a parallel stream, the same correspondence
291   * between elements will be made, but the order in which those pairs of elements are passed to the
292   * consumer is <i>not</i> defined.
293   *
294   * <p>Note that many usages of this method can be replaced with simpler calls to {@link #zip}.
295   * This method behaves equivalently to {@linkplain #zip zipping} the stream elements into
296   * temporary pair objects and then using {@link Stream#forEach} on that stream.
297   *
298   * @since 22.0
299   */
300  public static <A, B> void forEachPair(
301      Stream<A> streamA, Stream<B> streamB, BiConsumer<? super A, ? super B> consumer) {
302    checkNotNull(consumer);
303
304    if (streamA.isParallel() || streamB.isParallel()) {
305      zip(streamA, streamB, TemporaryPair::new).forEach(pair -> consumer.accept(pair.a, pair.b));
306    } else {
307      Iterator<A> iterA = streamA.iterator();
308      Iterator<B> iterB = streamB.iterator();
309      while (iterA.hasNext() && iterB.hasNext()) {
310        consumer.accept(iterA.next(), iterB.next());
311      }
312    }
313  }
314
315  // Use this carefully - it doesn't implement value semantics
316  private static class TemporaryPair<A, B> {
317    final A a;
318    final B b;
319
320    TemporaryPair(A a, B b) {
321      this.a = a;
322      this.b = b;
323    }
324  }
325
326  /**
327   * Returns a stream consisting of the results of applying the given function to the elements of
328   * {@code stream} and their indices in the stream. For example,
329   *
330   * <pre>{@code
331   * mapWithIndex(
332   *     Stream.of("a", "b", "c"),
333   *     (str, index) -> str + ":" + index)
334   * }</pre>
335   *
336   * <p>would return {@code Stream.of("a:0", "b:1", "c:2")}.
337   *
338   * <p>The resulting stream is <a
339   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
340   * if and only if {@code stream} was efficiently splittable and its underlying spliterator
341   * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
342   * comes from a data structure supporting efficient indexed random access, typically an array or
343   * list.
344   *
345   * <p>The order of the resulting stream is defined if and only if the order of the original stream
346   * was defined.
347   */
348  public static <T, R> Stream<R> mapWithIndex(
349      Stream<T> stream, FunctionWithIndex<? super T, ? extends R> function) {
350    checkNotNull(stream);
351    checkNotNull(function);
352    boolean isParallel = stream.isParallel();
353    Spliterator<T> fromSpliterator = stream.spliterator();
354
355    if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
356      Iterator<T> fromIterator = Spliterators.iterator(fromSpliterator);
357      return StreamSupport.stream(
358              new AbstractSpliterator<R>(
359                  fromSpliterator.estimateSize(),
360                  fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
361                long index = 0;
362
363                @Override
364                public boolean tryAdvance(Consumer<? super R> action) {
365                  if (fromIterator.hasNext()) {
366                    action.accept(function.apply(fromIterator.next(), index++));
367                    return true;
368                  }
369                  return false;
370                }
371              },
372              isParallel)
373          .onClose(stream::close);
374    }
375    class Splitr extends MapWithIndexSpliterator<Spliterator<T>, R, Splitr> implements Consumer<T> {
376      @NullableDecl T holder;
377
378      Splitr(Spliterator<T> splitr, long index) {
379        super(splitr, index);
380      }
381
382      @Override
383      public void accept(@NullableDecl T t) {
384        this.holder = t;
385      }
386
387      @Override
388      public boolean tryAdvance(Consumer<? super R> action) {
389        if (fromSpliterator.tryAdvance(this)) {
390          try {
391            action.accept(function.apply(holder, index++));
392            return true;
393          } finally {
394            holder = null;
395          }
396        }
397        return false;
398      }
399
400      @Override
401      Splitr createSplit(Spliterator<T> from, long i) {
402        return new Splitr(from, i);
403      }
404    }
405    return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
406  }
407
408  /**
409   * An analogue of {@link java.util.function.Function} also accepting an index.
410   *
411   * <p>This interface is only intended for use by callers of {@link #mapWithIndex(Stream,
412   * FunctionWithIndex)}.
413   *
414   * @since 21.0
415   */
416  @Beta
417  public interface FunctionWithIndex<T, R> {
418    /** Applies this function to the given argument and its index within a stream. */
419    R apply(T from, long index);
420  }
421
422  private abstract static class MapWithIndexSpliterator<
423          F extends Spliterator<?>, R, S extends MapWithIndexSpliterator<F, R, S>>
424      implements Spliterator<R> {
425    final F fromSpliterator;
426    long index;
427
428    MapWithIndexSpliterator(F fromSpliterator, long index) {
429      this.fromSpliterator = fromSpliterator;
430      this.index = index;
431    }
432
433    abstract S createSplit(F from, long i);
434
435    @Override
436    public S trySplit() {
437      @SuppressWarnings("unchecked")
438      F split = (F) fromSpliterator.trySplit();
439      if (split == null) {
440        return null;
441      }
442      S result = createSplit(split, index);
443      this.index += split.getExactSizeIfKnown();
444      return result;
445    }
446
447    @Override
448    public long estimateSize() {
449      return fromSpliterator.estimateSize();
450    }
451
452    @Override
453    public int characteristics() {
454      return fromSpliterator.characteristics()
455          & (Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED);
456    }
457  }
458
459  /**
460   * Returns a stream consisting of the results of applying the given function to the elements of
461   * {@code stream} and their indexes in the stream. For example,
462   *
463   * <pre>{@code
464   * mapWithIndex(
465   *     IntStream.of(0, 1, 2),
466   *     (i, index) -> i + ":" + index)
467   * }</pre>
468   *
469   * <p>...would return {@code Stream.of("0:0", "1:1", "2:2")}.
470   *
471   * <p>The resulting stream is <a
472   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
473   * if and only if {@code stream} was efficiently splittable and its underlying spliterator
474   * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
475   * comes from a data structure supporting efficient indexed random access, typically an array or
476   * list.
477   *
478   * <p>The order of the resulting stream is defined if and only if the order of the original stream
479   * was defined.
480   */
481  public static <R> Stream<R> mapWithIndex(IntStream stream, IntFunctionWithIndex<R> function) {
482    checkNotNull(stream);
483    checkNotNull(function);
484    boolean isParallel = stream.isParallel();
485    Spliterator.OfInt fromSpliterator = stream.spliterator();
486
487    if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
488      PrimitiveIterator.OfInt fromIterator = Spliterators.iterator(fromSpliterator);
489      return StreamSupport.stream(
490              new AbstractSpliterator<R>(
491                  fromSpliterator.estimateSize(),
492                  fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
493                long index = 0;
494
495                @Override
496                public boolean tryAdvance(Consumer<? super R> action) {
497                  if (fromIterator.hasNext()) {
498                    action.accept(function.apply(fromIterator.nextInt(), index++));
499                    return true;
500                  }
501                  return false;
502                }
503              },
504              isParallel)
505          .onClose(stream::close);
506    }
507    class Splitr extends MapWithIndexSpliterator<Spliterator.OfInt, R, Splitr>
508        implements IntConsumer, Spliterator<R> {
509      int holder;
510
511      Splitr(Spliterator.OfInt splitr, long index) {
512        super(splitr, index);
513      }
514
515      @Override
516      public void accept(int t) {
517        this.holder = t;
518      }
519
520      @Override
521      public boolean tryAdvance(Consumer<? super R> action) {
522        if (fromSpliterator.tryAdvance(this)) {
523          action.accept(function.apply(holder, index++));
524          return true;
525        }
526        return false;
527      }
528
529      @Override
530      Splitr createSplit(Spliterator.OfInt from, long i) {
531        return new Splitr(from, i);
532      }
533    }
534    return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
535  }
536
537  /**
538   * An analogue of {@link java.util.function.IntFunction} also accepting an index.
539   *
540   * <p>This interface is only intended for use by callers of {@link #mapWithIndex(IntStream,
541   * IntFunctionWithIndex)}.
542   *
543   * @since 21.0
544   */
545  @Beta
546  public interface IntFunctionWithIndex<R> {
547    /** Applies this function to the given argument and its index within a stream. */
548    R apply(int from, long index);
549  }
550
551  /**
552   * Returns a stream consisting of the results of applying the given function to the elements of
553   * {@code stream} and their indexes in the stream. For example,
554   *
555   * <pre>{@code
556   * mapWithIndex(
557   *     LongStream.of(0, 1, 2),
558   *     (i, index) -> i + ":" + index)
559   * }</pre>
560   *
561   * <p>...would return {@code Stream.of("0:0", "1:1", "2:2")}.
562   *
563   * <p>The resulting stream is <a
564   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
565   * if and only if {@code stream} was efficiently splittable and its underlying spliterator
566   * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
567   * comes from a data structure supporting efficient indexed random access, typically an array or
568   * list.
569   *
570   * <p>The order of the resulting stream is defined if and only if the order of the original stream
571   * was defined.
572   */
573  public static <R> Stream<R> mapWithIndex(LongStream stream, LongFunctionWithIndex<R> function) {
574    checkNotNull(stream);
575    checkNotNull(function);
576    boolean isParallel = stream.isParallel();
577    Spliterator.OfLong fromSpliterator = stream.spliterator();
578
579    if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
580      PrimitiveIterator.OfLong fromIterator = Spliterators.iterator(fromSpliterator);
581      return StreamSupport.stream(
582              new AbstractSpliterator<R>(
583                  fromSpliterator.estimateSize(),
584                  fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
585                long index = 0;
586
587                @Override
588                public boolean tryAdvance(Consumer<? super R> action) {
589                  if (fromIterator.hasNext()) {
590                    action.accept(function.apply(fromIterator.nextLong(), index++));
591                    return true;
592                  }
593                  return false;
594                }
595              },
596              isParallel)
597          .onClose(stream::close);
598    }
599    class Splitr extends MapWithIndexSpliterator<Spliterator.OfLong, R, Splitr>
600        implements LongConsumer, Spliterator<R> {
601      long holder;
602
603      Splitr(Spliterator.OfLong splitr, long index) {
604        super(splitr, index);
605      }
606
607      @Override
608      public void accept(long t) {
609        this.holder = t;
610      }
611
612      @Override
613      public boolean tryAdvance(Consumer<? super R> action) {
614        if (fromSpliterator.tryAdvance(this)) {
615          action.accept(function.apply(holder, index++));
616          return true;
617        }
618        return false;
619      }
620
621      @Override
622      Splitr createSplit(Spliterator.OfLong from, long i) {
623        return new Splitr(from, i);
624      }
625    }
626    return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
627  }
628
629  /**
630   * An analogue of {@link java.util.function.LongFunction} also accepting an index.
631   *
632   * <p>This interface is only intended for use by callers of {@link #mapWithIndex(LongStream,
633   * LongFunctionWithIndex)}.
634   *
635   * @since 21.0
636   */
637  @Beta
638  public interface LongFunctionWithIndex<R> {
639    /** Applies this function to the given argument and its index within a stream. */
640    R apply(long from, long index);
641  }
642
643  /**
644   * Returns a stream consisting of the results of applying the given function to the elements of
645   * {@code stream} and their indexes in the stream. For example,
646   *
647   * <pre>{@code
648   * mapWithIndex(
649   *     DoubleStream.of(0, 1, 2),
650   *     (x, index) -> x + ":" + index)
651   * }</pre>
652   *
653   * <p>...would return {@code Stream.of("0.0:0", "1.0:1", "2.0:2")}.
654   *
655   * <p>The resulting stream is <a
656   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
657   * if and only if {@code stream} was efficiently splittable and its underlying spliterator
658   * reported {@link Spliterator#SUBSIZED}. This is generally the case if the underlying stream
659   * comes from a data structure supporting efficient indexed random access, typically an array or
660   * list.
661   *
662   * <p>The order of the resulting stream is defined if and only if the order of the original stream
663   * was defined.
664   */
665  public static <R> Stream<R> mapWithIndex(
666      DoubleStream stream, DoubleFunctionWithIndex<R> function) {
667    checkNotNull(stream);
668    checkNotNull(function);
669    boolean isParallel = stream.isParallel();
670    Spliterator.OfDouble fromSpliterator = stream.spliterator();
671
672    if (!fromSpliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
673      PrimitiveIterator.OfDouble fromIterator = Spliterators.iterator(fromSpliterator);
674      return StreamSupport.stream(
675              new AbstractSpliterator<R>(
676                  fromSpliterator.estimateSize(),
677                  fromSpliterator.characteristics() & (Spliterator.ORDERED | Spliterator.SIZED)) {
678                long index = 0;
679
680                @Override
681                public boolean tryAdvance(Consumer<? super R> action) {
682                  if (fromIterator.hasNext()) {
683                    action.accept(function.apply(fromIterator.nextDouble(), index++));
684                    return true;
685                  }
686                  return false;
687                }
688              },
689              isParallel)
690          .onClose(stream::close);
691    }
692    class Splitr extends MapWithIndexSpliterator<Spliterator.OfDouble, R, Splitr>
693        implements DoubleConsumer, Spliterator<R> {
694      double holder;
695
696      Splitr(Spliterator.OfDouble splitr, long index) {
697        super(splitr, index);
698      }
699
700      @Override
701      public void accept(double t) {
702        this.holder = t;
703      }
704
705      @Override
706      public boolean tryAdvance(Consumer<? super R> action) {
707        if (fromSpliterator.tryAdvance(this)) {
708          action.accept(function.apply(holder, index++));
709          return true;
710        }
711        return false;
712      }
713
714      @Override
715      Splitr createSplit(Spliterator.OfDouble from, long i) {
716        return new Splitr(from, i);
717      }
718    }
719    return StreamSupport.stream(new Splitr(fromSpliterator, 0), isParallel).onClose(stream::close);
720  }
721
722  /**
723   * An analogue of {@link java.util.function.DoubleFunction} also accepting an index.
724   *
725   * <p>This interface is only intended for use by callers of {@link #mapWithIndex(DoubleStream,
726   * DoubleFunctionWithIndex)}.
727   *
728   * @since 21.0
729   */
730  @Beta
731  public interface DoubleFunctionWithIndex<R> {
732    /** Applies this function to the given argument and its index within a stream. */
733    R apply(double from, long index);
734  }
735
736  /**
737   * Returns the last element of the specified stream, or {@link java.util.Optional#empty} if the
738   * stream is empty.
739   *
740   * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
741   * method's runtime will be between O(log n) and O(n), performing better on <a
742   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
743   * streams.
744   *
745   * <p>If the stream has nondeterministic order, this has equivalent semantics to {@link
746   * Stream#findAny} (which you might as well use).
747   *
748   * @see Stream#findFirst()
749   * @throws NullPointerException if the last element of the stream is null
750   */
751  public static <T> java.util.Optional<T> findLast(Stream<T> stream) {
752    class OptionalState {
753      boolean set = false;
754      T value = null;
755
756      void set(@NullableDecl T value) {
757        this.set = true;
758        this.value = value;
759      }
760
761      T get() {
762        checkState(set);
763        return value;
764      }
765    }
766    OptionalState state = new OptionalState();
767
768    Deque<Spliterator<T>> splits = new ArrayDeque<>();
769    splits.addLast(stream.spliterator());
770
771    while (!splits.isEmpty()) {
772      Spliterator<T> spliterator = splits.removeLast();
773
774      if (spliterator.getExactSizeIfKnown() == 0) {
775        continue; // drop this split
776      }
777
778      // Many spliterators will have trySplits that are SUBSIZED even if they are not themselves
779      // SUBSIZED.
780      if (spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
781        // we can drill down to exactly the smallest nonempty spliterator
782        while (true) {
783          Spliterator<T> prefix = spliterator.trySplit();
784          if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
785            break;
786          } else if (spliterator.getExactSizeIfKnown() == 0) {
787            spliterator = prefix;
788            break;
789          }
790        }
791
792        // spliterator is known to be nonempty now
793        spliterator.forEachRemaining(state::set);
794        return java.util.Optional.of(state.get());
795      }
796
797      Spliterator<T> prefix = spliterator.trySplit();
798      if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
799        // we can't split this any further
800        spliterator.forEachRemaining(state::set);
801        if (state.set) {
802          return java.util.Optional.of(state.get());
803        }
804        // fall back to the last split
805        continue;
806      }
807      splits.addLast(prefix);
808      splits.addLast(spliterator);
809    }
810    return java.util.Optional.empty();
811  }
812
813  /**
814   * Returns the last element of the specified stream, or {@link OptionalInt#empty} if the stream is
815   * empty.
816   *
817   * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
818   * method's runtime will be between O(log n) and O(n), performing better on <a
819   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
820   * streams.
821   *
822   * @see IntStream#findFirst()
823   * @throws NullPointerException if the last element of the stream is null
824   */
825  public static OptionalInt findLast(IntStream stream) {
826    // findLast(Stream) does some allocation, so we might as well box some more
827    java.util.Optional<Integer> boxedLast = findLast(stream.boxed());
828    return boxedLast.isPresent() ? OptionalInt.of(boxedLast.get()) : OptionalInt.empty();
829  }
830
831  /**
832   * Returns the last element of the specified stream, or {@link OptionalLong#empty} if the stream
833   * is empty.
834   *
835   * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
836   * method's runtime will be between O(log n) and O(n), performing better on <a
837   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
838   * streams.
839   *
840   * @see LongStream#findFirst()
841   * @throws NullPointerException if the last element of the stream is null
842   */
843  public static OptionalLong findLast(LongStream stream) {
844    // findLast(Stream) does some allocation, so we might as well box some more
845    java.util.Optional<Long> boxedLast = findLast(stream.boxed());
846    return boxedLast.isPresent() ? OptionalLong.of(boxedLast.get()) : OptionalLong.empty();
847  }
848
849  /**
850   * Returns the last element of the specified stream, or {@link OptionalDouble#empty} if the stream
851   * is empty.
852   *
853   * <p>Equivalent to {@code stream.reduce((a, b) -> b)}, but may perform significantly better. This
854   * method's runtime will be between O(log n) and O(n), performing better on <a
855   * href="http://gee.cs.oswego.edu/dl/html/StreamParallelGuidance.html">efficiently splittable</a>
856   * streams.
857   *
858   * @see DoubleStream#findFirst()
859   * @throws NullPointerException if the last element of the stream is null
860   */
861  public static OptionalDouble findLast(DoubleStream stream) {
862    // findLast(Stream) does some allocation, so we might as well box some more
863    java.util.Optional<Double> boxedLast = findLast(stream.boxed());
864    return boxedLast.isPresent() ? OptionalDouble.of(boxedLast.get()) : OptionalDouble.empty();
865  }
866
867  private Streams() {}
868}