changeset 5889:c9630c23e453 it2-bootstrap

MapStream attachment to Map plus test and infrastructure additions.
author mduigou
date Sat, 01 Sep 2012 15:06:07 -0700
parents f1d080662bf3
children dc8c914e7cac
files src/share/classes/java/util/Map.java src/share/classes/java/util/MapIterator.java src/share/classes/java/util/MapTraversable.java src/share/classes/java/util/Traversable.java src/share/classes/java/util/streams/AbstractSequentialMapStreamAccessor.java src/share/classes/java/util/streams/AbstractSequentialStreamAccessor.java src/share/classes/java/util/streams/MapStream.java src/share/classes/java/util/streams/Streams.java test-ng/tests/org/openjdk/tests/java/util/streams/MapStreamTestDataProvider.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamTestDataProvider.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java
diffstat 11 files changed, 308 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/Map.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/src/share/classes/java/util/Map.java	Sat Sep 01 15:06:07 2012 -0700
@@ -25,7 +25,13 @@
 
 package java.util;
 
+import java.util.functions.BiBlock;
+import java.util.functions.Block;
 import java.util.functions.Predicate;
+import java.util.streams.MapStream;
+import java.util.streams.Stream;
+import java.util.streams.Streamable;
+import java.util.streams.Streams;
 
 /**
  * An object that maps keys to values.  A map cannot contain duplicate keys;
@@ -116,7 +122,7 @@
  * @see Set
  * @since 1.2
  */
-public interface Map<K,V> {
+public interface Map<K,V> extends Sized, Streamable<Mapping<K,V>>, MapTraversable<K,V> {
 
     // Query Operations
 
@@ -480,4 +486,20 @@
      */
     int hashCode();
 
+    @Override
+    MapIterator<K,V> iterator() default {
+        return new MapIterator.IteratorAdapter(entrySet().iterator());
+    }
+
+    @Override
+    Stream<Mapping<K,V>> stream() default {
+        return Streams.stream(this, size());
+    }
+
+    <M extends Mapping<? extends K, ? extends V>> void putAll(Stream<M> stream) default {
+        if (stream.isParallel())
+            stream = stream.sequential();
+        // @@@ Would use this::add but compiler doens't support that yet.
+        stream.forEach((M m) -> { put(m.getKey(),m.getValue()); });
+    }
 }
--- a/src/share/classes/java/util/MapIterator.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/src/share/classes/java/util/MapIterator.java	Sat Sep 01 15:06:07 2012 -0700
@@ -32,7 +32,7 @@
  *
  * @author Brian Goetz
  */
-public interface MapIterator<K, V> extends Iterator<Mapping<K, V>> {
+public interface MapIterator<K, V> extends Iterator<Mapping<K,V>> {
     /**
      * Advance the iterator and return the current key.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/MapTraversable.java	Sat Sep 01 15:06:07 2012 -0700
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, 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.functions.BiBlock;
+import java.util.functions.Block;
+
+/**
+ * Implementing this interface allows an object to indicate that it provides
+ * the {@code forEach} method for internal iteration.
+ *
+ * @param <K> type keys of elements to be traversed.
+ * @param <V> type values of elements to be traversed.
+ *
+ * @author Brian Goetz
+ */
+public interface MapTraversable<K,V> extends Traversable<Mapping<K,V>> {
+    /**
+     * Each element of the object will be provided to the specified Sink.
+     *
+     * @param block The Sink to which elements will be provided.
+     */
+    void forEach(BiBlock<? super K, ? super V> block) default {
+        for (Mapping<K,V> m : this) {
+            block.apply(m.getKey(), m.getValue());
+        }
+    }
+
+    @Override
+    MapIterator<K,V> iterator();
+}
--- a/src/share/classes/java/util/Traversable.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/src/share/classes/java/util/Traversable.java	Sat Sep 01 15:06:07 2012 -0700
@@ -41,7 +41,8 @@
      * @param block The Sink to which elements will be provided.
      */
     public void forEach(Block<? super T> block) default {
-        for (T t : this)
+        for (T t : this) {
             block.apply(t);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/AbstractSequentialMapStreamAccessor.java	Sat Sep 01 15:06:07 2012 -0700
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 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.streams;
+
+import java.util.Mapping;
+import java.util.Spliterator;
+
+/**
+ * AbstractSequentialMapStreamAccessor
+ *
+ */
+public abstract class AbstractSequentialMapStreamAccessor<K,V> implements MapStreamAccessor<K,V> {
+    @Override
+    public boolean isParallel() {
+        return false;
+    }
+
+    @Override
+    public boolean isPredictableSplits() {
+        return false;
+    }
+
+    @Override
+    public final Stream.Shape getShape() {
+        return Stream.Shape.KEY_VALUE;
+    }
+
+    @Override
+    public Spliterator<Mapping<K,V>> spliterator() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getStreamFlags() {
+        return 0;
+    }
+
+    @Override
+    public int getSizeOrEstimate() {
+        return -Integer.MAX_VALUE;
+    }
+}
--- a/src/share/classes/java/util/streams/AbstractSequentialStreamAccessor.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/src/share/classes/java/util/streams/AbstractSequentialStreamAccessor.java	Sat Sep 01 15:06:07 2012 -0700
@@ -43,7 +43,7 @@
     }
 
     @Override
-    public Stream.Shape getShape() {
+    public final Stream.Shape getShape() {
         return Stream.Shape.LINEAR;
     }
 
--- a/src/share/classes/java/util/streams/MapStream.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/src/share/classes/java/util/streams/MapStream.java	Sat Sep 01 15:06:07 2012 -0700
@@ -35,10 +35,9 @@
  *
  * @author Brian Goetz
  */
-public interface MapStream<K, V> {
+public interface MapStream<K, V> extends MapTraversable<K, V> {
     MapIterator<K, V> iterator();
 
-
     /**
      * Return the mapping which is semantically "first" in the stream. If the
      * stream is not ordered then repeated invocations may return a different
--- a/src/share/classes/java/util/streams/Streams.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/src/share/classes/java/util/streams/Streams.java	Sat Sep 01 15:06:07 2012 -0700
@@ -25,6 +25,7 @@
 package java.util.streams;
 
 import java.util.*;
+import java.util.functions.BiBlock;
 import java.util.functions.Block;
 
 /**
@@ -37,6 +38,14 @@
         throw new Error("no instances");
     }
 
+    public static<K,V> MapStream<K,V> stream(MapTraversable<K,V> source) {
+        return new MapPipeline<>(new TraversableMapStreamAccessor<K,V>(source));
+    }
+
+    public static<K,V> MapStream<K,V> stream(Map<K,V> source) {
+        return new MapPipeline<>(new TraversableMapStreamAccessor<K,V>(source, source.size()));
+    }
+
     public static<T> Stream<T> stream(Collection<T> source) {
         return new LinearPipeline<>(new TraversableStreamAccessor<>(source, source.size()));
     }
@@ -217,8 +226,7 @@
     }
 
     private static class TraversableStreamAccessor<T>
-            extends AbstractSequentialStreamAccessor<T>
-            implements StreamAccessor<T>, Iterator<T> {
+            extends AbstractSequentialStreamAccessor<T> implements Iterator<T> {
         private final Traversable<T> traversable;
         private final int size;
         Iterator<T> iterator = null;
@@ -274,4 +282,96 @@
             return (size >= 0) ? size : super.getSizeOrEstimate();
         }
     }
+
+    private static class TraversableMapStreamAccessor<K,V>
+            extends AbstractSequentialMapStreamAccessor<K,V>
+            implements MapIterator<K,V> {
+        private final MapTraversable<K,V> traversable;
+        private final int size;
+        MapIterator<K,V> iterator = null;
+
+        TraversableMapStreamAccessor(MapTraversable<K,V> traversable) {
+            this.traversable = traversable;
+            this.size = -1;
+        }
+
+        TraversableMapStreamAccessor(MapTraversable<K,V> traversable, int knownSize) {
+            this.traversable = traversable;
+            this.size = knownSize;
+        }
+
+        @Override
+        public MapIterator<K,V> iterator() {
+            if (iterator == null)
+                iterator = new MapIterator.IteratorAdapter<>(traversable.iterator());
+            return iterator;
+        }
+
+        @Override
+        public void forEach(final Block<? super Mapping<K,V>> block) {
+            if (iterator == null) {
+                traversable.forEach(block);
+                iterator = new MapIterator.IteratorAdapter<>(Collections.<Mapping<K,V>>emptyIterator());
+            }
+            else {
+                while (iterator.hasNext())
+                    block.apply(iterator.next());
+            }
+        }
+
+        @Override
+        public void forEach(final BiBlock<? super K,? super V> block) {
+            if (iterator == null) {
+                traversable.forEach((e) -> {block.apply(e.getKey(),e.getValue());});
+                iterator = new MapIterator.IteratorAdapter<>(Collections.<Mapping<K,V>>emptyIterator());
+            }
+            else {
+                while (iterator.hasNext())
+                    block.apply(iterator.nextKey(), iterator.curValue());
+            }
+        }
+
+        @Override
+        public Mapping<K,V> next() {
+            return iterator().next();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return iterator().hasNext();
+        }
+
+        @Override
+        public int getStreamFlags() {
+            int flags = super.getStreamFlags();
+            if (size >= 0)
+                flags |= Stream.STATE_SIZED;
+            return flags;
+        }
+
+        @Override
+        public int getSizeOrEstimate() {
+            return (size >= 0) ? size : super.getSizeOrEstimate();
+        }
+
+        @Override
+        public K nextKey() {
+            return iterator().nextKey();
+        }
+
+        @Override
+        public V nextValue() {
+            return iterator().nextValue();
+        }
+
+        @Override
+        public K curKey() {
+            return iterator().curKey();
+        }
+
+        @Override
+        public V curValue() {
+            return iterator().curValue();
+        }
+    }
 }
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/MapStreamTestDataProvider.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/MapStreamTestDataProvider.java	Sat Sep 01 15:06:07 2012 -0700
@@ -38,11 +38,10 @@
 
 /**
  * MapStreamTestDataProvider
- * <p/>
  */
 public class MapStreamTestDataProvider {
 
-    private static Map<Integer, Integer> makeIntegerIntegerMap(Class<? extends Map> type, int size) {
+    private static Map<Integer, Integer> makeIntegerIntegerMap(Class<? extends Map<Integer,Integer>> type, int size) {
         try {
             Map<Integer, Integer> map = type.newInstance();
             for (int i = 1; i <= size; i++) {
@@ -54,7 +53,7 @@
         }
     }
 
-    private static Map<Integer, String> makeIntegerStringMap(Class<? extends Map> type, int size) {
+    private static Map<Integer, String> makeIntegerStringMap(Class<? extends Map<Integer,String>> type, int size) {
         try {
             Map<Integer, String> map = type.newInstance();
             for (int i = 1; i <= size; i++) {
@@ -85,17 +84,17 @@
 
                 list.add(new Object[]{
                             String.format("%s%s%s", name, "<Integer,Integer>", range),
-                            makeIntegerIntegerMap(type, size)
+                            makeIntegerIntegerMap((Class<? extends Map<Integer,Integer>>) type, size)
                         });
                 list.add(new Object[]{
                             String.format("%s%s%s", name, "<Integer,String>", range),
-                            makeIntegerStringMap(type, size)});
+                            makeIntegerStringMap((Class<? extends Map<Integer,String>>) type, size)});
             }
         }
         TEST_DATA = list.toArray(new Object[0][]);
     }
 
-    // Return an array of ( String name, TestData<Integer> )
+    // Return an array of ( String name, TestData<Mapping<Integer,?>> )
     @DataProvider(name = "opMaps")
     public static Object[][] makeMapTestData() {
         return TEST_DATA;
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/StreamTestDataProvider.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/StreamTestDataProvider.java	Sat Sep 01 15:06:07 2012 -0700
@@ -86,6 +86,7 @@
         for (Object[] data : arrays) {
             list.add(new Object[] { "array:" + data[0], new StreamOpTestCase.ArrayTestData<>((Integer[]) data[1])});
             list.add(new Object[] { "ArrayList:" + data[0], new StreamOpTestCase.CollectionTestData<>(new ArrayList<>(Arrays.asList((Integer[]) data[1]))) });
+            list.add(new Object[] { "HashSet:" + data[0], new StreamOpTestCase.CollectionTestData<>(new HashSet<>(Arrays.asList((Integer[]) data[1]))) });
             list.add(new Object[] { "TreeSet:" + data[0], new StreamOpTestCase.CollectionTestData<>(new TreeSet<>(Arrays.asList((Integer[]) data[1]))) });
         }
         testData = list.toArray(new Object[0][]);
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Fri Aug 31 22:39:24 2012 -0700
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/StreamOpTestCase.java	Sat Sep 01 15:06:07 2012 -0700
@@ -28,9 +28,12 @@
 import org.testng.annotations.Test;
 
 import java.util.*;
+import java.util.Map;
+import java.util.Mapping;
 import java.util.concurrent.ForkJoinTask;
 import java.util.concurrent.ForkJoinUtils;
 import java.util.functions.BiPredicate;
+import java.util.functions.BiBlock;
 import java.util.functions.Block;
 import java.util.streams.*;
 import java.util.streams.ops.IntermediateOp;
@@ -322,7 +325,7 @@
         return sink;
     }
 
-    public static interface TestData<T> extends Iterable<T>, Traversable<T>, Sized {
+    public static interface TestData<T> extends Traversable<T>, Sized {
         AbstractPipeline<?, T> seq();
         AbstractPipeline<?, T> par();
         Iterator<T> iterator();
@@ -476,4 +479,55 @@
             return collection.toString();
         }
     }
+
+    public static class MapTestData<K,V> implements TestData<Mapping<K,V>> {
+        private final Map<K,V> map;
+
+        public MapTestData(Map<K,V> map) {
+            this.map = map;
+        }
+
+        @Override
+        @SuppressWarnings({ "raw", "unchecked" })
+        public AbstractPipeline<?, Mapping<K,V>> seq() {
+            return (AbstractPipeline<?, Mapping<K,V>>) map.stream();
+        }
+
+        @Override
+        @SuppressWarnings({ "raw", "unchecked" })
+        public AbstractPipeline<?, Mapping<K,V>> par() {
+            return (AbstractPipeline<?, Mapping<K,V>>) map.parallel();
+        }
+
+        @Override
+        public Iterator<Mapping<K,V>> iterator() {
+            return map.iterator();
+        }
+
+        @Override
+        @SuppressWarnings({ "raw", "unchecked" })
+        public Spliterator<Mapping<K,V>> spliterator() {
+            // @@@ FIXME!
+            return Arrays.spliterator((Mapping<K,V>[]) map.entrySet().toArray());
+        }
+
+        @Override
+        public void forEach(Block<? super Mapping<K,V>> block) {
+            map.forEach(block);
+        }
+
+        public void forEach(BiBlock<? super K, ? super V> block) {
+            map.forEach(block);
+        }
+
+        @Override
+        public int size() {
+            return map.size();
+        }
+
+        @Override
+        public String toString() {
+            return map.toString();
+        }
+    }
 }