OpenJDK / lambda / lambda / jdk
changeset 5889:c9630c23e453 it2-bootstrap
MapStream attachment to Map plus test and infrastructure additions.
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(); + } + } }