# HG changeset patch # User briangoetz # Date 1366134713 14400 # Node ID 674880648db489fb568d6db19a10491cb67918e5 # Parent 131686bea632e034a320b6574d99fe08e63367e4 8010096: Initial java.util.Spliterator putback Reviewed-by: mduigou, alanb, chegar, darcy Contributed-by: Paul Sandoz , Brian Goetz , Doug Lea diff -r 131686bea632 -r 674880648db4 src/share/classes/com/sun/tools/jdi/EventSetImpl.java --- a/src/share/classes/com/sun/tools/jdi/EventSetImpl.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/com/sun/tools/jdi/EventSetImpl.java Tue Apr 16 13:51:53 2013 -0400 @@ -851,6 +851,11 @@ } } + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(this, Spliterator.DISTINCT); + } + /* below make this unmodifiable */ public boolean add(Event o){ diff -r 131686bea632 -r 674880648db4 src/share/classes/java/lang/Iterable.java --- a/src/share/classes/java/lang/Iterable.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/lang/Iterable.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 + * + * For-each Loop + * * * @param the type of elements returned by the iterator * * @since 1.5 + * @jls 14.14.2 The enhanced for statement */ @FunctionalInterface public interface Iterable { - /** - * Returns an iterator over a set of elements of type T. + * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */ Iterator 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 + *

The default implementation behaves as if: + *

{@code
+     *     for (T t : this)
+     *         action.accept(t);
+     * }
+ * + * @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 action) { + Objects.requireNonNull(action); + for (T t : this) { + action.accept(t); + } + } } + diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Arrays.java --- a/src/share/classes/java/util/Arrays.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/util/Arrays.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 boolean contains(Object o) { return indexOf(o) != -1; } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(a, Spliterator.ORDERED); + } } /** @@ -4300,4 +4305,167 @@ buf.append(']'); dejaVu.remove(a); } + + /** + * Creates a {@link Spliterator} covering all of the specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param 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 Spliterator spliterator(T[] array) { + return Spliterators.spliterator(array, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Creates a {@link Spliterator} covering the specified range of the + * specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param Type of elements + * @param array The array, assumed to be unmodified during use + * @param fromIndex The least index (inclusive) to cover + * @param toIndex One past the greatest index to cover + * @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 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. + * + *

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

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

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

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

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

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); + } } diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Collection.java --- a/src/share/classes/java/util/Collection.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/util/Collection.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 @@ * * Java Collections Framework. * + * @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 the type of elements in this collection * * @author Josh Bloch @@ -453,4 +459,28 @@ * @see Object#equals(Object) */ int hashCode(); + + /** + * Creates a {@link Spliterator} over the elements in this collection. + * + *

The {@code Spliterator} reports {@link Spliterator#SIZED}. + * Implementations should document the reporting of additional + * characteristic values. + * + * @implSpec + * The default implementation creates a + * late-binding spliterator + * from the collections's {@code Iterator}. The spliterator inherits the + * fail-fast 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 spliterator() { + return Spliterators.spliterator(this, 0); + } } diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Iterator.java --- a/src/share/classes/java/util/Iterator.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/util/Iterator.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 @@ * 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 @@ * 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 + *

The default implementation behaves as if: + *

{@code
+     *     while (hasNext())
+     *         action.accept(next());
+     * }
+ * + * @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 action) { + Objects.requireNonNull(action); + while (hasNext()) + action.accept(next()); + } } diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/List.java --- a/src/share/classes/java/util/List.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/util/List.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 @@ * fromIndex > toIndex) */ List subList(int fromIndex, int toIndex); + + /** + * Creates a {@link Spliterator} over the elements in this list. + * + *

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 + * late-binding spliterator + * from the list's {@code Iterator}. The spliterator inherits the + * fail-fast 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 spliterator() { + return Spliterators.spliterator(this, Spliterator.ORDERED); + } } + diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/PrimitiveIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/PrimitiveIterator.java Tue Apr 16 13:51:53 2013 -0400 @@ -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. + * + *

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

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 the boxed type of the primitive type + * @since 1.8 + */ +public interface PrimitiveIterator extends Iterator { + + /** + * An Iterator specialized for {@code int} values. + * @since 1.8 + */ + public static interface OfInt extends PrimitiveIterator { + + /** + * 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 + *

The default implementation behaves as if: + *

{@code
+         *     while (hasNext())
+         *         action.accept(nextInt());
+         * }
+ * + * @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 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 { + + /** + * 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 + *

The default implementation behaves as if: + *

{@code
+         *     while (hasNext())
+         *         action.accept(nextLong());
+         * }
+ * + * @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 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 { + + /** + * 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 + *

The default implementation behaves as if: + *

{@code
+         *     while (hasNext())
+         *         action.accept(nextDouble());
+         * }
+ * + * @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 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); + } + } + } +} diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Set.java --- a/src/share/classes/java/util/Set.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/util/Set.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 @@ * @see Set#equals(Object) */ int hashCode(); + + /** + * Creates a {@code Spliterator} over the elements in this set. + * + *

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 + * late-binding spliterator + * from the set's {@code Iterator}. The spliterator inherits the + * fail-fast 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 spliterator() { + return Spliterators.spliterator(this, Spliterator.DISTINCT); + } } diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/SortedSet.java --- a/src/share/classes/java/util/SortedSet.java Wed Apr 17 12:31:34 2013 -0700 +++ b/src/share/classes/java/util/SortedSet.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 @@ * @throws NoSuchElementException if this set is empty */ E last(); + + /** + * Creates a {@code Spliterator} over the elements in this sorted set. + * + *

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

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 + * late-binding spliterator + * from the sorted set's {@code Iterator}. The spliterator inherits the + * fail-fast 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 spliterator() { + return new Spliterators.IteratorSpliterator( + this, Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED) { + @Override + public Comparator getComparator() { + return SortedSet.this.comparator(); + } + }; + } } diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Spliterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/Spliterator.java Tue Apr 16 13:51:53 2013 -0400 @@ -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. + * + *

A Spliterator may traverse elements individually ({@link + * #tryAdvance tryAdvance()}) or sequentially in bulk + * ({@link #forEachRemaining forEachRemaining()}). + * + *

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

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

A Spliterator that does not report {@code IMMUTABLE} or + * {@code CONCURRENT} is expected to have a documented policy concerning: + * when the spliterator binds to the element source; and detection of + * structural interference of the element source detected after binding. A + * late-binding 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 late-binding 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 fail-fast. + * + *

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

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 serial + * thread-confinement, 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. + * + *

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

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

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

Structural interference of a source can be managed in the following ways + * (in approximate order of decreasing desirability): + *

+ * + *

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

 {@code
+ * class TaggedArray {
+ *   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 spliterator() {
+ *     return new TaggedArraySpliterator<>(elements, 0, elements.length);
+ *   }
+ *
+ *   static class TaggedArraySpliterator implements Spliterator {
+ *     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 action) {
+ *       for (; origin < fence; origin += 2)
+ *         action.accept((T) array[origin]);
+ *     }
+ *
+ *     public boolean tryAdvance(Consumer action) {
+ *       if (origin < fence) {
+ *         action.accept((T) array[origin]);
+ *         origin += 2;
+ *         return true;
+ *       }
+ *       else // cannot advance
+ *         return false;
+ *     }
+ *
+ *     public Spliterator 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;
+ *     }
+ *   }
+ * }}
+ * + *

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

{@code
+ * static  void parEach(TaggedArray a, Consumer action) {
+ *   Spliterator s = a.spliterator();
+ *   long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
+ *   new ParEach(null, s, action, targetBatchSize).invoke();
+ * }
+ *
+ * static class ParEach extends CountedCompleter {
+ *   final Spliterator spliterator;
+ *   final Consumer action;
+ *   final long targetBatchSize;
+ *
+ *   ParEach(ParEach parent, Spliterator spliterator,
+ *           Consumer action, long targetBatchSize) {
+ *     super(parent);
+ *     this.spliterator = spliterator; this.action = action;
+ *     this.targetBatchSize = targetBatchSize;
+ *   }
+ *
+ *   public void compute() {
+ *     Spliterator sub;
+ *     while (spliterator.estimateSize() > targetBatchSize &&
+ *            (sub = spliterator.trySplit()) != null) {
+ *       addToPendingCount(1);
+ *       new ParEach<>(this, sub, action, targetBatchSize).fork();
+ *     }
+ *     spliterator.forEachRemaining(action);
+ *     propagateCompletion();
+ *   }
+ * }}
+ * + * @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 { + /** + * 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 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 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. + * + *

If this Spliterator is {@link #ORDERED}, the returned Spliterator + * must cover a strict prefix of the elements. + * + *

Unless this Spliterator covers an infinite number of elements, + * repeated calls to {@code trySplit()} must eventually return {@code null}. + * Upon non-null return: + *

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

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

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

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

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

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

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

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 { + + @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 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 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 { + + @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 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 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 { + + @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 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 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); + } + } + } +} diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Spliterators.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/Spliterators.java Tue Apr 16 13:51:53 2013 -0400 @@ -0,0 +1,2154 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util; + +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; + +/** + * Static classes and methods for operating on or creating instances of + * {@link Spliterator} and its primitive specializations + * {@link Spliterator.OfInt}, {@link Spliterator.OfLong}, and + * {@link Spliterator.OfDouble}. + * + * @see Spliterator + * @since 1.8 + */ +public final class Spliterators { + + // Suppresses default constructor, ensuring non-instantiability. + private Spliterators() {} + + // Empty spliterators + + /** + * Creates an empty {@code Spliterator} + * + *

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

The empty spliterator reports {@link Spliterator#SIZED} and + * {@link Spliterator#SUBSIZED}. Calls to + * {@link java.util.Spliterator#trySplit()} always return {@code null}. + * + * @return An empty spliterator + */ + public static Spliterator.OfInt emptyIntSpliterator() { + return EMPTY_INT_SPLITERATOR; + } + + private static final Spliterator.OfInt EMPTY_INT_SPLITERATOR = + new EmptySpliterator.OfInt(); + + /** + * Creates an empty {@code Spliterator.OfLong} + * + *

The empty spliterator reports {@link Spliterator#SIZED} and + * {@link Spliterator#SUBSIZED}. Calls to + * {@link java.util.Spliterator#trySplit()} always return {@code null}. + * + * @return An empty spliterator + */ + public static Spliterator.OfLong emptyLongSpliterator() { + return EMPTY_LONG_SPLITERATOR; + } + + private static final Spliterator.OfLong EMPTY_LONG_SPLITERATOR = + new EmptySpliterator.OfLong(); + + /** + * Creates an empty {@code Spliterator.OfDouble} + * + *

The empty spliterator reports {@link Spliterator#SIZED} and + * {@link Spliterator#SUBSIZED}. Calls to + * {@link java.util.Spliterator#trySplit()} always return {@code null}. + * + * @return An empty spliterator + */ + public static Spliterator.OfDouble emptyDoubleSpliterator() { + return EMPTY_DOUBLE_SPLITERATOR; + } + + private static final Spliterator.OfDouble EMPTY_DOUBLE_SPLITERATOR = + new EmptySpliterator.OfDouble(); + + // Array-based spliterators + + /** + * Creates a {@code Spliterator} covering the elements of a given array, + * using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(Object[])}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report; it is common to + * additionally specify {@code IMMUTABLE} and {@code ORDERED}. + * + * @param Type of elements + * @param array The array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @see Arrays#spliterator(Object[]) + */ + public static Spliterator spliterator(Object[] array, + int additionalCharacteristics) { + return new ArraySpliterator<>(Objects.requireNonNull(array), + additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator} covering a range of elements of a given + * array, using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(Object[])}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report; it is common to + * additionally specify {@code IMMUTABLE} and {@code ORDERED}. + * + * @param Type of elements + * @param array The array, assumed to be unmodified during use + * @param fromIndex The least index (inclusive) to cover + * @param toIndex One past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, + * {@code toIndex} is less than {@code fromIndex}, or + * {@code toIndex} is greater than the array size + * @see Arrays#spliterator(Object[], int, int) + */ + public static Spliterator spliterator(Object[] array, int fromIndex, int toIndex, + int additionalCharacteristics) { + checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex); + return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator.OfInt} covering the elements of a given array, + * using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(int[])}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report; it is common to + * additionally specify {@code IMMUTABLE} and {@code ORDERED}. + * + * @param array The array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @see Arrays#spliterator(int[]) + */ + public static Spliterator.OfInt spliterator(int[] array, + int additionalCharacteristics) { + return new IntArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator.OfInt} covering a range of elements of a + * given array, using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(int[], int, int)}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report; it is common to + * additionally specify {@code IMMUTABLE} and {@code ORDERED}. + * + * @param array The array, assumed to be unmodified during use + * @param fromIndex The least index (inclusive) to cover + * @param toIndex One past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, + * {@code toIndex} is less than {@code fromIndex}, or + * {@code toIndex} is greater than the array size + * @see Arrays#spliterator(int[], int, int) + */ + public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex, + int additionalCharacteristics) { + checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex); + return new IntArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator.OfLong} covering the elements of a given array, + * using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(long[])}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report; it is common to + * additionally specify {@code IMMUTABLE} and {@code ORDERED}. + * + * @param array The array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @see Arrays#spliterator(long[]) + */ + public static Spliterator.OfLong spliterator(long[] array, + int additionalCharacteristics) { + return new LongArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator.OfLong} covering a range of elements of a + * given array, using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(long[], int, int)}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report. (For example, if it is + * known the array will not be further modified, specify {@code IMMUTABLE}; + * if the array data is considered to have an an encounter order, specify + * {@code ORDERED}). The method {@link Arrays#spliterator(long[], int, int)} can + * often be used instead, which returns a spliterator that reports + * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}. + * + * @param array The array, assumed to be unmodified during use + * @param fromIndex The least index (inclusive) to cover + * @param toIndex One past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, + * {@code toIndex} is less than {@code fromIndex}, or + * {@code toIndex} is greater than the array size + * @see Arrays#spliterator(long[], int, int) + */ + public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex, + int additionalCharacteristics) { + checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex); + return new LongArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator.OfDouble} covering the elements of a given array, + * using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(double[])}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report; it is common to + * additionally specify {@code IMMUTABLE} and {@code ORDERED}. + * + * @param array The array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @see Arrays#spliterator(double[]) + */ + public static Spliterator.OfDouble spliterator(double[] array, + int additionalCharacteristics) { + return new DoubleArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics); + } + + /** + * Creates a {@code Spliterator.OfDouble} covering a range of elements of a + * given array, using a customized set of spliterator characteristics. + * + *

This method is provided as an implementation convenience for + * Spliterators which store portions of their elements in arrays, and need + * fine control over Spliterator characteristics. Most other situations in + * which a Spliterator for an array is needed should use + * {@link Arrays#spliterator(double[], int, int)}. + * + *

The returned spliterator always reports the characteristics + * {@code SIZED} and {@code SUBSIZED}. The caller may provide additional + * characteristics for the spliterator to report. (For example, if it is + * known the array will not be further modified, specify {@code IMMUTABLE}; + * if the array data is considered to have an an encounter order, specify + * {@code ORDERED}). The method {@link Arrays#spliterator(long[], int, int)} can + * often be used instead, which returns a spliterator that reports + * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}. + * + * @param array The array, assumed to be unmodified during use + * @param fromIndex The least index (inclusive) to cover + * @param toIndex One past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + * @return A spliterator for an array + * @throws NullPointerException if the given array is {@code null} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative, + * {@code toIndex} is less than {@code fromIndex}, or + * {@code toIndex} is greater than the array size + * @see Arrays#spliterator(double[], int, int) + */ + public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex, + int additionalCharacteristics) { + checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex); + return new DoubleArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics); + } + + /** + * Validate inclusive start index and exclusive end index against the length + * of an array. + * @param arrayLength The length of the array + * @param origin The inclusive start index + * @param fence The exclusive end index + * @throws ArrayIndexOutOfBoundsException if the start index is greater than + * the end index, if the start index is negative, or the end index is + * greater than the array length + */ + private static void checkFromToBounds(int arrayLength, int origin, int fence) { + if (origin > fence) { + throw new IllegalArgumentException( + "origin(" + origin + ") > fence(" + fence + ")"); + } + if (origin < 0) { + throw new ArrayIndexOutOfBoundsException(origin); + } + if (fence > arrayLength) { + throw new ArrayIndexOutOfBoundsException(fence); + } + } + + // Iterator-based spliterators + + /** + * Creates a {@code Spliterator} using the given collection's + * {@link 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 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 from an iterator + * @throws NullPointerException if the given collection is {@code null} + */ + public static Spliterator spliterator(Collection c, + int additionalCharacteristics) { + return new IteratorSpliterator<>(Objects.requireNonNull(c), + additionalCharacteristics); + } + + /** + * 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 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 from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator spliterator(Iterator iterator, + long size, + int additionalCharacteristics) { + return new IteratorSpliterator<>(Objects.requireNonNull(iterator), size, + additionalCharacteristics); + } + + /** + * 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 Properties of this spliterator's source + * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are + * ignored and are not reported.) + * @return A spliterator from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator spliteratorUnknownSize(Iterator iterator, + int characteristics) { + return new IteratorSpliterator<>(Objects.requireNonNull(iterator), characteristics); + } + + /** + * Creates a {@code Spliterator.OfInt} using a given + * {@code IntStream.IntIterator} as the source of elements, and with a given + * initially reported size. + * + *

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

Traversal of elements should be accomplished through the spliterator. + * The behaviour of splitting and traversal is undefined if the iterator is + * operated on after the spliterator is returned, or the initially reported + * size is not equal to the actual number of elements in the source. + * + * @param iterator The iterator for the source + * @param size The number of elements in the source, to be reported as + * initial {@code estimateSize}. + * @param 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 from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt iterator, + long size, + int additionalCharacteristics) { + return new IntIteratorSpliterator(Objects.requireNonNull(iterator), + size, additionalCharacteristics); + } + + /** + * 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 Properties of this spliterator's source + * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are + * ignored and are not reported.) + * @return A spliterator from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator.OfInt spliteratorUnknownSize(PrimitiveIterator.OfInt iterator, + int characteristics) { + return new IntIteratorSpliterator(Objects.requireNonNull(iterator), characteristics); + } + + /** + * Creates a {@code Spliterator.OfLong} using a given + * {@code LongStream.LongIterator} as the source of elements, and with a + * given initially reported size. + * + *

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 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 from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong iterator, + long size, + int additionalCharacteristics) { + return new LongIteratorSpliterator(Objects.requireNonNull(iterator), + size, additionalCharacteristics); + } + + /** + * 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 Properties of this spliterator's source + * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are + * ignored and are not reported.) + * @return A spliterator from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator.OfLong spliteratorUnknownSize(PrimitiveIterator.OfLong iterator, + int characteristics) { + return new LongIteratorSpliterator(Objects.requireNonNull(iterator), characteristics); + } + + /** + * Creates a {@code Spliterator.OfDouble} using a given + * {@code DoubleStream.DoubleIterator} as the source of elements, and with a + * given initially reported size. + * + *

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 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 from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble iterator, + long size, + int additionalCharacteristics) { + return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), + size, additionalCharacteristics); + } + + /** + * 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 Properties of this spliterator's source + * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are + * ignored and are not reported.) + * @return A spliterator from an iterator + * @throws NullPointerException if the given iterator is {@code null} + */ + public static Spliterator.OfDouble spliteratorUnknownSize(PrimitiveIterator.OfDouble iterator, + int characteristics) { + return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), characteristics); + } + + // Iterators from Spliterators + + /** + * Creates an {@code Iterator} from a {@code Spliterator}. + * + *

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 iteratorFromSpliterator(Spliterator spliterator) { + Objects.requireNonNull(spliterator); + class Adapter implements Iterator, Consumer { + boolean valueReady = false; + T nextElement; + + @Override + public void accept(T t) { + valueReady = true; + nextElement = t; + } + + @Override + public boolean hasNext() { + if (!valueReady) + spliterator.tryAdvance(this); + return valueReady; + } + + @Override + public T next() { + if (!valueReady && !hasNext()) + throw new NoSuchElementException(); + else { + valueReady = false; + return nextElement; + } + } + } + + 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 iteratorFromSpliterator(Spliterator.OfInt spliterator) { + Objects.requireNonNull(spliterator); + class Adapter implements PrimitiveIterator.OfInt, IntConsumer { + boolean valueReady = false; + int nextElement; + + @Override + public void accept(int t) { + valueReady = true; + nextElement = t; + } + + @Override + public boolean hasNext() { + if (!valueReady) + spliterator.tryAdvance(this); + return valueReady; + } + + @Override + public int nextInt() { + if (!valueReady && !hasNext()) + throw new NoSuchElementException(); + else { + valueReady = false; + return nextElement; + } + } + } + + return new Adapter(); + } + + /** + * Creates an {@code PrimitiveIterator.OfLong} from a + * {@code Spliterator.OfLong}. + * + *

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 iteratorFromSpliterator(Spliterator.OfLong spliterator) { + Objects.requireNonNull(spliterator); + class Adapter implements PrimitiveIterator.OfLong, LongConsumer { + boolean valueReady = false; + long nextElement; + + @Override + public void accept(long t) { + valueReady = true; + nextElement = t; + } + + @Override + public boolean hasNext() { + if (!valueReady) + spliterator.tryAdvance(this); + return valueReady; + } + + @Override + public long nextLong() { + if (!valueReady && !hasNext()) + throw new NoSuchElementException(); + else { + valueReady = false; + return nextElement; + } + } + } + + return new Adapter(); + } + + /** + * Creates an {@code PrimitiveIterator.OfDouble} from a + * {@code Spliterator.OfDouble}. + * + *

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 iteratorFromSpliterator(Spliterator.OfDouble spliterator) { + Objects.requireNonNull(spliterator); + class Adapter implements PrimitiveIterator.OfDouble, DoubleConsumer { + boolean valueReady = false; + double nextElement; + + @Override + public void accept(double t) { + valueReady = true; + nextElement = t; + } + + @Override + public boolean hasNext() { + if (!valueReady) + spliterator.tryAdvance(this); + return valueReady; + } + + @Override + public double nextDouble() { + if (!valueReady && !hasNext()) + throw new NoSuchElementException(); + else { + valueReady = false; + return nextElement; + } + } + } + + return new Adapter(); + } + + // Implementations + + private static abstract class EmptySpliterator, C> { + + EmptySpliterator() { } + + public S trySplit() { + return null; + } + + public boolean tryAdvance(C consumer) { + Objects.requireNonNull(consumer); + return false; + } + + public void forEachRemaining(C consumer) { + Objects.requireNonNull(consumer); + } + + public long estimateSize() { + return 0; + } + + public int characteristics() { + return Spliterator.SIZED | Spliterator.SUBSIZED; + } + + private static final class OfRef + extends EmptySpliterator, Consumer> + implements Spliterator { + OfRef() { } + } + + private static final class OfInt + extends EmptySpliterator + implements Spliterator.OfInt { + OfInt() { } + } + + private static final class OfLong + extends EmptySpliterator + implements Spliterator.OfLong { + OfLong() { } + } + + private static final class OfDouble + extends EmptySpliterator + implements Spliterator.OfDouble { + OfDouble() { } + } + } + + // Array-based spliterators + + /** + * A Spliterator designed for use by sources that traverse and split + * elements maintained in an unmodifiable {@code Object[]} array. + */ + static final class ArraySpliterator implements Spliterator { + /** + * The array, explicitly typed as Object[]. Unlike in some other + * classes (see for example CR 6260652), we do not need to + * screen arguments to ensure they are exactly of type Object[] + * so long as no methods write into the array or serialize it, + * which we ensure here by defining this class as final. + */ + private final Object[] array; + private int index; // current index, modified on advance/split + private final int fence; // one past last index + private final int characteristics; + + /** + * Creates a spliterator covering all of the given array. + * @param array the array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public ArraySpliterator(Object[] array, int additionalCharacteristics) { + this(array, 0, array.length, additionalCharacteristics); + } + + /** + * Creates a spliterator covering the given array and range + * @param array the array, assumed to be unmodified during use + * @param origin the least index (inclusive) to cover + * @param fence one past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public ArraySpliterator(Object[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + this.index = origin; + this.fence = fence; + this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public Spliterator trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) + ? null + : new ArraySpliterator<>(array, lo, index = mid, characteristics); + } + + @SuppressWarnings("unchecked") + @Override + public void forEachRemaining(Consumer action) { + Object[] a; int i, hi; // hoist accesses and checks from loop + if (action == null) + throw new NullPointerException(); + if ((a = array).length >= (hi = fence) && + (i = index) >= 0 && i < (index = hi)) { + do { action.accept((T)a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < fence) { + @SuppressWarnings("unchecked") T e = (T) array[index++]; + action.accept(e); + return true; + } + return false; + } + + @Override + public long estimateSize() { return (long)(fence - index); } + + @Override + public int characteristics() { + return characteristics; + } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } + + /** + * A Spliterator.OfInt designed for use by sources that traverse and split + * elements maintained in an unmodifiable {@code int[]} array. + */ + static final class IntArraySpliterator implements Spliterator.OfInt { + private final int[] array; + private int index; // current index, modified on advance/split + private final int fence; // one past last index + private final int characteristics; + + /** + * Creates a spliterator covering all of the given array. + * @param array the array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public IntArraySpliterator(int[] array, int additionalCharacteristics) { + this(array, 0, array.length, additionalCharacteristics); + } + + /** + * Creates a spliterator covering the given array and range + * @param array the array, assumed to be unmodified during use + * @param origin the least index (inclusive) to cover + * @param fence one past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + this.index = origin; + this.fence = fence; + this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public OfInt trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) + ? null + : new IntArraySpliterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(IntConsumer action) { + int[] a; int i, hi; // hoist accesses and checks from loop + if (action == null) + throw new NullPointerException(); + if ((a = array).length >= (hi = fence) && + (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public long estimateSize() { return (long)(fence - index); } + + @Override + public int characteristics() { + return characteristics; + } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } + + /** + * A Spliterator.OfLong designed for use by sources that traverse and split + * elements maintained in an unmodifiable {@code int[]} array. + */ + static final class LongArraySpliterator implements Spliterator.OfLong { + private final long[] array; + private int index; // current index, modified on advance/split + private final int fence; // one past last index + private final int characteristics; + + /** + * Creates a spliterator covering all of the given array. + * @param array the array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public LongArraySpliterator(long[] array, int additionalCharacteristics) { + this(array, 0, array.length, additionalCharacteristics); + } + + /** + * Creates a spliterator covering the given array and range + * @param array the array, assumed to be unmodified during use + * @param origin the least index (inclusive) to cover + * @param fence one past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public LongArraySpliterator(long[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + this.index = origin; + this.fence = fence; + this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public OfLong trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) + ? null + : new LongArraySpliterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(LongConsumer action) { + long[] a; int i, hi; // hoist accesses and checks from loop + if (action == null) + throw new NullPointerException(); + if ((a = array).length >= (hi = fence) && + (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(LongConsumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public long estimateSize() { return (long)(fence - index); } + + @Override + public int characteristics() { + return characteristics; + } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } + + /** + * A Spliterator.OfDouble designed for use by sources that traverse and split + * elements maintained in an unmodifiable {@code int[]} array. + */ + static final class DoubleArraySpliterator implements Spliterator.OfDouble { + private final double[] array; + private int index; // current index, modified on advance/split + private final int fence; // one past last index + private final int characteristics; + + /** + * Creates a spliterator covering all of the given array. + * @param array the array, assumed to be unmodified during use + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public DoubleArraySpliterator(double[] array, int additionalCharacteristics) { + this(array, 0, array.length, additionalCharacteristics); + } + + /** + * Creates a spliterator covering the given array and range + * @param array the array, assumed to be unmodified during use + * @param origin the least index (inclusive) to cover + * @param fence one past the greatest index to cover + * @param additionalCharacteristics Additional spliterator characteristics + * of this spliterator's source or elements beyond {@code SIZED} and + * {@code SUBSIZED} which are are always reported + */ + public DoubleArraySpliterator(double[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + this.index = origin; + this.fence = fence; + this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public OfDouble trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) + ? null + : new DoubleArraySpliterator(array, lo, index = mid, characteristics); + } + + @Override + public void forEachRemaining(DoubleConsumer action) { + double[] a; int i, hi; // hoist accesses and checks from loop + if (action == null) + throw new NullPointerException(); + if ((a = array).length >= (hi = fence) && + (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(DoubleConsumer action) { + if (action == null) + throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + + @Override + public long estimateSize() { return (long)(fence - index); } + + @Override + public int characteristics() { + return characteristics; + } + + @Override + public Comparator 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(java.util.function.Consumer) tryAdvance}. + * The extending class should override + * {@link #forEachRemaining(java.util.function.Consumer) forEach} if it can + * provide a more performant implementation. + * + * @apiNote + * This class is a useful aid for creating a spliterator when it is not + * possible or difficult to efficiently partition elements in a manner + * allowing balanced parallel computation. + * + *

An alternative to using this class, that also permits limited + * parallelism, is to create a spliterator from an iterator + * (see {@link #spliterator(Iterator, long, int)}. Depending on the + * circumstances using an iterator may be easier or more convenient than + * extending this class, such as when there is already an iterator + * available to use. + * + * @see #spliterator(Iterator, long, int) + * @since 1.8 + */ + public static abstract class AbstractSpliterator 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; + try { + a = new Object[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = holder.value; } while (++j < n && tryAdvance(holder)); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new ArraySpliterator<>(a, 0, j, characteristics()); + } + return null; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the estimated size as reported when + * created and, if the estimate size is known, decreases in size when + * split. + */ + @Override + public long estimateSize() { + return est; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the characteristics as reported when + * created. + */ + @Override + public int characteristics() { + return characteristics; + } + } + + /** + * An abstract {@code Spliterator.OfInt} that implements {@code trySplit} to + * permit limited parallelism. + * + *

To implement a spliterator an extending class need only + * implement {@link #tryAdvance(java.util.function.IntConsumer)} + * tryAdvance}. The extending class should override + * {@link #forEachRemaining(java.util.function.IntConsumer)} forEach} if it + * can provide a more performant implementation. + * + * @apiNote + * This class is a useful aid for creating a spliterator when it is not + * possible or difficult to efficiently partition elements in a manner + * allowing balanced parallel computation. + * + *

An alternative to using this class, that also permits limited + * parallelism, is to create a spliterator from an iterator + * (see {@link #spliterator(java.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(java.util.PrimitiveIterator.OfInt, long, int) + * @since 1.8 + */ + public static abstract class AbstractIntSpliterator implements Spliterator.OfInt { + static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH; + static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator reporting the given estimated size and + * characteristics. + * + * @param est the estimated size of this spliterator if known, otherwise + * {@code Long.MAX_VALUE}. + * @param additionalCharacteristics properties of this spliterator's + * source or elements. If {@code SIZED} is reported then this + * spliterator will additionally report {@code SUBSIZED}. + */ + protected AbstractIntSpliterator(long est, int additionalCharacteristics) { + this.est = est; + this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0) + ? additionalCharacteristics | Spliterator.SUBSIZED + : additionalCharacteristics; + } + + static final class HoldingIntConsumer implements IntConsumer { + int value; + + @Override + public void accept(int value) { + this.value = value; + } + } + + /** + * {@inheritDoc} + * + * This implementation permits limited parallelism. + */ + @Override + public 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; + try { + a = new int[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = holder.value; } while (++j < n && tryAdvance(holder)); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new IntArraySpliterator(a, 0, j, characteristics()); + } + return null; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the estimated size as reported when + * created and, if the estimate size is known, decreases in size when + * split. + */ + @Override + public long estimateSize() { + return est; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the characteristics as reported when + * created. + */ + @Override + public int characteristics() { + return characteristics; + } + } + + /** + * An abstract {@code Spliterator.OfLong} that implements {@code trySplit} + * to permit limited parallelism. + * + *

To implement a spliterator an extending class need only + * implement {@link #tryAdvance(java.util.function.LongConsumer)} + * tryAdvance}. The extending class should override + * {@link #forEachRemaining(java.util.function.LongConsumer)} forEach} if it + * can provide a more performant implementation. + * + * @apiNote + * This class is a useful aid for creating a spliterator when it is not + * possible or difficult to efficiently partition elements in a manner + * allowing balanced parallel computation. + * + *

An alternative to using this class, that also permits limited + * parallelism, is to create a spliterator from an iterator + * (see {@link #spliterator(java.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(java.util.PrimitiveIterator.OfLong, long, int) + * @since 1.8 + */ + public static abstract class AbstractLongSpliterator implements Spliterator.OfLong { + static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH; + static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator reporting the given estimated size and + * characteristics. + * + * @param est the estimated size of this spliterator if known, otherwise + * {@code Long.MAX_VALUE}. + * @param additionalCharacteristics properties of this spliterator's + * source or elements. If {@code SIZED} is reported then this + * spliterator will additionally report {@code SUBSIZED}. + */ + protected AbstractLongSpliterator(long est, int additionalCharacteristics) { + this.est = est; + this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0) + ? additionalCharacteristics | Spliterator.SUBSIZED + : additionalCharacteristics; + } + + static final class HoldingLongConsumer implements LongConsumer { + long value; + + @Override + public void accept(long value) { + this.value = value; + } + } + + /** + * {@inheritDoc} + * + * This implementation permits limited parallelism. + */ + @Override + public 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; + try { + a = new long[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = holder.value; } while (++j < n && tryAdvance(holder)); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new LongArraySpliterator(a, 0, j, characteristics()); + } + return null; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the estimated size as reported when + * created and, if the estimate size is known, decreases in size when + * split. + */ + @Override + public long estimateSize() { + return est; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the characteristics as reported when + * created. + */ + @Override + public int characteristics() { + return characteristics; + } + } + + /** + * An abstract {@code Spliterator.OfDouble} that implements + * {@code trySplit} to permit limited parallelism. + * + *

To implement a spliterator an extending class need only + * implement {@link #tryAdvance(java.util.function.DoubleConsumer)} + * tryAdvance}. The extending class should override + * {@link #forEachRemaining(java.util.function.DoubleConsumer)} forEach} if + * it can provide a more performant implementation. + * + * @apiNote + * This class is a useful aid for creating a spliterator when it is not + * possible or difficult to efficiently partition elements in a manner + * allowing balanced parallel computation. + * + *

An alternative to using this class, that also permits limited + * parallelism, is to create a spliterator from an iterator + * (see {@link #spliterator(java.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(java.util.PrimitiveIterator.OfDouble, long, int) + * @since 1.8 + */ + public static abstract class AbstractDoubleSpliterator implements Spliterator.OfDouble { + static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH; + static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator reporting the given estimated size and + * characteristics. + * + * @param est the estimated size of this spliterator if known, otherwise + * {@code Long.MAX_VALUE}. + * @param additionalCharacteristics properties of this spliterator's + * source or elements. If {@code SIZED} is reported then this + * spliterator will additionally report {@code SUBSIZED}. + */ + protected AbstractDoubleSpliterator(long est, int additionalCharacteristics) { + this.est = est; + this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0) + ? additionalCharacteristics | Spliterator.SUBSIZED + : additionalCharacteristics; + } + + static final class HoldingDoubleConsumer implements DoubleConsumer { + double value; + + @Override + public void accept(double value) { + this.value = value; + } + } + + /** + * {@inheritDoc} + * + * This implementation permits limited parallelism. + */ + @Override + public 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; + try { + a = new double[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = holder.value; } while (++j < n && tryAdvance(holder)); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new DoubleArraySpliterator(a, 0, j, characteristics()); + } + return null; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the estimated size as reported when + * created and, if the estimate size is known, decreases in size when + * split. + */ + @Override + public long estimateSize() { + return est; + } + + /** + * {@inheritDoc} + * + * @implSpec + * This implementation returns the characteristics as reported when + * created. + */ + @Override + public int characteristics() { + return characteristics; + } + } + + // Iterator-based Spliterators + + /** + * A Spliterator using a given Iterator for element + * operations. The spliterator implements {@code trySplit} to + * permit limited parallelism. + */ + static class IteratorSpliterator implements Spliterator { + static final int BATCH_UNIT = 1 << 10; // batch array size increment + static final int MAX_BATCH = 1 << 25; // max batch array size; + private final Collection collection; // null OK + private Iterator it; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator using the given given + * collection's {@link java.util.Collection#iterator()) for traversal, + * and reporting its {@link java.util.Collection#size()) as its initial + * size. + * + * @param c the collection + * @param characteristics properties of this spliterator's + * source or elements. + */ + public IteratorSpliterator(Collection collection, int characteristics) { + this.collection = collection; + this.it = null; + this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + /** + * Creates a spliterator using the given iterator + * for traversal, and reporting the given initial size + * and characteristics. + * + * @param iterator the iterator for the source + * @param size the number of elements in the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public IteratorSpliterator(Iterator iterator, long size, int characteristics) { + this.collection = null; + this.it = iterator; + this.est = size; + this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + /** + * Creates a spliterator using the given iterator + * for traversal, and reporting the given initial size + * and characteristics. + * + * @param iterator the iterator for the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public IteratorSpliterator(Iterator iterator, int characteristics) { + this.collection = null; + this.it = iterator; + this.est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + @Override + public Spliterator trySplit() { + /* + * Split into arrays of arithmetically increasing batch + * sizes. This will only improve parallel performance if + * per-element Consumer actions are more costly than + * transferring them into an array. The use of an + * arithmetic progression in split sizes provides overhead + * vs parallelism bounds that do not particularly favor or + * penalize cases of lightweight vs heavyweight element + * operations, across combinations of #elements vs #cores, + * whether or not either are known. We generate + * O(sqrt(#elements)) splits, allowing O(sqrt(#cores)) + * potential speedup. + */ + Iterator i; + long s; + if ((i = it) == null) { + i = it = collection.iterator(); + s = est = (long) collection.size(); + } + else + s = est; + if (s > 1 && i.hasNext()) { + int n = batch + BATCH_UNIT; + if (n > s) + n = (int) s; + if (n > MAX_BATCH) + n = MAX_BATCH; + Object[] a; + try { + a = new Object[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = i.next(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new ArraySpliterator<>(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(Consumer action) { + if (action == null) throw new NullPointerException(); + Iterator i; + if ((i = it) == null) { + i = it = collection.iterator(); + est = (long)collection.size(); + } + i.forEachRemaining(action); + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + if (it == null) { + it = collection.iterator(); + est = (long) collection.size(); + } + if (it.hasNext()) { + action.accept(it.next()); + return true; + } + return false; + } + + @Override + public long estimateSize() { + if (it == null) { + it = collection.iterator(); + return est = (long)collection.size(); + } + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } + + /** + * A Spliterator.OfInt using a given IntStream.IntIterator for element + * operations. The spliterator implements {@code trySplit} to + * permit limited parallelism. + */ + static final class IntIteratorSpliterator implements Spliterator.OfInt { + static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT; + static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH; + private PrimitiveIterator.OfInt it; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator using the given iterator + * for traversal, and reporting the given initial size + * and characteristics. + * + * @param iterator the iterator for the source + * @param size the number of elements in the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, long size, int characteristics) { + this.it = iterator; + this.est = size; + this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + /** + * Creates a spliterator using the given iterator for a + * source of unknown size, reporting the given + * characteristics. + * + * @param iterator the iterator for the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, int characteristics) { + this.it = iterator; + this.est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + @Override + public OfInt trySplit() { + PrimitiveIterator.OfInt i = it; + long s = est; + if (s > 1 && i.hasNext()) { + int n = batch + BATCH_UNIT; + if (n > s) + n = (int) s; + if (n > MAX_BATCH) + n = MAX_BATCH; + int[] a; + try { + a = new int[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = i.nextInt(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new IntArraySpliterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(IntConsumer action) { + if (action == null) throw new NullPointerException(); + it.forEachRemaining(action); + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (action == null) throw new NullPointerException(); + if (it.hasNext()) { + action.accept(it.nextInt()); + return true; + } + return false; + } + + @Override + public long estimateSize() { + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } + + static final class LongIteratorSpliterator implements Spliterator.OfLong { + static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT; + static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH; + private PrimitiveIterator.OfLong it; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator using the given iterator + * for traversal, and reporting the given initial size + * and characteristics. + * + * @param iterator the iterator for the source + * @param size the number of elements in the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, long size, int characteristics) { + this.it = iterator; + this.est = size; + this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + /** + * Creates a spliterator using the given iterator for a + * source of unknown size, reporting the given + * characteristics. + * + * @param iterator the iterator for the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, int characteristics) { + this.it = iterator; + this.est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + @Override + public OfLong trySplit() { + PrimitiveIterator.OfLong i = it; + long s = est; + if (s > 1 && i.hasNext()) { + int n = batch + BATCH_UNIT; + if (n > s) + n = (int) s; + if (n > MAX_BATCH) + n = MAX_BATCH; + long[] a; + try { + a = new long[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = i.nextLong(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new LongArraySpliterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(LongConsumer action) { + if (action == null) throw new NullPointerException(); + it.forEachRemaining(action); + } + + @Override + public boolean tryAdvance(LongConsumer action) { + if (action == null) throw new NullPointerException(); + if (it.hasNext()) { + action.accept(it.nextLong()); + return true; + } + return false; + } + + @Override + public long estimateSize() { + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } + + static final class DoubleIteratorSpliterator implements Spliterator.OfDouble { + static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT; + static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH; + private PrimitiveIterator.OfDouble it; + private final int characteristics; + private long est; // size estimate + private int batch; // batch size for splits + + /** + * Creates a spliterator using the given iterator + * for traversal, and reporting the given initial size + * and characteristics. + * + * @param iterator the iterator for the source + * @param size the number of elements in the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, long size, int characteristics) { + this.it = iterator; + this.est = size; + this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + /** + * Creates a spliterator using the given iterator for a + * source of unknown size, reporting the given + * characteristics. + * + * @param iterator the iterator for the source + * @param characteristics properties of this spliterator's + * source or elements. + */ + public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, int characteristics) { + this.it = iterator; + this.est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + @Override + public OfDouble trySplit() { + PrimitiveIterator.OfDouble i = it; + long s = est; + if (s > 1 && i.hasNext()) { + int n = batch + BATCH_UNIT; + if (n > s) + n = (int) s; + if (n > MAX_BATCH) + n = MAX_BATCH; + double[] a; + try { + a = new double[n]; + } catch (OutOfMemoryError oome) { + return null; + } + int j = 0; + do { a[j] = i.nextDouble(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new DoubleArraySpliterator(a, 0, j, characteristics); + } + return null; + } + + @Override + public void forEachRemaining(DoubleConsumer action) { + if (action == null) throw new NullPointerException(); + it.forEachRemaining(action); + } + + @Override + public boolean tryAdvance(DoubleConsumer action) { + if (action == null) throw new NullPointerException(); + if (it.hasNext()) { + action.accept(it.nextDouble()); + return true; + } + return false; + } + + @Override + public long estimateSize() { + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override + public Comparator getComparator() { + if (hasCharacteristics(Spliterator.SORTED)) + return null; + throw new IllegalStateException(); + } + } +} diff -r 131686bea632 -r 674880648db4 src/share/classes/java/util/Tripwire.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/Tripwire.java Tue Apr 16 13:51:53 2013 -0400 @@ -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: + *

{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+ * }
+ * + * @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.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()); + } +} diff -r 131686bea632 -r 674880648db4 test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java Tue Apr 16 13:51:53 2013 -0400 @@ -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 { + Collection asCollection(); + void update(); + } + + private static class SpliteratorDataBuilder { + final List data; + + final T newValue; + + final List exp; + + final Map mExp; + + SpliteratorDataBuilder(List data, T newValue, List exp) { + this.data = data; + this.newValue = newValue; + this.exp = exp; + this.mExp = createMap(exp); + } + + Map createMap(List l) { + Map m = new LinkedHashMap<>(); + for (T t : l) { + m.put(t, t); + } + return m; + } + + void add(String description, Supplier> s) { + description = joiner(description).toString(); + data.add(new Object[]{description, s}); + } + + void addCollection(Function, ? extends Collection> f) { + class CollectionSource implements Source { + final Collection c = f.apply(exp); + + final Consumer> updater; + + CollectionSource(Consumer> updater) { + this.updater = updater; + } + + @Override + public Collection asCollection() { + return c; + } + + @Override + public void update() { + updater.accept(c); + } + } + + String description = "new " + f.apply(Collections.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, ? extends List> l) { + // @@@ If collection is instance of List then add sub-list tests + addCollection(l); + } + + void addMap(Function, ? extends Map> mapConstructor) { + class MapSource implements Source { + final Map m = mapConstructor.apply(mExp); + + final Collection c; + + final Consumer> updater; + + MapSource(Function, Collection> f, Consumer> updater) { + this.c = f.apply(m); + this.updater = updater; + } + + @Override + public Collection asCollection() { + return c; + } + + @Override + public void update() { + updater.accept(m); + } + } + + Map>> 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.emptyMap()).getClass().getName(); + for (Map.Entry>> e : actions.entrySet()) { + add(description + ".keySet().spliterator() " + e.getKey(), + () -> new MapSource(m -> m.keySet(), e.getValue())); + add(description + ".values().spliterator() " + e.getKey(), + () -> new MapSource(m -> m.values(), e.getValue())); + add(description + ".entrySet().spliterator() " + e.getKey(), + () -> new MapSource>(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 data = new ArrayList<>(); + SpliteratorDataBuilder 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 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 void lateBindingTestWithForEach(String description, Supplier> ss) { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + source.update(); + + Set r = new HashSet<>(); + s.forEachRemaining(r::add); + + assertEquals(r, new HashSet<>(c)); + } + + @Test(dataProvider = "Source") + public void lateBindingTestWithTryAdvance(String description, Supplier> ss) { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + source.update(); + + Set r = new HashSet<>(); + while (s.tryAdvance(r::add)) { } + + assertEquals(r, new HashSet<>(c)); + } + + @Test(dataProvider = "Source") + public void lateBindingTestWithCharacteritics(String description, Supplier> ss) { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + s.characteristics(); + + Set r = new HashSet<>(); + s.forEachRemaining(r::add); + + assertEquals(r, new HashSet<>(c)); + } + + + @Test(dataProvider = "Source") + public void testFailFastTestWithTryAdvance(String description, Supplier> ss) { + { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + s.tryAdvance(e -> { + }); + source.update(); + + executeAndCatch(() -> s.tryAdvance(e -> { })); + } + + { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + s.tryAdvance(e -> { + }); + source.update(); + + executeAndCatch(() -> s.forEachRemaining(e -> { + })); + } + } + + @Test(dataProvider = "Source") + public void testFailFastTestWithForEach(String description, Supplier> ss) { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + executeAndCatch(() -> s.forEachRemaining(e -> { + source.update(); + })); + } + + @Test(dataProvider = "Source") + public void testFailFastTestWithEstimateSize(String description, Supplier> ss) { + { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + s.estimateSize(); + source.update(); + + executeAndCatch(() -> s.tryAdvance(e -> { })); + } + + { + Source source = ss.get(); + Collection c = source.asCollection(); + Spliterator s = c.spliterator(); + + s.estimateSize(); + source.update(); + + executeAndCatch(() -> s.forEachRemaining(e -> { + })); + } + } + + private void executeAndCatch(Runnable r) { + executeAndCatch(ConcurrentModificationException.class, r); + } + + private void executeAndCatch(Class 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())); + } + +} diff -r 131686bea632 -r 674880648db4 test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java Tue Apr 16 13:51:53 2013 -0400 @@ -0,0 +1,1257 @@ +/* + * 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. + */ + +/** + * @test + * @summary Spliterator traversing and splitting tests + * @run testng SpliteratorTraversingAndSplittingTest + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.AbstractCollection; +import java.util.AbstractList; +import java.util.AbstractSet; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +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.SortedSet; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.Stack; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.Vector; +import java.util.WeakHashMap; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.Function; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; + +@Test +public class SpliteratorTraversingAndSplittingTest { + + private static List SIZES = Arrays.asList(0, 1, 10, 100, 1000); + + private static class SpliteratorDataBuilder { + List data; + + List exp; + + Map mExp; + + SpliteratorDataBuilder(List data, List exp) { + this.data = data; + this.exp = exp; + this.mExp = createMap(exp); + } + + Map createMap(List l) { + Map m = new LinkedHashMap<>(); + for (T t : l) { + m.put(t, t); + } + return m; + } + + void add(String description, Collection expected, Supplier> s) { + description = joiner(description).toString(); + data.add(new Object[]{description, expected, s}); + } + + void add(String description, Supplier> s) { + add(description, exp, s); + } + + void addCollection(Function, ? extends Collection> c) { + add("new " + c.apply(Collections.emptyList()).getClass().getName() + ".spliterator()", + () -> c.apply(exp).spliterator()); + } + + void addList(Function, ? extends List> l) { + // @@@ If collection is instance of List then add sub-list tests + addCollection(l); + } + + void addMap(Function, ? extends Map> m) { + String description = "new " + m.apply(Collections.emptyMap()).getClass().getName(); + add(description + ".keySet().spliterator()", () -> m.apply(mExp).keySet().spliterator()); + add(description + ".values().spliterator()", () -> m.apply(mExp).values().spliterator()); + add(description + ".entrySet().spliterator()", mExp.entrySet(), () -> m.apply(mExp).entrySet().spliterator()); + } + + StringBuilder joiner(String description) { + return new StringBuilder(description). + append(" {"). + append("size=").append(exp.size()). + append("}"); + } + } + + static Object[][] spliteratorDataProvider; + + @DataProvider(name = "Spliterator") + public static Object[][] spliteratorDataProvider() { + if (spliteratorDataProvider != null) { + return spliteratorDataProvider; + } + + List data = new ArrayList<>(); + for (int size : SIZES) { + List exp = listIntRange(size); + SpliteratorDataBuilder db = new SpliteratorDataBuilder<>(data, exp); + + // Direct spliterator methods + + db.add("Spliterators.spliterator(Collection, ...)", + () -> Spliterators.spliterator(exp, 0)); + + db.add("Spliterators.spliterator(Iterator, ...)", + () -> Spliterators.spliterator(exp.iterator(), exp.size(), 0)); + + db.add("Spliterators.spliteratorUnknownSize(Iterator, ...)", + () -> Spliterators.spliteratorUnknownSize(exp.iterator(), 0)); + + db.add("Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Spliterator ), ...)", + () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(exp.spliterator()), exp.size(), 0)); + + db.add("Spliterators.spliterator(T[], ...)", + () -> Spliterators.spliterator(exp.toArray(new Integer[0]), 0)); + + db.add("Arrays.spliterator(T[], ...)", + () -> Arrays.spliterator(exp.toArray(new Integer[0]))); + + class SpliteratorFromIterator extends Spliterators.AbstractSpliterator { + Iterator it; + + SpliteratorFromIterator(Iterator it, long est) { + super(est, Spliterator.SIZED); + this.it = it; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (it.hasNext()) { + action.accept(it.next()); + return true; + } + else { + return false; + } + } + } + db.add("new Spliterators.AbstractAdvancingSpliterator()", + () -> new SpliteratorFromIterator(exp.iterator(), exp.size())); + + // Collections + + // default method implementations + + class AbstractCollectionImpl extends AbstractCollection { + Collection c; + + AbstractCollectionImpl(Collection c) { + this.c = c; + } + + @Override + public Iterator iterator() { + return c.iterator(); + } + + @Override + public int size() { + return c.size(); + } + } + db.addCollection( + c -> new AbstractCollectionImpl(c)); + + class AbstractListImpl extends AbstractList { + List l; + + AbstractListImpl(Collection c) { + this.l = new ArrayList<>(c); + } + + @Override + public Integer get(int index) { + return l.get(index); + } + + @Override + public int size() { + return l.size(); + } + } + db.addCollection( + c -> new AbstractListImpl(c)); + + class AbstractSetImpl extends AbstractSet { + Set s; + + AbstractSetImpl(Collection c) { + this.s = new HashSet<>(c); + } + + @Override + public Iterator iterator() { + return s.iterator(); + } + + @Override + public int size() { + return s.size(); + } + } + db.addCollection( + c -> new AbstractSetImpl(c)); + + class AbstractSortedSetImpl extends AbstractSet implements SortedSet { + SortedSet s; + + AbstractSortedSetImpl(Collection c) { + this.s = new TreeSet<>(c); + } + + @Override + public Iterator iterator() { + return s.iterator(); + } + + @Override + public int size() { + return s.size(); + } + + @Override + public Comparator comparator() { + return s.comparator(); + } + + @Override + public SortedSet subSet(Integer fromElement, Integer toElement) { + return s.subSet(fromElement, toElement); + } + + @Override + public SortedSet headSet(Integer toElement) { + return s.headSet(toElement); + } + + @Override + public SortedSet tailSet(Integer fromElement) { + return s.tailSet(fromElement); + } + + @Override + public Integer first() { + return s.first(); + } + + @Override + public Integer last() { + return s.last(); + } + + @Override + public Spliterator spliterator() { + return SortedSet.super.spliterator(); + } + } + db.addCollection( + c -> new AbstractSortedSetImpl(c)); + + // + + db.add("Arrays.asList().spliterator()", + () -> Spliterators.spliterator(Arrays.asList(exp.toArray(new Integer[0])), 0)); + + 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 s = new Stack<>(); s.addAll(c); return s;}); + + db.addCollection(PriorityQueue::new); + + db.addCollection(ArrayDeque::new); + + + db.addCollection(ConcurrentSkipListSet::new); + + if (size > 0) { + db.addCollection(c -> { + ArrayBlockingQueue abq = new ArrayBlockingQueue<>(size); + abq.addAll(c); + return abq; + }); + } + + db.addCollection(PriorityBlockingQueue::new); + + db.addCollection(LinkedBlockingQueue::new); + + db.addCollection(LinkedTransferQueue::new); + + db.addCollection(ConcurrentLinkedQueue::new); + + db.addCollection(LinkedBlockingDeque::new); + + db.addCollection(CopyOnWriteArrayList::new); + + db.addCollection(CopyOnWriteArraySet::new); + + if (size == 1) { + db.addCollection(c -> Collections.singleton(exp.get(0))); + db.addCollection(c -> Collections.singletonList(exp.get(0))); + } + + // @@@ Collections.synchronized/unmodifiable/checked wrappers + + // Maps + + db.addMap(HashMap::new); + + db.addMap(LinkedHashMap::new); + + db.addMap(IdentityHashMap::new); + + db.addMap(WeakHashMap::new); + + // @@@ Descending maps etc + db.addMap(TreeMap::new); + + db.addMap(ConcurrentHashMap::new); + + db.addMap(ConcurrentSkipListMap::new); + } + + return spliteratorDataProvider = data.toArray(new Object[0][]); + } + + private static List listIntRange(int upTo) { + List exp = new ArrayList<>(); + for (int i = 0; i < upTo; i++) + exp.add(i); + return Collections.unmodifiableList(exp); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testForEach(String description, Collection exp, Supplier s) { + testForEach(exp, s, (Consumer b) -> b); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testTryAdvance(String description, Collection exp, Supplier s) { + testTryAdvance(exp, s, (Consumer b) -> b); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testMixedTryAdvanceForEach(String description, Collection exp, Supplier s) { + testMixedTryAdvanceForEach(exp, s, (Consumer b) -> b); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testSplitAfterFullTraversal(String description, Collection exp, Supplier s) { + testSplitAfterFullTraversal(s, (Consumer b) -> b); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testSplitOnce(String description, Collection exp, Supplier s) { + testSplitOnce(exp, s, (Consumer b) -> b); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testSplitSixDeep(String description, Collection exp, Supplier s) { + testSplitSixDeep(exp, s, (Consumer b) -> b); + } + + @Test(dataProvider = "Spliterator") + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testSplitUntilNull(String description, Collection exp, Supplier s) { + testSplitUntilNull(exp, s, (Consumer b) -> b); + } + + // + + private static class SpliteratorOfIntDataBuilder { + List data; + + List exp; + + SpliteratorOfIntDataBuilder(List data, List exp) { + this.data = data; + this.exp = exp; + } + + void add(String description, List expected, Supplier s) { + description = joiner(description).toString(); + data.add(new Object[]{description, expected, s}); + } + + void add(String description, Supplier s) { + add(description, exp, s); + } + + StringBuilder joiner(String description) { + return new StringBuilder(description). + append(" {"). + append("size=").append(exp.size()). + append("}"); + } + } + + static Object[][] spliteratorOfIntDataProvider; + + @DataProvider(name = "Spliterator.OfInt") + public static Object[][] spliteratorOfIntDataProvider() { + if (spliteratorOfIntDataProvider != null) { + return spliteratorOfIntDataProvider; + } + + List data = new ArrayList<>(); + for (int size : SIZES) { + int exp[] = arrayIntRange(size); + SpliteratorOfIntDataBuilder db = new SpliteratorOfIntDataBuilder(data, listIntRange(size)); + + db.add("Spliterators.spliterator(int[], ...)", + () -> Spliterators.spliterator(exp, 0)); + + db.add("Arrays.spliterator(int[], ...)", + () -> Arrays.spliterator(exp)); + + db.add("Spliterators.spliterator(PrimitiveIterator.OfInt, ...)", + () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), exp.length, 0)); + + db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfInt, ...)", + () -> Spliterators.spliteratorUnknownSize(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), 0)); + + class IntSpliteratorFromArray extends Spliterators.AbstractIntSpliterator { + int[] a; + int index = 0; + + IntSpliteratorFromArray(int[] a) { + super(a.length, Spliterator.SIZED); + this.a = a; + } + + @Override + public boolean tryAdvance(IntConsumer action) { + if (index < a.length) { + action.accept(a[index++]); + return true; + } + else { + return false; + } + } + } + db.add("new Spliterators.AbstractIntAdvancingSpliterator()", + () -> new IntSpliteratorFromArray(exp)); + } + + return spliteratorOfIntDataProvider = data.toArray(new Object[0][]); + } + + private static int[] arrayIntRange(int upTo) { + int[] exp = new int[upTo]; + for (int i = 0; i < upTo; i++) + exp[i] = i; + return exp; + } + + private static UnaryOperator> intBoxingConsumer() { + class BoxingAdapter implements Consumer, IntConsumer { + private final Consumer b; + + BoxingAdapter(Consumer b) { + this.b = b; + } + + @Override + public void accept(Integer value) { + throw new IllegalStateException(); + } + + @Override + public void accept(int value) { + b.accept(value); + } + } + + return b -> new BoxingAdapter(b); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntForEach(String description, Collection exp, Supplier s) { + testForEach(exp, s, intBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntTryAdvance(String description, Collection exp, Supplier s) { + testTryAdvance(exp, s, intBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntMixedTryAdvanceForEach(String description, Collection exp, Supplier s) { + testMixedTryAdvanceForEach(exp, s, intBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntSplitAfterFullTraversal(String description, Collection exp, Supplier s) { + testSplitAfterFullTraversal(s, intBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntSplitOnce(String description, Collection exp, Supplier s) { + testSplitOnce(exp, s, intBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntSplitSixDeep(String description, Collection exp, Supplier s) { + testSplitSixDeep(exp, s, intBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfInt") + public void testIntSplitUntilNull(String description, Collection exp, Supplier s) { + testSplitUntilNull(exp, s, intBoxingConsumer()); + } + + // + + private static class SpliteratorOfLongDataBuilder { + List data; + + List exp; + + SpliteratorOfLongDataBuilder(List data, List exp) { + this.data = data; + this.exp = exp; + } + + void add(String description, List expected, Supplier s) { + description = joiner(description).toString(); + data.add(new Object[]{description, expected, s}); + } + + void add(String description, Supplier s) { + add(description, exp, s); + } + + StringBuilder joiner(String description) { + return new StringBuilder(description). + append(" {"). + append("size=").append(exp.size()). + append("}"); + } + } + + static Object[][] spliteratorOfLongDataProvider; + + @DataProvider(name = "Spliterator.OfLong") + public static Object[][] spliteratorOfLongDataProvider() { + if (spliteratorOfLongDataProvider != null) { + return spliteratorOfLongDataProvider; + } + + List data = new ArrayList<>(); + for (int size : SIZES) { + long exp[] = arrayLongRange(size); + SpliteratorOfLongDataBuilder db = new SpliteratorOfLongDataBuilder(data, listLongRange(size)); + + db.add("Spliterators.spliterator(long[], ...)", + () -> Spliterators.spliterator(exp, 0)); + + db.add("Arrays.spliterator(long[], ...)", + () -> Arrays.spliterator(exp)); + + db.add("Spliterators.spliterator(PrimitiveIterator.OfLong, ...)", + () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), exp.length, 0)); + + db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfLong, ...)", + () -> Spliterators.spliteratorUnknownSize(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), 0)); + + class LongSpliteratorFromArray extends Spliterators.AbstractLongSpliterator { + long[] a; + int index = 0; + + LongSpliteratorFromArray(long[] a) { + super(a.length, Spliterator.SIZED); + this.a = a; + } + + @Override + public boolean tryAdvance(LongConsumer action) { + if (index < a.length) { + action.accept(a[index++]); + return true; + } + else { + return false; + } + } + } + db.add("new Spliterators.AbstractLongAdvancingSpliterator()", + () -> new LongSpliteratorFromArray(exp)); + } + + return spliteratorOfLongDataProvider = data.toArray(new Object[0][]); + } + + private static List listLongRange(int upTo) { + List exp = new ArrayList<>(); + for (long i = 0; i < upTo; i++) + exp.add(i); + return Collections.unmodifiableList(exp); + } + + private static long[] arrayLongRange(int upTo) { + long[] exp = new long[upTo]; + for (int i = 0; i < upTo; i++) + exp[i] = i; + return exp; + } + + private static UnaryOperator> longBoxingConsumer() { + class BoxingAdapter implements Consumer, LongConsumer { + private final Consumer b; + + BoxingAdapter(Consumer b) { + this.b = b; + } + + @Override + public void accept(Long value) { + throw new IllegalStateException(); + } + + @Override + public void accept(long value) { + b.accept(value); + } + } + + return b -> new BoxingAdapter(b); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongForEach(String description, Collection exp, Supplier s) { + testForEach(exp, s, longBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongTryAdvance(String description, Collection exp, Supplier s) { + testTryAdvance(exp, s, longBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongMixedTryAdvanceForEach(String description, Collection exp, Supplier s) { + testMixedTryAdvanceForEach(exp, s, longBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongSplitAfterFullTraversal(String description, Collection exp, Supplier s) { + testSplitAfterFullTraversal(s, longBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongSplitOnce(String description, Collection exp, Supplier s) { + testSplitOnce(exp, s, longBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongSplitSixDeep(String description, Collection exp, Supplier s) { + testSplitSixDeep(exp, s, longBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfLong") + public void testLongSplitUntilNull(String description, Collection exp, Supplier s) { + testSplitUntilNull(exp, s, longBoxingConsumer()); + } + + // + + private static class SpliteratorOfDoubleDataBuilder { + List data; + + List exp; + + SpliteratorOfDoubleDataBuilder(List data, List exp) { + this.data = data; + this.exp = exp; + } + + void add(String description, List expected, Supplier s) { + description = joiner(description).toString(); + data.add(new Object[]{description, expected, s}); + } + + void add(String description, Supplier s) { + add(description, exp, s); + } + + StringBuilder joiner(String description) { + return new StringBuilder(description). + append(" {"). + append("size=").append(exp.size()). + append("}"); + } + } + + static Object[][] spliteratorOfDoubleDataProvider; + + @DataProvider(name = "Spliterator.OfDouble") + public static Object[][] spliteratorOfDoubleDataProvider() { + if (spliteratorOfDoubleDataProvider != null) { + return spliteratorOfDoubleDataProvider; + } + + List data = new ArrayList<>(); + for (int size : SIZES) { + double exp[] = arrayDoubleRange(size); + SpliteratorOfDoubleDataBuilder db = new SpliteratorOfDoubleDataBuilder(data, listDoubleRange(size)); + + db.add("Spliterators.spliterator(double[], ...)", + () -> Spliterators.spliterator(exp, 0)); + + db.add("Arrays.spliterator(double[], ...)", + () -> Arrays.spliterator(exp)); + + db.add("Spliterators.spliterator(PrimitiveIterator.OfDouble, ...)", + () -> Spliterators.spliterator(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), exp.length, 0)); + + db.add("Spliterators.spliteratorUnknownSize(PrimitiveIterator.OfDouble, ...)", + () -> Spliterators.spliteratorUnknownSize(Spliterators.iteratorFromSpliterator(Arrays.spliterator(exp)), 0)); + + class DoubleSpliteratorFromArray extends Spliterators.AbstractDoubleSpliterator { + double[] a; + int index = 0; + + DoubleSpliteratorFromArray(double[] a) { + super(a.length, Spliterator.SIZED); + this.a = a; + } + + @Override + public boolean tryAdvance(DoubleConsumer action) { + if (index < a.length) { + action.accept(a[index++]); + return true; + } + else { + return false; + } + } + } + db.add("new Spliterators.AbstractDoubleAdvancingSpliterator()", + () -> new DoubleSpliteratorFromArray(exp)); + } + + return spliteratorOfDoubleDataProvider = data.toArray(new Object[0][]); + } + + private static List listDoubleRange(int upTo) { + List exp = new ArrayList<>(); + for (double i = 0; i < upTo; i++) + exp.add(i); + return Collections.unmodifiableList(exp); + } + + private static double[] arrayDoubleRange(int upTo) { + double[] exp = new double[upTo]; + for (int i = 0; i < upTo; i++) + exp[i] = i; + return exp; + } + + private static UnaryOperator> doubleBoxingConsumer() { + class BoxingAdapter implements Consumer, DoubleConsumer { + private final Consumer b; + + BoxingAdapter(Consumer b) { + this.b = b; + } + + @Override + public void accept(Double value) { + throw new IllegalStateException(); + } + + @Override + public void accept(double value) { + b.accept(value); + } + } + + return b -> new BoxingAdapter(b); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleForEach(String description, Collection exp, Supplier s) { + testForEach(exp, s, doubleBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleTryAdvance(String description, Collection exp, Supplier s) { + testTryAdvance(exp, s, doubleBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleMixedTryAdvanceForEach(String description, Collection exp, Supplier s) { + testMixedTryAdvanceForEach(exp, s, doubleBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleSplitAfterFullTraversal(String description, Collection exp, Supplier s) { + testSplitAfterFullTraversal(s, doubleBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleSplitOnce(String description, Collection exp, Supplier s) { + testSplitOnce(exp, s, doubleBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleSplitSixDeep(String description, Collection exp, Supplier s) { + testSplitSixDeep(exp, s, doubleBoxingConsumer()); + } + + @Test(dataProvider = "Spliterator.OfDouble") + public void testDoubleSplitUntilNull(String description, Collection exp, Supplier s) { + testSplitUntilNull(exp, s, doubleBoxingConsumer()); + } + + // + + private static > void testForEach( + Collection exp, + Supplier supplier, + UnaryOperator> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + ArrayList fromForEach = new ArrayList<>(); + spliterator = supplier.get(); + Consumer addToFromForEach = boxingAdapter.apply(fromForEach::add); + spliterator.forEachRemaining(addToFromForEach); + + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + // Assert that tryAdvance now produce no elements + spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); + + // assert that size, tryAdvance, and forEach are consistent + if (sizeIfKnown >= 0) { + assertEquals(sizeIfKnown, exp.size()); + } + assertEquals(fromForEach.size(), exp.size()); + + assertContents(fromForEach, exp, isOrdered); + } + + private static > void testTryAdvance( + Collection exp, + Supplier supplier, + UnaryOperator> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + spliterator = supplier.get(); + ArrayList fromTryAdvance = new ArrayList<>(); + Consumer addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add); + while (spliterator.tryAdvance(addToFromTryAdvance)) { } + + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + // Assert that tryAdvance now produce no elements + spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); + + // assert that size, tryAdvance, and forEach are consistent + if (sizeIfKnown >= 0) { + assertEquals(sizeIfKnown, exp.size()); + } + assertEquals(fromTryAdvance.size(), exp.size()); + + assertContents(fromTryAdvance, exp, isOrdered); + } + + private static > void testMixedTryAdvanceForEach( + Collection exp, + Supplier supplier, + UnaryOperator> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + // tryAdvance first few elements, then forEach rest + ArrayList dest = new ArrayList<>(); + spliterator = supplier.get(); + Consumer addToDest = boxingAdapter.apply(dest::add); + for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { } + spliterator.forEachRemaining(addToDest); + + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + // Assert that tryAdvance now produce no elements + spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); + + if (sizeIfKnown >= 0) { + assertEquals(sizeIfKnown, dest.size()); + } + assertEquals(dest.size(), exp.size()); + + if (isOrdered) { + assertEquals(dest, exp); + } + else { + assertContentsUnordered(dest, exp); + } + } + + private static > void testSplitAfterFullTraversal( + Supplier supplier, + UnaryOperator> boxingAdapter) { + // Full traversal using tryAdvance + Spliterator spliterator = supplier.get(); + while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { } + Spliterator split = spliterator.trySplit(); + assertNull(split); + + // Full traversal using forEach + spliterator = supplier.get(); + spliterator.forEachRemaining(boxingAdapter.apply(e -> { + })); + split = spliterator.trySplit(); + assertNull(split); + + // Full traversal using tryAdvance then forEach + spliterator = supplier.get(); + spliterator.tryAdvance(boxingAdapter.apply(e -> { })); + spliterator.forEachRemaining(boxingAdapter.apply(e -> { + })); + split = spliterator.trySplit(); + assertNull(split); + } + + private static > void testSplitOnce( + Collection exp, + Supplier supplier, + UnaryOperator> boxingAdapter) { + S spliterator = supplier.get(); + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + ArrayList fromSplit = new ArrayList<>(); + Spliterator s1 = supplier.get(); + Spliterator s2 = s1.trySplit(); + long s1Size = s1.getExactSizeIfKnown(); + long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0; + Consumer addToFromSplit = boxingAdapter.apply(fromSplit::add); + if (s2 != null) + s2.forEachRemaining(addToFromSplit); + s1.forEachRemaining(addToFromSplit); + + if (sizeIfKnown >= 0) { + assertEquals(sizeIfKnown, fromSplit.size()); + if (s1Size >= 0 && s2Size >= 0) + assertEquals(sizeIfKnown, s1Size + s2Size); + } + assertContents(fromSplit, exp, isOrdered); + } + + private static > void testSplitSixDeep( + Collection exp, + Supplier supplier, + UnaryOperator> boxingAdapter) { + S spliterator = supplier.get(); + boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED); + + for (int depth=0; depth < 6; depth++) { + List dest = new ArrayList<>(); + spliterator = supplier.get(); + + assertSpliterator(spliterator); + + // verify splitting with forEach + visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false); + assertContents(dest, exp, isOrdered); + + // verify splitting with tryAdvance + dest.clear(); + spliterator = supplier.get(); + visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true); + assertContents(dest, exp, isOrdered); + } + } + + private static > void visit(int depth, int curLevel, + List dest, S spliterator, UnaryOperator> boxingAdapter, + int rootCharacteristics, boolean useTryAdvance) { + if (curLevel < depth) { + long beforeSize = spliterator.getExactSizeIfKnown(); + Spliterator split = spliterator.trySplit(); + if (split != null) { + assertSpliterator(split, rootCharacteristics); + assertSpliterator(spliterator, rootCharacteristics); + + if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 && + (rootCharacteristics & Spliterator.SIZED) != 0) { + assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize()); + } + visit(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance); + } + visit(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance); + } + else { + long sizeIfKnown = spliterator.getExactSizeIfKnown(); + if (useTryAdvance) { + Consumer addToDest = boxingAdapter.apply(dest::add); + int count = 0; + while (spliterator.tryAdvance(addToDest)) { + ++count; + } + + if (sizeIfKnown >= 0) + assertEquals(sizeIfKnown, count); + + // Assert that forEach now produces no elements + spliterator.forEachRemaining(boxingAdapter.apply(e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e))); + + Spliterator split = spliterator.trySplit(); + assertNull(split); + } + else { + List leafDest = new ArrayList<>(); + Consumer addToLeafDest = boxingAdapter.apply(leafDest::add); + spliterator.forEachRemaining(addToLeafDest); + + if (sizeIfKnown >= 0) + assertEquals(sizeIfKnown, leafDest.size()); + + // Assert that forEach now produces no elements + spliterator.tryAdvance(boxingAdapter.apply(e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e))); + + Spliterator split = spliterator.trySplit(); + assertNull(split); + + dest.addAll(leafDest); + } + } + } + + private static > void testSplitUntilNull( + Collection exp, + Supplier supplier, + UnaryOperator> boxingAdapter) { + Spliterator s = supplier.get(); + boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED); + assertSpliterator(s); + + List splits = new ArrayList<>(); + Consumer c = boxingAdapter.apply(splits::add); + + testSplitUntilNull(new SplitNode(c, s)); + assertContents(splits, exp, isOrdered); + } + + private static class SplitNode { + // Constant for every node + final Consumer c; + final int rootCharacteristics; + + final Spliterator s; + + SplitNode(Consumer c, Spliterator s) { + this(c, s.characteristics(), s); + } + + private SplitNode(Consumer c, int rootCharacteristics, Spliterator s) { + this.c = c; + this.rootCharacteristics = rootCharacteristics; + this.s = s; + } + + SplitNode fromSplit(Spliterator split) { + return new SplitNode<>(c, rootCharacteristics, split); + } + } + + /** + * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator + * while not unduly disrupting test infrastructure given the test data sizes that are used are small. + * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26). + */ + private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB + + private static void testSplitUntilNull(SplitNode e) { + // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator + // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or + // for a spliterator that is badly behaved. + Deque> stack = new ArrayDeque<>(); + stack.push(e); + + int iteration = 0; + while (!stack.isEmpty()) { + assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18"); + + e = stack.pop(); + Spliterator parentAndRightSplit = e.s; + + long parentEstimateSize = parentAndRightSplit.estimateSize(); + assertTrue(parentEstimateSize >= 0, + String.format("Split size estimate %d < 0", parentEstimateSize)); + + long parentSize = parentAndRightSplit.getExactSizeIfKnown(); + Spliterator leftSplit = parentAndRightSplit.trySplit(); + if (leftSplit == null) { + parentAndRightSplit.forEachRemaining(e.c); + continue; + } + + assertSpliterator(leftSplit, e.rootCharacteristics); + assertSpliterator(parentAndRightSplit, e.rootCharacteristics); + + if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0 && parentAndRightSplit.estimateSize() > 0) { + assertTrue(leftSplit.estimateSize() < parentEstimateSize, + String.format("Left split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize, + String.format("Right split size estimate %d >= parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + } + else { + assertTrue(leftSplit.estimateSize() <= parentEstimateSize, + String.format("Left split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize, + String.format("Right split size estimate %d > parent split size estimate %d", leftSplit.estimateSize(), parentEstimateSize)); + } + + long leftSize = leftSplit.getExactSizeIfKnown(); + long rightSize = parentAndRightSplit.getExactSizeIfKnown(); + if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0) + assertEquals(parentSize, leftSize + rightSize, + String.format("exact left split size %d + exact right split size %d != parent exact split size %d", + leftSize, rightSize, parentSize)); + + // Add right side to stack first so left side is popped off first + stack.push(e.fromSplit(parentAndRightSplit)); + stack.push(e.fromSplit(leftSplit)); + } + } + + private static void assertSpliterator(Spliterator s, int rootCharacteristics) { + if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) { + assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED), + "Child split is not SUBSIZED when root split is SUBSIZED"); + } + assertSpliterator(s); + } + + private static void assertSpliterator(Spliterator s) { + if (s.hasCharacteristics(Spliterator.SUBSIZED)) { + assertTrue(s.hasCharacteristics(Spliterator.SIZED)); + } + if (s.hasCharacteristics(Spliterator.SIZED)) { + assertTrue(s.estimateSize() != Long.MAX_VALUE); + assertTrue(s.getExactSizeIfKnown() >= 0); + } + try { + s.getComparator(); + assertTrue(s.hasCharacteristics(Spliterator.SORTED)); + } catch (IllegalStateException e) { + assertFalse(s.hasCharacteristics(Spliterator.SORTED)); + } + } + + private static void assertContents(Collection actual, Collection expected, boolean isOrdered) { + if (isOrdered) { + assertEquals(actual, expected); + } + else { + assertContentsUnordered(actual, expected); + } + } + + private static void assertContentsUnordered(Iterable actual, Iterable expected) { + assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected)); + } + + private static Map toBoxedMultiset(Iterable c) { + Map result = new HashMap<>(); + c.forEach(e -> { + if (result.containsKey(e)) result.put(e, result.get(e) + 1); + else result.put(e, 1); + }); + return result; + } +}