content: /*
   * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package java.util;
  
  import java.util.function.Consumer;
  import java.util.function.DoubleConsumer;
  import java.util.function.IntConsumer;
  import java.util.function.LongConsumer;
  
  /**
   * Static classes and methods for operating on or creating instances of
   * {@link Spliterator} and its primitive specializations
   * {@link Spliterator.OfInt}, {@link Spliterator.OfLong}, and
   * {@link Spliterator.OfDouble}.
   *
   * @see Spliterator
   * @since 1.8
   */
  public final class Spliterators {
  
      // Suppresses default constructor, ensuring non-instantiability.
      private Spliterators() {}
  
      // Empty spliterators
  
      /**
       * Creates an empty {@code Spliterator}
       *
       * <p>The empty spliterator reports {@link Spliterator#SIZED} and
       * {@link Spliterator#SUBSIZED}.  Calls to
       * {@link Spliterator#trySplit()} always return {@code null}.
       *
       * @param <T> Type of elements
       * @return An empty spliterator
       */
      @SuppressWarnings("unchecked")
      public static <T> Spliterator<T> emptySpliterator() {
          return (Spliterator<T>) EMPTY_SPLITERATOR;
      }
  
      private static final Spliterator<Object> EMPTY_SPLITERATOR =
              new EmptySpliterator.OfRef<>();
  
      /**
       * Creates an empty {@code Spliterator.OfInt}
       *
       * <p>The empty spliterator reports {@link Spliterator#SIZED} and
       * {@link Spliterator#SUBSIZED}.  Calls to
       * {@link Spliterator#trySplit()} always return {@code null}.
       *
       * @return An empty spliterator
       */
      public static Spliterator.OfInt emptyIntSpliterator() {
          return EMPTY_INT_SPLITERATOR;
      }
  
      private static final Spliterator.OfInt EMPTY_INT_SPLITERATOR =
              new EmptySpliterator.OfInt();
  
      /**
       * Creates an empty {@code Spliterator.OfLong}
       *
       * <p>The empty spliterator reports {@link Spliterator#SIZED} and
       * {@link Spliterator#SUBSIZED}.  Calls to
       * {@link Spliterator#trySplit()} always return {@code null}.
       *
       * @return An empty spliterator
       */
      public static Spliterator.OfLong emptyLongSpliterator() {
          return EMPTY_LONG_SPLITERATOR;
      }
  
      private static final Spliterator.OfLong EMPTY_LONG_SPLITERATOR =
              new EmptySpliterator.OfLong();
  
      /**
       * Creates an empty {@code Spliterator.OfDouble}
       *
       * <p>The empty spliterator reports {@link Spliterator#SIZED} and
       * {@link Spliterator#SUBSIZED}.  Calls to
       * {@link Spliterator#trySplit()} always return {@code null}.
       *
       * @return An empty spliterator
       */
      public static Spliterator.OfDouble emptyDoubleSpliterator() {
          return EMPTY_DOUBLE_SPLITERATOR;
      }
  
      private static final Spliterator.OfDouble EMPTY_DOUBLE_SPLITERATOR =
              new EmptySpliterator.OfDouble();
  
      // Array-based spliterators
  
      /**
       * Creates a {@code Spliterator} covering the elements of a given array,
       * using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(Object[])}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report; it is common to
       * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
       *
       * @param <T> Type of elements
       * @param array The array, assumed to be unmodified during use
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @see Arrays#spliterator(Object[])
       */
      public static <T> Spliterator<T> spliterator(Object[] array,
                                                   int additionalCharacteristics) {
          return new ArraySpliterator<>(Objects.requireNonNull(array),
                                        additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator} covering a range of elements of a given
       * array, using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(Object[])}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report; it is common to
       * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
       *
       * @param <T> Type of elements
       * @param array The array, assumed to be unmodified during use
       * @param fromIndex The least index (inclusive) to cover
       * @param toIndex One past the greatest index to cover
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
       *         {@code toIndex} is less than {@code fromIndex}, or
       *         {@code toIndex} is greater than the array size
       * @see Arrays#spliterator(Object[], int, int)
       */
      public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex,
                                                   int additionalCharacteristics) {
          checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
          return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfInt} covering the elements of a given array,
       * using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(int[])}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report; it is common to
       * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
       *
       * @param array The array, assumed to be unmodified during use
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @see Arrays#spliterator(int[])
       */
      public static Spliterator.OfInt spliterator(int[] array,
                                                  int additionalCharacteristics) {
          return new IntArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfInt} covering a range of elements of a
       * given array, using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(int[], int, int)}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report; it is common to
       * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
       *
       * @param array The array, assumed to be unmodified during use
       * @param fromIndex The least index (inclusive) to cover
       * @param toIndex One past the greatest index to cover
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
       *         {@code toIndex} is less than {@code fromIndex}, or
       *         {@code toIndex} is greater than the array size
       * @see Arrays#spliterator(int[], int, int)
       */
      public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex,
                                                  int additionalCharacteristics) {
          checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
          return new IntArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfLong} covering the elements of a given array,
       * using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(long[])}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report; it is common to
       * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
       *
       * @param array The array, assumed to be unmodified during use
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @see Arrays#spliterator(long[])
       */
      public static Spliterator.OfLong spliterator(long[] array,
                                                   int additionalCharacteristics) {
          return new LongArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfLong} covering a range of elements of a
       * given array, using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(long[], int, int)}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report.  (For example, if it is
       * known the array will not be further modified, specify {@code IMMUTABLE};
       * if the array data is considered to have an an encounter order, specify
       * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
       * often be used instead, which returns a spliterator that reports
       * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
       *
       * @param array The array, assumed to be unmodified during use
       * @param fromIndex The least index (inclusive) to cover
       * @param toIndex One past the greatest index to cover
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
       *         {@code toIndex} is less than {@code fromIndex}, or
       *         {@code toIndex} is greater than the array size
       * @see Arrays#spliterator(long[], int, int)
       */
      public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex,
                                                   int additionalCharacteristics) {
          checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
          return new LongArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfDouble} covering the elements of a given array,
       * using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(double[])}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report; it is common to
       * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
       *
       * @param array The array, assumed to be unmodified during use
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @see Arrays#spliterator(double[])
       */
      public static Spliterator.OfDouble spliterator(double[] array,
                                                     int additionalCharacteristics) {
          return new DoubleArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfDouble} covering a range of elements of a
       * given array, using a customized set of spliterator characteristics.
       *
       * <p>This method is provided as an implementation convenience for
       * Spliterators which store portions of their elements in arrays, and need
       * fine control over Spliterator characteristics.  Most other situations in
       * which a Spliterator for an array is needed should use
       * {@link Arrays#spliterator(double[], int, int)}.
       *
       * <p>The returned spliterator always reports the characteristics
       * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
       * characteristics for the spliterator to report.  (For example, if it is
       * known the array will not be further modified, specify {@code IMMUTABLE};
       * if the array data is considered to have an an encounter order, specify
       * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
       * often be used instead, which returns a spliterator that reports
       * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
       *
       * @param array The array, assumed to be unmodified during use
       * @param fromIndex The least index (inclusive) to cover
       * @param toIndex One past the greatest index to cover
       * @param additionalCharacteristics Additional spliterator characteristics
       *        of this spliterator's source or elements beyond {@code SIZED} and
       *        {@code SUBSIZED} which are are always reported
       * @return A spliterator for an array
       * @throws NullPointerException if the given array is {@code null}
       * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
       *         {@code toIndex} is less than {@code fromIndex}, or
       *         {@code toIndex} is greater than the array size
       * @see Arrays#spliterator(double[], int, int)
       */
      public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex,
                                                     int additionalCharacteristics) {
          checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
          return new DoubleArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
      }
  
      /**
       * Validate inclusive start index and exclusive end index against the length
       * of an array.
       * @param arrayLength The length of the array
       * @param origin The inclusive start index
       * @param fence The exclusive end index
       * @throws ArrayIndexOutOfBoundsException if the start index is greater than
       * the end index, if the start index is negative, or the end index is
       * greater than the array length
       */
      private static void checkFromToBounds(int arrayLength, int origin, int fence) {
          if (origin > fence) {
              throw new ArrayIndexOutOfBoundsException(
                      "origin(" + origin + ") > fence(" + fence + ")");
          }
          if (origin < 0) {
              throw new ArrayIndexOutOfBoundsException(origin);
          }
          if (fence > arrayLength) {
              throw new ArrayIndexOutOfBoundsException(fence);
          }
      }
  
      // Iterator-based spliterators
  
      /**
       * Creates a {@code Spliterator} using the given collection's
       * {@link Collection#iterator()} as the source of elements, and
       * reporting its {@link Collection#size()} as its initial size.
       *
       * <p>The spliterator is
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the collection's iterator, and
       * implements {@code trySplit} to permit limited parallelism.
       *
       * @param <T> Type of elements
       * @param c The collection
       * @param characteristics Characteristics of this spliterator's source or
       *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
       *        are additionally reported unless {@code CONCURRENT} is supplied.
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given collection is {@code null}
       */
      public static <T> Spliterator<T> spliterator(Collection<? extends T> c,
                                                   int characteristics) {
          return new IteratorSpliterator<>(Objects.requireNonNull(c),
                                           characteristics);
      }
  
      /**
       * Creates a {@code Spliterator} using a given {@code Iterator}
       * as the source of elements, and with a given initially reported size.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned, or the initially reported
       * size is not equal to the actual number of elements in the source.
       *
       * @param <T> Type of elements
       * @param iterator The iterator for the source
       * @param size The number of elements in the source, to be reported as
       *        initial {@code estimateSize}
       * @param characteristics Characteristics of this spliterator's source or
       *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
       *        are additionally reported unless {@code CONCURRENT} is supplied.
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static <T> Spliterator<T> spliterator(Iterator<? extends T> iterator,
                                                   long size,
                                                   int characteristics) {
          return new IteratorSpliterator<>(Objects.requireNonNull(iterator), size,
                                           characteristics);
      }
  
      /**
       * Creates a {@code Spliterator} using a given {@code Iterator}
       * as the source of elements, with no initial size estimate.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned.
       *
       * @param <T> Type of elements
       * @param iterator The iterator for the source
       * @param characteristics Characteristics of this spliterator's source
       *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
       *        ignored and are not reported.)
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator,
                                                              int characteristics) {
          return new IteratorSpliterator<>(Objects.requireNonNull(iterator), characteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfInt} using a given
       * {@code IntStream.IntIterator} as the source of elements, and with a given
       * initially reported size.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned, or the initially reported
       * size is not equal to the actual number of elements in the source.
       *
       * @param iterator The iterator for the source
       * @param size The number of elements in the source, to be reported as
       *        initial {@code estimateSize}.
       * @param characteristics Characteristics of this spliterator's source or
       *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
       *        are additionally reported unless {@code CONCURRENT} is supplied.
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt iterator,
                                                  long size,
                                                  int characteristics) {
          return new IntIteratorSpliterator(Objects.requireNonNull(iterator),
                                            size, characteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfInt} using a given
       * {@code IntStream.IntIterator} as the source of elements, with no initial
       * size estimate.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned.
       *
       * @param iterator The iterator for the source
       * @param characteristics Characteristics of this spliterator's source
       *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
       *        ignored and are not reported.)
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static Spliterator.OfInt spliteratorUnknownSize(PrimitiveIterator.OfInt iterator,
                                                             int characteristics) {
          return new IntIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfLong} using a given
       * {@code LongStream.LongIterator} as the source of elements, and with a
       * given initially reported size.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned, or the initially reported
       * size is not equal to the actual number of elements in the source.
       *
       * @param iterator The iterator for the source
       * @param size The number of elements in the source, to be reported as
       *        initial {@code estimateSize}.
       * @param characteristics Characteristics of this spliterator's source or
       *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
       *        are additionally reported unless {@code CONCURRENT} is supplied.
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong iterator,
                                                   long size,
                                                   int characteristics) {
          return new LongIteratorSpliterator(Objects.requireNonNull(iterator),
                                             size, characteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfLong} using a given
       * {@code LongStream.LongIterator} as the source of elements, with no
       * initial size estimate.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned.
       *
       * @param iterator The iterator for the source
       * @param characteristics Characteristics of this spliterator's source
       *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
       *        ignored and are not reported.)
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static Spliterator.OfLong spliteratorUnknownSize(PrimitiveIterator.OfLong iterator,
                                                              int characteristics) {
          return new LongIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfDouble} using a given
       * {@code DoubleStream.DoubleIterator} as the source of elements, and with a
       * given initially reported size.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned, or the initially reported
       * size is not equal to the actual number of elements in the source.
       *
       * @param iterator The iterator for the source
       * @param size The number of elements in the source, to be reported as
       *        initial {@code estimateSize}
       * @param characteristics Characteristics of this spliterator's source or
       *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
       *        are additionally reported unless {@code CONCURRENT} is supplied.
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble iterator,
                                                     long size,
                                                     int characteristics) {
          return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator),
                                               size, characteristics);
      }
  
      /**
       * Creates a {@code Spliterator.OfDouble} using a given
       * {@code DoubleStream.DoubleIterator} as the source of elements, with no
       * initial size estimate.
       *
       * <p>The spliterator is not
       * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
       * the <em>fail-fast</em> properties of the iterator, and implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>Traversal of elements should be accomplished through the spliterator.
       * The behaviour of splitting and traversal is undefined if the iterator is
       * operated on after the spliterator is returned.
       *
       * @param iterator The iterator for the source
       * @param characteristics Characteristics of this spliterator's source
       *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
       *        ignored and are not reported.)
       * @return A spliterator from an iterator
       * @throws NullPointerException if the given iterator is {@code null}
       */
      public static Spliterator.OfDouble spliteratorUnknownSize(PrimitiveIterator.OfDouble iterator,
                                                                int characteristics) {
          return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
      }
  
      // Iterators from Spliterators
  
      /**
       * Creates an {@code Iterator} from a {@code Spliterator}.
       *
       * <p>Traversal of elements should be accomplished through the iterator.
       * The behaviour of traversal is undefined if the spliterator is operated
       * after the iterator is returned.
       *
       * @param <T> Type of elements
       * @param spliterator The spliterator
       * @return An iterator
       * @throws NullPointerException if the given spliterator is {@code null}
       */
      public static<T> Iterator<T> iterator(Spliterator<? extends T> spliterator) {
          Objects.requireNonNull(spliterator);
          class Adapter implements Iterator<T>, Consumer<T> {
              boolean valueReady = false;
              T nextElement;
  
              @Override
              public void accept(T t) {
                  valueReady = true;
                  nextElement = t;
              }
  
              @Override
              public boolean hasNext() {
                  if (!valueReady)
                      spliterator.tryAdvance(this);
                  return valueReady;
              }
  
              @Override
              public T next() {
                  if (!valueReady && !hasNext())
                      throw new NoSuchElementException();
                  else {
                      valueReady = false;
                      return nextElement;
                  }
              }
          }
  
          return new Adapter();
      }
  
      /**
       * Creates an {@code PrimitiveIterator.OfInt} from a
       * {@code Spliterator.OfInt}.
       *
       * <p>Traversal of elements should be accomplished through the iterator.
       * The behaviour of traversal is undefined if the spliterator is operated
       * after the iterator is returned.
       *
       * @param spliterator The spliterator
       * @return An iterator
       * @throws NullPointerException if the given spliterator is {@code null}
       */
      public static PrimitiveIterator.OfInt iterator(Spliterator.OfInt spliterator) {
          Objects.requireNonNull(spliterator);
          class Adapter implements PrimitiveIterator.OfInt, IntConsumer {
              boolean valueReady = false;
              int nextElement;
  
              @Override
              public void accept(int t) {
                  valueReady = true;
                  nextElement = t;
              }
  
              @Override
              public boolean hasNext() {
                  if (!valueReady)
                      spliterator.tryAdvance(this);
                  return valueReady;
              }
  
              @Override
              public int nextInt() {
                  if (!valueReady && !hasNext())
                      throw new NoSuchElementException();
                  else {
                      valueReady = false;
                      return nextElement;
                  }
              }
          }
  
          return new Adapter();
      }
  
      /**
       * Creates an {@code PrimitiveIterator.OfLong} from a
       * {@code Spliterator.OfLong}.
       *
       * <p>Traversal of elements should be accomplished through the iterator.
       * The behaviour of traversal is undefined if the spliterator is operated
       * after the iterator is returned.
       *
       * @param spliterator The spliterator
       * @return An iterator
       * @throws NullPointerException if the given spliterator is {@code null}
       */
      public static PrimitiveIterator.OfLong iterator(Spliterator.OfLong spliterator) {
          Objects.requireNonNull(spliterator);
          class Adapter implements PrimitiveIterator.OfLong, LongConsumer {
              boolean valueReady = false;
              long nextElement;
  
              @Override
              public void accept(long t) {
                  valueReady = true;
                  nextElement = t;
              }
  
              @Override
              public boolean hasNext() {
                  if (!valueReady)
                      spliterator.tryAdvance(this);
                  return valueReady;
              }
  
              @Override
              public long nextLong() {
                  if (!valueReady && !hasNext())
                      throw new NoSuchElementException();
                  else {
                      valueReady = false;
                      return nextElement;
                  }
              }
          }
  
          return new Adapter();
      }
  
      /**
       * Creates an {@code PrimitiveIterator.OfDouble} from a
       * {@code Spliterator.OfDouble}.
       *
       * <p>Traversal of elements should be accomplished through the iterator.
       * The behaviour of traversal is undefined if the spliterator is operated
       * after the iterator is returned.
       *
       * @param spliterator The spliterator
       * @return An iterator
       * @throws NullPointerException if the given spliterator is {@code null}
       */
      public static PrimitiveIterator.OfDouble iterator(Spliterator.OfDouble spliterator) {
          Objects.requireNonNull(spliterator);
          class Adapter implements PrimitiveIterator.OfDouble, DoubleConsumer {
              boolean valueReady = false;
              double nextElement;
  
              @Override
              public void accept(double t) {
                  valueReady = true;
                  nextElement = t;
              }
  
              @Override
              public boolean hasNext() {
                  if (!valueReady)
                      spliterator.tryAdvance(this);
                  return valueReady;
              }
  
              @Override
              public double nextDouble() {
                  if (!valueReady && !hasNext())
                      throw new NoSuchElementException();
                  else {
                      valueReady = false;
                      return nextElement;
                  }
              }
          }
  
          return new Adapter();
      }
  
      // Implementations
  
      private static abstract class EmptySpliterator<T, S extends Spliterator<T>, C> {
  
          EmptySpliterator() { }
  
          public S trySplit() {
              return null;
          }
  
          public boolean tryAdvance(C consumer) {
              Objects.requireNonNull(consumer);
              return false;
          }
  
          public void forEachRemaining(C consumer) {
              Objects.requireNonNull(consumer);
          }
  
          public long estimateSize() {
              return 0;
          }
  
          public int characteristics() {
              return Spliterator.SIZED | Spliterator.SUBSIZED;
          }
  
          private static final class OfRef<T>
                  extends EmptySpliterator<T, Spliterator<T>, Consumer<? super T>>
                  implements Spliterator<T> {
              OfRef() { }
          }
  
          private static final class OfInt
                  extends EmptySpliterator<Integer, Spliterator.OfInt, IntConsumer>
                  implements Spliterator.OfInt {
              OfInt() { }
          }
  
          private static final class OfLong
                  extends EmptySpliterator<Long, Spliterator.OfLong, LongConsumer>
                  implements Spliterator.OfLong {
              OfLong() { }
          }
  
          private static final class OfDouble
                  extends EmptySpliterator<Double, Spliterator.OfDouble, DoubleConsumer>
                  implements Spliterator.OfDouble {
              OfDouble() { }
          }
      }
  
      // Array-based spliterators
  
      /**
       * A Spliterator designed for use by sources that traverse and split
       * elements maintained in an unmodifiable {@code Object[]} array.
       */
      static final class ArraySpliterator<T> implements Spliterator<T> {
          /**
           * The array, explicitly typed as Object[]. Unlike in some other
           * classes (see for example CR 6260652), we do not need to
           * screen arguments to ensure they are exactly of type Object[]
           * so long as no methods write into the array or serialize it,
           * which we ensure here by defining this class as final.
           */
          private final Object[] array;
          private int index;        // current index, modified on advance/split
          private final int fence;  // one past last index
          private final int characteristics;
  
          /**
           * Creates a spliterator covering all of the given array.
           * @param array the array, assumed to be unmodified during use
           * @param additionalCharacteristics Additional spliterator characteristics
           * of this spliterator's source or elements beyond {@code SIZED} and
           * {@code SUBSIZED} which are are always reported
           */
          public ArraySpliterator(Object[] array, int additionalCharacteristics) {
              this(array, 0, array.length, additionalCharacteristics);
          }
  
          /**
           * Creates a spliterator covering the given array and range
           * @param array the array, assumed to be unmodified during use
           * @param origin the least index (inclusive) to cover
           * @param fence one past the greatest index to cover
           * @param additionalCharacteristics Additional spliterator characteristics
           * of this spliterator's source or elements beyond {@code SIZED} and
           * {@code SUBSIZED} which are are always reported
           */
          public ArraySpliterator(Object[] array, int origin, int fence, int additionalCharacteristics) {
              this.array = array;
              this.index = origin;
              this.fence = fence;
              this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
          }
  
          @Override
          public Spliterator<T> trySplit() {
              int lo = index, mid = (lo + fence) >>> 1;
              return (lo >= mid)
                     ? null
                     : new ArraySpliterator<>(array, lo, index = mid, characteristics);
          }
  
          @SuppressWarnings("unchecked")
          @Override
          public void forEachRemaining(Consumer<? super T> action) {
              Object[] a; int i, hi; // hoist accesses and checks from loop
              if (action == null)
                  throw new NullPointerException();
              if ((a = array).length >= (hi = fence) &&
                  (i = index) >= 0 && i < (index = hi)) {
                  do { action.accept((T)a[i]); } while (++i < hi);
              }
          }
  
          @Override
          public boolean tryAdvance(Consumer<? super T> action) {
              if (action == null)
                  throw new NullPointerException();
              if (index >= 0 && index < fence) {
                  @SuppressWarnings("unchecked") T e = (T) array[index++];
                  action.accept(e);
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() { return (long)(fence - index); }
  
          @Override
          public int characteristics() {
              return characteristics;
          }
  
          @Override
          public Comparator<? super T> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      /**
       * A Spliterator.OfInt designed for use by sources that traverse and split
       * elements maintained in an unmodifiable {@code int[]} array.
       */
      static final class IntArraySpliterator implements Spliterator.OfInt {
          private final int[] array;
          private int index;        // current index, modified on advance/split
          private final int fence;  // one past last index
          private final int characteristics;
  
          /**
           * Creates a spliterator covering all of the given array.
           * @param array the array, assumed to be unmodified during use
           * @param additionalCharacteristics Additional spliterator characteristics
           *        of this spliterator's source or elements beyond {@code SIZED} and
           *        {@code SUBSIZED} which are are always reported
           */
          public IntArraySpliterator(int[] array, int additionalCharacteristics) {
              this(array, 0, array.length, additionalCharacteristics);
          }
  
          /**
           * Creates a spliterator covering the given array and range
           * @param array the array, assumed to be unmodified during use
           * @param origin the least index (inclusive) to cover
           * @param fence one past the greatest index to cover
           * @param additionalCharacteristics Additional spliterator characteristics
           *        of this spliterator's source or elements beyond {@code SIZED} and
           *        {@code SUBSIZED} which are are always reported
           */
          public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) {
              this.array = array;
              this.index = origin;
              this.fence = fence;
              this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
          }
  
          @Override
          public OfInt trySplit() {
              int lo = index, mid = (lo + fence) >>> 1;
              return (lo >= mid)
                     ? null
                     : new IntArraySpliterator(array, lo, index = mid, characteristics);
          }
  
          @Override
          public void forEachRemaining(IntConsumer action) {
              int[] a; int i, hi; // hoist accesses and checks from loop
              if (action == null)
                  throw new NullPointerException();
              if ((a = array).length >= (hi = fence) &&
                  (i = index) >= 0 && i < (index = hi)) {
                  do { action.accept(a[i]); } while (++i < hi);
              }
          }
  
          @Override
          public boolean tryAdvance(IntConsumer action) {
              if (action == null)
                  throw new NullPointerException();
              if (index >= 0 && index < fence) {
                  action.accept(array[index++]);
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() { return (long)(fence - index); }
  
          @Override
          public int characteristics() {
              return characteristics;
          }
  
          @Override
          public Comparator<? super Integer> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      /**
       * A Spliterator.OfLong designed for use by sources that traverse and split
       * elements maintained in an unmodifiable {@code int[]} array.
       */
      static final class LongArraySpliterator implements Spliterator.OfLong {
          private final long[] array;
          private int index;        // current index, modified on advance/split
          private final int fence;  // one past last index
          private final int characteristics;
  
          /**
           * Creates a spliterator covering all of the given array.
           * @param array the array, assumed to be unmodified during use
           * @param additionalCharacteristics Additional spliterator characteristics
           *        of this spliterator's source or elements beyond {@code SIZED} and
           *        {@code SUBSIZED} which are are always reported
           */
          public LongArraySpliterator(long[] array, int additionalCharacteristics) {
              this(array, 0, array.length, additionalCharacteristics);
          }
  
          /**
           * Creates a spliterator covering the given array and range
           * @param array the array, assumed to be unmodified during use
           * @param origin the least index (inclusive) to cover
           * @param fence one past the greatest index to cover
           * @param additionalCharacteristics Additional spliterator characteristics
           *        of this spliterator's source or elements beyond {@code SIZED} and
           *        {@code SUBSIZED} which are are always reported
           */
          public LongArraySpliterator(long[] array, int origin, int fence, int additionalCharacteristics) {
              this.array = array;
              this.index = origin;
              this.fence = fence;
              this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
          }
  
          @Override
          public OfLong trySplit() {
              int lo = index, mid = (lo + fence) >>> 1;
              return (lo >= mid)
                     ? null
                     : new LongArraySpliterator(array, lo, index = mid, characteristics);
          }
  
          @Override
          public void forEachRemaining(LongConsumer action) {
              long[] a; int i, hi; // hoist accesses and checks from loop
              if (action == null)
                  throw new NullPointerException();
              if ((a = array).length >= (hi = fence) &&
                  (i = index) >= 0 && i < (index = hi)) {
                  do { action.accept(a[i]); } while (++i < hi);
              }
          }
  
          @Override
          public boolean tryAdvance(LongConsumer action) {
              if (action == null)
                  throw new NullPointerException();
              if (index >= 0 && index < fence) {
                  action.accept(array[index++]);
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() { return (long)(fence - index); }
  
          @Override
          public int characteristics() {
              return characteristics;
          }
  
          @Override
          public Comparator<? super Long> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      /**
       * A Spliterator.OfDouble designed for use by sources that traverse and split
       * elements maintained in an unmodifiable {@code int[]} array.
       */
      static final class DoubleArraySpliterator implements Spliterator.OfDouble {
          private final double[] array;
          private int index;        // current index, modified on advance/split
          private final int fence;  // one past last index
          private final int characteristics;
  
          /**
           * Creates a spliterator covering all of the given array.
           * @param array the array, assumed to be unmodified during use
           * @param additionalCharacteristics Additional spliterator characteristics
           *        of this spliterator's source or elements beyond {@code SIZED} and
           *        {@code SUBSIZED} which are are always reported
           */
          public DoubleArraySpliterator(double[] array, int additionalCharacteristics) {
              this(array, 0, array.length, additionalCharacteristics);
          }
  
          /**
           * Creates a spliterator covering the given array and range
           * @param array the array, assumed to be unmodified during use
           * @param origin the least index (inclusive) to cover
           * @param fence one past the greatest index to cover
           * @param additionalCharacteristics Additional spliterator characteristics
           *        of this spliterator's source or elements beyond {@code SIZED} and
           *        {@code SUBSIZED} which are are always reported
           */
          public DoubleArraySpliterator(double[] array, int origin, int fence, int additionalCharacteristics) {
              this.array = array;
              this.index = origin;
              this.fence = fence;
              this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
          }
  
          @Override
          public OfDouble trySplit() {
              int lo = index, mid = (lo + fence) >>> 1;
              return (lo >= mid)
                     ? null
                     : new DoubleArraySpliterator(array, lo, index = mid, characteristics);
          }
  
          @Override
          public void forEachRemaining(DoubleConsumer action) {
              double[] a; int i, hi; // hoist accesses and checks from loop
              if (action == null)
                  throw new NullPointerException();
              if ((a = array).length >= (hi = fence) &&
                  (i = index) >= 0 && i < (index = hi)) {
                  do { action.accept(a[i]); } while (++i < hi);
              }
          }
  
          @Override
          public boolean tryAdvance(DoubleConsumer action) {
              if (action == null)
                  throw new NullPointerException();
              if (index >= 0 && index < fence) {
                  action.accept(array[index++]);
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() { return (long)(fence - index); }
  
          @Override
          public int characteristics() {
              return characteristics;
          }
  
          @Override
          public Comparator<? super Double> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      //
  
      /**
       * An abstract {@code Spliterator} that implements {@code trySplit} to
       * permit limited parallelism.
       *
       * <p>An extending class need only
       * implement {@link #tryAdvance(Consumer) tryAdvance}.
       * The extending class should override
       * {@link #forEachRemaining(Consumer) forEach} if it can
       * provide a more performant implementation.
       *
       * @apiNote
       * This class is a useful aid for creating a spliterator when it is not
       * possible or difficult to efficiently partition elements in a manner
       * allowing balanced parallel computation.
       *
       * <p>An alternative to using this class, that also permits limited
       * parallelism, is to create a spliterator from an iterator
       * (see {@link #spliterator(Iterator, long, int)}.  Depending on the
       * circumstances using an iterator may be easier or more convenient than
       * extending this class, such as when there is already an iterator
       * available to use.
       *
       * @see #spliterator(Iterator, long, int)
       * @since 1.8
       */
      public static abstract class AbstractSpliterator<T> implements Spliterator<T> {
          static final int BATCH_UNIT = 1 << 10;  // batch array size increment
          static final int MAX_BATCH = 1 << 25;  // max batch array size;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator reporting the given estimated size and
           * additionalCharacteristics.
           *
           * @param est the estimated size of this spliterator if known, otherwise
           *        {@code Long.MAX_VALUE}.
           * @param additionalCharacteristics properties of this spliterator's
           *        source or elements.  If {@code SIZED} is reported then this
           *        spliterator will additionally report {@code SUBSIZED}.
           */
          protected AbstractSpliterator(long est, int additionalCharacteristics) {
              this.est = est;
              this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
                                     ? additionalCharacteristics | Spliterator.SUBSIZED
                                     : additionalCharacteristics;
          }
  
          static final class HoldingConsumer<T> implements Consumer<T> {
              Object value;
  
              @Override
              public void accept(T value) {
                  this.value = value;
              }
          }
  
          /**
           * {@inheritDoc}
           *
           * This implementation permits limited parallelism.
           */
          @Override
          public Spliterator<T> trySplit() {
              /*
               * Split into arrays of arithmetically increasing batch
               * sizes.  This will only improve parallel performance if
               * per-element Consumer actions are more costly than
               * transferring them into an array.  The use of an
               * arithmetic progression in split sizes provides overhead
               * vs parallelism bounds that do not particularly favor or
               * penalize cases of lightweight vs heavyweight element
               * operations, across combinations of #elements vs #cores,
               * whether or not either are known.  We generate
               * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
               * potential speedup.
               */
              HoldingConsumer<T> holder = new HoldingConsumer<>();
              long s = est;
              if (s > 1 && tryAdvance(holder)) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  Object[] a = new Object[n];
                  int j = 0;
                  do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new ArraySpliterator<>(a, 0, j, characteristics());
              }
              return null;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the estimated size as reported when
           * created and, if the estimate size is known, decreases in size when
           * split.
           */
          @Override
          public long estimateSize() {
              return est;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the characteristics as reported when
           * created.
           */
          @Override
          public int characteristics() {
              return characteristics;
          }
      }
  
      /**
       * An abstract {@code Spliterator.OfInt} that implements {@code trySplit} to
       * permit limited parallelism.
       *
       * <p>To implement a spliterator an extending class need only
       * implement {@link #tryAdvance(IntConsumer)}
       * tryAdvance}.  The extending class should override
       * {@link #forEachRemaining(IntConsumer)} forEach} if it
       * can provide a more performant implementation.
       *
       * @apiNote
       * This class is a useful aid for creating a spliterator when it is not
       * possible or difficult to efficiently partition elements in a manner
       * allowing balanced parallel computation.
       *
       * <p>An alternative to using this class, that also permits limited
       * parallelism, is to create a spliterator from an iterator
       * (see {@link #spliterator(PrimitiveIterator.OfInt, long, int)}.
       * Depending on the circumstances using an iterator may be easier or more
       * convenient than extending this class. For example, if there is already an
       * iterator available to use then there is no need to extend this class.
       *
       * @see #spliterator(PrimitiveIterator.OfInt, long, int)
       * @since 1.8
       */
      public static abstract class AbstractIntSpliterator implements Spliterator.OfInt {
          static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
          static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator reporting the given estimated size and
           * characteristics.
           *
           * @param est the estimated size of this spliterator if known, otherwise
           *        {@code Long.MAX_VALUE}.
           * @param additionalCharacteristics properties of this spliterator's
           *        source or elements.  If {@code SIZED} is reported then this
           *        spliterator will additionally report {@code SUBSIZED}.
           */
          protected AbstractIntSpliterator(long est, int additionalCharacteristics) {
              this.est = est;
              this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
                                     ? additionalCharacteristics | Spliterator.SUBSIZED
                                     : additionalCharacteristics;
          }
  
          static final class HoldingIntConsumer implements IntConsumer {
              int value;
  
              @Override
              public void accept(int value) {
                  this.value = value;
              }
          }
  
          /**
           * {@inheritDoc}
           *
           * This implementation permits limited parallelism.
           */
          @Override
          public OfInt trySplit() {
              HoldingIntConsumer holder = new HoldingIntConsumer();
              long s = est;
              if (s > 1 && tryAdvance(holder)) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  int[] a = new int[n];
                  int j = 0;
                  do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new IntArraySpliterator(a, 0, j, characteristics());
              }
              return null;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the estimated size as reported when
           * created and, if the estimate size is known, decreases in size when
           * split.
           */
          @Override
          public long estimateSize() {
              return est;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the characteristics as reported when
           * created.
           */
          @Override
          public int characteristics() {
              return characteristics;
          }
      }
  
      /**
       * An abstract {@code Spliterator.OfLong} that implements {@code trySplit}
       * to permit limited parallelism.
       *
       * <p>To implement a spliterator an extending class need only
       * implement {@link #tryAdvance(LongConsumer)}
       * tryAdvance}.  The extending class should override
       * {@link #forEachRemaining(LongConsumer)} forEach} if it
       * can provide a more performant implementation.
       *
       * @apiNote
       * This class is a useful aid for creating a spliterator when it is not
       * possible or difficult to efficiently partition elements in a manner
       * allowing balanced parallel computation.
       *
       * <p>An alternative to using this class, that also permits limited
       * parallelism, is to create a spliterator from an iterator
       * (see {@link #spliterator(PrimitiveIterator.OfLong, long, int)}.
       * Depending on the circumstances using an iterator may be easier or more
       * convenient than extending this class. For example, if there is already an
       * iterator available to use then there is no need to extend this class.
       *
       * @see #spliterator(PrimitiveIterator.OfLong, long, int)
       * @since 1.8
       */
      public static abstract class AbstractLongSpliterator implements Spliterator.OfLong {
          static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
          static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator reporting the given estimated size and
           * characteristics.
           *
           * @param est the estimated size of this spliterator if known, otherwise
           *        {@code Long.MAX_VALUE}.
           * @param additionalCharacteristics properties of this spliterator's
           *        source or elements.  If {@code SIZED} is reported then this
           *        spliterator will additionally report {@code SUBSIZED}.
           */
          protected AbstractLongSpliterator(long est, int additionalCharacteristics) {
              this.est = est;
              this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
                                     ? additionalCharacteristics | Spliterator.SUBSIZED
                                     : additionalCharacteristics;
          }
  
          static final class HoldingLongConsumer implements LongConsumer {
              long value;
  
              @Override
              public void accept(long value) {
                  this.value = value;
              }
          }
  
          /**
           * {@inheritDoc}
           *
           * This implementation permits limited parallelism.
           */
          @Override
          public OfLong trySplit() {
              HoldingLongConsumer holder = new HoldingLongConsumer();
              long s = est;
              if (s > 1 && tryAdvance(holder)) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  long[] a = new long[n];
                  int j = 0;
                  do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new LongArraySpliterator(a, 0, j, characteristics());
              }
              return null;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the estimated size as reported when
           * created and, if the estimate size is known, decreases in size when
           * split.
           */
          @Override
          public long estimateSize() {
              return est;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the characteristics as reported when
           * created.
           */
          @Override
          public int characteristics() {
              return characteristics;
          }
      }
  
      /**
       * An abstract {@code Spliterator.OfDouble} that implements
       * {@code trySplit} to permit limited parallelism.
       *
       * <p>To implement a spliterator an extending class need only
       * implement {@link #tryAdvance(DoubleConsumer)}
       * tryAdvance}.  The extending class should override
       * {@link #forEachRemaining(DoubleConsumer)} forEach} if
       * it can provide a more performant implementation.
       *
       * @apiNote
       * This class is a useful aid for creating a spliterator when it is not
       * possible or difficult to efficiently partition elements in a manner
       * allowing balanced parallel computation.
       *
       * <p>An alternative to using this class, that also permits limited
       * parallelism, is to create a spliterator from an iterator
       * (see {@link #spliterator(PrimitiveIterator.OfDouble, long, int)}.
       * Depending on the circumstances using an iterator may be easier or more
       * convenient than extending this class. For example, if there is already an
       * iterator available to use then there is no need to extend this class.
       *
       * @see #spliterator(PrimitiveIterator.OfDouble, long, int)
       * @since 1.8
       */
      public static abstract class AbstractDoubleSpliterator implements Spliterator.OfDouble {
          static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
          static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator reporting the given estimated size and
           * characteristics.
           *
           * @param est the estimated size of this spliterator if known, otherwise
           *        {@code Long.MAX_VALUE}.
           * @param additionalCharacteristics properties of this spliterator's
           *        source or elements.  If {@code SIZED} is reported then this
           *        spliterator will additionally report {@code SUBSIZED}.
           */
          protected AbstractDoubleSpliterator(long est, int additionalCharacteristics) {
              this.est = est;
              this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
                                     ? additionalCharacteristics | Spliterator.SUBSIZED
                                     : additionalCharacteristics;
          }
  
          static final class HoldingDoubleConsumer implements DoubleConsumer {
              double value;
  
              @Override
              public void accept(double value) {
                  this.value = value;
              }
          }
  
          /**
           * {@inheritDoc}
           *
           * This implementation permits limited parallelism.
           */
          @Override
          public OfDouble trySplit() {
              HoldingDoubleConsumer holder = new HoldingDoubleConsumer();
              long s = est;
              if (s > 1 && tryAdvance(holder)) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  double[] a = new double[n];
                  int j = 0;
                  do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new DoubleArraySpliterator(a, 0, j, characteristics());
              }
              return null;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the estimated size as reported when
           * created and, if the estimate size is known, decreases in size when
           * split.
           */
          @Override
          public long estimateSize() {
              return est;
          }
  
          /**
           * {@inheritDoc}
           *
           * @implSpec
           * This implementation returns the characteristics as reported when
           * created.
           */
          @Override
          public int characteristics() {
              return characteristics;
          }
      }
  
      // Iterator-based Spliterators
  
      /**
       * A Spliterator using a given Iterator for element
       * operations. The spliterator implements {@code trySplit} to
       * permit limited parallelism.
       */
      static class IteratorSpliterator<T> implements Spliterator<T> {
          static final int BATCH_UNIT = 1 << 10;  // batch array size increment
          static final int MAX_BATCH = 1 << 25;  // max batch array size;
          private final Collection<? extends T> collection; // null OK
          private Iterator<? extends T> it;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator using the given given
           * collection's {@link Collection#iterator()) for traversal,
           * and reporting its {@link Collection#size()) as its initial
           * size.
           *
           * @param c the collection
           * @param characteristics properties of this spliterator's
           *        source or elements.
           */
          public IteratorSpliterator(Collection<? extends T> collection, int characteristics) {
              this.collection = collection;
              this.it = null;
              this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
                                     ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
                                     : characteristics;
          }
  
          /**
           * Creates a spliterator using the given iterator
           * for traversal, and reporting the given initial size
           * and characteristics.
           *
           * @param iterator the iterator for the source
           * @param size the number of elements in the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public IteratorSpliterator(Iterator<? extends T> iterator, long size, int characteristics) {
              this.collection = null;
              this.it = iterator;
              this.est = size;
              this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
                                     ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
                                     : characteristics;
          }
  
          /**
           * Creates a spliterator using the given iterator
           * for traversal, and reporting the given initial size
           * and characteristics.
           *
           * @param iterator the iterator for the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public IteratorSpliterator(Iterator<? extends T> iterator, int characteristics) {
              this.collection = null;
              this.it = iterator;
              this.est = Long.MAX_VALUE;
              this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
          }
  
          @Override
          public Spliterator<T> trySplit() {
              /*
               * Split into arrays of arithmetically increasing batch
               * sizes.  This will only improve parallel performance if
               * per-element Consumer actions are more costly than
               * transferring them into an array.  The use of an
               * arithmetic progression in split sizes provides overhead
               * vs parallelism bounds that do not particularly favor or
               * penalize cases of lightweight vs heavyweight element
               * operations, across combinations of #elements vs #cores,
               * whether or not either are known.  We generate
               * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
               * potential speedup.
               */
              Iterator<? extends T> i;
              long s;
              if ((i = it) == null) {
                  i = it = collection.iterator();
                  s = est = (long) collection.size();
              }
              else
                  s = est;
              if (s > 1 && i.hasNext()) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  Object[] a = new Object[n];
                  int j = 0;
                  do { a[j] = i.next(); } while (++j < n && i.hasNext());
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new ArraySpliterator<>(a, 0, j, characteristics);
              }
              return null;
          }
  
          @Override
          public void forEachRemaining(Consumer<? super T> action) {
              if (action == null) throw new NullPointerException();
              Iterator<? extends T> i;
              if ((i = it) == null) {
                  i = it = collection.iterator();
                  est = (long)collection.size();
              }
              i.forEachRemaining(action);
          }
  
          @Override
          public boolean tryAdvance(Consumer<? super T> action) {
              if (action == null) throw new NullPointerException();
              if (it == null) {
                  it = collection.iterator();
                  est = (long) collection.size();
              }
              if (it.hasNext()) {
                  action.accept(it.next());
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() {
              if (it == null) {
                  it = collection.iterator();
                  return est = (long)collection.size();
              }
              return est;
          }
  
          @Override
          public int characteristics() { return characteristics; }
  
          @Override
          public Comparator<? super T> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      /**
       * A Spliterator.OfInt using a given IntStream.IntIterator for element
       * operations. The spliterator implements {@code trySplit} to
       * permit limited parallelism.
       */
      static final class IntIteratorSpliterator implements Spliterator.OfInt {
          static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
          static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
          private PrimitiveIterator.OfInt it;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator using the given iterator
           * for traversal, and reporting the given initial size
           * and characteristics.
           *
           * @param iterator the iterator for the source
           * @param size the number of elements in the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, long size, int characteristics) {
              this.it = iterator;
              this.est = size;
              this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
                                     ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
                                     : characteristics;
          }
  
          /**
           * Creates a spliterator using the given iterator for a
           * source of unknown size, reporting the given
           * characteristics.
           *
           * @param iterator the iterator for the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, int characteristics) {
              this.it = iterator;
              this.est = Long.MAX_VALUE;
              this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
          }
  
          @Override
          public OfInt trySplit() {
              PrimitiveIterator.OfInt i = it;
              long s = est;
              if (s > 1 && i.hasNext()) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  int[] a = new int[n];
                  int j = 0;
                  do { a[j] = i.nextInt(); } while (++j < n && i.hasNext());
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new IntArraySpliterator(a, 0, j, characteristics);
              }
              return null;
          }
  
          @Override
          public void forEachRemaining(IntConsumer action) {
              if (action == null) throw new NullPointerException();
              it.forEachRemaining(action);
          }
  
          @Override
          public boolean tryAdvance(IntConsumer action) {
              if (action == null) throw new NullPointerException();
              if (it.hasNext()) {
                  action.accept(it.nextInt());
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() {
              return est;
          }
  
          @Override
          public int characteristics() { return characteristics; }
  
          @Override
          public Comparator<? super Integer> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      static final class LongIteratorSpliterator implements Spliterator.OfLong {
          static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
          static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
          private PrimitiveIterator.OfLong it;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator using the given iterator
           * for traversal, and reporting the given initial size
           * and characteristics.
           *
           * @param iterator the iterator for the source
           * @param size the number of elements in the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, long size, int characteristics) {
              this.it = iterator;
              this.est = size;
              this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
                                     ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
                                     : characteristics;
          }
  
          /**
           * Creates a spliterator using the given iterator for a
           * source of unknown size, reporting the given
           * characteristics.
           *
           * @param iterator the iterator for the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, int characteristics) {
              this.it = iterator;
              this.est = Long.MAX_VALUE;
              this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
          }
  
          @Override
          public OfLong trySplit() {
              PrimitiveIterator.OfLong i = it;
              long s = est;
              if (s > 1 && i.hasNext()) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  long[] a = new long[n];
                  int j = 0;
                  do { a[j] = i.nextLong(); } while (++j < n && i.hasNext());
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new LongArraySpliterator(a, 0, j, characteristics);
              }
              return null;
          }
  
          @Override
          public void forEachRemaining(LongConsumer action) {
              if (action == null) throw new NullPointerException();
              it.forEachRemaining(action);
          }
  
          @Override
          public boolean tryAdvance(LongConsumer action) {
              if (action == null) throw new NullPointerException();
              if (it.hasNext()) {
                  action.accept(it.nextLong());
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() {
              return est;
          }
  
          @Override
          public int characteristics() { return characteristics; }
  
          @Override
          public Comparator<? super Long> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  
      static final class DoubleIteratorSpliterator implements Spliterator.OfDouble {
          static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
          static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
          private PrimitiveIterator.OfDouble it;
          private final int characteristics;
          private long est;             // size estimate
          private int batch;            // batch size for splits
  
          /**
           * Creates a spliterator using the given iterator
           * for traversal, and reporting the given initial size
           * and characteristics.
           *
           * @param iterator the iterator for the source
           * @param size the number of elements in the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, long size, int characteristics) {
              this.it = iterator;
              this.est = size;
              this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
                                     ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
                                     : characteristics;
          }
  
          /**
           * Creates a spliterator using the given iterator for a
           * source of unknown size, reporting the given
           * characteristics.
           *
           * @param iterator the iterator for the source
           * @param characteristics properties of this spliterator's
           * source or elements.
           */
          public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, int characteristics) {
              this.it = iterator;
              this.est = Long.MAX_VALUE;
              this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
          }
  
          @Override
          public OfDouble trySplit() {
              PrimitiveIterator.OfDouble i = it;
              long s = est;
              if (s > 1 && i.hasNext()) {
                  int n = batch + BATCH_UNIT;
                  if (n > s)
                      n = (int) s;
                  if (n > MAX_BATCH)
                      n = MAX_BATCH;
                  double[] a = new double[n];
                  int j = 0;
                  do { a[j] = i.nextDouble(); } while (++j < n && i.hasNext());
                  batch = j;
                  if (est != Long.MAX_VALUE)
                      est -= j;
                  return new DoubleArraySpliterator(a, 0, j, characteristics);
              }
              return null;
          }
  
          @Override
          public void forEachRemaining(DoubleConsumer action) {
              if (action == null) throw new NullPointerException();
              it.forEachRemaining(action);
          }
  
          @Override
          public boolean tryAdvance(DoubleConsumer action) {
              if (action == null) throw new NullPointerException();
              if (it.hasNext()) {
                  action.accept(it.nextDouble());
                  return true;
              }
              return false;
          }
  
          @Override
          public long estimateSize() {
              return est;
          }
  
          @Override
          public int characteristics() { return characteristics; }
  
          @Override
          public Comparator<? super Double> getComparator() {
              if (hasCharacteristics(Spliterator.SORTED))
                  return null;
              throw new IllegalStateException();
          }
      }
  }
  