8238286: Add new flatMap stream operation that is more amenable to pushing

This patch adds a new flatmap-like operation called mapMulti to the java.util.Stream class as well as the primitive variations of this operation i.e. mapMultiToInt, IntStream mapMulti, etc.

Reviewed-by: psandoz, smarks
This commit is contained in:
Patrick Concannon 2020-08-31 16:12:32 +01:00
parent dd89c92c50
commit 79d12507b3
10 changed files with 899 additions and 15 deletions

View file

@ -164,6 +164,43 @@ public interface IntStream extends BaseStream<Integer, IntStream> {
*/
IntStream flatMap(IntFunction<? extends IntStream> mapper);
/**
* Returns a stream consisting of the results of replacing each element of
* this stream with multiple elements, specifically zero or more elements.
* Replacement is performed by applying the provided mapping function to each
* element in conjunction with a {@linkplain IntConsumer consumer} argument
* that accepts replacement elements. The mapping function calls the consumer
* zero or more times to provide the replacement elements.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* <p>If the {@linkplain IntConsumer consumer} argument is used outside the scope of
* its application to the mapping function, the results are undefined.
*
* @implSpec
* The default implementation invokes {@link #flatMap flatMap} on this stream,
* passing a function that behaves as follows. First, it calls the mapper function
* with an {@code IntConsumer} that accumulates replacement elements into a newly created
* internal buffer. When the mapper function returns, it creates an {@code IntStream} from the
* internal buffer. Finally, it returns this stream to {@code flatMap}.
*
* @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function that generates replacement elements
* @return the new stream
* @see Stream#mapMulti Stream.mapMulti
* @since 16
*/
default IntStream mapMulti(IntMapMultiConsumer mapper) {
Objects.requireNonNull(mapper);
return flatMap(e -> {
SpinedBuffer.OfInt buffer = new SpinedBuffer.OfInt();
mapper.accept(e, buffer);
return StreamSupport.intStream(buffer.spliterator(), false);
});
}
/**
* Returns a stream consisting of the distinct elements of this stream.
*
@ -1173,4 +1210,30 @@ public interface IntStream extends BaseStream<Integer, IntStream> {
*/
IntStream build();
}
/**
* Represents an operation that accepts an {@code int}-valued argument
* and an IntConsumer, and returns no result. This functional interface is
* used by {@link IntStream#mapMulti(IntMapMultiConsumer) IntStream.mapMulti}
* to replace an int value with zero or more int values.
*
* <p>This is a <a href="../function/package-summary.html">functional interface</a>
* whose functional method is {@link #accept(int, IntConsumer)}.
*
* @see IntStream#mapMulti(IntMapMultiConsumer)
*
* @since 16
*/
@FunctionalInterface
interface IntMapMultiConsumer {
/**
* Replaces the given {@code value} with zero or more values by feeding the mapped
* values to the {@code ic} consumer.
*
* @param value the int value coming from upstream
* @param ic an {@code IntConsumer} accepting the mapped values
*/
void accept(int value, IntConsumer ic);
}
}