8010096: Initial java.util.Spliterator putback
Co-authored-by: Paul Sandoz <paul.sandoz@oracle.com> Co-authored-by: Doug Lea <dl@cs.oswego.edu> Reviewed-by: mduigou, alanb, chegar, darcy
This commit is contained in:
parent
35ff6ba00e
commit
95fadac5c6
@ -851,6 +851,11 @@ public class EventSetImpl extends ArrayList<Event> implements EventSet {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Event> spliterator() {
|
||||
return Spliterators.spliterator(this, Spliterator.DISTINCT);
|
||||
}
|
||||
|
||||
/* below make this unmodifiable */
|
||||
|
||||
public boolean add(Event o){
|
||||
|
@ -22,26 +22,55 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Implementing this interface allows an object to be the target of
|
||||
* the "foreach" statement.
|
||||
* the "for-each loop" statement. See
|
||||
* <strong>
|
||||
* <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
|
||||
* </strong>
|
||||
*
|
||||
* @param <T> the type of elements returned by the iterator
|
||||
*
|
||||
* @since 1.5
|
||||
* @jls 14.14.2 The enhanced for statement
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Iterable<T> {
|
||||
|
||||
/**
|
||||
* Returns an iterator over a set of elements of type T.
|
||||
* Returns an iterator over elements of type {@code T}.
|
||||
*
|
||||
* @return an Iterator.
|
||||
*/
|
||||
Iterator<T> iterator();
|
||||
|
||||
/**
|
||||
* Performs the given action on the contents of the {@code Iterable}, in the
|
||||
* order elements occur when iterating, until all elements have been
|
||||
* processed or the action throws an exception. Errors or runtime
|
||||
* exceptions thrown by the action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation behaves as if:
|
||||
* <pre>{@code
|
||||
* for (T t : this)
|
||||
* action.accept(t);
|
||||
* }</pre>
|
||||
*
|
||||
* @param action The action to be performed for each element
|
||||
* @throws NullPointerException if the specified action is null
|
||||
* @since 1.8
|
||||
*/
|
||||
default void forEach(Consumer<? super T> action) {
|
||||
Objects.requireNonNull(action);
|
||||
for (T t : this) {
|
||||
action.accept(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3518,6 +3518,11 @@ public class Arrays {
|
||||
public boolean contains(Object o) {
|
||||
return indexOf(o) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator(a, Spliterator.ORDERED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4300,4 +4305,167 @@ public class Arrays {
|
||||
buf.append(']');
|
||||
dejaVu.remove(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator} covering all of the specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @param <T> Type of elements
|
||||
* @param array The array, assumed to be unmodified during use
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified array is {@code null}
|
||||
* @since 1.8
|
||||
*/
|
||||
public static <T> Spliterator<T> spliterator(T[] array) {
|
||||
return Spliterators.spliterator(array,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator} covering the specified range of the
|
||||
* specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @param <T> Type of elements
|
||||
* @param array The array, assumed to be unmodified during use
|
||||
* @param fromIndex The least index (inclusive) to cover
|
||||
* @param toIndex One past the greatest index to cover
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified 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
|
||||
* @since 1.8
|
||||
*/
|
||||
public static <T> Spliterator<T> spliterator(T[] array, int fromIndex, int toIndex) {
|
||||
return Spliterators.spliterator(array, fromIndex, toIndex,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator.OfInt} covering all of the specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @param array The array, assumed to be unmodified during use
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified array is {@code null}
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Spliterator.OfInt spliterator(int[] array) {
|
||||
return Spliterators.spliterator(array,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator.OfInt} covering the specified range of the
|
||||
* specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @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
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified 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
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex) {
|
||||
return Spliterators.spliterator(array, fromIndex, toIndex,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator.OfLong} covering all of the specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @param array The array, assumed to be unmodified during use
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified array is {@code null}
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Spliterator.OfLong spliterator(long[] array) {
|
||||
return Spliterators.spliterator(array,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator.OfLong} covering the specified range of the
|
||||
* specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @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
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified 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
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex) {
|
||||
return Spliterators.spliterator(array, fromIndex, toIndex,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator.OfDouble} covering all of the specified
|
||||
* array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @param array The array, assumed to be unmodified during use
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified array is {@code null}
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Spliterator.OfDouble spliterator(double[] array) {
|
||||
return Spliterators.spliterator(array,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator.OfDouble} covering the specified range of
|
||||
* the specified array.
|
||||
*
|
||||
* <p>The spliterator reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
|
||||
* {@link Spliterator#IMMUTABLE}.
|
||||
*
|
||||
* @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
|
||||
* @return A spliterator from the array
|
||||
* @throws NullPointerException if the specified 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
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex) {
|
||||
return Spliterators.spliterator(array, fromIndex, toIndex,
|
||||
Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -104,6 +104,12 @@ package java.util;
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
* Java Collections Framework</a>.
|
||||
*
|
||||
* @implSpec
|
||||
* The default method implementations (inherited or otherwise) do not apply any
|
||||
* synchronization protocol. If a {@code Collection} implementation has a
|
||||
* specific synchronization protocol, then it must override default
|
||||
* implementations to apply that protocol.
|
||||
*
|
||||
* @param <E> the type of elements in this collection
|
||||
*
|
||||
* @author Josh Bloch
|
||||
@ -453,4 +459,28 @@ public interface Collection<E> extends Iterable<E> {
|
||||
* @see Object#equals(Object)
|
||||
*/
|
||||
int hashCode();
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator} over the elements in this collection.
|
||||
*
|
||||
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED}.
|
||||
* Implementations should document the reporting of additional
|
||||
* characteristic values.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation creates a
|
||||
* <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
|
||||
* from the collections's {@code Iterator}. The spliterator inherits the
|
||||
* <em>fail-fast</em> properties of the collection's iterator.
|
||||
*
|
||||
* @implNote
|
||||
* The created {@code Spliterator} additionally reports
|
||||
* {@link Spliterator#SUBSIZED}.
|
||||
*
|
||||
* @return a {@code Spliterator} over the elements in this collection
|
||||
* @since 1.8
|
||||
*/
|
||||
default Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator(this, 0);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package java.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An iterator over a collection. {@code Iterator} takes the place of
|
||||
* {@link Enumeration} in the Java Collections Framework. Iterators
|
||||
@ -75,6 +77,10 @@ public interface Iterator<E> {
|
||||
* iteration is in progress in any way other than by calling this
|
||||
* method.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation throws an instance of
|
||||
* {@link UnsupportedOperationException} and performs no other action.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the {@code remove}
|
||||
* operation is not supported by this iterator
|
||||
*
|
||||
@ -83,5 +89,30 @@ public interface Iterator<E> {
|
||||
* been called after the last call to the {@code next}
|
||||
* method
|
||||
*/
|
||||
void remove();
|
||||
default void remove() {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, in the order
|
||||
* elements occur when iterating, until all elements have been processed or
|
||||
* the action throws an exception. Errors or runtime exceptions thrown by
|
||||
* the action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation behaves as if:
|
||||
* <pre>{@code
|
||||
* while (hasNext())
|
||||
* action.accept(next());
|
||||
* }</pre>
|
||||
*
|
||||
* @param action The action to be performed for each element
|
||||
* @throws NullPointerException if the specified action is null
|
||||
* @since 1.8
|
||||
*/
|
||||
default void forEachRemaining(Consumer<? super E> action) {
|
||||
Objects.requireNonNull(action);
|
||||
while (hasNext())
|
||||
action.accept(next());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -597,4 +597,30 @@ public interface List<E> extends Collection<E> {
|
||||
* fromIndex > toIndex</tt>)
|
||||
*/
|
||||
List<E> subList(int fromIndex, int toIndex);
|
||||
|
||||
/**
|
||||
* Creates a {@link Spliterator} over the elements in this list.
|
||||
*
|
||||
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
|
||||
* {@link Spliterator#ORDERED}. Implementations should document the
|
||||
* reporting of additional characteristic values.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation creates a
|
||||
* <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
|
||||
* from the list's {@code Iterator}. The spliterator inherits the
|
||||
* <em>fail-fast</em> properties of the collection's iterator.
|
||||
*
|
||||
* @implNote
|
||||
* The created {@code Spliterator} additionally reports
|
||||
* {@link Spliterator#SUBSIZED}.
|
||||
*
|
||||
* @return a {@code Spliterator} over the elements in this list
|
||||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
default Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator(this, Spliterator.ORDERED);
|
||||
}
|
||||
}
|
||||
|
||||
|
274
jdk/src/share/classes/java/util/PrimitiveIterator.java
Normal file
274
jdk/src/share/classes/java/util/PrimitiveIterator.java
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.DoubleConsumer;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
/**
|
||||
* A base type for primitive specializations of {@code Iterator}. Specialized
|
||||
* subtypes are provided for {@link OfInt int}, {@link OfLong long}, and
|
||||
* {@link OfDouble double} values.
|
||||
*
|
||||
* <p>The specialized subtype default implementations of {@link Iterator#next}
|
||||
* and {@link Iterator#forEachRemaining(java.util.function.Consumer)} box
|
||||
* primitive values to instances of their corresponding wrapper class. Such
|
||||
* boxing may offset any advantages gained when using the primitive
|
||||
* specializations. To avoid boxing, the corresponding primitive-based methods
|
||||
* should be used. For example, {@link PrimitiveIterator.OfInt#nextInt()} and
|
||||
* {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
|
||||
* should be used in preference to {@link PrimitiveIterator.OfInt#next()} and
|
||||
* {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
|
||||
*
|
||||
* <p>Iteration of primitive values using boxing-based methods
|
||||
* {@link Iterator#next next()} and
|
||||
* {@link Iterator#forEachRemaining(java.util.function.Consumer) forEachRemaining()},
|
||||
* does not affect the order in which the values, transformed to boxed values,
|
||||
* are encountered.
|
||||
*
|
||||
* @implNote
|
||||
* If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
|
||||
* is set to {@code true} then diagnostic warnings are reported if boxing of
|
||||
* primitive values occur when operating on primitive subtype specializations.
|
||||
*
|
||||
* @param <T> the boxed type of the primitive type
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface PrimitiveIterator<T> extends Iterator<T> {
|
||||
|
||||
/**
|
||||
* An Iterator specialized for {@code int} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public static interface OfInt extends PrimitiveIterator<Integer> {
|
||||
|
||||
/**
|
||||
* Returns the next {@code int} element in the iteration.
|
||||
*
|
||||
* @return the next {@code int} element in the iteration
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
int nextInt();
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, in the order
|
||||
* elements occur when iterating, until all elements have been processed
|
||||
* or the action throws an exception. Errors or runtime exceptions
|
||||
* thrown by the action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation behaves as if:
|
||||
* <pre>{@code
|
||||
* while (hasNext())
|
||||
* action.accept(nextInt());
|
||||
* }</pre>
|
||||
*
|
||||
* @param action The action to be performed for each element
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(IntConsumer action) {
|
||||
while (hasNext())
|
||||
action.accept(nextInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* The default implementation boxes the result of calling
|
||||
* {@link #nextInt()}, and returns that boxed result.
|
||||
*/
|
||||
@Override
|
||||
default Integer next() {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
|
||||
return nextInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code IntConsumer} then it is cast
|
||||
* to {@code IntConsumer} and passed to {@link #forEachRemaining};
|
||||
* otherwise the action is adapted to an instance of
|
||||
* {@code IntConsumer}, by boxing the argument of {@code IntConsumer},
|
||||
* and then passed to {@link #forEachRemaining}.
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Integer> action) {
|
||||
if (action instanceof IntConsumer) {
|
||||
forEachRemaining((IntConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.forEachRemainingInt(action::accept)");
|
||||
forEachRemaining((IntConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An Iterator specialized for {@code long} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public static interface OfLong extends PrimitiveIterator<Long> {
|
||||
|
||||
/**
|
||||
* Returns the next {@code long} element in the iteration.
|
||||
*
|
||||
* @return the next {@code long} element in the iteration
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
long nextLong();
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, in the order
|
||||
* elements occur when iterating, until all elements have been processed
|
||||
* or the action throws an exception. Errors or runtime exceptions
|
||||
* thrown by the action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation behaves as if:
|
||||
* <pre>{@code
|
||||
* while (hasNext())
|
||||
* action.accept(nextLong());
|
||||
* }</pre>
|
||||
*
|
||||
* @param action The action to be performed for each element
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(LongConsumer action) {
|
||||
while (hasNext())
|
||||
action.accept(nextLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* The default implementation boxes the result of calling
|
||||
* {@link #nextLong()}, and returns that boxed result.
|
||||
*/
|
||||
@Override
|
||||
default Long next() {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.nextLong()");
|
||||
return nextLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code LongConsumer} then it is cast
|
||||
* to {@code LongConsumer} and passed to {@link #forEachRemaining};
|
||||
* otherwise the action is adapted to an instance of
|
||||
* {@code LongConsumer}, by boxing the argument of {@code LongConsumer},
|
||||
* and then passed to {@link #forEachRemaining}.
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Long> action) {
|
||||
if (action instanceof LongConsumer) {
|
||||
forEachRemaining((LongConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.forEachRemainingLong(action::accept)");
|
||||
forEachRemaining((LongConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Iterator specialized for {@code double} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public static interface OfDouble extends PrimitiveIterator<Double> {
|
||||
|
||||
/**
|
||||
* Returns the next {@code double} element in the iteration.
|
||||
*
|
||||
* @return the next {@code double} element in the iteration
|
||||
* @throws NoSuchElementException if the iteration has no more elements
|
||||
*/
|
||||
double nextDouble();
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, in the order
|
||||
* elements occur when iterating, until all elements have been processed
|
||||
* or the action throws an exception. Errors or runtime exceptions
|
||||
* thrown by the action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* <p>The default implementation behaves as if:
|
||||
* <pre>{@code
|
||||
* while (hasNext())
|
||||
* action.accept(nextDouble());
|
||||
* }</pre>
|
||||
*
|
||||
* @param action The action to be performed for each element
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(DoubleConsumer action) {
|
||||
while (hasNext())
|
||||
action.accept(nextDouble());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* The default implementation boxes the result of calling
|
||||
* {@link #nextDouble()}, and returns that boxed result.
|
||||
*/
|
||||
@Override
|
||||
default Double next() {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.nextLong()");
|
||||
return nextDouble();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code DoubleConsumer} then it is
|
||||
* cast to {@code DoubleConsumer} and passed to
|
||||
* {@link #forEachRemaining}; otherwise the action is adapted to
|
||||
* an instance of {@code DoubleConsumer}, by boxing the argument of
|
||||
* {@code DoubleConsumer}, and then passed to
|
||||
* {@link #forEachRemaining}.
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Double> action) {
|
||||
if (action instanceof DoubleConsumer) {
|
||||
forEachRemaining((DoubleConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.forEachRemainingDouble(action::accept)");
|
||||
forEachRemaining((DoubleConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -382,4 +382,29 @@ public interface Set<E> extends Collection<E> {
|
||||
* @see Set#equals(Object)
|
||||
*/
|
||||
int hashCode();
|
||||
|
||||
/**
|
||||
* Creates a {@code Spliterator} over the elements in this set.
|
||||
*
|
||||
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
|
||||
* {@link Spliterator#DISTINCT}. Implementations should document the
|
||||
* reporting of additional characteristic values.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation creates a
|
||||
* <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
|
||||
* from the set's {@code Iterator}. The spliterator inherits the
|
||||
* <em>fail-fast</em> properties of the collection's iterator.
|
||||
*
|
||||
* @implNote
|
||||
* The created {@code Spliterator} additionally reports
|
||||
* {@link Spliterator#SUBSIZED}.
|
||||
*
|
||||
* @return a {@code Spliterator} over the elements in this set
|
||||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
default Spliterator<E> spliterator() {
|
||||
return Spliterators.spliterator(this, Spliterator.DISTINCT);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -219,4 +219,43 @@ public interface SortedSet<E> extends Set<E> {
|
||||
* @throws NoSuchElementException if this set is empty
|
||||
*/
|
||||
E last();
|
||||
|
||||
/**
|
||||
* Creates a {@code Spliterator} over the elements in this sorted set.
|
||||
*
|
||||
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
|
||||
* {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED} and
|
||||
* {@link Spliterator#ORDERED}. Implementations should document the
|
||||
* reporting of additional characteristic values.
|
||||
*
|
||||
* <p>The spliterator's comparator (see
|
||||
* {@link java.util.Spliterator#getComparator()}) must be {@code null} if
|
||||
* the sorted set's comparator (see {@link #comparator()}) is {@code null}.
|
||||
* Otherwise, the spliterator's comparator must be the same as or impose the
|
||||
* same total ordering as the sorted set's comparator.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation creates a
|
||||
* <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
|
||||
* from the sorted set's {@code Iterator}. The spliterator inherits the
|
||||
* <em>fail-fast</em> properties of the collection's iterator. The
|
||||
* spliterator's comparator is the same as the sorted set's comparator.
|
||||
*
|
||||
* @implNote
|
||||
* The created {@code Spliterator} additionally reports
|
||||
* {@link Spliterator#SUBSIZED}.
|
||||
*
|
||||
* @return a {@code Spliterator} over the elements in this sorted set
|
||||
* @since 1.8
|
||||
*/
|
||||
@Override
|
||||
default Spliterator<E> spliterator() {
|
||||
return new Spliterators.IteratorSpliterator<E>(
|
||||
this, Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED) {
|
||||
@Override
|
||||
public Comparator<? super E> getComparator() {
|
||||
return SortedSet.this.comparator();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
835
jdk/src/share/classes/java/util/Spliterator.java
Normal file
835
jdk/src/share/classes/java/util/Spliterator.java
Normal file
@ -0,0 +1,835 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.DoubleConsumer;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
/**
|
||||
* An object for traversing and partitioning elements of a source. The source
|
||||
* of elements covered by a Spliterator could be, for example, an array, a
|
||||
* {@link Collection}, an IO channel, or a generator function.
|
||||
*
|
||||
* <p>A Spliterator may traverse elements individually ({@link
|
||||
* #tryAdvance tryAdvance()}) or sequentially in bulk
|
||||
* ({@link #forEachRemaining forEachRemaining()}).
|
||||
*
|
||||
* <p>A Spliterator may also partition off some of its elements (using
|
||||
* {@link #trySplit}) as another Spliterator, to be used in
|
||||
* possibly-parallel operations. Operations using a Spliterator that
|
||||
* cannot split, or does so in a highly imbalanced or inefficient
|
||||
* manner, are unlikely to benefit from parallelism. Traversal
|
||||
* and splitting exhaust elements; each Spliterator is useful for only a single
|
||||
* bulk computation.
|
||||
*
|
||||
* <p>A Spliterator also reports a set of {@link #characteristics()} of its
|
||||
* structure, source, and elements from among {@link #ORDERED},
|
||||
* {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL},
|
||||
* {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may
|
||||
* be employed by Spliterator clients to control, specialize or simplify
|
||||
* computation. For example, a Spliterator for a {@link Collection} would
|
||||
* report {@code SIZED}, a Spliterator for a {@link Set} would report
|
||||
* {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also
|
||||
* report {@code SORTED}. Characteristics are reported as a simple unioned bit
|
||||
* set.
|
||||
*
|
||||
* Some characteristics additionally constrain method behavior; for example if
|
||||
* {@code ORDERED}, traversal methods must conform to their documented ordering.
|
||||
* New characteristics may be defined in the future, so implementors should not
|
||||
* assign meanings to unlisted values.
|
||||
*
|
||||
* <p><a name="binding"/>A Spliterator that does not report {@code IMMUTABLE} or
|
||||
* {@code CONCURRENT} is expected to have a documented policy concerning:
|
||||
* when the spliterator <em>binds</em> to the element source; and detection of
|
||||
* structural interference of the element source detected after binding. A
|
||||
* <em>late-binding</em> Spliterator binds to the source of elements at the
|
||||
* point of first traversal, first split, or first query for estimated size,
|
||||
* rather than at the time the Spliterator is created. A Spliterator that is
|
||||
* not <em>late-binding</em> binds to the source of elements at the point of
|
||||
* construction or first invocation of any method. Modifications made to the
|
||||
* source prior to binding are reflected when the Spliterator is traversed.
|
||||
* After binding a Spliterator should, on a best-effort basis, throw
|
||||
* {@link ConcurrentModificationException} if structural interference is
|
||||
* detected. Spliterators that do this are called <em>fail-fast</em>.
|
||||
*
|
||||
* <p>Spliterators can provide an estimate of the number of remaining elements
|
||||
* via the {@link #estimateSize} method. Ideally, as reflected in characteristic
|
||||
* {@link #SIZED}, this value corresponds exactly to the number of elements
|
||||
* that would be encountered in a successful traversal. However, even when not
|
||||
* exactly known, an estimated value value may still be useful to operations
|
||||
* being performed on the source, such as helping to determine whether it is
|
||||
* preferable to split further or traverse the remaining elements sequentially.
|
||||
*
|
||||
* <p>Despite their obvious utility in parallel algorithms, spliterators are not
|
||||
* expected to be thread-safe; instead, implementations of parallel algorithms
|
||||
* using spliterators should ensure that the spliterator is only used by one
|
||||
* thread at a time. This is generally easy to attain via <em>serial
|
||||
* thread-confinement</em>, which often is a natural consequence of typical
|
||||
* parallel algorithms that work by recursive decomposition. A thread calling
|
||||
* {@link #trySplit()} may hand over the returned Spliterator to another thread,
|
||||
* which in turn may traverse or further split that Spliterator. The behaviour
|
||||
* of splitting and traversal is undefined if two or more threads operate
|
||||
* concurrently on the same spliterator. If the original thread hands a
|
||||
* spliterator off to another thread for processing, it is best if that handoff
|
||||
* occurs before any elements are consumed with {@link #tryAdvance(Consumer)
|
||||
* tryAdvance()}, as certain guarantees (such as the accuracy of
|
||||
* {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before
|
||||
* traversal has begun.
|
||||
*
|
||||
* <p>Primitive subtype specializations of {@code Spliterator} are provided for
|
||||
* {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values.
|
||||
* The subtype default implementations of
|
||||
* {@link Spliterator#tryAdvance(java.util.function.Consumer)}
|
||||
* and {@link Spliterator#forEachRemaining(java.util.function.Consumer)} box
|
||||
* primitive values to instances of their corresponding wrapper class. Such
|
||||
* boxing may undermine any performance advantages gained by using the primitive
|
||||
* specializations. To avoid boxing, the corresponding primitive-based methods
|
||||
* should be used. For example,
|
||||
* {@link Spliterator.OfInt#tryAdvance(java.util.function.IntConsumer)}
|
||||
* and {@link Spliterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
|
||||
* should be used in preference to
|
||||
* {@link Spliterator.OfInt#tryAdvance(java.util.function.Consumer)} and
|
||||
* {@link Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
|
||||
* Traversal of primitive values using boxing-based methods
|
||||
* {@link #tryAdvance tryAdvance()} and
|
||||
* {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining()}
|
||||
* does not affect the order in which the values, transformed to boxed values,
|
||||
* are encountered.
|
||||
*
|
||||
* @apiNote
|
||||
* <p>Spliterators, like {@code Iterators}s, are for traversing the elements of
|
||||
* a source. The {@code Spliterator} API was designed to support efficient
|
||||
* parallel traversal in addition to sequential traversal, by supporting
|
||||
* decomposition as well as single-element iteration. In addition, the
|
||||
* protocol for accessing elements via a Spliterator is designed to impose
|
||||
* smaller per-element overhead than {@code Iterator}, and to avoid the inherent
|
||||
* race involved in having separate methods for {@code hasNext()} and
|
||||
* {@code next()}.
|
||||
*
|
||||
* <p>For mutable sources, arbitrary and non-deterministic behavior may occur if
|
||||
* the source is structurally interfered with (elements added, replaced, or
|
||||
* removed) between the time that the Spliterator binds to its data source and
|
||||
* the end of traversal. For example, such interference will produce arbitrary,
|
||||
* non-deterministic results when using the {@code java.util.stream} framework.
|
||||
*
|
||||
* <p>Structural interference of a source can be managed in the following ways
|
||||
* (in approximate order of decreasing desirability):
|
||||
* <ul>
|
||||
* <li>The source cannot be structurally interfered with.
|
||||
* </br>For example, an instance of
|
||||
* {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
|
||||
* A Spliterator created from the source reports a characteristic of
|
||||
* {@code IMMUTABLE}.</li>
|
||||
* <li>The source manages concurrent modifications.
|
||||
* </br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
|
||||
* is a concurrent source. A Spliterator created from the source reports a
|
||||
* characteristic of {@code CONCURRENT}.</li>
|
||||
* <li>The mutable source provides a late-binding and fail-fast Spliterator.
|
||||
* </br>Late binding narrows the window during which interference can affect
|
||||
* the calculation; fail-fast detects, on a best-effort basis, that structural
|
||||
* interference has occurred after traversal has commenced and throws
|
||||
* {@link ConcurrentModificationException}. For example, {@link ArrayList},
|
||||
* and many other non-concurrent {@code Collection} classes in the JDK, provide
|
||||
* a late-binding, fail-fast spliterator.</li>
|
||||
* <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
|
||||
* </br>The source increases the likelihood of throwing
|
||||
* {@code ConcurrentModificationException} since the window of potential
|
||||
* interference is larger.</li>
|
||||
* <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
|
||||
* </br>The source risks arbitrary, non-deterministic behavior after traversal
|
||||
* has commenced since interference is not detected.
|
||||
* </li>
|
||||
* <li>The mutable source provides a non-late-binding and non-fail-fast
|
||||
* Spliterator.
|
||||
* </br>The source increases the risk of arbitrary, non-deterministic behavior
|
||||
* since non-detected interference may occur after construction.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>Example.</b> Here is a class (not a very useful one, except
|
||||
* for illustration) that maintains an array in which the actual data
|
||||
* are held in even locations, and unrelated tag data are held in odd
|
||||
* locations. Its Spliterator ignores the tags.
|
||||
*
|
||||
* <pre> {@code
|
||||
* class TaggedArray<T> {
|
||||
* private final Object[] elements; // immutable after construction
|
||||
* TaggedArray(T[] data, Object[] tags) {
|
||||
* int size = data.length;
|
||||
* if (tags.length != size) throw new IllegalArgumentException();
|
||||
* this.elements = new Object[2 * size];
|
||||
* for (int i = 0, j = 0; i < size; ++i) {
|
||||
* elements[j++] = data[i];
|
||||
* elements[j++] = tags[i];
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public Spliterator<T> spliterator() {
|
||||
* return new TaggedArraySpliterator<>(elements, 0, elements.length);
|
||||
* }
|
||||
*
|
||||
* static class TaggedArraySpliterator<T> implements Spliterator<T> {
|
||||
* private final Object[] array;
|
||||
* private int origin; // current index, advanced on split or traversal
|
||||
* private final int fence; // one past the greatest index
|
||||
*
|
||||
* TaggedArraySpliterator(Object[] array, int origin, int fence) {
|
||||
* this.array = array; this.origin = origin; this.fence = fence;
|
||||
* }
|
||||
*
|
||||
* public void forEachRemaining(Consumer<? super T> action) {
|
||||
* for (; origin < fence; origin += 2)
|
||||
* action.accept((T) array[origin]);
|
||||
* }
|
||||
*
|
||||
* public boolean tryAdvance(Consumer<? super T> action) {
|
||||
* if (origin < fence) {
|
||||
* action.accept((T) array[origin]);
|
||||
* origin += 2;
|
||||
* return true;
|
||||
* }
|
||||
* else // cannot advance
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* public Spliterator<T> trySplit() {
|
||||
* int lo = origin; // divide range in half
|
||||
* int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
|
||||
* if (lo < mid) { // split out left half
|
||||
* origin = mid; // reset this Spliterator's origin
|
||||
* return new TaggedArraySpliterator<>(array, lo, mid);
|
||||
* }
|
||||
* else // too small to split
|
||||
* return null;
|
||||
* }
|
||||
*
|
||||
* public long estimateSize() {
|
||||
* return (long)((fence - origin) / 2);
|
||||
* }
|
||||
*
|
||||
* public int characteristics() {
|
||||
* return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
|
||||
* }
|
||||
* }
|
||||
* }}</pre>
|
||||
*
|
||||
* <p>As an example how a parallel computation framework, such as the
|
||||
* {@code java.util.stream} package, would use Spliterator in a parallel
|
||||
* computation, here is one way to implement an associated parallel forEach,
|
||||
* that illustrates the primary usage idiom of splitting off subtasks until
|
||||
* the estimated amount of work is small enough to perform
|
||||
* sequentially. Here we assume that the order of processing across
|
||||
* subtasks doesn't matter; different (forked) tasks may further split
|
||||
* and process elements concurrently in undetermined order. This
|
||||
* example uses a {@link java.util.concurrent.CountedCompleter};
|
||||
* similar usages apply to other parallel task constructions.
|
||||
*
|
||||
* <pre>{@code
|
||||
* static <T> void parEach(TaggedArray<T> a, Consumer<T> action) {
|
||||
* Spliterator<T> s = a.spliterator();
|
||||
* long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
|
||||
* new ParEach(null, s, action, targetBatchSize).invoke();
|
||||
* }
|
||||
*
|
||||
* static class ParEach<T> extends CountedCompleter<Void> {
|
||||
* final Spliterator<T> spliterator;
|
||||
* final Consumer<T> action;
|
||||
* final long targetBatchSize;
|
||||
*
|
||||
* ParEach(ParEach<T> parent, Spliterator<T> spliterator,
|
||||
* Consumer<T> action, long targetBatchSize) {
|
||||
* super(parent);
|
||||
* this.spliterator = spliterator; this.action = action;
|
||||
* this.targetBatchSize = targetBatchSize;
|
||||
* }
|
||||
*
|
||||
* public void compute() {
|
||||
* Spliterator<T> sub;
|
||||
* while (spliterator.estimateSize() > targetBatchSize &&
|
||||
* (sub = spliterator.trySplit()) != null) {
|
||||
* addToPendingCount(1);
|
||||
* new ParEach<>(this, sub, action, targetBatchSize).fork();
|
||||
* }
|
||||
* spliterator.forEachRemaining(action);
|
||||
* propagateCompletion();
|
||||
* }
|
||||
* }}</pre>
|
||||
*
|
||||
* @implNote
|
||||
* If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
|
||||
* is set to {@code true} then diagnostic warnings are reported if boxing of
|
||||
* primitive values occur when operating on primitive subtype specializations.
|
||||
*
|
||||
* @see Collection
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface Spliterator<T> {
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
* returning {@code true}; else returns {@code false}. If this
|
||||
* Spliterator is {@link #ORDERED} the action is performed on the
|
||||
* next element in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @param action The action
|
||||
* @return {@code false} if no remaining elements existed
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
boolean tryAdvance(Consumer<? super T> action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
* the current thread, until all elements have been processed or the action
|
||||
* throws an exception. If this Spliterator is {@link #ORDERED}, actions
|
||||
* are performed in encounter order. Exceptions thrown by the action
|
||||
* are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation repeatedly invokes {@link #tryAdvance} until
|
||||
* it returns {@code false}. It should be overridden whenever possible.
|
||||
*
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(Consumer<? super T> action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* If this spliterator can be partitioned, returns a Spliterator
|
||||
* covering elements, that will, upon return from this method, not
|
||||
* be covered by this Spliterator.
|
||||
*
|
||||
* <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator
|
||||
* must cover a strict prefix of the elements.
|
||||
*
|
||||
* <p>Unless this Spliterator covers an infinite number of elements,
|
||||
* repeated calls to {@code trySplit()} must eventually return {@code null}.
|
||||
* Upon non-null return:
|
||||
* <ul>
|
||||
* <li>the value reported for {@code estimateSize()} before splitting,
|
||||
* if not already zero or {@code Long.MAX_VALUE}, must, after splitting, be
|
||||
* greater than {@code estimateSize()} for this and the returned
|
||||
* Spliterator; and</li>
|
||||
* <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
|
||||
* for this spliterator before splitting must be equal to the sum of
|
||||
* {@code estimateSize()} for this and the returned Spliterator after
|
||||
* splitting.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This method may return {@code null} for any reason,
|
||||
* including emptiness, inability to split after traversal has
|
||||
* commenced, data structure constraints, and efficiency
|
||||
* considerations.
|
||||
*
|
||||
* @apiNote
|
||||
* An ideal {@code trySplit} method efficiently (without
|
||||
* traversal) divides its elements exactly in half, allowing
|
||||
* balanced parallel computation. Many departures from this ideal
|
||||
* remain highly effective; for example, only approximately
|
||||
* splitting an approximately balanced tree, or for a tree in
|
||||
* which leaf nodes may contain either one or two elements,
|
||||
* failing to further split these nodes. However, large
|
||||
* deviations in balance and/or overly inefficient {@code
|
||||
* trySplit} mechanics typically result in poor parallel
|
||||
* performance.
|
||||
*
|
||||
* @return a {@code Spliterator} covering some portion of the
|
||||
* elements, or {@code null} if this spliterator cannot be split
|
||||
*/
|
||||
Spliterator<T> trySplit();
|
||||
|
||||
/**
|
||||
* Returns an estimate of the number of elements that would be
|
||||
* encountered by a {@link #forEachRemaining} traversal, or returns {@link
|
||||
* Long#MAX_VALUE} if infinite, unknown, or too expensive to compute.
|
||||
*
|
||||
* <p>If this Spliterator is {@link #SIZED} and has not yet been partially
|
||||
* traversed or split, or this Spliterator is {@link #SUBSIZED} and has
|
||||
* not yet been partially traversed, this estimate must be an accurate
|
||||
* count of elements that would be encountered by a complete traversal.
|
||||
* Otherwise, this estimate may be arbitrarily inaccurate, but must decrease
|
||||
* as specified across invocations of {@link #trySplit}.
|
||||
*
|
||||
* @apiNote
|
||||
* Even an inexact estimate is often useful and inexpensive to compute.
|
||||
* For example, a sub-spliterator of an approximately balanced binary tree
|
||||
* may return a value that estimates the number of elements to be half of
|
||||
* that of its parent; if the root Spliterator does not maintain an
|
||||
* accurate count, it could estimate size to be the power of two
|
||||
* corresponding to its maximum depth.
|
||||
*
|
||||
* @return the estimated size, or {@code Long.MAX_VALUE} if infinite,
|
||||
* unknown, or too expensive to compute.
|
||||
*/
|
||||
long estimateSize();
|
||||
|
||||
/**
|
||||
* Convenience method that returns {@link #estimateSize()} if this
|
||||
* Spliterator is {@link #SIZED}, else {@code -1}.
|
||||
* @implSpec
|
||||
* The default returns the result of {@code estimateSize()} if the
|
||||
* Spliterator reports a characteristic of {@code SIZED}, and {@code -1}
|
||||
* otherwise.
|
||||
*
|
||||
* @return the exact size, if known, else {@code -1}.
|
||||
*/
|
||||
default long getExactSizeIfKnown() {
|
||||
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of characteristics of this Spliterator and its
|
||||
* elements. The result is represented as ORed values from {@link
|
||||
* #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED},
|
||||
* {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT},
|
||||
* {@link #SUBSIZED}. Repeated calls to {@code characteristics()} on
|
||||
* a given spliterator should always return the same result.
|
||||
*
|
||||
* <p>If a Spliterator reports an inconsistent set of
|
||||
* characteristics (either those returned from a single invocation
|
||||
* or across multiple invocations), no guarantees can be made
|
||||
* about any computation using this Spliterator.
|
||||
*
|
||||
* @return a representation of characteristics
|
||||
*/
|
||||
int characteristics();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this Spliterator's {@link
|
||||
* #characteristics} contain all of the given characteristics.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation returns true if the corresponding bits
|
||||
* of the given characteristics are set.
|
||||
*
|
||||
* @return {@code true} if all the specified characteristics are present,
|
||||
* else {@code false}
|
||||
*/
|
||||
default boolean hasCharacteristics(int characteristics) {
|
||||
return (characteristics() & characteristics) == characteristics;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this Spliterator's source is {@link #SORTED} by a {@link Comparator},
|
||||
* returns that {@code Comparator}. If the source is {@code SORTED} in
|
||||
* {@linkplain Comparable natural order, returns {@code null}. Otherwise,
|
||||
* if the source is not {@code SORTED}, throws {@link IllegalStateException}.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation always throws {@link IllegalStateException}.
|
||||
*
|
||||
* @return a Comparator, or {@code null} if the elements are sorted in the
|
||||
* natural order.
|
||||
* @throws IllegalStateException if the spliterator does not report
|
||||
* a characteristic of {@code SORTED}.
|
||||
*/
|
||||
default Comparator<? super T> getComparator() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that an encounter order is defined for
|
||||
* elements. If so, this Spliterator guarantees that method
|
||||
* {@link #trySplit} splits a strict prefix of elements, that method
|
||||
* {@link #tryAdvance} steps by one element in prefix order, and that
|
||||
* {@link #forEachRemaining} performs actions in encounter order.
|
||||
*
|
||||
* <p>A {@link Collection} has an encounter order if the corresponding
|
||||
* {@link Collection#iterator} documents an order. If so, the encounter
|
||||
* order is the same as the documented order. Otherwise, a collection does
|
||||
* not have an encounter order.
|
||||
*
|
||||
* @apiNote Encounter order is guaranteed to be ascending index order for
|
||||
* any {@link List}. But no order is guaranteed for hash-based collections
|
||||
* such as {@link HashSet}. Clients of a Spliterator that reports
|
||||
* {@code ORDERED} are expected to preserve ordering constraints in
|
||||
* non-commutative parallel computations.
|
||||
*/
|
||||
public static final int ORDERED = 0x00000010;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that, for each pair of
|
||||
* encountered elements {@code x, y}, {@code !x.equals(y)}. This
|
||||
* applies for example, to a Spliterator based on a {@link Set}.
|
||||
*/
|
||||
public static final int DISTINCT = 0x00000001;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that encounter order follows a defined
|
||||
* sort order. If so, method {@link #getComparator()} returns the associated
|
||||
* Comparator, or {@code null} if all elements are {@link Comparable} and
|
||||
* are sorted by their natural ordering.
|
||||
*
|
||||
* <p>A Spliterator that reports {@code SORTED} must also report
|
||||
* {@code ORDERED}.
|
||||
*
|
||||
* @apiNote The spliterators for {@code Collection} classes in the JDK that
|
||||
* implement {@link NavigableSet} or {@link SortedSet} report {@code SORTED}.
|
||||
*/
|
||||
public static final int SORTED = 0x00000004;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that the value returned from
|
||||
* {@code estimateSize()} prior to traversal or splitting represents a
|
||||
* finite size that, in the absence of structural source modification,
|
||||
* represents an exact count of the number of elements that would be
|
||||
* encountered by a complete traversal.
|
||||
*
|
||||
* @apiNote Most Spliterators for Collections, that cover all elements of a
|
||||
* {@code Collection} report this characteristic. Sub-spliterators, such as
|
||||
* those for {@link HashSet}, that cover a sub-set of elements and
|
||||
* approximate their reported size do not.
|
||||
*/
|
||||
public static final int SIZED = 0x00000040;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that the source guarantees that
|
||||
* encountered elements will not be {@code null}. (This applies,
|
||||
* for example, to most concurrent collections, queues, and maps.)
|
||||
*/
|
||||
public static final int NONNULL = 0x00000100;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that the element source cannot be
|
||||
* structurally modified; that is, elements cannot be added, replaced, or
|
||||
* removed, so such changes cannot occur during traversal. A Spliterator
|
||||
* that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected
|
||||
* to have a documented policy (for example throwing
|
||||
* {@link ConcurrentModificationException}) concerning structural
|
||||
* interference detected during traversal.
|
||||
*/
|
||||
public static final int IMMUTABLE = 0x00000400;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that the element source may be safely
|
||||
* concurrently modified (allowing additions, replacements, and/or removals)
|
||||
* by multiple threads without external synchronization. If so, the
|
||||
* Spliterator is expected to have a documented policy concerning the impact
|
||||
* of modifications during traversal.
|
||||
*
|
||||
* <p>A top-level Spliterator should not report {@code CONCURRENT} and
|
||||
* {@code SIZED}, since the finite size, if known, may change if the source
|
||||
* is concurrently modified during traversal. Such a Spliterator is
|
||||
* inconsistent and no guarantees can be made about any computation using
|
||||
* that Spliterator. Sub-spliterators may report {@code SIZED} if the
|
||||
* sub-split size is known and additions or removals to the source are not
|
||||
* reflected when traversing.
|
||||
*
|
||||
* @apiNote Most concurrent collections maintain a consistency policy
|
||||
* guaranteeing accuracy with respect to elements present at the point of
|
||||
* Spliterator construction, but possibly not reflecting subsequent
|
||||
* additions or removals.
|
||||
*/
|
||||
public static final int CONCURRENT = 0x00001000;
|
||||
|
||||
/**
|
||||
* Characteristic value signifying that all Spliterators resulting from
|
||||
* {@code trySplit()} will be both {@link #SIZED} and {@link #SUBSIZED}.
|
||||
* (This means that all child Spliterators, whether direct or indirect, will
|
||||
* be {@code SIZED}.)
|
||||
*
|
||||
* <p>A Spliterator that does not report {@code SIZED} as required by
|
||||
* {@code SUBSIZED} is inconsistent and no guarantees can be made about any
|
||||
* computation using that Spliterator.
|
||||
*
|
||||
* @apiNote Some spliterators, such as the top-level spliterator for an
|
||||
* approximately balanced binary tree, will report {@code SIZED} but not
|
||||
* {@code SUBSIZED}, since it is common to know the size of the entire tree
|
||||
* but not the exact sizes of subtrees.
|
||||
*/
|
||||
public static final int SUBSIZED = 0x00004000;
|
||||
|
||||
/**
|
||||
* A Spliterator specialized for {@code int} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfInt extends Spliterator<Integer> {
|
||||
|
||||
@Override
|
||||
OfInt trySplit();
|
||||
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
* returning {@code true}; else returns {@code false}. If this
|
||||
* Spliterator is {@link #ORDERED} the action is performed on the
|
||||
* next element in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @param action The action
|
||||
* @return {@code false} if no remaining elements existed
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
boolean tryAdvance(IntConsumer action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
* the current thread, until all elements have been processed or the
|
||||
* action throws an exception. If this Spliterator is {@link #ORDERED},
|
||||
* actions are performed in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation repeatedly invokes {@link #tryAdvance}
|
||||
* until it returns {@code false}. It should be overridden whenever
|
||||
* possible.
|
||||
*
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(IntConsumer action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code IntConsumer} then it is cast
|
||||
* to {@code IntConsumer} and passed to
|
||||
* {@link #tryAdvance(java.util.function.IntConsumer)}; otherwise
|
||||
* the action is adapted to an instance of {@code IntConsumer}, by
|
||||
* boxing the argument of {@code IntConsumer}, and then passed to
|
||||
* {@link #tryAdvance(java.util.function.IntConsumer)}.
|
||||
*/
|
||||
@Override
|
||||
default boolean tryAdvance(Consumer<? super Integer> action) {
|
||||
if (action instanceof IntConsumer) {
|
||||
return tryAdvance((IntConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(),
|
||||
"{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
|
||||
return tryAdvance((IntConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code IntConsumer} then it is cast
|
||||
* to {@code IntConsumer} and passed to
|
||||
* {@link #forEachRemaining(java.util.function.IntConsumer)}; otherwise
|
||||
* the action is adapted to an instance of {@code IntConsumer}, by
|
||||
* boxing the argument of {@code IntConsumer}, and then passed to
|
||||
* {@link #forEachRemaining(java.util.function.IntConsumer)}.
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Integer> action) {
|
||||
if (action instanceof IntConsumer) {
|
||||
forEachRemaining((IntConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(),
|
||||
"{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
|
||||
forEachRemaining((IntConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Spliterator specialized for {@code long} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfLong extends Spliterator<Long> {
|
||||
|
||||
@Override
|
||||
OfLong trySplit();
|
||||
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
* returning {@code true}; else returns {@code false}. If this
|
||||
* Spliterator is {@link #ORDERED} the action is performed on the
|
||||
* next element in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @param action The action
|
||||
* @return {@code false} if no remaining elements existed
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
boolean tryAdvance(LongConsumer action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
* the current thread, until all elements have been processed or the
|
||||
* action throws an exception. If this Spliterator is {@link #ORDERED},
|
||||
* actions are performed in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation repeatedly invokes {@link #tryAdvance}
|
||||
* until it returns {@code false}. It should be overridden whenever
|
||||
* possible.
|
||||
*
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(LongConsumer action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code LongConsumer} then it is cast
|
||||
* to {@code LongConsumer} and passed to
|
||||
* {@link #tryAdvance(java.util.function.LongConsumer)}; otherwise
|
||||
* the action is adapted to an instance of {@code LongConsumer}, by
|
||||
* boxing the argument of {@code LongConsumer}, and then passed to
|
||||
* {@link #tryAdvance(java.util.function.LongConsumer)}.
|
||||
*/
|
||||
@Override
|
||||
default boolean tryAdvance(Consumer<? super Long> action) {
|
||||
if (action instanceof LongConsumer) {
|
||||
return tryAdvance((LongConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(),
|
||||
"{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)");
|
||||
return tryAdvance((LongConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code LongConsumer} then it is cast
|
||||
* to {@code LongConsumer} and passed to
|
||||
* {@link #forEachRemaining(java.util.function.LongConsumer)}; otherwise
|
||||
* the action is adapted to an instance of {@code LongConsumer}, by
|
||||
* boxing the argument of {@code LongConsumer}, and then passed to
|
||||
* {@link #forEachRemaining(java.util.function.LongConsumer)}.
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Long> action) {
|
||||
if (action instanceof LongConsumer) {
|
||||
forEachRemaining((LongConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(),
|
||||
"{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)");
|
||||
forEachRemaining((LongConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Spliterator specialized for {@code double} values.
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface OfDouble extends Spliterator<Double> {
|
||||
|
||||
@Override
|
||||
OfDouble trySplit();
|
||||
|
||||
/**
|
||||
* If a remaining element exists, performs the given action on it,
|
||||
* returning {@code true}; else returns {@code false}. If this
|
||||
* Spliterator is {@link #ORDERED} the action is performed on the
|
||||
* next element in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @param action The action
|
||||
* @return {@code false} if no remaining elements existed
|
||||
* upon entry to this method, else {@code true}.
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
boolean tryAdvance(DoubleConsumer action);
|
||||
|
||||
/**
|
||||
* Performs the given action for each remaining element, sequentially in
|
||||
* the current thread, until all elements have been processed or the
|
||||
* action throws an exception. If this Spliterator is {@link #ORDERED},
|
||||
* actions are performed in encounter order. Exceptions thrown by the
|
||||
* action are relayed to the caller.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation repeatedly invokes {@link #tryAdvance}
|
||||
* until it returns {@code false}. It should be overridden whenever
|
||||
* possible.
|
||||
*
|
||||
* @param action The action
|
||||
* @throws NullPointerException if the specified action is null
|
||||
*/
|
||||
default void forEachRemaining(DoubleConsumer action) {
|
||||
do { } while (tryAdvance(action));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code DoubleConsumer} then it is
|
||||
* cast to {@code DoubleConsumer} and passed to
|
||||
* {@link #tryAdvance(java.util.function.DoubleConsumer)}; otherwise
|
||||
* the action is adapted to an instance of {@code DoubleConsumer}, by
|
||||
* boxing the argument of {@code DoubleConsumer}, and then passed to
|
||||
* {@link #tryAdvance(java.util.function.DoubleConsumer)}.
|
||||
*/
|
||||
@Override
|
||||
default boolean tryAdvance(Consumer<? super Double> action) {
|
||||
if (action instanceof DoubleConsumer) {
|
||||
return tryAdvance((DoubleConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(),
|
||||
"{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)");
|
||||
return tryAdvance((DoubleConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @implSpec
|
||||
* If the action is an instance of {@code DoubleConsumer} then it is
|
||||
* cast to {@code DoubleConsumer} and passed to
|
||||
* {@link #forEachRemaining(java.util.function.DoubleConsumer)};
|
||||
* otherwise the action is adapted to an instance of
|
||||
* {@code DoubleConsumer}, by boxing the argument of
|
||||
* {@code DoubleConsumer}, and then passed to
|
||||
* {@link #forEachRemaining(java.util.function.DoubleConsumer)}.
|
||||
*/
|
||||
@Override
|
||||
default void forEachRemaining(Consumer<? super Double> action) {
|
||||
if (action instanceof DoubleConsumer) {
|
||||
forEachRemaining((DoubleConsumer) action);
|
||||
}
|
||||
else {
|
||||
if (Tripwire.ENABLED)
|
||||
Tripwire.trip(getClass(),
|
||||
"{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)");
|
||||
forEachRemaining((DoubleConsumer) action::accept);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2154
jdk/src/share/classes/java/util/Spliterators.java
Normal file
2154
jdk/src/share/classes/java/util/Spliterators.java
Normal file
File diff suppressed because it is too large
Load Diff
69
jdk/src/share/classes/java/util/Tripwire.java
Normal file
69
jdk/src/share/classes/java/util/Tripwire.java
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.util;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Utility class for detecting inadvertent uses of boxing in
|
||||
* {@code java.util} classes. The detection is turned on or off based on
|
||||
* whether the system property {@code org.openjdk.java.util.stream.tripwire} is
|
||||
* considered {@code true} according to {@link Boolean#getBoolean(String)}.
|
||||
* This should normally be turned off for production use.
|
||||
*
|
||||
* @apiNote
|
||||
* Typical usage would be for boxing code to do:
|
||||
* <pre>{@code
|
||||
* if (Tripwire.ENABLED)
|
||||
* Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
|
||||
* }</pre>
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class Tripwire {
|
||||
private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
|
||||
|
||||
/** Should debugging checks be enabled? */
|
||||
static final boolean ENABLED = AccessController.doPrivileged(
|
||||
(PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
|
||||
|
||||
private Tripwire() { }
|
||||
|
||||
/**
|
||||
* Produces a log warning, using {@code PlatformLogger.getLogger(className)},
|
||||
* using the supplied message. The class name of {@code trippingClass} will
|
||||
* be used as the first parameter to the message.
|
||||
*
|
||||
* @param trippingClass Name of the class generating the message
|
||||
* @param msg A message format string of the type expected by
|
||||
* {@link PlatformLogger}
|
||||
*/
|
||||
static void trip(Class<?> trippingClass, String msg) {
|
||||
PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
|
||||
}
|
||||
}
|
@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Stack;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Vector;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Spliterator last-binding and fail-fast tests
|
||||
* @run testng SpliteratorLateBindingFailFastTest
|
||||
*/
|
||||
|
||||
@Test
|
||||
public class SpliteratorLateBindingFailFastTest {
|
||||
|
||||
private interface Source<T> {
|
||||
Collection<T> asCollection();
|
||||
void update();
|
||||
}
|
||||
|
||||
private static class SpliteratorDataBuilder<T> {
|
||||
final List<Object[]> data;
|
||||
|
||||
final T newValue;
|
||||
|
||||
final List<T> exp;
|
||||
|
||||
final Map<T, T> mExp;
|
||||
|
||||
SpliteratorDataBuilder(List<Object[]> data, T newValue, List<T> exp) {
|
||||
this.data = data;
|
||||
this.newValue = newValue;
|
||||
this.exp = exp;
|
||||
this.mExp = createMap(exp);
|
||||
}
|
||||
|
||||
Map<T, T> createMap(List<T> l) {
|
||||
Map<T, T> m = new LinkedHashMap<>();
|
||||
for (T t : l) {
|
||||
m.put(t, t);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void add(String description, Supplier<Source<?>> s) {
|
||||
description = joiner(description).toString();
|
||||
data.add(new Object[]{description, s});
|
||||
}
|
||||
|
||||
void addCollection(Function<Collection<T>, ? extends Collection<T>> f) {
|
||||
class CollectionSource implements Source<T> {
|
||||
final Collection<T> c = f.apply(exp);
|
||||
|
||||
final Consumer<Collection<T>> updater;
|
||||
|
||||
CollectionSource(Consumer<Collection<T>> updater) {
|
||||
this.updater = updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> asCollection() {
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
updater.accept(c);
|
||||
}
|
||||
}
|
||||
|
||||
String description = "new " + f.apply(Collections.<T>emptyList()).getClass().getName() + ".spliterator() ";
|
||||
add(description + "ADD", () -> new CollectionSource(c -> c.add(newValue)));
|
||||
add(description + "REMOVE", () -> new CollectionSource(c -> c.remove(c.iterator().next())));
|
||||
}
|
||||
|
||||
void addList(Function<Collection<T>, ? extends List<T>> l) {
|
||||
// @@@ If collection is instance of List then add sub-list tests
|
||||
addCollection(l);
|
||||
}
|
||||
|
||||
void addMap(Function<Map<T, T>, ? extends Map<T, T>> mapConstructor) {
|
||||
class MapSource<U> implements Source<U> {
|
||||
final Map<T, T> m = mapConstructor.apply(mExp);
|
||||
|
||||
final Collection<U> c;
|
||||
|
||||
final Consumer<Map<T, T>> updater;
|
||||
|
||||
MapSource(Function<Map<T, T>, Collection<U>> f, Consumer<Map<T, T>> updater) {
|
||||
this.c = f.apply(m);
|
||||
this.updater = updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<U> asCollection() {
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
updater.accept(m);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Consumer<Map<T, T>>> actions = new HashMap<>();
|
||||
actions.put("ADD", m -> m.put(newValue, newValue));
|
||||
actions.put("REMOVE", m -> m.remove(m.keySet().iterator().next()));
|
||||
|
||||
String description = "new " + mapConstructor.apply(Collections.<T, T>emptyMap()).getClass().getName();
|
||||
for (Map.Entry<String, Consumer<Map<T, T>>> e : actions.entrySet()) {
|
||||
add(description + ".keySet().spliterator() " + e.getKey(),
|
||||
() -> new MapSource<T>(m -> m.keySet(), e.getValue()));
|
||||
add(description + ".values().spliterator() " + e.getKey(),
|
||||
() -> new MapSource<T>(m -> m.values(), e.getValue()));
|
||||
add(description + ".entrySet().spliterator() " + e.getKey(),
|
||||
() -> new MapSource<Map.Entry<T, T>>(m -> m.entrySet(), e.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder joiner(String description) {
|
||||
return new StringBuilder(description).
|
||||
append(" {").
|
||||
append("size=").append(exp.size()).
|
||||
append("}");
|
||||
}
|
||||
}
|
||||
|
||||
static Object[][] spliteratorDataProvider;
|
||||
|
||||
@DataProvider(name = "Source")
|
||||
public static Object[][] spliteratorDataProvider() {
|
||||
if (spliteratorDataProvider != null) {
|
||||
return spliteratorDataProvider;
|
||||
}
|
||||
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
SpliteratorDataBuilder<Integer> db = new SpliteratorDataBuilder<>(data, 5, Arrays.asList(1, 2, 3, 4));
|
||||
|
||||
// Collections
|
||||
|
||||
db.addList(ArrayList::new);
|
||||
|
||||
db.addList(LinkedList::new);
|
||||
|
||||
db.addList(Vector::new);
|
||||
|
||||
|
||||
db.addCollection(HashSet::new);
|
||||
|
||||
db.addCollection(LinkedHashSet::new);
|
||||
|
||||
db.addCollection(TreeSet::new);
|
||||
|
||||
|
||||
db.addCollection(c -> { Stack<Integer> s = new Stack<>(); s.addAll(c); return s;});
|
||||
|
||||
db.addCollection(PriorityQueue::new);
|
||||
|
||||
// ArrayDeque fails some tests since it's fail-fast support is weaker
|
||||
// than other collections and limited to detecting most, but not all,
|
||||
// removals. It probably requires it's own test since it is difficult
|
||||
// to abstract out the conditions under which it fails-fast.
|
||||
// db.addCollection(ArrayDeque::new);
|
||||
|
||||
// Maps
|
||||
|
||||
db.addMap(HashMap::new);
|
||||
|
||||
db.addMap(LinkedHashMap::new);
|
||||
|
||||
// This fails when run through jrteg but passes when run though
|
||||
// ant
|
||||
// db.addMap(IdentityHashMap::new);
|
||||
|
||||
db.addMap(WeakHashMap::new);
|
||||
|
||||
// @@@ Descending maps etc
|
||||
db.addMap(TreeMap::new);
|
||||
|
||||
return spliteratorDataProvider = data.toArray(new Object[0][]);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "Source")
|
||||
public <T> void lateBindingTestWithForEach(String description, Supplier<Source<T>> ss) {
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
source.update();
|
||||
|
||||
Set<T> r = new HashSet<>();
|
||||
s.forEachRemaining(r::add);
|
||||
|
||||
assertEquals(r, new HashSet<>(c));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "Source")
|
||||
public <T> void lateBindingTestWithTryAdvance(String description, Supplier<Source<T>> ss) {
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
source.update();
|
||||
|
||||
Set<T> r = new HashSet<>();
|
||||
while (s.tryAdvance(r::add)) { }
|
||||
|
||||
assertEquals(r, new HashSet<>(c));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "Source")
|
||||
public <T> void lateBindingTestWithCharacteritics(String description, Supplier<Source<T>> ss) {
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
s.characteristics();
|
||||
|
||||
Set<T> r = new HashSet<>();
|
||||
s.forEachRemaining(r::add);
|
||||
|
||||
assertEquals(r, new HashSet<>(c));
|
||||
}
|
||||
|
||||
|
||||
@Test(dataProvider = "Source")
|
||||
public <T> void testFailFastTestWithTryAdvance(String description, Supplier<Source<T>> ss) {
|
||||
{
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
s.tryAdvance(e -> {
|
||||
});
|
||||
source.update();
|
||||
|
||||
executeAndCatch(() -> s.tryAdvance(e -> { }));
|
||||
}
|
||||
|
||||
{
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
s.tryAdvance(e -> {
|
||||
});
|
||||
source.update();
|
||||
|
||||
executeAndCatch(() -> s.forEachRemaining(e -> {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "Source")
|
||||
public <T> void testFailFastTestWithForEach(String description, Supplier<Source<T>> ss) {
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
executeAndCatch(() -> s.forEachRemaining(e -> {
|
||||
source.update();
|
||||
}));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "Source")
|
||||
public <T> void testFailFastTestWithEstimateSize(String description, Supplier<Source<T>> ss) {
|
||||
{
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
s.estimateSize();
|
||||
source.update();
|
||||
|
||||
executeAndCatch(() -> s.tryAdvance(e -> { }));
|
||||
}
|
||||
|
||||
{
|
||||
Source<T> source = ss.get();
|
||||
Collection<T> c = source.asCollection();
|
||||
Spliterator<T> s = c.spliterator();
|
||||
|
||||
s.estimateSize();
|
||||
source.update();
|
||||
|
||||
executeAndCatch(() -> s.forEachRemaining(e -> {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void executeAndCatch(Runnable r) {
|
||||
executeAndCatch(ConcurrentModificationException.class, r);
|
||||
}
|
||||
|
||||
private void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
|
||||
Exception caught = null;
|
||||
try {
|
||||
r.run();
|
||||
}
|
||||
catch (Exception e) {
|
||||
caught = e;
|
||||
}
|
||||
|
||||
assertNotNull(caught,
|
||||
String.format("No Exception was thrown, expected an Exception of %s to be thrown",
|
||||
expected.getName()));
|
||||
assertTrue(expected.isInstance(caught),
|
||||
String.format("Exception thrown %s not an instance of %s",
|
||||
caught.getClass().getName(), expected.getName()));
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user