diff --git a/src/share/classes/java/util/Spliterator.java b/src/share/classes/java/util/Spliterator.java index 542aec76cdea248d35645cb53587b26f207d59c1..08d8f1522ca503e909e22dbe3f164e9529f17d4d 100644 --- a/src/share/classes/java/util/Spliterator.java +++ b/src/share/classes/java/util/Spliterator.java @@ -539,7 +539,7 @@ public interface Spliterator { * 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 + *

A top-level Spliterator should not report both {@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 diff --git a/src/share/classes/java/util/Spliterators.java b/src/share/classes/java/util/Spliterators.java index afa2fd379cc3972d9233ac05e589a5bda797e820..3f97a833a68ee3c9c7a285884472efceb06eb405 100644 --- a/src/share/classes/java/util/Spliterators.java +++ b/src/share/classes/java/util/Spliterators.java @@ -409,16 +409,16 @@ public final class Spliterators { * * @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 + * @param characteristics Characteristics of this spliterator's source or + * elements. The characteristics {@code SIZED} and {@code SUBSIZED} + * are additionally reported unless {@code CONCURRENT} is supplied. * @return A spliterator from an iterator * @throws NullPointerException if the given collection is {@code null} */ public static Spliterator spliterator(Collection c, - int additionalCharacteristics) { + int characteristics) { return new IteratorSpliterator<>(Objects.requireNonNull(c), - additionalCharacteristics); + characteristics); } /** @@ -439,17 +439,17 @@ public final class Spliterators { * @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 + * @param characteristics Characteristics of this spliterator's source or + * elements. The characteristics {@code SIZED} and {@code SUBSIZED} + * are additionally reported unless {@code CONCURRENT} is supplied. * @return A spliterator from an iterator * @throws NullPointerException if the given iterator is {@code null} */ public static Spliterator spliterator(Iterator iterator, long size, - int additionalCharacteristics) { + int characteristics) { return new IteratorSpliterator<>(Objects.requireNonNull(iterator), size, - additionalCharacteristics); + characteristics); } /** @@ -467,7 +467,7 @@ public final class Spliterators { * * @param Type of elements * @param iterator The iterator for the source - * @param characteristics Properties of this spliterator's source + * @param characteristics Characteristics of this spliterator's source * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are * ignored and are not reported.) * @return A spliterator from an iterator @@ -496,17 +496,17 @@ public final class Spliterators { * @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 + * @param characteristics Characteristics of this spliterator's source or + * elements. The characteristics {@code SIZED} and {@code SUBSIZED} + * are additionally reported unless {@code CONCURRENT} is supplied. * @return A spliterator from an iterator * @throws NullPointerException if the given iterator is {@code null} */ public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt iterator, long size, - int additionalCharacteristics) { + int characteristics) { return new IntIteratorSpliterator(Objects.requireNonNull(iterator), - size, additionalCharacteristics); + size, characteristics); } /** @@ -524,7 +524,7 @@ public final class Spliterators { * operated on after the spliterator is returned. * * @param iterator The iterator for the source - * @param characteristics Properties of this spliterator's source + * @param characteristics Characteristics of this spliterator's source * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are * ignored and are not reported.) * @return A spliterator from an iterator @@ -553,17 +553,17 @@ public final class Spliterators { * @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 + * @param characteristics Characteristics of this spliterator's source or + * elements. The characteristics {@code SIZED} and {@code SUBSIZED} + * are additionally reported unless {@code CONCURRENT} is supplied. * @return A spliterator from an iterator * @throws NullPointerException if the given iterator is {@code null} */ public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong iterator, long size, - int additionalCharacteristics) { + int characteristics) { return new LongIteratorSpliterator(Objects.requireNonNull(iterator), - size, additionalCharacteristics); + size, characteristics); } /** @@ -581,7 +581,7 @@ public final class Spliterators { * operated on after the spliterator is returned. * * @param iterator The iterator for the source - * @param characteristics Properties of this spliterator's source + * @param characteristics Characteristics of this spliterator's source * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are * ignored and are not reported.) * @return A spliterator from an iterator @@ -610,17 +610,17 @@ public final class Spliterators { * @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 + * @param characteristics Characteristics of this spliterator's source or + * elements. The characteristics {@code SIZED} and {@code SUBSIZED} + * are additionally reported unless {@code CONCURRENT} is supplied. * @return A spliterator from an iterator * @throws NullPointerException if the given iterator is {@code null} */ public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble iterator, long size, - int additionalCharacteristics) { + int characteristics) { return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), - size, additionalCharacteristics); + size, characteristics); } /** @@ -638,7 +638,7 @@ public final class Spliterators { * operated on after the spliterator is returned. * * @param iterator The iterator for the source - * @param characteristics Properties of this spliterator's source + * @param characteristics Characteristics of this spliterator's source * or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are * ignored and are not reported.) * @return A spliterator from an iterator @@ -1710,7 +1710,9 @@ public final class Spliterators { public IteratorSpliterator(Collection collection, int characteristics) { this.collection = collection; this.it = null; - this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; } /** @@ -1727,7 +1729,9 @@ public final class Spliterators { this.collection = null; this.it = iterator; this.est = size; - this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; } /** @@ -1857,7 +1861,9 @@ public final class Spliterators { public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, long size, int characteristics) { this.it = iterator; this.est = size; - this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; } /** @@ -1949,7 +1955,9 @@ public final class Spliterators { public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, long size, int characteristics) { this.it = iterator; this.est = size; - this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; } /** @@ -2041,7 +2049,9 @@ public final class Spliterators { public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, long size, int characteristics) { this.it = iterator; this.est = size; - this.characteristics = characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; } /** diff --git a/test/java/util/Spliterator/SpliteratorCharacteristics.java b/test/java/util/Spliterator/SpliteratorCharacteristics.java index 3c74ce29dc1a9129af9327727e88cc994b405564..37fbcc769d0bbf2b05008aa881cb89b70c4599d4 100644 --- a/test/java/util/Spliterator/SpliteratorCharacteristics.java +++ b/test/java/util/Spliterator/SpliteratorCharacteristics.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8020156 8020009 8022326 8012913 + * @bug 8020156 8020009 8022326 8012913 8024405 * @run testng SpliteratorCharacteristics */ @@ -36,21 +36,150 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.PrimitiveIterator; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import java.util.Spliterator; +import java.util.Spliterators; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ConcurrentSkipListSet; +import java.util.function.Supplier; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; import static org.testng.Assert.*; @Test public class SpliteratorCharacteristics { + public void testSpliteratorFromCollection() { + List l = Arrays.asList(1, 2, 3, 4); + + { + Spliterator s = Spliterators.spliterator(l, 0); + assertCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliterator(l, Spliterator.CONCURRENT); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliterator(l.iterator( ), 1, 0); + assertCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliterator(l.iterator( ), 1, Spliterator.CONCURRENT); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize(l.iterator( ), 0); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize( + l.iterator(), Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + } + + public void testSpliteratorOfIntFromIterator() { + Supplier si = () -> IntStream.of(1, 2, 3, 4).iterator(); + + { + Spliterator s = Spliterators.spliterator(si.get(), 1, 0); + assertCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliterator(si.get(), 1, Spliterator.CONCURRENT); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize(si.get(), 0); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize( + si.get(), Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + } + + public void testSpliteratorOfLongFromIterator() { + Supplier si = () -> LongStream.of(1, 2, 3, 4).iterator(); + + { + Spliterator s = Spliterators.spliterator(si.get(), 1, 0); + assertCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliterator(si.get(), 1, Spliterator.CONCURRENT); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize(si.get(), 0); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize( + si.get(), Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + } + + public void testSpliteratorOfDoubleFromIterator() { + Supplier si = () -> DoubleStream.of(1, 2, 3, 4).iterator(); + + { + Spliterator s = Spliterators.spliterator(si.get(), 1, 0); + assertCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliterator(si.get(), 1, Spliterator.CONCURRENT); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + assertCharacteristics(s, Spliterator.CONCURRENT); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize(si.get(), 0); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + + { + Spliterator s = Spliterators.spliteratorUnknownSize( + si.get(), Spliterator.SIZED | Spliterator.SUBSIZED); + assertHasNotCharacteristics(s, Spliterator.SIZED | Spliterator.SUBSIZED); + } + } + + // + public void testHashMap() { assertMapCharacteristics(new HashMap<>(), Spliterator.SIZED | Spliterator.DISTINCT); @@ -199,10 +328,19 @@ public class SpliteratorCharacteristics { } void assertCharacteristics(Collection c, int expectedCharacteristics) { - assertTrue(c.spliterator().hasCharacteristics(expectedCharacteristics), + assertCharacteristics(c.spliterator(), expectedCharacteristics); + } + + void assertCharacteristics(Spliterator s, int expectedCharacteristics) { + assertTrue(s.hasCharacteristics(expectedCharacteristics), "Spliterator characteristics"); } + void assertHasNotCharacteristics(Spliterator s, int expectedCharacteristics) { + assertFalse(s.hasCharacteristics(expectedCharacteristics), + "Spliterator characteristics"); + } + void assertNullComparator(Collection c) { assertNull(c.spliterator().getComparator(), "Comparator of Spliterator of Collection"); diff --git a/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java b/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java index a84cbbeaebe2fed360b9bc22216834f7c98c908c..69c7cf5743630ce41a9224a79d3e382cb4f421f9 100644 --- a/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java +++ b/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java @@ -1159,7 +1159,7 @@ public class SpliteratorTraversingAndSplittingTest { List dest = new ArrayList<>(); spliterator = supplier.get(); - assertSpliterator(spliterator); + assertRootSpliterator(spliterator); // verify splitting with forEach visit(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false); @@ -1234,7 +1234,7 @@ public class SpliteratorTraversingAndSplittingTest { UnaryOperator> boxingAdapter) { Spliterator s = supplier.get(); boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED); - assertSpliterator(s); + assertRootSpliterator(s); List splits = new ArrayList<>(); Consumer c = boxingAdapter.apply(splits::add); @@ -1326,6 +1326,13 @@ public class SpliteratorTraversingAndSplittingTest { } } + private static void assertRootSpliterator(Spliterator s) { + assertFalse(s.hasCharacteristics(Spliterator.SIZED | Spliterator.CONCURRENT), + "Root spliterator should not be SIZED and CONCURRENT"); + + assertSpliterator(s); + } + private static void assertSpliterator(Spliterator s, int rootCharacteristics) { if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) { assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),