Scan functions for Sequences and Iterable #KT-7657
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
package templates
|
||||
|
||||
import templates.DocExtensions.mapResult
|
||||
import templates.Family.*
|
||||
import templates.SequenceClass.*
|
||||
|
||||
@@ -1037,6 +1038,371 @@ object Aggregates : TemplateGroupBase() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun scanAccMutationNote(hasInitial: Boolean, f: Family): String {
|
||||
if (!hasInitial && f.isPrimitiveSpecialization) return ""
|
||||
|
||||
val initialValueRequirement = if (hasInitial && f == Sequences)
|
||||
"""The [initial] value should also be immutable (or should not be mutated)
|
||||
as it may be passed to [operation] function later because of sequence's lazy nature.
|
||||
""" else
|
||||
""
|
||||
return """
|
||||
Note that `acc` value passed to [operation] function should not be mutated;
|
||||
otherwise it would affect the previous value in resulting ${f.mapResult}.
|
||||
$initialValueRequirement"""
|
||||
}
|
||||
|
||||
val f_scan = fn("scan(initial: R, operation: (acc: R, T) -> R)") {
|
||||
includeDefault()
|
||||
include(CharSequences, ArraysOfUnsigned)
|
||||
} builder {
|
||||
since("1.3")
|
||||
annotation("@ExperimentalStdlibApi")
|
||||
|
||||
specialFor(Iterables, ArraysOfObjects, CharSequences) { inline() }
|
||||
specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() }
|
||||
|
||||
typeParam("R")
|
||||
|
||||
returns("List<R>")
|
||||
specialFor(Sequences) { returns("Sequence<R>") }
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right
|
||||
to each ${f.element} and current accumulator value that starts with [initial] value.
|
||||
${scanAccMutationNote(true, f)}
|
||||
@param [operation] function that takes current accumulator value and ${f.element.prefixWithArticle()}, and calculates the next accumulator value.
|
||||
"""
|
||||
}
|
||||
sample("samples.collections.Collections.Aggregates.scan")
|
||||
sequenceClassification(intermediate, stateless)
|
||||
|
||||
body(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) {
|
||||
"""
|
||||
if (isEmpty()) return listOf(initial)
|
||||
|
||||
val result = ArrayList<R>(${f.code.size} + 1).apply { add(initial) }
|
||||
var accumulator = initial
|
||||
for (element in this) {
|
||||
accumulator = operation(accumulator, element)
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Iterables) {
|
||||
"""
|
||||
val estimatedSize = collectionSizeOrDefault(9)
|
||||
if (estimatedSize == 0) return listOf(initial)
|
||||
|
||||
val result = ArrayList<R>(estimatedSize + 1).apply { add(initial) }
|
||||
var accumulator = initial
|
||||
for (element in this) {
|
||||
accumulator = operation(accumulator, element)
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Sequences) {
|
||||
"""
|
||||
return sequence {
|
||||
yield(initial)
|
||||
var accumulator = initial
|
||||
for (element in this@scan) {
|
||||
accumulator = operation(accumulator, element)
|
||||
yield(accumulator)
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_scanIndexed = fn("scanIndexed(initial: R, operation: (index: Int, acc: R, T) -> R)") {
|
||||
includeDefault()
|
||||
include(CharSequences, ArraysOfUnsigned)
|
||||
} builder {
|
||||
since("1.3")
|
||||
annotation("@ExperimentalStdlibApi")
|
||||
|
||||
specialFor(Iterables, ArraysOfObjects, CharSequences) { inline() }
|
||||
specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() }
|
||||
|
||||
typeParam("R")
|
||||
|
||||
returns("List<R>")
|
||||
specialFor(Sequences) { returns("Sequence<R>") }
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right
|
||||
to each ${f.element}, its index in the original ${f.collection} and current accumulator value that starts with [initial] value.
|
||||
${scanAccMutationNote(true, f)}
|
||||
@param [operation] function that takes the index of ${f.element.prefixWithArticle()}, current accumulator value
|
||||
and the ${f.element} itself, and calculates the next accumulator value.
|
||||
"""
|
||||
}
|
||||
sample("samples.collections.Collections.Aggregates.scan")
|
||||
sequenceClassification(intermediate, stateless)
|
||||
|
||||
body(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) {
|
||||
"""
|
||||
if (isEmpty()) return listOf(initial)
|
||||
|
||||
val result = ArrayList<R>(${f.code.size} + 1).apply { add(initial) }
|
||||
var accumulator = initial
|
||||
for (index in indices) {
|
||||
accumulator = operation(index, accumulator, this[index])
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Iterables) {
|
||||
"""
|
||||
val estimatedSize = collectionSizeOrDefault(9)
|
||||
if (estimatedSize == 0) return listOf(initial)
|
||||
|
||||
val result = ArrayList<R>(estimatedSize + 1).apply { add(initial) }
|
||||
var index = 0
|
||||
var accumulator = initial
|
||||
for (element in this) {
|
||||
accumulator = operation(index++, accumulator, element)
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Sequences) {
|
||||
"""
|
||||
return sequence {
|
||||
yield(initial)
|
||||
var index = 0
|
||||
var accumulator = initial
|
||||
for (element in this@scanIndexed) {
|
||||
accumulator = operation(checkIndexOverflow(index++), accumulator, element)
|
||||
yield(accumulator)
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_scanReduce = fn("scanReduce(operation: (acc: T, T) -> T)") {
|
||||
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
|
||||
} builder {
|
||||
since("1.3")
|
||||
annotation("@ExperimentalStdlibApi")
|
||||
|
||||
specialFor(CharSequences) { inline() }
|
||||
specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() }
|
||||
|
||||
returns("List<T>")
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns a list containing successive accumulation values generated by applying [operation] from left to right
|
||||
to each ${f.element} and current accumulator value that starts with the first ${f.element} of this ${f.collection}.
|
||||
${scanAccMutationNote(false, f)}
|
||||
@param [operation] function that takes current accumulator value and ${f.element.prefixWithArticle()}, and calculates the next accumulator value.
|
||||
"""
|
||||
}
|
||||
sample("samples.collections.Collections.Aggregates.scanReduce")
|
||||
|
||||
body {
|
||||
"""
|
||||
if (isEmpty()) return emptyList()
|
||||
|
||||
var accumulator = this[0]
|
||||
val result = ArrayList<T>(${f.code.size}).apply { add(accumulator) }
|
||||
for (index in 1 until ${f.code.size}) {
|
||||
accumulator = operation(accumulator, this[index])
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_scanReduceIndexed = fn("scanReduceIndexed(operation: (index: Int, acc: T, T) -> T)") {
|
||||
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
|
||||
} builder {
|
||||
since("1.3")
|
||||
annotation("@ExperimentalStdlibApi")
|
||||
|
||||
specialFor(CharSequences) { inline() }
|
||||
specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() }
|
||||
|
||||
returns("List<T>")
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns a list containing successive accumulation values generated by applying [operation] from left to right
|
||||
to each ${f.element}, its index in the original ${f.collection} and current accumulator value that starts with the first ${f.element} of this ${f.collection}.
|
||||
${scanAccMutationNote(false, f)}
|
||||
@param [operation] function that takes the index of ${f.element.prefixWithArticle()}, current accumulator value
|
||||
and the ${f.element} itself, and calculates the next accumulator value.
|
||||
"""
|
||||
}
|
||||
sample("samples.collections.Collections.Aggregates.scanReduce")
|
||||
|
||||
body {
|
||||
"""
|
||||
if (isEmpty()) return emptyList()
|
||||
|
||||
var accumulator = this[0]
|
||||
val result = ArrayList<T>(${f.code.size}).apply { add(accumulator) }
|
||||
for (index in 1 until ${f.code.size}) {
|
||||
accumulator = operation(index, accumulator, this[index])
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_scanReduceSuper = fn("scanReduce(operation: (acc: S, T) -> S)") {
|
||||
include(ArraysOfObjects, Iterables, Sequences)
|
||||
} builder {
|
||||
since("1.3")
|
||||
annotation("@ExperimentalStdlibApi")
|
||||
|
||||
specialFor(ArraysOfObjects, Iterables) { inline() }
|
||||
|
||||
typeParam("S")
|
||||
typeParam("T : S")
|
||||
|
||||
returns("List<S>")
|
||||
specialFor(Sequences) { returns("Sequence<S>") }
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right
|
||||
to each ${f.element} and current accumulator value that starts with the first ${f.element} of this ${f.collection}.
|
||||
${scanAccMutationNote(false, f)}
|
||||
@param [operation] function that takes current accumulator value and the ${f.element}, and calculates the next accumulator value.
|
||||
"""
|
||||
}
|
||||
sample("samples.collections.Collections.Aggregates.scanReduce")
|
||||
sequenceClassification(intermediate, stateless)
|
||||
|
||||
body(ArraysOfObjects) {
|
||||
"""
|
||||
if (isEmpty()) return emptyList()
|
||||
|
||||
var accumulator: S = this[0]
|
||||
val result = ArrayList<S>(size).apply { add(accumulator) }
|
||||
for (index in 1 until size) {
|
||||
accumulator = operation(accumulator, this[index])
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Iterables) {
|
||||
"""
|
||||
val iterator = this.iterator()
|
||||
if (!iterator.hasNext()) return emptyList()
|
||||
|
||||
var accumulator: S = iterator.next()
|
||||
val result = ArrayList<S>(collectionSizeOrDefault(10)).apply { add(accumulator) }
|
||||
while (iterator.hasNext()) {
|
||||
accumulator = operation(accumulator, iterator.next())
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Sequences) {
|
||||
"""
|
||||
return sequence {
|
||||
val iterator = iterator()
|
||||
if (iterator.hasNext()) {
|
||||
var accumulator: S = iterator.next()
|
||||
yield(accumulator)
|
||||
while (iterator.hasNext()) {
|
||||
accumulator = operation(accumulator, iterator.next())
|
||||
yield(accumulator)
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_scanReduceIndexedSuper = fn("scanReduceIndexed(operation: (index: Int, acc: S, T) -> S)") {
|
||||
include(ArraysOfObjects, Iterables, Sequences)
|
||||
} builder {
|
||||
since("1.3")
|
||||
annotation("@ExperimentalStdlibApi")
|
||||
|
||||
specialFor(ArraysOfObjects, Iterables) { inline() }
|
||||
|
||||
typeParam("S")
|
||||
typeParam("T : S")
|
||||
|
||||
returns("List<S>")
|
||||
specialFor(Sequences) { returns("Sequence<S>") }
|
||||
|
||||
doc {
|
||||
"""
|
||||
Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right
|
||||
to each ${f.element}, its index in the original ${f.collection} and current accumulator value that starts with the first ${f.element} of this ${f.collection}.
|
||||
${scanAccMutationNote(false, f)}
|
||||
@param [operation] function that takes the index of ${f.element.prefixWithArticle()}, current accumulator value
|
||||
and the ${f.element} itself, and calculates the next accumulator value.
|
||||
"""
|
||||
}
|
||||
sample("samples.collections.Collections.Aggregates.scanReduce")
|
||||
sequenceClassification(intermediate, stateless)
|
||||
|
||||
body(ArraysOfObjects) {
|
||||
"""
|
||||
if (isEmpty()) return emptyList()
|
||||
|
||||
var accumulator: S = this[0]
|
||||
val result = ArrayList<S>(size).apply { add(accumulator) }
|
||||
for (index in 1 until size) {
|
||||
accumulator = operation(index, accumulator, this[index])
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Iterables) {
|
||||
"""
|
||||
val iterator = this.iterator()
|
||||
if (!iterator.hasNext()) return emptyList()
|
||||
|
||||
var accumulator: S = iterator.next()
|
||||
val result = ArrayList<S>(collectionSizeOrDefault(10)).apply { add(accumulator) }
|
||||
var index = 1
|
||||
while (iterator.hasNext()) {
|
||||
accumulator = operation(index++, accumulator, iterator.next())
|
||||
result.add(accumulator)
|
||||
}
|
||||
return result
|
||||
"""
|
||||
}
|
||||
body(Sequences) {
|
||||
"""
|
||||
return sequence {
|
||||
val iterator = iterator()
|
||||
if (iterator.hasNext()) {
|
||||
var accumulator: S = iterator.next()
|
||||
yield(accumulator)
|
||||
var index = 1
|
||||
while (iterator.hasNext()) {
|
||||
accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next())
|
||||
yield(accumulator)
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
val f_onEach = fn("onEach(action: (T) -> Unit)") {
|
||||
include(Iterables, Maps, CharSequences, Sequences)
|
||||
} builder {
|
||||
|
||||
Reference in New Issue
Block a user