guava/src/com/google/common/collect/CollectSpliterators.java
static <F, T> Spliterator<T> flatMap(
      Spliterator<F> fromSpliterator,
      Function<? super F, Spliterator<T>> function,
      int topCharacteristics,
      long topSize) {
    checkArgument(
        (topCharacteristics & Spliterator.SUBSIZED) == 0,
        "flatMap does not support SUBSIZED characteristic");
    checkArgument(
        (topCharacteristics & Spliterator.SORTED) == 0,
        "flatMap does not support SORTED characteristic");
    checkNotNull(fromSpliterator);
    checkNotNull(function);
    class FlatMapSpliterator implements Spliterator<T> {
      @Nullable Spliterator<T> prefix;
      final Spliterator<F> from;
      int characteristics;
      long estimatedSize;

      FlatMapSpliterator(
          Spliterator<T> prefix, Spliterator<F> from, int characteristics, long estimatedSize) {
        this.prefix = prefix;
        this.from = from;
        this.characteristics = characteristics;
        this.estimatedSize = estimatedSize;
      }

      @Override
      public boolean tryAdvance(Consumer<? super T> action) {
        while (true) {
          if (prefix != null && prefix.tryAdvance(action)) {
            if (estimatedSize != Long.MAX_VALUE) {
              estimatedSize--;
            }
            return true;
          } else {
            prefix = null;
          }
          if (!from.tryAdvance(fromElement -> prefix = function.apply(fromElement))) {
            return false;
          }
        }
      }

      @Override
      public void forEachRemaining(Consumer<? super T> action) {
        if (prefix != null) {
          prefix.forEachRemaining(action);
          prefix = null;
        }
        from.forEachRemaining(fromElement -> function.apply(fromElement).forEachRemaining(action));
        estimatedSize = 0;
      }

      @Override
      public Spliterator<T> trySplit() {
        Spliterator<F> fromSplit = from.trySplit();
        if (fromSplit != null) {
          int splitCharacteristics = characteristics & ~Spliterator.SIZED;
          long estSplitSize = estimateSize();
          if (estSplitSize < Long.MAX_VALUE) {
            estSplitSize /= 2;
            this.estimatedSize -= estSplitSize;
            this.characteristics = splitCharacteristics;
          }
          Spliterator<T> result =
              new FlatMapSpliterator(this.prefix, fromSplit, splitCharacteristics, estSplitSize);
          this.prefix = null;
          return result;
        } else if (prefix != null) {
          Spliterator<T> result = prefix;
          this.prefix = null;
          return result;
        } else {
          return null;
        }
      }

      @Override
      public long estimateSize() {
        if (prefix != null) {
          estimatedSize = Math.max(estimatedSize, prefix.estimateSize());
        }
        return Math.max(estimatedSize, 0);
      }

      @Override
      public int characteristics() {
        return characteristics;
      }
    }
    return new FlatMapSpliterator(null, fromSpliterator, topCharacteristics, topSize);
  }
static <F, T> Spliterator<T> flatMap(
      Spliterator<F> fromSpliterator,
      Function<? super F, Spliterator<T>> function,
      int topCharacteristics,
      long topSize) {
    checkArgument(
        (topCharacteristics & Spliterator.SUBSIZED) == 0,
        "flatMap does not support SUBSIZED characteristic");
    checkArgument(
        (topCharacteristics & Spliterator.SORTED) == 0,
        "flatMap does not support SORTED characteristic");
    checkNotNull(fromSpliterator);
    checkNotNull(function);
    class FlatMapSpliterator implements Spliterator<T> {
      @Nullable Spliterator<T> prefix;
      final Spliterator<F> from;
      int characteristics;
      long estimatedSize;

      FlatMapSpliterator(
          Spliterator<T> prefix, Spliterator<F> from, int characteristics, long estimatedSize) {
        this.prefix = prefix;
        this.from = from;
        this.characteristics = characteristics;
        this.estimatedSize = estimatedSize;
      }

      @Override
      public boolean tryAdvance(Consumer<? super T> action) {
        while (true) {
          if (prefix != null && prefix.tryAdvance(action)) {
            if (estimatedSize != Long.MAX_VALUE) {
              estimatedSize--;
            }
            return true;
          } else {
            prefix = null;
          }
          if (!from.tryAdvance(fromElement -> prefix = function.apply(fromElement))) {
            return false;
          }
        }
      }

      @Override
      public void forEachRemaining(Consumer<? super T> action) {
        if (prefix != null) {
          prefix.forEachRemaining(action);
          prefix = null;
        }
        from.forEachRemaining(fromElement -> function.apply(fromElement).forEachRemaining(action));
        estimatedSize = 0;
      }

      @Override
      public Spliterator<T> trySplit() {
        Spliterator<F> fromSplit = from.trySplit();
        if (fromSplit != null) {
          int splitCharacteristics = characteristics & ~Spliterator.SIZED;
          long estSplitSize = estimateSize();
          if (estSplitSize < Long.MAX_VALUE) {
            estSplitSize /= 2;
            this.estimatedSize -= estSplitSize;
            this.characteristics = splitCharacteristics;
          }
          Spliterator<T> result =
              new FlatMapSpliterator(this.prefix, fromSplit, splitCharacteristics, estSplitSize);
          this.prefix = null;
          return result;
        } else if (prefix != null) {
          Spliterator<T> result = prefix;
          this.prefix = null;
          return result;
        } else {
          return null;
        }
      }

      @Override
      public long estimateSize() {
        if (prefix != null) {
          estimatedSize = Math.max(estimatedSize, prefix.estimateSize());
        }
        return Math.max(estimatedSize, 0);
      }

      @Override
      public int characteristics() {
        return characteristics;
      }
    }
    return new FlatMapSpliterator(null, fromSpliterator, topCharacteristics, topSize);
  }
static < F , T > Spliterator < T > flatMap ( Spliterator < F > fromSpliterator , Function < ? super F , Spliterator < T > > function , int topCharacteristics , long topSize ) { checkArgument ( ( topCharacteristics & Spliterator . SUBSIZED ) == 0 , "flatMap does not support SUBSIZED characteristic" ) ; checkArgument ( ( topCharacteristics & Spliterator . SORTED ) == 0 , "flatMap does not support SORTED characteristic" ) ; checkNotNull ( fromSpliterator ) ; checkNotNull ( function ) ; class FlatMapSpliterator implements Spliterator < T > { @ Nullable Spliterator < T > prefix ; final Spliterator < F > from ; int characteristics ; long estimatedSize ; FlatMapSpliterator ( Spliterator < T > prefix , Spliterator < F > from , int characteristics , long estimatedSize ) { this . prefix = prefix ; this . from = from ; this . characteristics = characteristics ; this . estimatedSize = estimatedSize ; } @ Override public boolean tryAdvance ( Consumer < ? super T > action ) { while ( true ) { if ( prefix != null && prefix . tryAdvance ( action ) ) { if ( estimatedSize != Long . MAX_VALUE ) { estimatedSize -- ; } return true ; } else { prefix = null ; } if ( ! from . tryAdvance ( fromElement -> prefix = function . apply ( fromElement ) ) ) { return false ; } } } @ Override public void forEachRemaining ( Consumer < ? super T > action ) { if ( prefix != null ) { prefix . forEachRemaining ( action ) ; prefix = null ; } from . forEachRemaining ( fromElement -> function . apply ( fromElement ) . forEachRemaining ( action ) ) ; estimatedSize = 0 ; } @ Override public Spliterator < T > trySplit ( ) { Spliterator < F > fromSplit = from . trySplit ( ) ; if ( fromSplit != null ) { int splitCharacteristics = characteristics & ~ Spliterator . SIZED ; long estSplitSize = estimateSize ( ) ; if ( estSplitSize < Long . MAX_VALUE ) { estSplitSize /= 2 ; this . estimatedSize -= estSplitSize ; this . characteristics = splitCharacteristics ; } Spliterator < T > result = new FlatMapSpliterator ( this . prefix , fromSplit , splitCharacteristics , estSplitSize ) ; this . prefix = null ; return result ; } else if ( prefix != null ) { Spliterator < T > result = prefix ; this . prefix = null ; return result ; } else { return null ; } } @ Override public long estimateSize ( ) { if ( prefix != null ) { estimatedSize = Math . max ( estimatedSize , prefix . estimateSize ( ) ) ; } return Math . max ( estimatedSize , 0 ) ; } @ Override public int characteristics ( ) { return characteristics ; } } return new FlatMapSpliterator ( null , fromSpliterator , topCharacteristics , topSize ) ; }
Returns a {@code Spliterator} that iterates over the elements of the spliterators generated by
applying {@code function} to the elements of {@code fromSpliterator}.
Returns a {