diff --git a/js/js.libraries/src/core/generated/_ArraysJs.kt b/js/js.libraries/src/core/generated/_ArraysJs.kt index 5dd5395b8a1..0ec724bd14b 100644 --- a/js/js.libraries/src/core/generated/_ArraysJs.kt +++ b/js/js.libraries/src/core/generated/_ArraysJs.kt @@ -12518,6 +12518,8 @@ public fun CharArray.asIterable(): Iterable { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun Array.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12526,6 +12528,8 @@ public fun Array.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun ByteArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12534,6 +12538,8 @@ public fun ByteArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun ShortArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12542,6 +12548,8 @@ public fun ShortArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun IntArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12550,6 +12558,8 @@ public fun IntArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun LongArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12558,6 +12568,8 @@ public fun LongArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun FloatArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12566,6 +12578,8 @@ public fun FloatArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun DoubleArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12574,6 +12588,8 @@ public fun DoubleArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun BooleanArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12582,6 +12598,8 @@ public fun BooleanArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun CharArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() diff --git a/js/js.libraries/src/core/generated/_CollectionsJs.kt b/js/js.libraries/src/core/generated/_CollectionsJs.kt index 88ebedc4259..575519856ca 100644 --- a/js/js.libraries/src/core/generated/_CollectionsJs.kt +++ b/js/js.libraries/src/core/generated/_CollectionsJs.kt @@ -2031,6 +2031,8 @@ public inline fun Iterable.asIterable(): Iterable { /** * Creates a [Sequence] instance that wraps the original collection returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromCollection */ public fun Iterable.asSequence(): Sequence { return Sequence { this.iterator() } diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index 4e1441150c5..f8ce1ad42f8 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -7143,46 +7143,64 @@ public header fun CharArray.asIterable(): Iterable /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun Array.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun ByteArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun ShortArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun IntArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun LongArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun FloatArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun DoubleArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun BooleanArray.asSequence(): Sequence /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public header fun CharArray.asSequence(): Sequence diff --git a/libraries/stdlib/common/src/generated/_Collections.kt b/libraries/stdlib/common/src/generated/_Collections.kt index 7f0ef0c4118..074f587703a 100644 --- a/libraries/stdlib/common/src/generated/_Collections.kt +++ b/libraries/stdlib/common/src/generated/_Collections.kt @@ -1041,6 +1041,8 @@ public header inline fun Iterable.asIterable(): Iterable /** * Creates a [Sequence] instance that wraps the original collection returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromCollection */ public header fun Iterable.asSequence(): Sequence diff --git a/libraries/stdlib/samples/test/samples/collections/collections.kt b/libraries/stdlib/samples/test/samples/collections/collections.kt index 358778c23a9..d26fd140848 100644 --- a/libraries/stdlib/samples/test/samples/collections/collections.kt +++ b/libraries/stdlib/samples/test/samples/collections/collections.kt @@ -18,7 +18,6 @@ package samples.collections import samples.* import kotlin.test.* -import java.util.* @RunWith(Enclosed::class) diff --git a/libraries/stdlib/samples/test/samples/collections/maps.kt b/libraries/stdlib/samples/test/samples/collections/maps.kt index 580526e102b..7c78e5fe9ad 100644 --- a/libraries/stdlib/samples/test/samples/collections/maps.kt +++ b/libraries/stdlib/samples/test/samples/collections/maps.kt @@ -3,7 +3,6 @@ package samples.collections import samples.* import kotlin.test.* import java.util.* -import kotlin.comparisons.* @RunWith(Enclosed::class) class Maps { diff --git a/libraries/stdlib/samples/test/samples/collections/sequences.kt b/libraries/stdlib/samples/test/samples/collections/sequences.kt new file mode 100644 index 00000000000..85a5cd8c230 --- /dev/null +++ b/libraries/stdlib/samples/test/samples/collections/sequences.kt @@ -0,0 +1,144 @@ +package samples.collections + +import samples.* +import kotlin.test.* +import kotlin.coroutines.experimental.buildIterator +import kotlin.coroutines.experimental.buildSequence + +@RunWith(Enclosed::class) +class Sequences { + class Building { + + @Sample + fun generateSequence() { + var count = 3 + + val sequence = generateSequence { + (count--).takeIf { it > 0 } // will return null, when value becomes non-positive, + // and that will terminate the sequence + } + + assertPrints(sequence.toList(), "[3, 2, 1]") + + // sequence.forEach { } // <- iterating that sequence second time will fail + } + + @Sample + fun generateSequenceWithSeed() { + + fun fibonacci(): Sequence { + // fibonacci terms + // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, ... + return generateSequence(Pair(0, 1), { Pair(it.second, it.first + it.second) }).map { it.first } + } + + assertPrints(fibonacci().take(10).toList(), "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]") + } + + @Sample + fun generateSequenceWithLazySeed() { + class LinkedValue(val value: T, val next: LinkedValue? = null) + + fun LinkedValue?.asSequence(): Sequence> = generateSequence( + seedFunction = { this }, + nextFunction = { it.next } + ) + + fun LinkedValue?.valueSequence(): Sequence = asSequence().map { it.value } + + val singleItem = LinkedValue(42) + val twoItems = LinkedValue(24, singleItem) + + assertPrints(twoItems.valueSequence().toList(), "[24, 42]") + assertPrints(singleItem.valueSequence().toList(), "[42]") + assertPrints(singleItem.next.valueSequence().toList(), "[]") + } + + @Sample + fun sequenceOfValues() { + val sequence = sequenceOf("first", "second", "last") + sequence.forEach(::println) + } + + @Sample + fun sequenceFromCollection() { + val collection = listOf('a', 'b', 'c') + val sequence = collection.asSequence() + + assertPrints(sequence.joinToString(), "a, b, c") + } + + @Sample + fun sequenceFromArray() { + val array = arrayOf('a', 'b', 'c') + val sequence = array.asSequence() + + assertPrints(sequence.joinToString(), "a, b, c") + } + + @Sample + fun sequenceFromIterator() { + val array = arrayOf(1, 2, 3) + + // create a sequence with a function, returning an iterator + val sequence1 = Sequence { array.iterator() } + assertPrints(sequence1.joinToString(), "1, 2, 3") + assertPrints(sequence1.drop(1).joinToString(), "2, 3") + + // create a sequence from an existing iterator + // can be iterated only once + val sequence2 = array.iterator().asSequence() + assertPrints(sequence2.joinToString(), "1, 2, 3") + // sequence2.drop(1).joinToString() // <- iterating sequence second time will fail + } + + @Sample + fun buildFibonacciSequence() { + fun fibonacci() = buildSequence { + var terms = Pair(0, 1) + + // this sequence is infinite + while(true) { + yield(terms.first) + terms = Pair(terms.second, terms.first + terms.second) + } + } + + assertPrints(fibonacci().take(10).toList(), "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]") + } + + @Sample + fun buildSequenceYieldAll() { + val sequence = buildSequence { + val start = 0 + // yielding a single value + yield(start) + // yielding an iterable + yieldAll(1..5 step 2) + // yielding an infinite sequence + yieldAll(generateSequence(8) { it * 3 }) + } + + assertPrints(sequence.take(7).toList(), "[0, 1, 3, 5, 8, 24, 72]") + } + + @Sample + fun buildIterator() { + val collection = listOf(1, 2, 3) + val wrappedCollection = object : AbstractCollection() { + override val size: Int = collection.size + 2 + + override fun iterator(): Iterator = buildIterator { + yield("first") + yieldAll(collection) + yield("last") + } + } + + assertPrints(wrappedCollection, "[first, 1, 2, 3, last]") + } + + } + + +} \ No newline at end of file diff --git a/libraries/stdlib/src/generated/_Arrays.kt b/libraries/stdlib/src/generated/_Arrays.kt index 1cc0e84208e..45e4095bea5 100644 --- a/libraries/stdlib/src/generated/_Arrays.kt +++ b/libraries/stdlib/src/generated/_Arrays.kt @@ -12599,6 +12599,8 @@ public fun CharArray.asIterable(): Iterable { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun Array.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12607,6 +12609,8 @@ public fun Array.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun ByteArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12615,6 +12619,8 @@ public fun ByteArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun ShortArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12623,6 +12629,8 @@ public fun ShortArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun IntArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12631,6 +12639,8 @@ public fun IntArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun LongArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12639,6 +12649,8 @@ public fun LongArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun FloatArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12647,6 +12659,8 @@ public fun FloatArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun DoubleArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12655,6 +12669,8 @@ public fun DoubleArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun BooleanArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() @@ -12663,6 +12679,8 @@ public fun BooleanArray.asSequence(): Sequence { /** * Creates a [Sequence] instance that wraps the original array returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromArray */ public fun CharArray.asSequence(): Sequence { if (isEmpty()) return emptySequence() diff --git a/libraries/stdlib/src/generated/_Collections.kt b/libraries/stdlib/src/generated/_Collections.kt index 880545c6748..6a3978e0380 100644 --- a/libraries/stdlib/src/generated/_Collections.kt +++ b/libraries/stdlib/src/generated/_Collections.kt @@ -2041,6 +2041,8 @@ public inline fun Iterable.asIterable(): Iterable { /** * Creates a [Sequence] instance that wraps the original collection returning its elements when being iterated. + * + * @sample samples.collections.Sequences.Building.sequenceFromCollection */ public fun Iterable.asSequence(): Sequence { return Sequence { this.iterator() } diff --git a/libraries/stdlib/src/kotlin/collections/Sequences.kt b/libraries/stdlib/src/kotlin/collections/Sequences.kt index 956041139a6..132aa920bdc 100644 --- a/libraries/stdlib/src/kotlin/collections/Sequences.kt +++ b/libraries/stdlib/src/kotlin/collections/Sequences.kt @@ -7,6 +7,8 @@ package kotlin.sequences * Given an [iterator] function constructs a [Sequence] that returns values through the [Iterator] * provided by that function. * The values are evaluated lazily, and the sequence is potentially infinite. + * + * @sample samples.collections.Sequences.Building.sequenceFromIterator */ @kotlin.internal.InlineOnly public inline fun Sequence(crossinline iterator: () -> Iterator): Sequence = object : Sequence { @@ -15,6 +17,8 @@ public inline fun Sequence(crossinline iterator: () -> Iterator): Sequenc /** * Creates a sequence that returns all elements from this iterator. The sequence is constrained to be iterated only once. + * + * @sample samples.collections.Sequences.Building.sequenceFromIterator */ public fun Iterator.asSequence(): Sequence = Sequence { this }.constrainOnce() @@ -27,6 +31,8 @@ public inline fun java.util.Enumeration.asSequence(): Sequence = this.i /** * Creates a sequence that returns the specified values. + * + * @sample samples.collections.Sequences.Building.sequenceOfValues */ public fun sequenceOf(vararg elements: T): Sequence = if (elements.isEmpty()) emptySequence() else elements.asSequence() @@ -552,6 +558,9 @@ private class ConstrainedOnceSequence(sequence: Sequence) : Sequence { * The returned sequence is constrained to be iterated only once. * * @see constrainOnce + * @see kotlin.coroutines.experimental.buildSequence + * + * @sample samples.collections.Sequences.Building.generateSequence */ public fun generateSequence(nextFunction: () -> T?): Sequence { return GeneratorSequence(nextFunction, { nextFunction() }).constrainOnce() @@ -565,6 +574,10 @@ public fun generateSequence(nextFunction: () -> T?): Sequence { * If [seed] is `null`, an empty sequence is produced. * * The sequence can be iterated multiple times, each time starting with [seed]. + * + * @see kotlin.coroutines.experimental.buildSequence + * + * @sample samples.collections.Sequences.Building.generateSequenceWithSeed */ @kotlin.internal.LowPriorityInOverloadResolution public fun generateSequence(seed: T?, nextFunction: (T) -> T?): Sequence = @@ -581,6 +594,10 @@ public fun generateSequence(seed: T?, nextFunction: (T) -> T?): Sequen * If [seedFunction] returns `null`, an empty sequence is produced. * * The sequence can be iterated multiple times. + * + * @see kotlin.coroutines.experimental.buildSequence + * + * @sample samples.collections.Sequences.Building.generateSequenceWithLazySeed */ public fun generateSequence(seedFunction: () -> T?, nextFunction: (T) -> T?): Sequence = GeneratorSequence(seedFunction, nextFunction) diff --git a/libraries/stdlib/src/kotlin/coroutines/experimental/SequenceBuilder.kt b/libraries/stdlib/src/kotlin/coroutines/experimental/SequenceBuilder.kt index 8df9d4dcb03..3f1b16c9025 100644 --- a/libraries/stdlib/src/kotlin/coroutines/experimental/SequenceBuilder.kt +++ b/libraries/stdlib/src/kotlin/coroutines/experimental/SequenceBuilder.kt @@ -21,13 +21,20 @@ package kotlin.coroutines.experimental import kotlin.coroutines.experimental.intrinsics.* /** - * Builds a [Sequence] lazily yielding values one by one. + * Builds a [Sequence] lazily yielding values one by one. + * + * @see kotlin.sequences.generateSequence + * + * @sample samples.collections.Sequences.Building.buildSequenceYieldAll + * @sample samples.collections.Sequences.Building.buildFibonacciSequence */ @SinceKotlin("1.1") public fun buildSequence(builderAction: suspend SequenceBuilder.() -> Unit): Sequence = Sequence { buildIterator(builderAction) } /** * Builds an [Iterator] lazily yielding values one by one. + * + * @sample samples.collections.Sequences.Building.buildIterator */ @SinceKotlin("1.1") public fun buildIterator(builderAction: suspend SequenceBuilder.() -> Unit): Iterator { @@ -38,12 +45,21 @@ public fun buildIterator(builderAction: suspend SequenceBuilder.() -> Uni /** * Builder for a [Sequence] or an [Iterator], provides [yield] and [yieldAll] suspension functions. + * + * @see buildSequence + * @see buildIterator + * + * @sample samples.collections.Sequences.Building.buildSequenceYieldAll + * @sample samples.collections.Sequences.Building.buildFibonacciSequence */ @RestrictsSuspension @SinceKotlin("1.1") public abstract class SequenceBuilder internal constructor() { /** * Yields a value to the [Iterator] being built. + * + * @sample samples.collections.Sequences.Building.buildSequenceYieldAll + * @sample samples.collections.Sequences.Building.buildFibonacciSequence */ public abstract suspend fun yield(value: T) @@ -51,11 +67,15 @@ public abstract class SequenceBuilder internal constructor() { * Yields all values from the `iterator` to the [Iterator] being built. * * The sequence of values returned by the given iterator can be potentially infinite. + * + * @sample samples.collections.Sequences.Building.buildSequenceYieldAll */ public abstract suspend fun yieldAll(iterator: Iterator) /** * Yields a collections of values to the [Iterator] being built. + * + * @sample samples.collections.Sequences.Building.buildSequenceYieldAll */ public suspend fun yieldAll(elements: Iterable) { if (elements is Collection && elements.isEmpty()) return @@ -66,6 +86,8 @@ public abstract class SequenceBuilder internal constructor() { * Yields potentially infinite sequence of values to the [Iterator] being built. * * The sequence can be potentially infinite. + * + * @sample samples.collections.Sequences.Building.buildSequenceYieldAll */ public suspend fun yieldAll(sequence: Sequence) = yieldAll(sequence.iterator()) } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Sequence.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Sequence.kt index 7e613694e16..154824ca54b 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Sequence.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Sequence.kt @@ -29,7 +29,13 @@ fun sequences(): List { templates add f("asSequence()") { include(CharSequences, Maps) - doc { f -> "Creates a [Sequence] instance that wraps the original ${f.collection} returning its ${f.element.pluralize()} when being iterated." } + doc { f -> + """ + Creates a [Sequence] instance that wraps the original ${f.collection} returning its ${f.element.pluralize()} when being iterated. + + ${if (f in listOf(ArraysOfPrimitives, ArraysOfObjects, Iterables)) "@sample samples.collections.Sequences.Building.sequenceFrom${f.doc.collection.capitalize()}" else ""} + """ + } returns("Sequence") body { f -> """