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 extends T> 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 extends T> 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 extends T> 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 super T> 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 extends T> 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 extends T> 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 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.
*
* 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 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.
*
* 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 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.
*
* 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 extends T> 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 super T>>
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 super T> 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 super T> 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 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
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 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
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 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
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 super Double> 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 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 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 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 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 = 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) {
Objects.requireNonNull(action);
Iterator extends T> i;
if ((i = it) == null) {
i = it = collection.iterator();
est = collection.size();
}
Iterators.forEachRemaining(i, action);
}
@Override
public boolean tryAdvance(Consumer super T> 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 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 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 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 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 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 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 super Double> 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;
}
}