blob: 255df8372bc30f12fd7f36df06d80de1605d9592 [file] [log] [blame]
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package templates
import templates.DocExtensions.collection
import templates.DocExtensions.element
import templates.DocExtensions.mapResult
import templates.DocExtensions.prefixWithArticle
import templates.Family.*
import templates.SequenceClass.*
object Aggregates : TemplateGroupBase() {
init {
defaultBuilder {
if (sequenceClassification.isEmpty()) {
sequenceClassification(terminal)
}
specialFor(ArraysOfUnsigned) {
sinceAtLeast("1.3")
annotation("@ExperimentalUnsignedTypes")
}
}
}
val f_all = fn("all(predicate: (T) -> Boolean)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Returns `true` if all ${f.element.pluralize()} match the given [predicate].
Note that if the ${f.collection} contains no ${f.element.pluralize()}, the function returns `true`
because there are no ${f.element.pluralize()} in it that _do not_ match the predicate.
See a more detailed explanation of this logic concept in ["Vacuous truth"](https://en.wikipedia.org/wiki/Vacuous_truth) article.
"""
}
sample("samples.collections.Collections.Aggregates.all")
returns("Boolean")
body {
"""
${when (f) {
Iterables -> "if (this is Collection && isEmpty()) return true"
Maps -> "if (isEmpty()) return true"
else -> ""
}}
for (element in this) if (!predicate(element)) return false
return true
"""
}
}
val f_none_predicate = fn("none(predicate: (T) -> Boolean)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Returns `true` if no ${f.element.pluralize()} match the given [predicate].
"""
}
sample("samples.collections.Collections.Aggregates.noneWithPredicate")
returns("Boolean")
body {
"""
${when (f) {
Iterables -> "if (this is Collection && isEmpty()) return true"
Maps -> "if (isEmpty()) return true"
else -> ""
}}
for (element in this) if (predicate(element)) return false
return true
"""
}
}
val f_none = fn("none()") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Returns `true` if the ${f.collection} has no ${f.element.pluralize()}.
"""
}
sample("samples.collections.Collections.Aggregates.none")
returns("Boolean")
body {
"return !iterator().hasNext()"
}
specialFor(Iterables) {
body {
"""
if (this is Collection) return isEmpty()
return !iterator().hasNext()
"""
}
}
body(Maps, CharSequences, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
"return isEmpty()"
}
}
val f_any_predicate = fn("any(predicate: (T) -> Boolean)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Returns `true` if at least one ${f.element} matches the given [predicate].
"""
}
sample("samples.collections.Collections.Aggregates.anyWithPredicate")
returns("Boolean")
body {
"""
${when (f) {
Iterables -> "if (this is Collection && isEmpty()) return false"
Maps -> "if (isEmpty()) return false"
else -> ""
}}
for (element in this) if (predicate(element)) return true
return false
"""
}
}
val f_any = fn("any()") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
doc {
"""
Returns `true` if ${f.collection} has at least one ${f.element}.
"""
}
sample("samples.collections.Collections.Aggregates.any")
returns("Boolean")
body {
"return iterator().hasNext()"
}
body(Iterables) {
"""
if (this is Collection) return !isEmpty()
return iterator().hasNext()
"""
}
body(Maps, CharSequences, ArraysOfObjects, ArraysOfPrimitives) { "return !isEmpty()" }
specialFor(ArraysOfUnsigned) {
inlineOnly()
body { "return storage.any()" }
}
}
val f_count_predicate = fn("count(predicate: (T) -> Boolean)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { "Returns the number of ${f.element.pluralize()} matching the given [predicate]." }
returns("Int")
body {
fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkCountOverflow($value)" else value
"""
${when (f) {
Iterables -> "if (this is Collection && isEmpty()) return 0"
Maps -> "if (isEmpty()) return 0"
else -> ""
}}
var count = 0
for (element in this) if (predicate(element)) ${checkOverflow("++count")}
return count
"""
}
}
val f_count = fn("count()") {
includeDefault()
include(Collections, Maps, CharSequences)
} builder {
doc { "Returns the number of ${f.element.pluralize()} in this ${f.collection}." }
returns("Int")
body {
fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkCountOverflow($value)" else value
"""
${if (f == Iterables) "if (this is Collection) return size" else ""}
var count = 0
for (element in this) ${checkOverflow("++count")}
return count
"""
}
specialFor(CharSequences, Maps, Collections, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() }
specialFor(CharSequences) {
doc { "Returns the length of this char sequence." }
body { "return length" }
}
body(Maps, Collections, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
"return size"
}
}
val f_sumBy = fn("sumBy(selector: (T) -> Int)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
} builder {
deprecate(Deprecation("Use sumOf instead.", "this.sumOf(selector)", DeprecationLevel.WARNING, warningSince = "1.5"))
inline()
doc { "Returns the sum of all values produced by [selector] function applied to each ${f.element} in the ${f.collection}." }
returns("Int")
body {
"""
var sum: Int = 0
for (element in this) {
sum += selector(element)
}
return sum
"""
}
specialFor(ArraysOfUnsigned) {
inlineOnly()
signature("sumBy(selector: (T) -> UInt)")
returns("UInt")
body {
"""
var sum: UInt = 0u
for (element in this) {
sum += selector(element)
}
return sum
"""
}
}
}
fun f_sumOf() = listOf("Int", "Long", "UInt", "ULong", "Double", "java.math.BigInteger", "java.math.BigDecimal").map { selectorType ->
fn("sumOf(selector: (T) -> $selectorType)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
if (selectorType.startsWith("java")) platforms(Platform.JVM)
} builder {
inlineOnly()
since("1.4")
val typeShortName = when {
selectorType.startsWith("java") -> selectorType.substringAfterLast('.')
else -> selectorType
}
annotation("@OptIn(kotlin.experimental.ExperimentalTypeInference::class)")
annotation("@OverloadResolutionByLambdaReturnType")
specialFor(ArraysOfUnsigned) {
annotation("""@Suppress("INAPPLICABLE_JVM_NAME")""")
}
annotation("""@kotlin.jvm.JvmName("sumOf$typeShortName")""") // should not be needed if inline return type is mangled
if (selectorType.startsWith("U")) {
since("1.5")
wasExperimental("ExperimentalUnsignedTypes")
}
doc { "Returns the sum of all values produced by [selector] function applied to each ${f.element} in the ${f.collection}." }
returns(selectorType)
body {
"""
var sum: $selectorType = 0.to$typeShortName()
for (element in this) {
sum += selector(element)
}
return sum
"""
}
}
}
val f_sumByDouble = fn("sumByDouble(selector: (T) -> Double)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
} builder {
deprecate(Deprecation("Use sumOf instead.", "this.sumOf(selector)", DeprecationLevel.WARNING, warningSince = "1.5"))
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { "Returns the sum of all values produced by [selector] function applied to each ${f.element} in the ${f.collection}." }
returns("Double")
body {
"""
var sum: Double = 0.0
for (element in this) {
sum += selector(element)
}
return sum
"""
}
}
val f_minMax = sequence {
val genericSpecializations = PrimitiveType.floatingPointPrimitives + setOf(null)
fun def(op: String, nullable: Boolean, legacy: Boolean = false, orNull: String = "OrNull".ifOrEmpty(nullable)) =
fn("$op$orNull()") {
if (legacy) platforms(Platform.JVM)
include(Iterables, genericSpecializations)
include(Sequences, genericSpecializations)
include(ArraysOfObjects, genericSpecializations)
include(ArraysOfPrimitives, PrimitiveType.defaultPrimitives - PrimitiveType.Boolean)
include(ArraysOfUnsigned)
include(CharSequences)
} builder {
typeParam("T : Comparable<T>")
returns("T" + "?".ifOrEmpty(nullable))
val isFloat = primitive?.isFloatingPoint() == true
val isUnsigned = family == ArraysOfUnsigned
if (!nullable || legacy) suppress("CONFLICTING_OVERLOADS")
if (legacy) {
deprecate(Deprecation("Use ${op}OrNull instead.", "this.${op}OrNull()", warningSince = "1.4", errorSince = "1.5", hiddenSince = "1.6"))
val isGeneric = f in listOf(Iterables, Sequences, ArraysOfObjects)
if (isFloat && isGeneric) {
since("1.1")
}
body { "return ${op}OrNull()" }
return@builder
}
val doOnEmpty = if (nullable) "return null" else "throw NoSuchElementException()"
since("1.4")
if (!nullable) since("1.7")
doc {
"Returns the ${if (op == "max") "largest" else "smallest"} ${f.element}${" or `null` if there are no ${f.element.pluralize()}".ifOrEmpty(nullable)}." +
if (isFloat) "\n\n" + "If any of ${f.element.pluralize()} is `NaN` returns `NaN`." else ""
}
if (!nullable) {
throws("NoSuchElementException", "if the ${f.collection} is empty.")
annotation("@kotlin.jvm.JvmName(\"${op}OrThrow${"-U".ifOrEmpty(isUnsigned)}\")")
}
val acc = op
val cmpBlock = if (isFloat)
"""$acc = ${op}Of($acc, e)"""
else
"""if ($acc ${if (op == "max") "<" else ">"} e) $acc = e"""
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) $doOnEmpty
var $acc = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
$cmpBlock
}
return $acc
"""
}
body(ArraysOfObjects, ArraysOfPrimitives, CharSequences, ArraysOfUnsigned) {
"""
if (isEmpty()) $doOnEmpty
var $acc = this[0]
for (i in 1..lastIndex) {
val e = this[i]
$cmpBlock
}
return $acc
"""
}
}
for (op in listOf("min", "max")) {
for (nullable in listOf(false, true))
yield(def(op, nullable))
yield(def(op, nullable = true, legacy = true, orNull = ""))
}
}
val f_minMaxBy = sequence {
fun def(op: String, nullable: Boolean, legacy: Boolean = false, orNull: String = "OrNull".ifOrEmpty(nullable)) =
fn("$op$orNull(selector: (T) -> R)") {
if (legacy) platforms(Platform.JVM)
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
specialFor(Maps) { if (op == "maxBy" || !legacy) inlineOnly() }
typeParam("R : Comparable<R>")
returns("T" + "?".ifOrEmpty(nullable))
val isUnsigned = family == ArraysOfUnsigned
if (!nullable || legacy) suppress("CONFLICTING_OVERLOADS")
if (legacy) {
deprecate(Deprecation("Use ${op}OrNull instead.", "this.${op}OrNull(selector)", warningSince = "1.4", errorSince = "1.5", hiddenSince = "1.6"))
body { "return ${op}OrNull(selector)" }
return@builder
}
val doOnEmpty = if (nullable) "return null" else "throw NoSuchElementException()"
since("1.4")
if (!nullable) since("1.7")
doc { "Returns the first ${f.element} yielding the ${if (op == "maxBy") "largest" else "smallest"} value of the given function${" or `null` if there are no ${f.element.pluralize()}".ifOrEmpty(nullable)}." }
sample("samples.collections.Collections.Aggregates.$op$orNull")
if (!nullable) {
throws("NoSuchElementException", "if the ${f.collection} is empty.")
annotation("@kotlin.jvm.JvmName(\"${op}OrThrow${"-U".ifOrEmpty(isUnsigned)}\")")
}
val (elem, value, cmp) = if (op == "minBy") Triple("minElem", "minValue", ">") else Triple("maxElem", "maxValue", "<")
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) $doOnEmpty
var $elem = iterator.next()
if (!iterator.hasNext()) return $elem
var $value = selector($elem)
do {
val e = iterator.next()
val v = selector(e)
if ($value $cmp v) {
$elem = e
$value = v
}
} while (iterator.hasNext())
return $elem
"""
}
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
"""
if (isEmpty()) $doOnEmpty
var $elem = this[0]
val lastIndex = this.lastIndex
if (lastIndex == 0) return $elem
var $value = selector($elem)
for (i in 1..lastIndex) {
val e = this[i]
val v = selector(e)
if ($value $cmp v) {
$elem = e
$value = v
}
}
return $elem
"""
}
body(Maps) { "return entries.$op$orNull(selector)" }
}
for (op in listOf("minBy", "maxBy")) {
for (nullable in listOf(false, true))
yield(def(op, nullable))
yield(def(op, nullable = true, legacy = true, orNull = ""))
}
}
val f_minMaxWith = sequence {
fun def(op: String, nullable: Boolean, legacy: Boolean = false, orNull: String = "OrNull".ifOrEmpty(nullable)) =
fn("$op$orNull(comparator: Comparator<in T>)") {
if (legacy) platforms(Platform.JVM)
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
specialFor(Maps) { if (op == "maxWith" || !legacy) inlineOnly() }
returns("T" + "?".ifOrEmpty(nullable))
val isUnsigned = family == ArraysOfUnsigned
if (!nullable || legacy) suppress("CONFLICTING_OVERLOADS")
if (legacy) {
deprecate(Deprecation("Use ${op}OrNull instead.", "this.${op}OrNull(comparator)", warningSince = "1.4", errorSince = "1.5", hiddenSince = "1.6"))
body { "return ${op}OrNull(comparator)" }
return@builder
}
val doOnEmpty = if (nullable) "return null" else "throw NoSuchElementException()"
since("1.4")
if (!nullable) since("1.7")
doc { "Returns the first ${f.element} having the ${if (op == "maxWith") "largest" else "smallest"} value according to the provided [comparator]${" or `null` if there are no ${f.element.pluralize()}".ifOrEmpty(nullable)}." }
if (!nullable) {
throws("NoSuchElementException", "if the ${f.collection} is empty.")
annotation("@kotlin.jvm.JvmName(\"${op}OrThrow${"-U".ifOrEmpty(isUnsigned)}\")")
}
val (acc, cmp) = if (op == "minWith") Pair("min", ">") else Pair("max", "<")
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) $doOnEmpty
var $acc = iterator.next()
while (iterator.hasNext()) {
val e = iterator.next()
if (comparator.compare($acc, e) $cmp 0) $acc = e
}
return $acc
"""
}
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
"""
if (isEmpty()) $doOnEmpty
var $acc = this[0]
for (i in 1..lastIndex) {
val e = this[i]
if (comparator.compare($acc, e) $cmp 0) $acc = e
}
return $acc
"""
}
body(Maps) { "return entries.$op$orNull(comparator)" }
}
for (op in listOf("minWith", "maxWith")) {
for (nullable in listOf(false, true))
yield(def(op, nullable))
yield(def(op, nullable = true, legacy = true, orNull = ""))
}
}
fun f_minMaxOf() = sequence {
fun def(op: String, selectorType: String, nullable: Boolean, orNull: String = "OrNull".ifOrEmpty(nullable)) =
fn("${op}Of$orNull(selector: (T) -> $selectorType)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inlineOnly()
since("1.4")
annotation("@OptIn(kotlin.experimental.ExperimentalTypeInference::class)")
annotation("@OverloadResolutionByLambdaReturnType")
val isFloat = selectorType != "R"
doc {
"""
Returns the ${if (op == "max") "largest" else "smallest"} value among all values produced by [selector] function
applied to each ${f.element} in the ${f.collection}${" or `null` if there are no ${f.element.pluralize()}".ifOrEmpty(nullable)}.
""" +
"""
If any of values produced by [selector] function is `NaN`, the returned result is `NaN`.
""".ifOrEmpty(isFloat)
}
if (!nullable) {
throws("NoSuchElementException", "if the ${f.collection} is empty.")
}
if (!isFloat) typeParam("R : Comparable<R>")
returns(selectorType + "?".ifOrEmpty(nullable))
val doOnEmpty = if (nullable) "return null" else "throw NoSuchElementException()"
val acc = op + "Value"
val cmpBlock = if (isFloat)
"""$acc = ${op}Of($acc, v)"""
else
"""if ($acc ${if (op == "max") "<" else ">"} v) {
$acc = v
}"""
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) $doOnEmpty
var $acc = selector(iterator.next())
while (iterator.hasNext()) {
val v = selector(iterator.next())
$cmpBlock
}
return $acc
"""
}
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
"""
if (isEmpty()) $doOnEmpty
var $acc = selector(this[0])
for (i in 1..lastIndex) {
val v = selector(this[i])
$cmpBlock
}
return $acc
"""
}
specialFor(Maps) {
inlineOnly()
body { "return entries.${op}Of$orNull(selector)" }
}
}
for (op in listOf("min", "max"))
for (selectorType in listOf("R", "Float", "Double"))
for (nullable in listOf(false, true))
yield(def(op, selectorType, nullable))
}
fun f_minMaxOfWith() = sequence {
val selectorType = "R"
fun def(op: String, nullable: Boolean, orNull: String = "OrNull".ifOrEmpty(nullable)) =
fn("${op}OfWith$orNull(comparator: Comparator<in R>, selector: (T) -> $selectorType)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inlineOnly()
since("1.4")
annotation("@OptIn(kotlin.experimental.ExperimentalTypeInference::class)")
annotation("@OverloadResolutionByLambdaReturnType")
doc {
"""
Returns the ${if (op == "max") "largest" else "smallest"} value according to the provided [comparator]
among all values produced by [selector] function applied to each ${f.element} in the ${f.collection}${" or `null` if there are no ${f.element.pluralize()}".ifOrEmpty(nullable)}.
""" +
"""
@throws NoSuchElementException if the ${f.collection} is empty.
""".ifOrEmpty(!nullable)
}
typeParam(selectorType)
returns(selectorType + "?".ifOrEmpty(nullable))
val doOnEmpty = if (nullable) "return null" else "throw NoSuchElementException()"
val acc = op + "Value"
val cmp = if (op == "max") "<" else ">"
body {
"""
val iterator = iterator()
if (!iterator.hasNext()) $doOnEmpty
var $acc = selector(iterator.next())
while (iterator.hasNext()) {
val v = selector(iterator.next())
if (comparator.compare($acc, v) $cmp 0) {
$acc = v
}
}
return $acc
"""
}
body(CharSequences, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
"""
if (isEmpty()) $doOnEmpty
var $acc = selector(this[0])
for (i in 1..lastIndex) {
val v = selector(this[i])
if (comparator.compare($acc, v) $cmp 0) {
$acc = v
}
}
return $acc
"""
}
specialFor(Maps) {
body { "return entries.${op}OfWith$orNull(comparator, selector)" }
}
}
for (op in listOf("min", "max"))
for (nullable in listOf(false, true))
yield(def(op, nullable))
}
val f_foldIndexed = fn("foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R)") {
includeDefault()
include(CharSequences)
include(ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Accumulates value starting with [initial] value and applying [operation] from left to right
to current accumulator value and each ${f.element} with its index in the original ${f.collection}.
Returns the specified [initial] value if the ${f.collection} is empty.
@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.
"""
}
typeParam("R")
returns("R")
body {
fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkIndexOverflow($value)" else value
"""
var index = 0
var accumulator = initial
for (element in this) accumulator = operation(${checkOverflow("index++")}, accumulator, element)
return accumulator
"""
}
}
val f_foldRightIndexed = fn("foldRightIndexed(initial: R, operation: (index: Int, T, acc: R) -> R)") {
include(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Accumulates value starting with [initial] value and applying [operation] from right to left
to each ${f.element} with its index in the original ${f.collection} and current accumulator value.
Returns the specified [initial] value if the ${f.collection} is empty.
@param [operation] function that takes the index of ${f.element.prefixWithArticle()}, the ${f.element} itself
and current accumulator value, and calculates the next accumulator value.
"""
}
typeParam("R")
returns("R")
body {
"""
var index = lastIndex
var accumulator = initial
while (index >= 0) {
accumulator = operation(index, get(index), accumulator)
--index
}
return accumulator
"""
}
body(Lists) {
"""
var accumulator = initial
if (!isEmpty()) {
val iterator = listIterator(size)
while (iterator.hasPrevious()) {
val index = iterator.previousIndex()
accumulator = operation(index, iterator.previous(), accumulator)
}
}
return accumulator
"""
}
}
val f_fold = fn("fold(initial: R, operation: (acc: R, T) -> R)") {
includeDefault()
include(CharSequences)
include(ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Accumulates value starting with [initial] value and applying [operation] from left to right
to current accumulator value and each ${f.element}.
Returns the specified [initial] value if the ${f.collection} is empty.
@param [operation] function that takes current accumulator value and ${f.element.prefixWithArticle()}, and calculates the next accumulator value.
"""
}
typeParam("R")
returns("R")
body {
"""
var accumulator = initial
for (element in this) accumulator = operation(accumulator, element)
return accumulator
"""
}
}
val f_foldRight = fn("foldRight(initial: R, operation: (T, acc: R) -> R)") {
include(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Accumulates value starting with [initial] value and applying [operation] from right to left
to each ${f.element} and current accumulator value.
Returns the specified [initial] value if the ${f.collection} is empty.
@param [operation] function that takes ${f.element.prefixWithArticle()} and current accumulator value, and calculates the next accumulator value.
"""
}
typeParam("R")
returns("R")
body {
"""
var index = lastIndex
var accumulator = initial
while (index >= 0) {
accumulator = operation(get(index--), accumulator)
}
return accumulator
"""
}
body(Lists) {
"""
var accumulator = initial
if (!isEmpty()) {
val iterator = listIterator(size)
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
}
return accumulator
"""
}
}
private fun MemberBuilder.reduceDoc(fName: String): String {
fun summaryDoc(isLeftToRight: Boolean, isIndexed: Boolean): String {
val acc = "current accumulator value"
val element = if (isIndexed) "each ${f.element} with its index in the original ${f.collection}" else "each ${f.element}"
val start = if (isLeftToRight) "first" else "last"
val iteration = if (isLeftToRight) "left to right\nto $acc and $element" else "right to left\nto $element and $acc"
return """
Accumulates value starting with the $start ${f.element} and applying [operation] from $iteration."""
}
fun paramDoc(isLeftToRight: Boolean, isIndexed: Boolean): String {
val acc = "current accumulator value"
val element = if (isIndexed) "the ${f.element} itself" else f.element.prefixWithArticle()
val index = if (isIndexed) "the index of ${f.element.prefixWithArticle()}, " else ""
return """
@param [operation] function that takes $index${if (isLeftToRight) "$acc and $element" else "$element and $acc"},
and calculates the next accumulator value."""
}
fun emptyNote(isThrowing: Boolean): String = if (isThrowing) """
Throws an exception if this ${f.collection} is empty. If the ${f.collection} can be empty in an expected way,
please use [${fName}OrNull] instead. It returns `null` when its receiver is empty."""
else """
Returns `null` if the ${f.collection} is empty."""
val isLeftToRight = fName.contains("Right").not()
val isIndexed = fName.contains("Indexed")
val isThrowing = fName.contains("OrNull").not()
return """
${summaryDoc(isLeftToRight, isIndexed)}
${emptyNote(isThrowing)}
${paramDoc(isLeftToRight, isIndexed)}"""
}
val f_reduceIndexed = fn("reduceIndexed(operation: (index: Int, acc: T, T) -> T)") {
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceIndexed") }
sample("samples.collections.Collections.Aggregates.reduce")
returns("T")
body {
"""
if (isEmpty())
throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator = this[0]
for (index in 1..lastIndex) {
accumulator = operation(index, accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceIndexedSuper = fn("reduceIndexed(operation: (index: Int, acc: S, T) -> S)") {
include(ArraysOfObjects, Iterables, Sequences)
} builder {
inline()
doc { reduceDoc("reduceIndexed") }
typeParam("S")
typeParam("T : S")
sample("samples.collections.Collections.Aggregates.reduce")
returns("S")
body {
fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkIndexOverflow($value)" else value
"""
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var index = 1
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(${checkOverflow("index++")}, accumulator, iterator.next())
}
return accumulator
"""
}
body(ArraysOfObjects) {
"""
if (isEmpty())
throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(index, accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceIndexedOrNull = fn("reduceIndexedOrNull(operation: (index: Int, acc: T, T) -> T)") {
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
} builder {
since("1.4")
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceIndexedOrNull") }
sample("samples.collections.Collections.Aggregates.reduceOrNull")
returns("T?")
body {
"""
if (isEmpty())
return null
var accumulator = this[0]
for (index in 1..lastIndex) {
accumulator = operation(index, accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceIndexedOrNullSuper = fn("reduceIndexedOrNull(operation: (index: Int, acc: S, T) -> S)") {
include(ArraysOfObjects, Iterables, Sequences)
} builder {
since("1.4")
inline()
doc { reduceDoc("reduceIndexedOrNull") }
typeParam("S")
typeParam("T : S")
sample("samples.collections.Collections.Aggregates.reduceOrNull")
returns("S?")
body {
fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkIndexOverflow($value)" else value
"""
val iterator = this.iterator()
if (!iterator.hasNext()) return null
var index = 1
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(${checkOverflow("index++")}, accumulator, iterator.next())
}
return accumulator
"""
}
body(ArraysOfObjects) {
"""
if (isEmpty())
return null
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(index, accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceRightIndexed = fn("reduceRightIndexed(operation: (index: Int, T, acc: T) -> T)") {
include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceRightIndexed") }
sample("samples.collections.Collections.Aggregates.reduceRight")
returns("T")
body {
"""
var index = lastIndex
if (index < 0) throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator = get(index--)
while (index >= 0) {
accumulator = operation(index, get(index), accumulator)
--index
}
return accumulator
"""
}
}
val f_reduceRightIndexedSuper = fn("reduceRightIndexed(operation: (index: Int, T, acc: S) -> S)") {
include(Lists, ArraysOfObjects)
} builder {
inline()
doc { reduceDoc("reduceRightIndexed") }
sample("samples.collections.Collections.Aggregates.reduceRight")
typeParam("S")
typeParam("T : S")
returns("S")
body {
"""
var index = lastIndex
if (index < 0) throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator: S = get(index--)
while (index >= 0) {
accumulator = operation(index, get(index), accumulator)
--index
}
return accumulator
"""
}
body(Lists) {
"""
val iterator = listIterator(size)
if (!iterator.hasPrevious())
throw UnsupportedOperationException("Empty list can't be reduced.")
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
val index = iterator.previousIndex()
accumulator = operation(index, iterator.previous(), accumulator)
}
return accumulator
"""
}
}
val f_reduceRightIndexedOrNull = fn("reduceRightIndexedOrNull(operation: (index: Int, T, acc: T) -> T)") {
include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned)
} builder {
since("1.4")
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceRightIndexedOrNull") }
sample("samples.collections.Collections.Aggregates.reduceRightOrNull")
returns("T?")
body {
"""
var index = lastIndex
if (index < 0) return null
var accumulator = get(index--)
while (index >= 0) {
accumulator = operation(index, get(index), accumulator)
--index
}
return accumulator
"""
}
}
val f_reduceRightIndexedOrNullSuper = fn("reduceRightIndexedOrNull(operation: (index: Int, T, acc: S) -> S)") {
include(Lists, ArraysOfObjects)
} builder {
since("1.4")
inline()
doc { reduceDoc("reduceRightIndexedOrNull") }
sample("samples.collections.Collections.Aggregates.reduceRightOrNull")
typeParam("S")
typeParam("T : S")
returns("S?")
body {
"""
var index = lastIndex
if (index < 0) return null
var accumulator: S = get(index--)
while (index >= 0) {
accumulator = operation(index, get(index), accumulator)
--index
}
return accumulator
"""
}
body(Lists) {
"""
val iterator = listIterator(size)
if (!iterator.hasPrevious())
return null
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
val index = iterator.previousIndex()
accumulator = operation(index, iterator.previous(), accumulator)
}
return accumulator
"""
}
}
val f_reduce = fn("reduce(operation: (acc: T, T) -> T)") {
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduce") }
sample("samples.collections.Collections.Aggregates.reduce")
returns("T")
body {
"""
if (isEmpty())
throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceSuper = fn("reduce(operation: (acc: S, T) -> S)") {
include(ArraysOfObjects, Iterables, Sequences)
} builder {
inline()
doc { reduceDoc("reduce") }
sample("samples.collections.Collections.Aggregates.reduce")
typeParam("S")
typeParam("T : S")
returns("S")
body {
"""
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
"""
}
body(ArraysOfObjects) {
"""
if (isEmpty())
throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceOrNull = fn("reduceOrNull(operation: (acc: T, T) -> T)") {
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
} builder {
since("1.4")
wasExperimental("ExperimentalStdlibApi")
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceOrNull") }
sample("samples.collections.Collections.Aggregates.reduceOrNull")
returns("T?")
body {
"""
if (isEmpty())
return null
var accumulator = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceOrNullSuper = fn("reduceOrNull(operation: (acc: S, T) -> S)") {
include(ArraysOfObjects, Iterables, Sequences)
} builder {
since("1.4")
wasExperimental("ExperimentalStdlibApi")
inline()
doc { reduceDoc("reduceOrNull") }
sample("samples.collections.Collections.Aggregates.reduceOrNull")
typeParam("S")
typeParam("T : S")
returns("S?")
body {
"""
val iterator = this.iterator()
if (!iterator.hasNext()) return null
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
"""
}
body(ArraysOfObjects) {
"""
if (isEmpty())
return null
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
"""
}
}
val f_reduceRight = fn("reduceRight(operation: (T, acc: T) -> T)") {
include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceRight") }
sample("samples.collections.Collections.Aggregates.reduceRight")
returns("T")
body {
"""
var index = lastIndex
if (index < 0) throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator = get(index--)
while (index >= 0) {
accumulator = operation(get(index--), accumulator)
}
return accumulator
"""
}
}
val f_reduceRightSuper = fn("reduceRight(operation: (T, acc: S) -> S)") {
include(Lists, ArraysOfObjects)
} builder {
inline()
doc { reduceDoc("reduceRight") }
sample("samples.collections.Collections.Aggregates.reduceRight")
typeParam("S")
typeParam("T : S")
returns("S")
body {
"""
var index = lastIndex
if (index < 0) throw UnsupportedOperationException("Empty ${f.doc.collection} can't be reduced.")
var accumulator: S = get(index--)
while (index >= 0) {
accumulator = operation(get(index--), accumulator)
}
return accumulator
"""
}
body(Lists) {
"""
val iterator = listIterator(size)
if (!iterator.hasPrevious())
throw UnsupportedOperationException("Empty list can't be reduced.")
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
return accumulator
"""
}
}
val f_reduceRightOrNull = fn("reduceRightOrNull(operation: (T, acc: T) -> T)") {
include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned)
} builder {
since("1.4")
wasExperimental("ExperimentalStdlibApi")
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { reduceDoc("reduceRightOrNull") }
sample("samples.collections.Collections.Aggregates.reduceRightOrNull")
returns("T?")
body {
"""
var index = lastIndex
if (index < 0) return null
var accumulator = get(index--)
while (index >= 0) {
accumulator = operation(get(index--), accumulator)
}
return accumulator
"""
}
}
val f_reduceRightOrNullSuper = fn("reduceRightOrNull(operation: (T, acc: S) -> S)") {
include(Lists, ArraysOfObjects)
} builder {
since("1.4")
wasExperimental("ExperimentalStdlibApi")
inline()
doc { reduceDoc("reduceRightOrNull") }
sample("samples.collections.Collections.Aggregates.reduceRightOrNull")
typeParam("S")
typeParam("T : S")
returns("S?")
body {
"""
var index = lastIndex
if (index < 0) return null
var accumulator: S = get(index--)
while (index >= 0) {
accumulator = operation(get(index--), accumulator)
}
return accumulator
"""
}
body(Lists) {
"""
val iterator = listIterator(size)
if (!iterator.hasPrevious())
return null
var accumulator: S = iterator.previous()
while (iterator.hasPrevious()) {
accumulator = operation(iterator.previous(), accumulator)
}
return accumulator
"""
}
}
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_runningFold = fn("runningFold(initial: R, operation: (acc: R, T) -> R)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
} builder {
since("1.4")
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.runningFold")
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@runningFold) {
accumulator = operation(accumulator, element)
yield(accumulator)
}
}
"""
}
}
val f_scan = fn("scan(initial: R, operation: (acc: R, T) -> R)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
} builder {
since("1.4")
wasExperimental("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 { "return runningFold(initial, operation)" }
}
val f_runningFoldIndexed = fn("runningFoldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
} builder {
since("1.4")
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.runningFold")
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@runningFoldIndexed) {
accumulator = operation(checkIndexOverflow(index++), 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.4")
wasExperimental("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 { "return runningFoldIndexed(initial, operation)" }
}
val f_runningReduce = fn("runningReduce(operation: (acc: T, T) -> T)") {
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
} builder {
since("1.4")
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.runningReduce")
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_runningReduceIndexed = fn("runningReduceIndexed(operation: (index: Int, acc: T, T) -> T)") {
include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences)
} builder {
since("1.4")
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.runningReduce")
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_runningReduceSuper = fn("runningReduce(operation: (acc: S, T) -> S)") {
include(ArraysOfObjects, Iterables, Sequences)
} builder {
since("1.4")
wasExperimental("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.runningReduce")
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_runningReduceIndexedSuper = fn("runningReduceIndexed(operation: (index: Int, acc: S, T) -> S)") {
include(ArraysOfObjects, Iterables, Sequences)
} builder {
since("1.4")
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.runningReduce")
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)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
since("1.1")
doc { "Performs the given [action] on each ${f.element} and returns the ${f.collection} itself afterwards." }
specialFor(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
since("1.4")
inlineOnly()
returns("SELF")
body { "return apply { for (element in this) action(element) }" }
}
specialFor(Iterables, Maps, CharSequences) {
inline()
val collectionType = when (f) {
Maps -> "M"
CharSequences -> "S"
else -> "C"
}
receiver(collectionType)
returns(collectionType)
typeParam("$collectionType : SELF")
body { "return apply { for (element in this) action(element) }" }
}
specialFor(Sequences) {
returns("SELF")
doc { "Returns a sequence which performs the given [action] on each ${f.element} of the original sequence as they pass through it." }
sequenceClassification(intermediate, stateless)
body {
"""
return map {
action(it)
it
}
"""
}
}
}
val f_onEachIndexed = fn("onEachIndexed(action: (index: Int, T) -> Unit)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
since("1.4")
doc {
"""
Performs the given [action] on each ${f.element}, providing sequential index with the ${f.element},
and returns the ${f.collection} itself afterwards.
@param [action] function that takes the index of ${f.element.prefixWithArticle()} and the ${f.element} itself
and performs the action on the ${f.element}.
"""
}
specialFor(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) {
inlineOnly()
returns("SELF")
body { "return apply { forEachIndexed(action) }" }
}
specialFor(Maps, Iterables, CharSequences) {
inline()
val collectionType = when (f) {
Maps -> "M"
CharSequences -> "S"
else -> "C"
}
receiver(collectionType)
returns(collectionType)
typeParam("$collectionType : SELF")
body { "return apply { ${if (f == Maps) "entries." else ""}forEachIndexed(action) }" }
}
specialFor(Sequences) {
returns("SELF")
doc {
"""
Returns a sequence which performs the given [action] on each ${f.element} of the original sequence as they pass through it.
@param [action] function that takes the index of ${f.element.prefixWithArticle()} and the ${f.element} itself
and performs the action on the ${f.element}.
"""
}
sequenceClassification(intermediate, stateless)
body {
"""
return mapIndexed { index, element ->
action(index, element)
element
}
"""
}
}
}
val f_forEach = fn("forEach(action: (T) -> Unit)") {
includeDefault()
include(Maps, CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc { "Performs the given [action] on each ${f.element}." }
specialFor(Iterables, Maps) { annotation("@kotlin.internal.HidesMembers") }
returns("Unit")
body {
"""
for (element in this) action(element)
"""
}
}
val f_forEachIndexed = fn("forEachIndexed(action: (index: Int, T) -> Unit)") {
includeDefault()
include(CharSequences, ArraysOfUnsigned)
} builder {
inline()
specialFor(ArraysOfUnsigned) { inlineOnly() }
doc {
"""
Performs the given [action] on each ${f.element}, providing sequential index with the ${f.element}.
@param [action] function that takes the index of ${f.element.prefixWithArticle()} and the ${f.element} itself
and performs the action on the ${f.element}.
""" }
returns("Unit")
body {
fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkIndexOverflow($value)" else value
"""
var index = 0
for (item in this) action(${checkOverflow("index++")}, item)
"""
}
}
}