changeset 6434:f7c32272e02f

Streams cleanups; add optimized forEach implementations; include subList in tested lists
author briangoetz
date Sun, 18 Nov 2012 13:56:58 -0500
parents 7c6e15368d4d
children b5c2376af431
files src/share/classes/java/util/ArrayList.java src/share/classes/java/util/Arrays.java src/share/classes/java/util/Vector.java src/share/classes/java/util/stream/Spliterator.java src/share/classes/java/util/stream/Streams.java test-ng/tests/org/openjdk/tests/java/util/stream/StreamTestDataProvider.java
diffstat 6 files changed, 72 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/ArrayList.java	Sat Nov 17 12:31:13 2012 -0500
+++ b/src/share/classes/java/util/ArrayList.java	Sun Nov 18 13:56:58 2012 -0500
@@ -25,6 +25,7 @@
 
 package java.util;
 
+import java.util.function.Block;
 import java.util.stream.Stream;
 import java.util.stream.StreamOpFlags;
 import java.util.stream.Streams;
@@ -817,6 +818,8 @@
             }
         }
 
+        // @@@ Add optimized forEach
+
         final void checkForComodification() {
             if (modCount != expectedModCount)
                 throw new ConcurrentModificationException();
@@ -1052,6 +1055,8 @@
                     return (E) elementData[offset + (lastRet = i)];
                 }
 
+                // @@@ Add optimized forEach
+
                 public int nextIndex() {
                     return cursor;
                 }
@@ -1134,6 +1139,16 @@
     }
 
     @Override
+    public void forEach(Block<? super E> block) {
+        E[] elementData = (E[]) this.elementData;
+        int size = this.size;
+        if (size > elementData.length)
+            throw new ConcurrentModificationException();
+        for (int i=0; i<size; i++)
+            block.accept(elementData[i]);
+    }
+
+    @Override
     public Stream<E> stream() {
         return Streams.stream(() -> Arrays.spliterator((E[]) elementData, 0, size),
                               StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SIZED);
--- a/src/share/classes/java/util/Arrays.java	Sat Nov 17 12:31:13 2012 -0500
+++ b/src/share/classes/java/util/Arrays.java	Sun Nov 18 13:56:58 2012 -0500
@@ -3715,14 +3715,10 @@
         }
 
         private ArrayIterator(T[] elements, int startOffset, int len) {
+            checkBounds(elements, startOffset, len);
             this.elements = Objects.requireNonNull(elements);
             this.endOffset = startOffset + len;
             this.curOffset = startOffset;
-
-            assert curOffset >= 0 : "offset not positive";
-            assert endOffset >= curOffset : "end lower than start";
-            assert (curOffset < elements.length) || (0 == len && 0 == curOffset) : "offset not in array";
-            assert endOffset <= elements.length : "end not in array";
         }
 
         public T next() {
@@ -3737,6 +3733,14 @@
         public final boolean hasNext() {
             return curOffset < endOffset;
         }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            for (int i=curOffset; i < endOffset; i++)
+                block.accept(elements[i]);
+            // update only once -- reduce heap write traffic
+            curOffset = endOffset;
+        }
     }
 
     private static class ArraySpliterator<T> extends ArrayIterator<T> implements Spliterator<T> {
@@ -3748,7 +3752,6 @@
 
         ArraySpliterator(T[] elements, int offset, int length) {
             super(elements, offset, length);
-            Arrays.checkBounds(elements, offset, length);
         }
 
         @Override
@@ -3767,18 +3770,14 @@
         }
 
         @Override
+        public int getNaturalSplits() {
+            return (endOffset - curOffset > 1) ? 1 : 0;
+        }
+
+        @Override
         public void forEach(Block<? super T> block) {
             traversing = true;
-            for (int i= curOffset; i<endOffset; i++) {
-                block.accept(elements[i]);
-            }
-            // update only once; reduce heap write traffic
-            curOffset = endOffset;
-        }
-
-        @Override
-        public int getNaturalSplits() {
-            return (endOffset - curOffset > 1) ? 1 : 0;
+            super.forEach(block);
         }
 
         @Override
@@ -3810,10 +3809,10 @@
         }
 
         ArraySink(T[] array, int offset, int length) {
+            checkBounds(array, offset, length);
             this.array = Objects.requireNonNull(array);
             this.offset = offset;
             this.length = length;
-            checkBounds(array, offset, length);
         }
 
         @Override
@@ -3848,6 +3847,22 @@
         return () -> iterator(array, offset, length);
     }
 
+    public static <T> Spliterator<T> spliterator(T[] array) {
+        return spliterator(array, 0, array.length);
+    }
+
+    public static <T> Spliterator<T> spliterator(T[] array, int offset, int length) throws IndexOutOfBoundsException {
+        return new ArraySpliterator<>(array, offset, length);
+    }
+
+    public static<T> Sink<T> sink(T[] array) {
+        return sink(array, 0, array.length);
+    }
+
+    public static<T> Sink<T> sink(T[] array, int offset, int length) {
+        return new ArraySink<>(array, offset, length);
+    }
+
     public static <T> Stream<T> stream(T[] array) {
         return stream(array, 0, array.length);
     }
@@ -3857,14 +3872,6 @@
                               StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
     }
 
-    public static <T> Spliterator<T> spliterator(T[] array) {
-        return spliterator(array, 0, array.length);
-    }
-
-    public static <T> Spliterator<T> spliterator(T[] array, int offset, int length) throws IndexOutOfBoundsException {
-        return new ArraySpliterator<>(array, offset, length);
-    }
-
     public static <T> Stream<T> parallel(T[] array) {
         return parallel(array, 0, array.length);
     }
@@ -3873,12 +3880,4 @@
         return Streams.parallel(spliterator(array, offset, length),
                               StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
     }
-
-    public static<T> Sink<T> sink(T[] array) {
-        return sink(array, 0, array.length);
-    }
-
-    public static<T> Sink<T> sink(T[] array, int offset, int length) {
-        return new ArraySink<>(array, offset, length);
-    }
 }
--- a/src/share/classes/java/util/Vector.java	Sat Nov 17 12:31:13 2012 -0500
+++ b/src/share/classes/java/util/Vector.java	Sun Nov 18 13:56:58 2012 -0500
@@ -25,6 +25,7 @@
 
 package java.util;
 
+import java.util.function.Block;
 import java.util.stream.Stream;
 import java.util.stream.StreamOpFlags;
 import java.util.stream.Streams;
@@ -1215,6 +1216,13 @@
     }
 
     @Override
+    public synchronized void forEach(Block<? super E> block) {
+        E[] elementData = (E[]) this.elementData;
+        for (int i=0; i<elementCount; i++)
+            block.accept(elementData[i]);
+    }
+
+    @Override
     public Stream<E> stream() {
         return Streams.stream(() -> Arrays.spliterator((E[]) elementData, 0, elementCount),
                               StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SIZED);
--- a/src/share/classes/java/util/stream/Spliterator.java	Sat Nov 17 12:31:13 2012 -0500
+++ b/src/share/classes/java/util/stream/Spliterator.java	Sun Nov 18 13:56:58 2012 -0500
@@ -88,10 +88,7 @@
      * @param block The sink to which elements will be provided.
      */
     default void forEach(Block<? super T> block) {
-        Iterator<T> remaining = iterator();
-        while (remaining.hasNext()) {
-            block.accept(remaining.next());
-        }
+        iterator().forEach(block);
     }
 
     /**
--- a/src/share/classes/java/util/stream/Streams.java	Sat Nov 17 12:31:13 2012 -0500
+++ b/src/share/classes/java/util/stream/Streams.java	Sun Nov 18 13:56:58 2012 -0500
@@ -65,17 +65,7 @@
 
     public static<U, T extends Iterator<U>> Spliterator<U> sequentialSpliterator(T iterator) {
         Objects.requireNonNull(iterator);
-        return new Spliterator.Sequential<U>() {
-            @Override
-            public Iterator<U> iterator() {
-                return iterator;
-            }
-
-            @Override
-            public void forEach(Block<? super U> block) {
-                iterator.forEach(block);
-            }
-        };
+        return (Spliterator.Sequential<U>) () -> iterator;
     }
 
     // Stream
@@ -88,12 +78,12 @@
 
     public static<U> Stream<U> stream(Spliterator<U> spliterator, int flags) {
         Objects.requireNonNull(spliterator);
-        return new ReferencePipeline<>(spliterator, flags);
+        return new ReferencePipeline<>(spliterator, flags & ~StreamOpFlags.IS_PARALLEL);
     }
 
     public static <T> Stream<T> stream(Supplier<Spliterator<T>> proxy, int flags) {
         Objects.requireNonNull(proxy);
-        return new ReferencePipeline<>(new ProxySpliterator<>(proxy), flags);
+        return new ReferencePipeline<>(new ProxySpliterator<>(proxy), flags & ~StreamOpFlags.IS_PARALLEL);
     }
 
     public static<T> Stream<T> parallel(Spliterator<T> spliterator, int flags) {
@@ -263,15 +253,20 @@
         }
 
         @Override
-        public void forEach(Block<? super T> block) {
+        public int getSizeIfKnown() {
             initiate();
-            iterator.forEach(block);
+            return size;
         }
 
         @Override
-        public int getSizeIfKnown() {
-            initiate();
-            return size;
+        public void forEach(Block<? super T> block) {
+            if (iterator == null) {
+                iterable.forEach(block);
+                iterator = Collections.emptyIterator();
+                size = (sizeProvider != null) ? sizeProvider.size() : -1;
+            }
+            else
+                iterator.forEach(block);
         }
     }
 
--- a/test-ng/tests/org/openjdk/tests/java/util/stream/StreamTestDataProvider.java	Sat Nov 17 12:31:13 2012 -0500
+++ b/test-ng/tests/org/openjdk/tests/java/util/stream/StreamTestDataProvider.java	Sun Nov 18 13:56:58 2012 -0500
@@ -90,6 +90,9 @@
             list.add(e("array:" + name, ints, StreamTestData.ArrayData::new));
             list.add(e("ArrayList.asList:" + name, Arrays.asList(ints), StreamTestData.CollectionData::new));
             list.add(e("ArrayList:" + name, new ArrayList<>(Arrays.asList(ints)), StreamTestData.CollectionData::new));
+            List<Integer> aList = new ArrayList<>(Arrays.asList(ints));
+            list.add(e("Sublist:" + name, (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2),
+                       StreamTestData.CollectionData::new));
             list.add(e("HashSet:" + name, new HashSet<>(Arrays.asList(ints)), StreamTestData.CollectionData::new));
             list.add(e("TreeSet:" + name, new TreeSet<>(Arrays.asList(ints)), StreamTestData.CollectionData::new));
         }