8153293: Preserve SORTED and DISTINCT characteristics for boxed() and asLongStream() operations
Reviewed-by: psandoz
--- a/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java Sat Apr 30 00:30:31 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java Fri Apr 29 16:57:57 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -167,6 +167,19 @@
return Nodes.doubleBuilder(exactSizeIfKnown);
}
+ private <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper, int opFlags) {
+ return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE, opFlags) {
+ @Override
+ Sink<Double> opWrapSink(int flags, Sink<U> sink) {
+ return new Sink.ChainedDouble<U>(sink) {
+ @Override
+ public void accept(double t) {
+ downstream.accept(mapper.apply(t));
+ }
+ };
+ }
+ };
+ }
// DoubleStream
@@ -184,7 +197,7 @@
@Override
public final Stream<Double> boxed() {
- return mapToObj(Double::valueOf);
+ return mapToObj(Double::valueOf, 0);
}
@Override
@@ -207,18 +220,7 @@
@Override
public final <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
Objects.requireNonNull(mapper);
- return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE,
- StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
- @Override
- Sink<Double> opWrapSink(int flags, Sink<U> sink) {
- return new Sink.ChainedDouble<U>(sink) {
- @Override
- public void accept(double t) {
- downstream.accept(mapper.apply(t));
- }
- };
- }
- };
+ return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
}
@Override
--- a/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java Sat Apr 30 00:30:31 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java Fri Apr 29 16:57:57 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -170,6 +170,19 @@
return Nodes.intBuilder(exactSizeIfKnown);
}
+ private <U> Stream<U> mapToObj(IntFunction<? extends U> mapper, int opFlags) {
+ return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE, opFlags) {
+ @Override
+ Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
+ return new Sink.ChainedInt<U>(sink) {
+ @Override
+ public void accept(int t) {
+ downstream.accept(mapper.apply(t));
+ }
+ };
+ }
+ };
+ }
// IntStream
@@ -187,8 +200,7 @@
@Override
public final LongStream asLongStream() {
- return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
- StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+ return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE, 0) {
@Override
Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
return new Sink.ChainedInt<Long>(sink) {
@@ -203,8 +215,7 @@
@Override
public final DoubleStream asDoubleStream() {
- return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
- StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+ return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE, 0) {
@Override
Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedInt<Double>(sink) {
@@ -219,7 +230,7 @@
@Override
public final Stream<Integer> boxed() {
- return mapToObj(Integer::valueOf);
+ return mapToObj(Integer::valueOf, 0);
}
@Override
@@ -242,18 +253,7 @@
@Override
public final <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
Objects.requireNonNull(mapper);
- return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE,
- StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
- @Override
- Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
- return new Sink.ChainedInt<U>(sink) {
- @Override
- public void accept(int t) {
- downstream.accept(mapper.apply(t));
- }
- };
- }
- };
+ return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
}
@Override
--- a/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java Sat Apr 30 00:30:31 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java Fri Apr 29 16:57:57 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -167,6 +167,19 @@
return Nodes.longBuilder(exactSizeIfKnown);
}
+ private <U> Stream<U> mapToObj(LongFunction<? extends U> mapper, int opFlags) {
+ return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE, opFlags) {
+ @Override
+ Sink<Long> opWrapSink(int flags, Sink<U> sink) {
+ return new Sink.ChainedLong<U>(sink) {
+ @Override
+ public void accept(long t) {
+ downstream.accept(mapper.apply(t));
+ }
+ };
+ }
+ };
+ }
// LongStream
@@ -184,8 +197,7 @@
@Override
public final DoubleStream asDoubleStream() {
- return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
- StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+ return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_DISTINCT) {
@Override
Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
return new Sink.ChainedLong<Double>(sink) {
@@ -200,7 +212,7 @@
@Override
public final Stream<Long> boxed() {
- return mapToObj(Long::valueOf);
+ return mapToObj(Long::valueOf, 0);
}
@Override
@@ -223,18 +235,7 @@
@Override
public final <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
Objects.requireNonNull(mapper);
- return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE,
- StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
- @Override
- Sink<Long> opWrapSink(int flags, Sink<U> sink) {
- return new Sink.ChainedLong<U>(sink) {
- @Override
- public void accept(long t) {
- downstream.accept(mapper.apply(t));
- }
- };
- }
- };
+ return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
}
@Override
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java Sat Apr 30 00:30:31 2016 +0100
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java Fri Apr 29 16:57:57 2016 -0700
@@ -27,11 +27,18 @@
import java.util.Arrays;
import java.util.Random;
+import java.util.Spliterator;
import java.util.stream.DoubleStream;
import java.util.stream.LongStream;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+/**
+ * @test
+ * @bug 8153293
+ */
@Test
public class DoublePrimitiveOpsTests {
@@ -42,6 +49,13 @@
assertEquals(sum, 1.0 + 2.0 + 3.0 + 4.0 + 5.0);
}
+ public void testFlags() {
+ assertTrue(LongStream.range(1, 10).asDoubleStream().boxed().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ assertFalse(DoubleStream.of(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ }
+
public void testToArray() {
{
double[] array = LongStream.range(1, 10).asDoubleStream().map(i -> i * 2).toArray();
@@ -72,6 +86,22 @@
}
}
+ public void testSortDistinct() {
+ {
+ double[] range = LongStream.range(0, 10).asDoubleStream().toArray();
+
+ assertEquals(LongStream.range(0, 10).asDoubleStream().sorted().distinct().toArray(), range);
+ assertEquals(LongStream.range(0, 10).asDoubleStream().parallel().sorted().distinct().toArray(), range);
+
+ double[] data = {5, 3, 1, 1, 5, Double.NaN, 3, 9, Double.POSITIVE_INFINITY,
+ Double.NEGATIVE_INFINITY, 2, 9, 1, 0, 8, Double.NaN, -0.0};
+ double[] expected = {Double.NEGATIVE_INFINITY, -0.0, 0, 1, 2, 3, 5, 8, 9,
+ Double.POSITIVE_INFINITY, Double.NaN};
+ assertEquals(DoubleStream.of(data).sorted().distinct().toArray(), expected);
+ assertEquals(DoubleStream.of(data).parallel().sorted().distinct().toArray(), expected);
+ }
+ }
+
public void testSortSort() {
Random r = new Random();
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java Sat Apr 30 00:30:31 2016 +0100
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java Fri Apr 29 16:57:57 2016 -0700
@@ -28,13 +28,21 @@
import java.util.Arrays;
import java.util.List;
import java.util.Random;
+import java.util.Spliterator;
+import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntConsumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+/**
+ * @test
+ * @bug 8153293
+ */
@Test
public class IntPrimitiveOpsTests {
@@ -85,6 +93,29 @@
assertEquals(sum, 15);
}
+ public void testFlags() {
+ assertTrue(IntStream.range(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+ assertFalse(IntStream.of(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ assertFalse(IntStream.of(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.DISTINCT));
+
+ assertTrue(IntStream.range(1, 10).asLongStream().spliterator()
+ .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+ assertFalse(IntStream.of(1, 10).asLongStream().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ assertFalse(IntStream.of(1, 10).asLongStream().spliterator()
+ .hasCharacteristics(Spliterator.DISTINCT));
+
+ assertTrue(IntStream.range(1, 10).asDoubleStream().spliterator()
+ .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+ assertFalse(IntStream.of(1, 10).asDoubleStream().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ assertFalse(IntStream.of(1, 10).asDoubleStream().spliterator()
+ .hasCharacteristics(Spliterator.DISTINCT));
+ }
+
public void testToArray() {
{
int[] array = IntStream.range(1, 10).map(i -> i * 2).toArray();
@@ -115,6 +146,35 @@
}
}
+ public void testSortDistinct() {
+ {
+ int[] range = IntStream.range(0, 10).toArray();
+
+ assertEquals(IntStream.range(0, 10).sorted().distinct().toArray(), range);
+ assertEquals(IntStream.range(0, 10).parallel().sorted().distinct().toArray(), range);
+
+ int[] data = {5, 3, 1, 1, 5, 3, 9, 2, 9, 1, 0, 8};
+ int[] expected = {0, 1, 2, 3, 5, 8, 9};
+ assertEquals(IntStream.of(data).sorted().distinct().toArray(), expected);
+ assertEquals(IntStream.of(data).parallel().sorted().distinct().toArray(), expected);
+ }
+
+ {
+ int[] input = new Random().ints(100, -10, 10).map(x -> x+Integer.MAX_VALUE).toArray();
+ TreeSet<Long> longs = new TreeSet<>();
+ for(int i : input) longs.add((long)i);
+ long[] expectedLongs = longs.stream().mapToLong(Long::longValue).toArray();
+ assertEquals(IntStream.of(input).sorted().asLongStream().sorted().distinct().toArray(),
+ expectedLongs);
+
+ TreeSet<Double> doubles = new TreeSet<>();
+ for(int i : input) doubles.add((double)i);
+ double[] expectedDoubles = doubles.stream().mapToDouble(Double::doubleValue).toArray();
+ assertEquals(IntStream.of(input).sorted().distinct().asDoubleStream()
+ .sorted().distinct().toArray(), expectedDoubles);
+ }
+ }
+
public void testSortSort() {
Random r = new Random();
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java Sat Apr 30 00:30:31 2016 +0100
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java Fri Apr 29 16:57:57 2016 -0700
@@ -28,13 +28,21 @@
import java.util.Arrays;
import java.util.List;
import java.util.Random;
+import java.util.Spliterator;
+import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.LongConsumer;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+/**
+ * @test
+ * @bug 8153293
+ */
@Test
public class LongPrimitiveOpsTests {
@@ -85,6 +93,22 @@
assertEquals(sum, 15);
}
+ public void testFlags() {
+ assertTrue(LongStream.range(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+ assertFalse(LongStream.of(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ assertFalse(LongStream.of(1, 10).boxed().spliterator()
+ .hasCharacteristics(Spliterator.DISTINCT));
+
+ assertTrue(LongStream.range(1, 10).asDoubleStream().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ assertFalse(LongStream.range(1, 10).asDoubleStream().spliterator()
+ .hasCharacteristics(Spliterator.DISTINCT));
+ assertFalse(LongStream.of(1, 10).asDoubleStream().spliterator()
+ .hasCharacteristics(Spliterator.SORTED));
+ }
+
public void testToArray() {
{
long[] array = LongStream.range(1, 10).map(i -> i * 2).toArray();
@@ -115,6 +139,30 @@
}
}
+ public void testSortDistinct() {
+ {
+ long[] range = LongStream.range(0, 10).toArray();
+
+ assertEquals(LongStream.range(0, 10).sorted().distinct().toArray(), range);
+ assertEquals(LongStream.range(0, 10).parallel().sorted().distinct().toArray(), range);
+
+ long[] data = {5, 3, 1, 1, 5, 3, 9, 2, 9, 1, 0, 8};
+ long[] expected = {0, 1, 2, 3, 5, 8, 9};
+ assertEquals(LongStream.of(data).sorted().distinct().toArray(), expected);
+ assertEquals(LongStream.of(data).parallel().sorted().distinct().toArray(), expected);
+ }
+
+ {
+ long[] input = new Random().longs(100, -10, 10).map(x -> x+Long.MAX_VALUE).toArray();
+
+ TreeSet<Double> doubles = new TreeSet<>();
+ for(long i : input) doubles.add((double)i);
+ double[] expectedDoubles = doubles.stream().mapToDouble(Double::doubleValue).toArray();
+ assertEquals(LongStream.of(input).sorted().distinct().asDoubleStream()
+ .sorted().distinct().toArray(), expectedDoubles);
+ }
+ }
+
public void testSortSort() {
Random r = new Random();