8021863: Stream.concat incorrectly calculates unsized state
authorpsandoz
Tue, 30 Jul 2013 11:32:26 +0100
changeset 19072 8f176099ec00
parent 19071 bc096b85d91d
child 19073 a4d1398d9897
8021863: Stream.concat incorrectly calculates unsized state Reviewed-by: chegar
jdk/src/share/classes/java/util/stream/Streams.java
jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java
--- a/jdk/src/share/classes/java/util/stream/Streams.java	Tue Jul 30 15:47:35 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/Streams.java	Tue Jul 30 11:32:26 2013 +0100
@@ -681,11 +681,9 @@
             this.aSpliterator = aSpliterator;
             this.bSpliterator = bSpliterator;
             beforeSplit = true;
-            // The spliterator is unsized before splitting if a and b are
-            // sized and the sum of the estimates overflows
-            unsized = aSpliterator.hasCharacteristics(SIZED)
-                      && aSpliterator.hasCharacteristics(SIZED)
-                      && aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
+            // The spliterator is known to be unsized before splitting if the
+            // sum of the estimates overflows.
+            unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
         }
 
         @Override
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java	Tue Jul 30 15:47:35 2013 -0700
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java	Tue Jul 30 11:32:26 2013 +0100
@@ -22,6 +22,8 @@
  */
 package org.openjdk.tests.java.util.stream;
 
+import java.util.Spliterator;
+import java.util.stream.BaseStream;
 import java.util.stream.OpTestCase;
 import java.util.stream.StreamTestDataProvider;
 
@@ -34,16 +36,107 @@
 import java.util.stream.TestData;
 
 import static java.util.stream.LambdaTestHelpers.*;
+import static org.testng.Assert.assertEquals;
 
+/**
+ * @test
+ * @bug 8021863
+ */
 public class ConcatOpTest extends OpTestCase {
 
     // Sanity to make sure all type of stream source works
     @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
-    public void testOpsSequential(String name, TestData.OfRef<Integer> data) {
+    public void testOps(String name, TestData.OfRef<Integer> data) {
         exerciseOpsInt(data,
                        s -> Stream.concat(s, data.stream()),
                        s -> IntStream.concat(s, data.stream().mapToInt(Integer::intValue)),
                        s -> LongStream.concat(s, data.stream().mapToLong(Integer::longValue)),
                        s -> DoubleStream.concat(s, data.stream().mapToDouble(Integer::doubleValue)));
     }
+
+    public void testSize() {
+        assertSized(Stream.concat(
+                LongStream.range(0, Long.MAX_VALUE / 2).boxed(),
+                LongStream.range(0, Long.MAX_VALUE / 2).boxed()));
+
+        assertUnsized(Stream.concat(
+                LongStream.range(0, Long.MAX_VALUE).boxed(),
+                LongStream.range(0, Long.MAX_VALUE).boxed()));
+
+        assertUnsized(Stream.concat(
+                LongStream.range(0, Long.MAX_VALUE).boxed(),
+                Stream.iterate(0, i -> i + 1)));
+
+        assertUnsized(Stream.concat(
+                Stream.iterate(0, i -> i + 1),
+                LongStream.range(0, Long.MAX_VALUE).boxed()));
+    }
+
+    public void testLongSize() {
+        assertSized(LongStream.concat(
+                LongStream.range(0, Long.MAX_VALUE / 2),
+                LongStream.range(0, Long.MAX_VALUE / 2)));
+
+        assertUnsized(LongStream.concat(
+                LongStream.range(0, Long.MAX_VALUE),
+                LongStream.range(0, Long.MAX_VALUE)));
+
+        assertUnsized(LongStream.concat(
+                LongStream.range(0, Long.MAX_VALUE),
+                LongStream.iterate(0, i -> i + 1)));
+
+        assertUnsized(LongStream.concat(
+                LongStream.iterate(0, i -> i + 1),
+                LongStream.range(0, Long.MAX_VALUE)));
+    }
+
+    public void testIntSize() {
+        assertSized(IntStream.concat(
+                IntStream.range(0, Integer.MAX_VALUE),
+                IntStream.range(0, Integer.MAX_VALUE)));
+
+        assertUnsized(IntStream.concat(
+                LongStream.range(0, Long.MAX_VALUE).mapToInt(i -> (int) i),
+                LongStream.range(0, Long.MAX_VALUE).mapToInt(i -> (int) i)));
+
+        assertUnsized(IntStream.concat(
+                LongStream.range(0, Long.MAX_VALUE).mapToInt(i -> (int) i),
+                IntStream.iterate(0, i -> i + 1)));
+
+        assertUnsized(IntStream.concat(
+                IntStream.iterate(0, i -> i + 1),
+                LongStream.range(0, Long.MAX_VALUE).mapToInt(i -> (int) i)));
+    }
+
+    public void testDoubleSize() {
+        assertSized(DoubleStream.concat(
+                IntStream.range(0, Integer.MAX_VALUE).mapToDouble(i -> i),
+                IntStream.range(0, Integer.MAX_VALUE).mapToDouble(i -> i)));
+
+        assertUnsized(DoubleStream.concat(
+                LongStream.range(0, Long.MAX_VALUE).mapToDouble(i -> i),
+                LongStream.range(0, Long.MAX_VALUE).mapToDouble(i -> i)));
+
+        assertUnsized(DoubleStream.concat(
+                LongStream.range(0, Long.MAX_VALUE).mapToDouble(i -> i),
+                DoubleStream.iterate(0, i -> i + 1)));
+
+        assertUnsized(DoubleStream.concat(
+                DoubleStream.iterate(0, i -> i + 1),
+                LongStream.range(0, Long.MAX_VALUE).mapToDouble(i -> i)));
+    }
+
+    void assertUnsized(BaseStream<?, ?> s) {
+        Spliterator<?> sp = s.spliterator();
+
+        assertFalse(sp.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED));
+        assertEquals(sp.estimateSize(), Long.MAX_VALUE);
+    }
+
+    void assertSized(BaseStream<?, ?> s) {
+        Spliterator<?> sp = s.spliterator();
+
+        assertTrue(sp.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED));
+        assertTrue(sp.estimateSize() < Long.MAX_VALUE);
+    }
 }