8148115: Stream.findFirst for unordered source optimization

Reviewed-by: psandoz
This commit is contained in:
Tagir F. Valeev 2016-02-08 10:40:00 +01:00
parent 9e65963f4f
commit e41fea88e7
4 changed files with 54 additions and 31 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 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
@ -107,7 +107,7 @@ final class FindOps {
*/
private static final class FindOp<T, O> implements TerminalOp<T, O> {
private final StreamShape shape;
final boolean mustFindFirst;
final int opFlags;
final O emptyValue;
final Predicate<O> presentPredicate;
final Supplier<TerminalSink<T, O>> sinkSupplier;
@ -129,7 +129,7 @@ final class FindOps {
O emptyValue,
Predicate<O> presentPredicate,
Supplier<TerminalSink<T, O>> sinkSupplier) {
this.mustFindFirst = mustFindFirst;
this.opFlags = StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
this.shape = shape;
this.emptyValue = emptyValue;
this.presentPredicate = presentPredicate;
@ -138,7 +138,7 @@ final class FindOps {
@Override
public int getOpFlags() {
return StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
return opFlags;
}
@Override
@ -156,7 +156,10 @@ final class FindOps {
@Override
public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
Spliterator<P_IN> spliterator) {
return new FindTask<>(this, helper, spliterator).invoke();
// This takes into account the upstream ops flags and the terminal
// op flags and therefore takes into account findFirst or findAny
boolean mustFindFirst = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
return new FindTask<>(this, mustFindFirst, helper, spliterator).invoke();
}
}
@ -250,16 +253,20 @@ final class FindOps {
private static final class FindTask<P_IN, P_OUT, O>
extends AbstractShortCircuitTask<P_IN, P_OUT, O, FindTask<P_IN, P_OUT, O>> {
private final FindOp<P_OUT, O> op;
private final boolean mustFindFirst;
FindTask(FindOp<P_OUT, O> op,
boolean mustFindFirst,
PipelineHelper<P_OUT> helper,
Spliterator<P_IN> spliterator) {
super(helper, spliterator);
this.mustFindFirst = mustFindFirst;
this.op = op;
}
FindTask(FindTask<P_IN, P_OUT, O> parent, Spliterator<P_IN> spliterator) {
super(parent, spliterator);
this.mustFindFirst = parent.mustFindFirst;
this.op = parent.op;
}
@ -283,7 +290,7 @@ final class FindOps {
@Override
protected O doLeaf() {
O result = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).get();
if (!op.mustFindFirst) {
if (!mustFindFirst) {
if (result != null)
shortCircuit(result);
return null;
@ -300,7 +307,7 @@ final class FindOps {
@Override
public void onCompletion(CountedCompleter<?> caller) {
if (op.mustFindFirst) {
if (mustFindFirst) {
for (FindTask<P_IN, P_OUT, O> child = leftChild, p = null; child != p;
p = child, child = rightChild) {
O result = child.getLocalResult();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -47,6 +47,7 @@ import java.util.function.ToLongFunction;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;
/**
* LambdaTestHelpers -- assertion methods and useful objects for lambda test cases
@ -400,6 +401,16 @@ public class LambdaTestHelpers {
assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
}
public static<T> void assertContains(Optional<T> actual, Iterator<T> it) {
actual.ifPresentOrElse(r -> {
boolean contained = false;
while (!contained && it.hasNext()) {
contained = Objects.equals(r, it.next());
}
assertTrue(contained, "Not found: "+r);
}, () -> assertFalse(it.hasNext()));
}
public static void launderAssertion(Runnable r, Supplier<String> additionalInfo) {
try {
r.run();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 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
@ -20,6 +20,12 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8148115
*/
package org.openjdk.tests.java.util.stream;
import java.util.*;
@ -61,18 +67,7 @@ public class FindAnyOpTest extends OpTestCase {
void exerciseStream(TestData.OfRef<Integer> data, Function<Stream<Integer>, Stream<Integer>> fs) {
Optional<Integer> or = withData(data).terminal(fs, s -> s.findAny()).equalator(VALID_ANSWER).exercise();
if (or.isPresent()) {
Integer r = or.get();
Iterator<Integer> it = fs.apply(data.stream()).iterator();
boolean contained = false;
while (!contained && it.hasNext()) {
contained = Objects.equals(r, it.next());
}
assertTrue(contained);
}
else {
assertFalse(fs.apply(data.stream()).iterator().hasNext());
}
assertContains(or, fs.apply(data.stream()).iterator());
}
@Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, 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
@ -20,6 +20,12 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8148115
*/
package org.openjdk.tests.java.util.stream;
import java.util.*;
@ -59,15 +65,19 @@ public class FindFirstOpTest extends OpTestCase {
}
void exerciseStream(TestData.OfRef<Integer> data, Function<Stream<Integer>, Stream<Integer>> fs) {
Optional<Integer> r = exerciseTerminalOps(data, fs, s -> s.findFirst());
if (r.isPresent()) {
Iterator<Integer> i = fs.apply(data.stream()).iterator();
assertTrue(i.hasNext());
assertEquals(i.next(), r.get());
}
else {
assertFalse(fs.apply(data.stream()).iterator().hasNext());
}
Iterator<Integer> i = fs.apply(data.stream()).iterator();
Optional<Integer> expected = i.hasNext() ? Optional.of(i.next()) : Optional.empty();
withData(data).terminal(fs, s -> s.findFirst())
.expectedResult(expected)
.resultAsserter((act, exp, ord, par) -> {
if (par & !ord) {
assertContains(act, fs.apply(data.stream()).iterator());
}
else {
assertEquals(act, exp);
}
})
.exercise();
}
@Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)