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

java9.util.Spliterators Maven / Gradle / Ivy

Go to download

Backport of Java 9 java.util.stream API for Android Studio 3+ desugar toolchain, forked from http://sourceforge.net/projects/streamsupport

There is a newer version: 1.7.4
Show newest version
/*
 * Copyright (c) 2013, 2016 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 java9.util;

import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.AbstractList;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedSet;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;

import java9.util.Objects;
import java9.util.function.Consumer;
import java9.util.function.DoubleConsumer;
import java9.util.function.IntConsumer;
import java9.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 {

    private static final String NATIVE_OPT_ENABLED_P = Spliterators.class.getName() + ".assume.oracle.collections.impl";
    private static final String DELEGATION_ENABLED_P = Spliterators.class.getName() + ".jre.delegation.enabled";
    private static final String RNDACC_SPLITER_ENABLED_P = Spliterators.class.getName() + ".randomaccess.spliterator.enabled";

    // defaults to true
    static final boolean NATIVE_SPECIALIZATION = getBooleanPropVal(NATIVE_OPT_ENABLED_P, true);
    // defaults to true
    static final boolean DELEGATION_ENABLED = getBooleanPropVal(DELEGATION_ENABLED_P, true);

    // introduced in 1.4.3 - just in case something gets wrong (defaults to true)
    private static final boolean ALLOW_RNDACC_SPLITER_OPT = getBooleanPropVal(RNDACC_SPLITER_ENABLED_P, true);
    // is this RoboVM? (defaults to false)
    private static final boolean IS_ROBOVM = isRoboVm();

    // is this Android? (defaults to false)
    static final boolean IS_ANDROID = isAndroid();
    // is this an Apache Harmony-based Android? (defaults to false)
    static final boolean IS_HARMONY_ANDROID = IS_ANDROID && !isClassPresent("android.opengl.GLES32$DebugProc");
    // is this Android O or later (defaults to false)
    static final boolean IS_ANDROID_O = IS_ANDROID && isClassPresent("java.time.DateTimeException");
    // is this Java 6? (defaults to false - as of 1.4.2, Android doesn't get identified as Java 6 anymore!)
    static final boolean IS_JAVA6 = !IS_ANDROID && isJava6();
    // defaults to false
    static final boolean HAS_STREAMS = isStreamEnabled();
    // defaults to false
    static final boolean IS_JAVA9 = isClassPresent("java.lang.StackWalker$Option");

    // Suppresses default constructor, ensuring non-instantiability.
    private Spliterators() {}

    // Empty spliterators

    /**
     * Creates an empty {@code Spliterator}
     *
     * 

The empty spliterator reports {@link Spliterator#SIZED} and * {@link Spliterator#SUBSIZED}. Calls to * {@link java9.util.Spliterator#trySplit()} always return {@code null}. * * @param Type of elements * @return An empty spliterator */ @SuppressWarnings("unchecked") public static Spliterator emptySpliterator() { return (Spliterator) EMPTY_SPLITERATOR; } private static final Spliterator EMPTY_SPLITERATOR = new EmptySpliterator.OfRef<>(); /** * Creates an empty {@code Spliterator.OfInt} * *

The empty spliterator reports {@link Spliterator#SIZED} and * {@link Spliterator#SUBSIZED}. Calls to * {@link java9.util.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} * *

The empty spliterator reports {@link Spliterator#SIZED} and * {@link Spliterator#SUBSIZED}. Calls to * {@link java9.util.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} * *

The empty spliterator reports {@link Spliterator#SIZED} and * {@link Spliterator#SUBSIZED}. Calls to * {@link java9.util.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. * *

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[])}. * *

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 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 Spliterator 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. * *

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[])}. * *

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 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 Spliterator 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. * *

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[])}. * *

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. * *

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)}. * *

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. * *

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[])}. * *

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. * *

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)}. * *

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. * *

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[])}. * *

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. * *

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)}. * *

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); } } /** * Creates either a specialized {@code Spliterator} (effectively the same * one that Java 8 uses) for the given collection provided it is one of the * types listed below or a {@code Spliterator} using the given collection's * {@link java.util.Collection#iterator()} as the source of elements, and * reporting its {@link java.util.Collection#size()} as its initial size. * *

* In the latter case, if the given collection implements one of the * interfaces {@link java.util.List}, {@link java.util.Set} or * {@link java.util.SortedSet} the returned {@code Spliterator} will * resemble the corresponding interface default implementation of the * respective {@code spliterator()} method from Java 8. Otherwise the Java 8 * default implementation of {@code java.util.Collection.spliterator()} is * used (which is essentially the same as calling * {@link #spliterator(Collection, int)} with a {@code characteristics} * value equal to {@code 0}). * *

* Particularly, if the given collection is a {@link java.util.List}, the * implementation creates a * late-binding * spliterator as follows: *

    *
  • If the list is an instance of {@link java.util.RandomAccess} then * the default implementation creates a spliterator that traverses * elements by invoking the method {@link java.util.List#get}. If * such invocation results or would result in an * {@code IndexOutOfBoundsException} then the spliterator will * fail-fast and throw a {@code ConcurrentModificationException}. * If the list is also an instance of {@link java.util.AbstractList} * then the spliterator will use the list's * {@link java.util.AbstractList#modCount modCount} field to provide * additional fail-fast behavior. *
  • Otherwise, the default implementation creates a spliterator from * the list's {@code Iterator}. The spliterator inherits the * fail-fast of the list's iterator. *
* *

* Currently, the collections that have specializations available are the * following: * *

    *
  • java.util.ArrayList
  • *
  • java.util.Arrays.ArrayList
  • *
  • java.util.ArrayDeque
  • *
  • java.util.Vector
  • *
  • java.util.LinkedList
  • *
  • java.util.HashSet
  • *
  • java.util.LinkedHashSet
  • *
  • java.util.PriorityQueue
  • *
  • java.util.concurrent.ArrayBlockingQueue
  • *
  • java.util.concurrent.LinkedBlockingQueue
  • *
  • java.util.concurrent.LinkedBlockingDeque
  • *
  • java.util.concurrent.PriorityBlockingQueue
  • *
  • java.util.concurrent.CopyOnWriteArrayList
  • *
  • java.util.concurrent.CopyOnWriteArraySet
  • *
  • The collections returned from the java.util.HashMap methods * #keySet(), #entrySet() and #values()
  • *
* *

* The {@code Spliterator}s for {@code CopyOnWriteArrayList} and * {@code CopyOnWriteArraySet} provide a snapshot of the state of the * collection when the Spliterator was created, otherwise the spliterator is * late-binding, inherits * the fail-fast properties of the collection's iterator, and * implements {@code trySplit} to permit limited parallelism. * * @param * Type of elements * @param c * The collection * @return Either a specialized spliterator if the given collection is one * of the types listed above or a spliterator from an iterator * @throws NullPointerException * if the given collection is {@code null} */ public static Spliterator spliterator(Collection c) { Objects.requireNonNull(c); if (HAS_STREAMS && (DELEGATION_ENABLED || IS_JAVA9) && !hasAndroid7LHMBug(c)) { // always use spliterator delegation on Java 9 from 1.5.6 onwards // https://sourceforge.net/p/streamsupport/tickets/299/ return delegatingSpliterator(c); } String name = c.getClass().getName(); if (c instanceof List) { return listSpliterator((List) c, name); } if (c instanceof Set) { return setSpliterator((Set) c, name); } if (c instanceof Queue) { return queueSpliterator((Queue) c); } if ((!IS_HARMONY_ANDROID && NATIVE_SPECIALIZATION) && "java.util.HashMap$Values".equals(name)) { return HMSpliterators.getValuesSpliterator((Collection) c); } // default (anything else) return spliterator(c, 0); } private static Spliterator listSpliterator(List c, String name) { if (NATIVE_SPECIALIZATION || IS_ANDROID) { if (c instanceof ArrayList) { return ArrayListSpliterator.spliterator((ArrayList) c); } if ("java.util.Arrays$ArrayList".equals(name)) { return ArraysArrayListSpliterator.spliterator((List) c); } if (c instanceof CopyOnWriteArrayList) { return COWArrayListSpliterator .spliterator((CopyOnWriteArrayList) c); } if (c instanceof LinkedList) { return LinkedListSpliterator.spliterator((LinkedList) c); } if (c instanceof Vector) { return VectorSpliterator.spliterator((Vector) c); } } if (ALLOW_RNDACC_SPLITER_OPT && c instanceof RandomAccess) { if (!(c instanceof AbstractList) && isFromJdk(name)) { // have to use an IteratorSpliterator in this special // case otherwise some tests would fail (ticket #217) return spliterator(c, Spliterator.ORDERED); } // if NATIVE_SPECIALIZATION == false and c is a COWArrayList we'd // get into trouble with the RASpliterator for parallel streams as // Collection8Test reveals (testDetectRaces / testStreamForEachConcurrentStressTest) if (!(c instanceof CopyOnWriteArrayList)) { // this doesn't count as a native specialization for AbstractList // since its 'modCount' field is a well-documented part of its API return RASpliterator.spliterator((List) c); } } // default from j.u.List return spliterator(c, Spliterator.ORDERED); } private static Spliterator setSpliterator(Set c, String name) { if (!IS_HARMONY_ANDROID && NATIVE_SPECIALIZATION) { if ("java.util.HashMap$EntrySet".equals(name)) { return (Spliterator) HMSpliterators . getEntrySetSpliterator((Set>) c); } if ("java.util.HashMap$KeySet".equals(name)) { return HMSpliterators.getKeySetSpliterator((Set) c); } } if (c instanceof LinkedHashSet) { return spliterator(c, Spliterator.DISTINCT | Spliterator.ORDERED); } if (!IS_HARMONY_ANDROID && NATIVE_SPECIALIZATION) { if (c instanceof HashSet) { return HMSpliterators.getHashSetSpliterator((HashSet) c); } } // default from j.u.SortedSet if (c instanceof SortedSet) { return new IteratorSpliterator(c, Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED) { @Override public Comparator getComparator() { return ((SortedSet) c).comparator(); } }; } if ((NATIVE_SPECIALIZATION || IS_ANDROID) && c instanceof CopyOnWriteArraySet) { return COWArraySetSpliterator .spliterator((CopyOnWriteArraySet) c); } // default from j.u.Set return Spliterators.spliterator(c, Spliterator.DISTINCT); } private static Spliterator queueSpliterator(Queue c) { if (c instanceof ArrayBlockingQueue) { return spliterator(c, Spliterator.ORDERED | Spliterator.NONNULL | Spliterator.CONCURRENT); } if (NATIVE_SPECIALIZATION || IS_ANDROID) { if (c instanceof LinkedBlockingQueue) { return LBQSpliterator.spliterator((LinkedBlockingQueue) c); } if (c instanceof ArrayDeque) { return ArrayDequeSpliterator.spliterator((ArrayDeque) c); } if (c instanceof LinkedBlockingDeque) { return LBDSpliterator.spliterator((LinkedBlockingDeque) c); } if (c instanceof PriorityBlockingQueue) { return PBQueueSpliterator.spliterator((PriorityBlockingQueue) c); } if (c instanceof PriorityQueue) { return PQueueSpliterator.spliterator((PriorityQueue) c); } } // cases where the spliterator is known to be ORDERED // https://sourceforge.net/p/streamsupport/tickets/274/ if (c instanceof Deque || (c.getClass().getName().startsWith("java.util") && !(c instanceof PriorityBlockingQueue) && !(c instanceof PriorityQueue) && !(c instanceof DelayQueue) && !(c instanceof SynchronousQueue))) { // https://sourceforge.net/p/streamsupport/tickets/297/ return spliterator(c, c instanceof ArrayDeque ? Spliterator.NONNULL | Spliterator.ORDERED : Spliterator.ORDERED); } // default from j.u.Collection return spliterator(c, 0); } private static Spliterator delegatingSpliterator(Collection c) { return new DelegatingSpliterator(((Collection) c).spliterator()); } // Iterator-based spliterators /** * Creates a {@code Spliterator} using the given collection's * {@link java.util.Collection#iterator()} as the source of elements, and * reporting its {@link java.util.Collection#size()} as its initial size. * *

The spliterator is * late-binding, inherits * the fail-fast properties of the collection's iterator, and * implements {@code trySplit} to permit limited parallelism. * * @param 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 Spliterator spliterator(Collection 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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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 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 Spliterator spliterator(Iterator 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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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 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 Spliterator spliteratorUnknownSize(Iterator 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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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(java9.util.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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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(java9.util.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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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(java9.util.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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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(java9.util.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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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(java9.util.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. * *

The spliterator is not * late-binding, inherits * the fail-fast properties of the iterator, and implements * {@code trySplit} to permit limited parallelism. * *

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(java9.util.PrimitiveIterator.OfDouble iterator, int characteristics) { return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), characteristics); } // Iterators from Spliterators /** * Creates an {@code Iterator} from a {@code Spliterator}. * *

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 Type of elements * @param spliterator The spliterator * @return An iterator * @throws NullPointerException if the given spliterator is {@code null} */ public static Iterator iterator(Spliterator spliterator) { Objects.requireNonNull(spliterator); class Adapter implements Iterator, Consumer { 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; } } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } return new Adapter(); } /** * Creates an {@code PrimitiveIterator.OfInt} from a * {@code Spliterator.OfInt}. * *

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; } } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } return new Adapter(); } /** * Creates an {@code PrimitiveIterator.OfLong} from a * {@code Spliterator.OfLong}. * *

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; } } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } return new Adapter(); } /** * Creates an {@code PrimitiveIterator.OfDouble} from a * {@code Spliterator.OfDouble}. * *

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; } } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } return new Adapter(); } // Implementations private abstract static class EmptySpliterator, 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 extends EmptySpliterator, Consumer> implements Spliterator { OfRef() { } } private static final class OfInt extends EmptySpliterator implements Spliterator.OfInt { OfInt() { } } private static final class OfLong extends EmptySpliterator implements Spliterator.OfLong { OfLong() { } } private static final class OfDouble extends EmptySpliterator 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 implements Spliterator { /** * 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 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 action) { Objects.requireNonNull(action); Object[] a; int i, hi; // hoist accesses and checks from loop 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 action) { Objects.requireNonNull(action); 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 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 Objects.requireNonNull(action); 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) { Objects.requireNonNull(action); 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 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 Objects.requireNonNull(action); 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) { Objects.requireNonNull(action); 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 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 Objects.requireNonNull(action); 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) { Objects.requireNonNull(action); 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 getComparator() { if (hasCharacteristics(Spliterator.SORTED)) return null; throw new IllegalStateException(); } } // /** * An abstract {@code Spliterator} that implements {@code trySplit} to * permit limited parallelism. * *

An extending class need only * implement {@link #tryAdvance(java9.util.function.Consumer) tryAdvance}. * The extending class should override * {@link #forEachRemaining(java9.util.function.Consumer) forEachRemaining} * if it can provide a more performant implementation. * *

API Note:
* 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. * *

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 abstract static class AbstractSpliterator implements Spliterator { 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 implements Consumer { Object value; @Override public void accept(T value) { this.value = value; } } /** * {@inheritDoc} * * This implementation permits limited parallelism. */ @Override public Spliterator 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 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} * *

Implementation Requirements:
* 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} * *

Implementation Requirements:
* 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. * *

To implement a spliterator an extending class need only * implement {@link #tryAdvance(java9.util.function.IntConsumer) * tryAdvance}. The extending class should override * {@link #forEachRemaining(java9.util.function.IntConsumer) forEachRemaining} * if it can provide a more performant implementation. * *

API Note:
* 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. * *

An alternative to using this class, that also permits limited * parallelism, is to create a spliterator from an iterator * (see {@link #spliterator(java9.util.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(java9.util.PrimitiveIterator.OfInt, long, int) * @since 1.8 */ public abstract static 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 Spliterator.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} * *

Implementation Requirements:
* 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} * *

Implementation Requirements:
* 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. * *

To implement a spliterator an extending class need only * implement {@link #tryAdvance(java9.util.function.LongConsumer) * tryAdvance}. The extending class should override * {@link #forEachRemaining(java9.util.function.LongConsumer) forEachRemaining} * if it can provide a more performant implementation. * *

API Note:
* 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. * *

An alternative to using this class, that also permits limited * parallelism, is to create a spliterator from an iterator * (see {@link #spliterator(java9.util.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(java9.util.PrimitiveIterator.OfLong, long, int) * @since 1.8 */ public abstract static 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 Spliterator.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} * *

Implementation Requirements:
* 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} * *

Implementation Requirements:
* 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. * *

To implement a spliterator an extending class need only * implement {@link #tryAdvance(java9.util.function.DoubleConsumer) * tryAdvance}. The extending class should override * {@link #forEachRemaining(java9.util.function.DoubleConsumer) forEachRemaining} * if it can provide a more performant implementation. * *

API Note:
* 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. * *

An alternative to using this class, that also permits limited * parallelism, is to create a spliterator from an iterator * (see {@link #spliterator(java9.util.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(java9.util.PrimitiveIterator.OfDouble, long, int) * @since 1.8 */ public abstract static 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 Spliterator.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} * *

Implementation Requirements:
* 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} * *

Implementation Requirements:
* 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 implements Spliterator { 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 collection; // null OK private Iterator 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 java.util.Collection#iterator()} for traversal, * and reporting its {@link java.util.Collection#size()} as its initial * size. * * @param collection the collection * @param characteristics properties of this spliterator's * source or elements. */ public IteratorSpliterator(Collection 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 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 iterator, int characteristics) { this.collection = null; this.it = iterator; this.est = Long.MAX_VALUE; this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); } @Override public Spliterator 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 i; long s; if ((i = it) == null) { i = it = collection.iterator(); s = est = 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 action) { Objects.requireNonNull(action); Iterator i; if ((i = it) == null) { i = it = collection.iterator(); est = collection.size(); } Iterators.forEachRemaining(i, action); } @Override public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); if (it == null) { it = collection.iterator(); est = 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 = collection.size(); } return est; } @Override public int characteristics() { return characteristics; } @Override public Comparator 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 java9.util.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(java9.util.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(java9.util.PrimitiveIterator.OfInt iterator, int characteristics) { this.it = iterator; this.est = Long.MAX_VALUE; this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); } @Override public OfInt trySplit() { java9.util.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) { it.forEachRemaining(Objects.requireNonNull(action)); } @Override public boolean tryAdvance(IntConsumer action) { Objects.requireNonNull(action); 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 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 java9.util.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(java9.util.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(java9.util.PrimitiveIterator.OfLong iterator, int characteristics) { this.it = iterator; this.est = Long.MAX_VALUE; this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); } @Override public OfLong trySplit() { java9.util.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) { it.forEachRemaining(Objects.requireNonNull(action)); } @Override public boolean tryAdvance(LongConsumer action) { Objects.requireNonNull(action); 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 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 java9.util.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(java9.util.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(java9.util.PrimitiveIterator.OfDouble iterator, int characteristics) { this.it = iterator; this.est = Long.MAX_VALUE; this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); } @Override public OfDouble trySplit() { java9.util.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) { it.forEachRemaining(Objects.requireNonNull(action)); } @Override public boolean tryAdvance(DoubleConsumer action) { Objects.requireNonNull(action); 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 getComparator() { if (hasCharacteristics(Spliterator.SORTED)) { return null; } throw new IllegalStateException(); } } private static boolean getBooleanPropVal(String prop, boolean defVal) { return AccessController.doPrivileged(new PrivilegedAction() { @Override public Boolean run() { boolean val = defVal; try { String s = System.getProperty(prop, Boolean.toString(defVal)); val = Boolean.parseBoolean(s.trim()); } catch (IllegalArgumentException ignore) { } catch (NullPointerException ignore) { } return val; } }); } /** * Used to detect the presence or absence of android.util.DisplayMetrics * and other classes. Gets employed when we need to establish whether we * are running on Android and, if yes, whether the version of Android is * based on Apache Harmony or on OpenJDK. * * @param name * fully qualified class name * @return {@code true} if class is present, otherwise {@code false}. */ private static boolean isClassPresent(String name) { Class clazz = null; try { // avoid which triggers a lot of JNI code in the case // of android.util.DisplayMetrics clazz = Class.forName(name, false, Spliterators.class.getClassLoader()); } catch (Throwable notPresent) { // ignore } return clazz != null; } /** * Are we running on a Java 6 JRE (i.e., is "java.class.version" < "51.0")? * Note: Here, we rely on the fact that you couldn't run streamsupport on * 49.0 or lower anyways given that it is compiled for 50.0. * * @return {@code true} if yes, otherwise {@code false}. */ private static boolean isJava6() { return isVersionBelow("java.class.version", 51.0); } private static boolean isRoboVm() { return isClassPresent("org.robovm.rt.bro.Bro"); } private static boolean isAndroid() { return isClassPresent("android.util.DisplayMetrics") || IS_ROBOVM; } /** * Does the current platform have the JSR 335 APIs? * @return {@code true} if yes, otherwise {@code false}. */ private static boolean isStreamEnabled() { // a) must have at least major version number 52 (Java 8) // or, alternatively, be an Android version that supports // streams (check for that below) if (!isAndroid() && isVersionBelow("java.class.version", 52.0)) { return false; } // b) j.u.f.Consumer & j.u.Spliterator must exist Class c = null; for (String cn : new String[] { "java.util.function.Consumer", "java.util.Spliterator" }) { try { c = Class.forName(cn); } catch (Exception ignore) { return false; } } // c) j.u.Collection must have a spliterator() method Method m = null; if (c != null) { try { m = Collection.class.getDeclaredMethod("spliterator", new Class[0]); } catch (Exception ignore) { return false; } } return m != null; } /** * Used to parse double-valued system properties that are version numbers. * Assumes that the passed system property is present and can be parsed as a * double. * * @param prop * name of the system property * @param maxVer * upper bound on the version number * @return {@code true} if the version number is strictly below * {@code maxVer}, otherwise {@code false}. */ private static boolean isVersionBelow(String prop, double maxVer) { try { String v = System.getProperty(prop); if (v != null) { double d = Double.parseDouble(v); if (d < maxVer) { return true; } } } catch (Exception ignore) { // ignore } return false; } /** * Test for three JDK special cases where a List is RandomAccess but doesn't * inherit from AbstractList. Namely: *

*

    *
  • java.util.Collections.SynchronizedRandomAccessList
  • *
  • java.util.Collections.UnmodifiableRandomAccessList
  • *
  • java.util.Collections.CheckedRandomAccessList
  • *
*

* These three require a special treatment as they are used in our * fail-fastness and late-binding tests and wouldn't pass if * {@code RASpliterator} is used to split them. * * @param name * the class name * @return {@code true} if an {@code IteratorSpliterator} must be used, * otherwise {@code false} */ private static boolean isFromJdk(String name) { // see https://sourceforge.net/p/streamsupport/tickets/217/ if (name.startsWith("java.util.Collections$", 0) && name.endsWith("RandomAccessList")) { // Collections.SynchronizedRandomAccessList // Collections.UnmodifiableRandomAccessList // Collections.CheckedRandomAccessList return true; } return false; } /** * As of 2016-12-15 all Android 7.0, 7.1 and 7.1.1 releases (at least up to * and including tag 7.1.1_r6) have a bug in LinkedHashMap's collection * views' spliterators which correctly report that they are ORDERED but * actually aren't ORDERED (instead the unordered HashMap spliterators are * used). A fix for this bug has been merged into AOSP master on 2016-08-17 * but still hasn't been rolled out yet. *

* We'd want to avoid delegation to these flawed spliterators whenever * possible and use the reflective implementation instead. *

* This check isn't 100% fool-proof as the LinkedHashMap (or its collection * view) could be wrapped, for example in a j.u.Collections$UnmodifiableMap * (whose UnmodifiableEntrySetSpliterator delegates back to the defective * HashMap$EntrySpliterator). Since we can't know the wrapper beforehand * this is as good as it can get. *

* Note that delegation will start to work automatically on Android 7.x * releases that contain the above mentioned fix from AOSP master (this * method will return {@code false} then). * * @param c * the collection to check for the Android 7.x LinkedHashMap bug * @return {@code true} if the argument is a Android 7.x LinkedHashMap * collection view that exhibits the unordered spliterator bug */ private static boolean hasAndroid7LHMBug(Collection c) { // is this Android API level 24 or 25? if (IS_ANDROID && !(IS_HARMONY_ANDROID || IS_ANDROID_O)) { String name = c.getClass().getName(); if (name.startsWith("java.util.HashMap$")) { // Since it is a Collection this must be one of KeySet, Values // or EnrySet. It is a bug (most likely a collection view from // LinkedHashMap) if its Spliterator reports ORDERED! return c.spliterator().hasCharacteristics(Spliterator.ORDERED); } } return false; } }