From 65da4cb2fb05a91e02034f7cc8fca3811cf9c8bd Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Mon, 9 Jun 2014 14:23:35 +0400 Subject: [PATCH] Generalize zip(..) to merge(..) { t1, t2 -> ... }, add merge for maps. --- libraries/stdlib/src/generated/_Generators.kt | 473 ++++++++++++------ .../stdlib/src/kotlin/collections/Stream.kt | 6 +- .../stdlib/test/collections/CollectionTest.kt | 14 + libraries/stdlib/test/collections/MapTest.kt | 2 +- .../stdlib/test/collections/StreamTest.kt | 7 + .../src/templates/Generators.kt | 87 +++- 6 files changed, 413 insertions(+), 176 deletions(-) diff --git a/libraries/stdlib/src/generated/_Generators.kt b/libraries/stdlib/src/generated/_Generators.kt index 5bdebb21b70..4949aa2280c 100644 --- a/libraries/stdlib/src/generated/_Generators.kt +++ b/libraries/stdlib/src/generated/_Generators.kt @@ -7,6 +7,299 @@ package kotlin import java.util.* +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Array.merge(array: Array, transform: (T, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun BooleanArray.merge(array: Array, transform: (Boolean, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ByteArray.merge(array: Array, transform: (Byte, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun CharArray.merge(array: Array, transform: (Char, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun DoubleArray.merge(array: Array, transform: (Double, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun FloatArray.merge(array: Array, transform: (Float, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun IntArray.merge(array: Array, transform: (Int, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun LongArray.merge(array: Array, transform: (Long, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ShortArray.merge(array: Array, transform: (Short, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Iterable.merge(array: Array, transform: (T, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun String.merge(array: Array, transform: (Char, R) -> V): List { + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Array.merge(other: Iterable, transform: (T, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun BooleanArray.merge(other: Iterable, transform: (Boolean, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ByteArray.merge(other: Iterable, transform: (Byte, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun CharArray.merge(other: Iterable, transform: (Char, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun DoubleArray.merge(other: Iterable, transform: (Double, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun FloatArray.merge(other: Iterable, transform: (Float, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun IntArray.merge(other: Iterable, transform: (Int, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun LongArray.merge(other: Iterable, transform: (Long, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun ShortArray.merge(other: Iterable, transform: (Short, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun Iterable.merge(other: Iterable, transform: (T, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + */ +public inline fun String.merge(other: Iterable, transform: (Char, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Returns a stream of values built from elements of both collections with same indexes using provided *transform*. Stream has length of shortest stream. + */ +public fun Stream.merge(stream: Stream, transform: (T, R) -> V): Stream { + return MergingStream(this, stream, transform) +} + /** * Splits original collection into pair of collections, * where *first* collection contains elements for which predicate yielded *true*, @@ -518,286 +811,154 @@ public fun Stream.plus(stream: Stream): Stream { * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Array.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun BooleanArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ByteArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun CharArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun DoubleArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun FloatArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun IntArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun LongArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ShortArray.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Iterable.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun String.zip(array: Array): List> { - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Array.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun BooleanArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ByteArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun CharArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun DoubleArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun FloatArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun IntArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun LongArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun ShortArray.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun Iterable.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ public fun String.zip(other: Iterable): List> { - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } } /** @@ -814,9 +975,9 @@ public fun String.zip(other: String): List> { } /** - * Returns a stream of pairs built from elements of both collections with same indexes. List has length of shortest collection. + * Returns a stream of pairs built from elements of both collections with same indexes. Stream has length of shortest stream. */ public fun Stream.zip(stream: Stream): Stream> { - return ZippingStream(this, stream) + return MergingStream(this, stream) { (t1, t2) -> t1 to t2 } } diff --git a/libraries/stdlib/src/kotlin/collections/Stream.kt b/libraries/stdlib/src/kotlin/collections/Stream.kt index f1701e46c9a..357e78ff1b6 100644 --- a/libraries/stdlib/src/kotlin/collections/Stream.kt +++ b/libraries/stdlib/src/kotlin/collections/Stream.kt @@ -38,13 +38,13 @@ public class TransformingStream(val stream: Stream, val transformer: (T } } -class ZippingStream(val stream1: Stream, val stream2: Stream) : Stream> { - override fun iterator(): Iterator> = object : AbstractIterator>() { +public class MergingStream(val stream1: Stream, val stream2: Stream, val transform: (T1, T2) -> V) : Stream { + override fun iterator(): Iterator = object : AbstractIterator() { val iterator1 = stream1.iterator() val iterator2 = stream2.iterator() override fun computeNext() { if (iterator1.hasNext() && iterator2.hasNext()) { - setNext(iterator1.next() to iterator2.next()) + setNext(transform(iterator1.next(), iterator2.next())) } else { done() } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index cc2627ff3f9..72ea5224722 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -120,6 +120,20 @@ class CollectionTest { } } + test + fun merge() { + expect(listOf("ab", "bc", "cd")) { + listOf("a", "b", "c").merge(listOf("b", "c", "d")) { a, b -> a + b } + } + } + + test + fun zip() { + expect(listOf("a" to "b", "b" to "c", "c" to "d")) { + listOf("a", "b", "c").zip(listOf("b", "c", "d")) + } + } + test fun partition() { val data = arrayListOf("foo", "bar", "something", "xyz") val pair = data.partition { it.size == 3 } diff --git a/libraries/stdlib/test/collections/MapTest.kt b/libraries/stdlib/test/collections/MapTest.kt index 43dc8cb5de1..4638138a035 100644 --- a/libraries/stdlib/test/collections/MapTest.kt +++ b/libraries/stdlib/test/collections/MapTest.kt @@ -53,7 +53,7 @@ class MapTest { assertEquals(map.size(), 1) assertEquals("James", map["name"]) } - + test fun iterate() { val map = TreeMap() map["beverage"] = "beer" diff --git a/libraries/stdlib/test/collections/StreamTest.kt b/libraries/stdlib/test/collections/StreamTest.kt index c65dc8a820d..4efc8b8c3c6 100644 --- a/libraries/stdlib/test/collections/StreamTest.kt +++ b/libraries/stdlib/test/collections/StreamTest.kt @@ -73,6 +73,13 @@ public class StreamTest { assertEquals("13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ...", fibonacci().drop(3).drop(4).joinToString(limit = 10)) } + test + fun merge() { + expect(listOf("ab", "bc", "cd")) { + streamOf("a", "b", "c").merge(streamOf("b", "c", "d")) { a, b -> a + b }.toList() + } + } + test fun toStringJoinsNoMoreThanTheFirstTenElements() { assertEquals("0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...", fibonacci().joinToString(limit = 10)) assertEquals("13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ...", fibonacci().filter { it > 10 }.joinToString(limit = 10)) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt index 3d1cb6599c6..1345cff7f72 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt @@ -118,6 +118,73 @@ fun generators(): List { } } + templates add f("merge(other: Iterable, transform: (T, R) -> V)") { + exclude(Streams) + doc { + """ + Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + """ + } + typeParam("R") + typeParam("V") + returns("List") + inline(true) + body { + """ + val first = iterator() + val second = other.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list + """ + } + } + + templates add f("merge(array: Array, transform: (T, R) -> V)") { + exclude(Streams) + doc { + """ + Returns a list of values built from elements of both collections with same indexes using provided *transform*. List has length of shortest collection. + """ + } + typeParam("R") + typeParam("V") + returns("List") + inline(true) + body { + """ + val first = iterator() + val second = array.iterator() + val list = arrayListOf() + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list + """ + } + } + + + templates add f("merge(stream: Stream, transform: (T, R) -> V)") { + only(Streams) + doc { + """ + Returns a stream of values built from elements of both collections with same indexes using provided *transform*. Stream has length of shortest stream. + """ + } + typeParam("R") + typeParam("V") + returns("Stream") + body { + """ + return MergingStream(this, stream, transform) + """ + } + } + + templates add f("zip(other: Iterable)") { exclude(Streams) doc { @@ -129,13 +196,7 @@ fun generators(): List { returns("List>") body { """ - val first = iterator() - val second = other.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(other) { (t1, t2) -> t1 to t2 } """ } } @@ -172,13 +233,7 @@ fun generators(): List { returns("List>") body { """ - val first = iterator() - val second = array.iterator() - val list = ArrayList>() - while (first.hasNext() && second.hasNext()) { - list.add(first.next() to second.next()) - } - return list + return merge(array) { (t1, t2) -> t1 to t2 } """ } } @@ -187,14 +242,14 @@ fun generators(): List { only(Streams) doc { """ - Returns a stream of pairs built from elements of both collections with same indexes. List has length of shortest collection. + Returns a stream of pairs built from elements of both collections with same indexes. Stream has length of shortest stream. """ } typeParam("R") returns("Stream>") body { """ - return ZippingStream(this, stream) + return MergingStream(this, stream) { (t1, t2) -> t1 to t2 } """ } }