From afeb1b2d557f45ec8df3290ae73358cec94f2d04 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Tue, 24 Jan 2017 15:27:08 +0300 Subject: [PATCH] More of stdlib. (#183) --- .../kotlin/backend/konan/descriptors/utils.kt | 2 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 2 + runtime/src/main/cpp/Operator.cpp | 10 +- runtime/src/main/kotlin/konan/Annotations.kt | 25 + runtime/src/main/kotlin/kotlin/Annotations.kt | 3 +- runtime/src/main/kotlin/kotlin/Array.kt | 7 - runtime/src/main/kotlin/kotlin/Arrays.kt | 304 ++- runtime/src/main/kotlin/kotlin/Comparable.kt | 5 + runtime/src/main/kotlin/kotlin/Numbers.kt | 39 + .../kotlin/kotlin/collections/ArrayList.kt | 2 +- .../kotlin/kotlin/collections/Collections.kt | 2125 ++++++++++++++++- .../main/kotlin/kotlin/collections/HashMap.kt | 5 +- .../main/kotlin/kotlin/collections/HashSet.kt | 5 +- .../kotlin/kotlin/collections/IndexedValue.kt | 9 + .../kotlin/kotlin/collections/Iterables.kt | 82 + .../kotlin/kotlin/collections/Iterators.kt | 28 + .../main/kotlin/kotlin/collections/Maps.kt | 73 +- .../kotlin/collections/MutableCollections.kt | 81 +- .../kotlin/kotlin/collections/RandomAccess.kt | 3 + .../kotlin/kotlin/comparisons/Comparisons.kt | 300 +++ .../src/main/kotlin/kotlin/ranges/Ranges.kt | 9 + .../{collections => sequences}/Sequence.kt | 19 + .../main/kotlin/kotlin/sequences/Sequences.kt | 1527 ++++++++++++ .../src/main/kotlin/kotlin/text/Appendable.kt | 7 + .../main/kotlin/kotlin/text/StringBuilder.kt | 12 +- .../main/kotlin/kotlin/util/Preconditions.kt | 98 + 26 files changed, 4613 insertions(+), 169 deletions(-) create mode 100644 runtime/src/main/kotlin/kotlin/Numbers.kt create mode 100644 runtime/src/main/kotlin/kotlin/collections/IndexedValue.kt create mode 100644 runtime/src/main/kotlin/kotlin/collections/Iterables.kt create mode 100644 runtime/src/main/kotlin/kotlin/collections/RandomAccess.kt create mode 100644 runtime/src/main/kotlin/kotlin/comparisons/Comparisons.kt rename runtime/src/main/kotlin/kotlin/{collections => sequences}/Sequence.kt (66%) create mode 100644 runtime/src/main/kotlin/kotlin/sequences/Sequences.kt create mode 100644 runtime/src/main/kotlin/kotlin/text/Appendable.kt create mode 100644 runtime/src/main/kotlin/kotlin/util/Preconditions.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt index 50848338d7e..5ab5c6fbc63 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt @@ -37,5 +37,5 @@ val PropertyDescriptor.backingField: PropertyDescriptor? } fun DeclarationDescriptor.deepPrint() { - this!!.accept(DeepPrintVisitor(PrintVisitor()), 0) + this.accept(DeepPrintVisitor(PrintVisitor()), 0) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 8088e1d225a..dd41c2912aa 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1334,6 +1334,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun genInstanceOf(obj: LLVMValueRef, type: KotlinType): LLVMValueRef { val dstDescriptor = TypeUtils.getClassDescriptor(type) // Get class descriptor for dst type. + // Reified parameters are not yet supported. + assert(dstDescriptor != null) val dstTypeInfo = codegen.typeInfoValue(dstDescriptor!!) // Get TypeInfo for dst type. val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. diff --git a/runtime/src/main/cpp/Operator.cpp b/runtime/src/main/cpp/Operator.cpp index e88bbeb3bba..0408aa043f3 100644 --- a/runtime/src/main/cpp/Operator.cpp +++ b/runtime/src/main/cpp/Operator.cpp @@ -370,7 +370,11 @@ KInt Kotlin_Float_bits (KFloat a) { return alias.i; } -//--- Double ------------------------------------------------------------------// +KBoolean Kotlin_Float_isNaN (KFloat a) { return isnan(a); } +KBoolean Kotlin_Float_isInfinite (KFloat a) { return isinf(a); } +KBoolean Kotlin_Float_isFinite (KFloat a) { return isfinite(a); } + + //--- Double ------------------------------------------------------------------// KInt Kotlin_Double_compareTo_Byte (KDouble a, KByte b) { if (a == b) return 0; return (a < b) ? -1 : 1; } KInt Kotlin_Double_compareTo_Short (KDouble a, KShort b) { if (a == b) return 0; return (a < b) ? -1 : 1; } @@ -435,4 +439,8 @@ KLong Kotlin_Double_bits (KDouble a) { return alias.l; } +KBoolean Kotlin_Double_isNaN (KDouble a) { return isnan(a); } +KBoolean Kotlin_Double_isInfinite (KDouble a) { return isinf(a); } +KBoolean Kotlin_Double_isFinite (KDouble a) { return isfinite(a); } + } // extern "C" diff --git a/runtime/src/main/kotlin/konan/Annotations.kt b/runtime/src/main/kotlin/konan/Annotations.kt index dbd0712ed4f..c83a8807deb 100644 --- a/runtime/src/main/kotlin/konan/Annotations.kt +++ b/runtime/src/main/kotlin/konan/Annotations.kt @@ -31,6 +31,31 @@ public annotation class Used */ public annotation class FixmeInner +/** + * Need to be fixed because of reification support. + */ +public annotation class FixmeReified + +/** + * Need to be fixed because of sorting support. + */ +public annotation class FixmeSorting + +/** + * Need to be fixed because of specialization support. + */ +public annotation class FixmeSpecialization + +/** + * Need to be fixed because of sequences support. + */ +public annotation class FixmeSequences + +/** + * Need to be fixed because of variance support. + */ +public annotation class FixmeVariance + /** * Need to be fixed. */ diff --git a/runtime/src/main/kotlin/kotlin/Annotations.kt b/runtime/src/main/kotlin/kotlin/Annotations.kt index f0419f3ee78..edc4e8af6c4 100644 --- a/runtime/src/main/kotlin/kotlin/Annotations.kt +++ b/runtime/src/main/kotlin/kotlin/Annotations.kt @@ -6,7 +6,8 @@ package kotlin */ //@Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, // CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPE, EXPRESSION, FILE, TYPEALIAS) -@Target(AnnotationTarget.TYPE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) +@Target(AnnotationTarget.TYPE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION, + AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.FUNCTION) //@Retention(SOURCE) public annotation class Suppress(vararg val names: String) diff --git a/runtime/src/main/kotlin/kotlin/Array.kt b/runtime/src/main/kotlin/kotlin/Array.kt index 7b02c11f628..53e5b9d41f9 100644 --- a/runtime/src/main/kotlin/kotlin/Array.kt +++ b/runtime/src/main/kotlin/kotlin/Array.kt @@ -48,13 +48,6 @@ private class IteratorImpl(val collection: Array) : Iterator { fun arrayOf(vararg elements: T) : Array = elements -public fun > Array.toCollection(destination: C): C { - for (item in this) { - destination.add(item) - } - return destination -} - @kotlin.internal.InlineOnly public inline operator fun Array.plus(elements: Array): Array { val result = copyOfUninitializedElements(this.size + elements.size) diff --git a/runtime/src/main/kotlin/kotlin/Arrays.kt b/runtime/src/main/kotlin/kotlin/Arrays.kt index 78e5f6c0bab..182585a5b92 100644 --- a/runtime/src/main/kotlin/kotlin/Arrays.kt +++ b/runtime/src/main/kotlin/kotlin/Arrays.kt @@ -488,14 +488,6 @@ public inline fun Array.lastOrNull(predicate: (T) -> Boolean): T? { return null } -/** - * Returns `true` if the array is empty. - */ -@kotlin.internal.InlineOnly -public inline fun Array.isEmpty(): Boolean { - return size == 0 -} - /** * Returns the range of valid indices for the array. */ @@ -592,4 +584,300 @@ public fun Array.sum(): Double { return sum } +// From _Arrays.kt. +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun Array.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun ByteArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun ShortArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun IntArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun LongArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun FloatArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun DoubleArray.isEmpty(): Boolean { + return size == 0 +} +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun BooleanArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is empty. + */ +@kotlin.internal.InlineOnly +public inline fun CharArray.isEmpty(): Boolean { + return size == 0 +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun Array.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun ByteArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun ShortArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun IntArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun LongArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun FloatArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun DoubleArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun BooleanArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Returns `true` if the array is not empty. + */ +@kotlin.internal.InlineOnly +public inline fun CharArray.isNotEmpty(): Boolean { + return !isEmpty() +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > Array.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > ByteArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > ShortArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > IntArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > LongArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > FloatArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > DoubleArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > BooleanArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > CharArray.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun Array.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun ByteArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun ShortArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun IntArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun LongArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun FloatArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun DoubleArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun BooleanArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun CharArray.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(size))) +} diff --git a/runtime/src/main/kotlin/kotlin/Comparable.kt b/runtime/src/main/kotlin/kotlin/Comparable.kt index ea286e91e02..9ef2491dc2b 100644 --- a/runtime/src/main/kotlin/kotlin/Comparable.kt +++ b/runtime/src/main/kotlin/kotlin/Comparable.kt @@ -1,5 +1,7 @@ package kotlin +import kotlin.comparisons.Comparator + /** * Classes which inherit from this interface have a defined total ordering between their instances. */ @@ -11,3 +13,6 @@ public interface Comparable { */ public operator fun compareTo(other: T): Int } + +typealias Comparator = kotlin.comparisons.Comparator + diff --git a/runtime/src/main/kotlin/kotlin/Numbers.kt b/runtime/src/main/kotlin/kotlin/Numbers.kt new file mode 100644 index 00000000000..3d0e5f8b6bd --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/Numbers.kt @@ -0,0 +1,39 @@ +package kotlin + +/** + * Returns `true` if the specified number is a + * Not-a-Number (NaN) value, `false` otherwise. + */ +@SymbolName("Kotlin_Double_isNaN") +external public fun Double.isNaN(): Boolean + +/** + * Returns `true` if the specified number is a + * Not-a-Number (NaN) value, `false` otherwise. + */ +@SymbolName("Kotlin_Float_isNaN") +external public fun Float.isNaN(): Boolean + +/** + * Returns `true` if this value is infinitely large in magnitude. + */ +@SymbolName("Kotlin_Double_isInfinite") +external public fun Double.isInfinite(): Boolean + +/** + * Returns `true` if this value is infinitely large in magnitude. + */ +@SymbolName("Kotlin_Float_isInfinite") +external public fun Float.isInfinite(): Boolean + +/** + * Returns `true` if the argument is a finite floating-point value; returns `false` otherwise (for `NaN` and infinity arguments). + */ +@SymbolName("Kotlin_Double_isFinite") +external public fun Double.isFinite(): Boolean + +/** + * Returns `true` if the argument is a finite floating-point value; returns `false` otherwise (for `NaN` and infinity arguments). + */ +@SymbolName("Kotlin_Float_isFinite") +external public fun Float.isFinite(): Boolean diff --git a/runtime/src/main/kotlin/kotlin/collections/ArrayList.kt b/runtime/src/main/kotlin/kotlin/collections/ArrayList.kt index f97e037b53b..c8cfb957108 100644 --- a/runtime/src/main/kotlin/kotlin/collections/ArrayList.kt +++ b/runtime/src/main/kotlin/kotlin/collections/ArrayList.kt @@ -5,7 +5,7 @@ class ArrayList private constructor( private var offset: Int, private var length: Int, private val backing: ArrayList? -) : MutableList { +) : MutableList, RandomAccess { constructor() : this(10) diff --git a/runtime/src/main/kotlin/kotlin/collections/Collections.kt b/runtime/src/main/kotlin/kotlin/collections/Collections.kt index 783add20e8c..99740b8cd25 100644 --- a/runtime/src/main/kotlin/kotlin/collections/Collections.kt +++ b/runtime/src/main/kotlin/kotlin/collections/Collections.kt @@ -1,5 +1,7 @@ package kotlin.collections +import kotlin.comparisons.* + internal object EmptyIterator : ListIterator { override fun hasNext(): Boolean = false override fun hasPrevious(): Boolean = false @@ -115,7 +117,7 @@ public inline fun <@kotlin.internal.OnlyInputTypes T> Collection.containsAll( // copies typed varargs array to array of objects // TODO: generally wrong, wrt specialization. -@Fixme +@FixmeSpecialization private fun Array.copyToArrayOfAny(isVarargs: Boolean): Array = if (isVarargs) // if the array came from varargs and already is array of Any, copying isn't required. @@ -147,61 +149,8 @@ public interface MutableIterable : Iterable { override fun iterator(): MutableIterator } -/** - * Returns `true` if all elements match the given [predicate]. - */ -public inline fun Iterable.all(predicate: (T) -> Boolean): Boolean { - for (element in this) if (!predicate(element)) return false - return true -} - -/** - * Returns `true` if collection has at least one element. - */ -public fun Iterable.any(): Boolean { - for (element in this) return true - return false -} - -/** - * Returns `true` if at least one element matches the given [predicate]. - */ -public inline fun Iterable.any(predicate: (T) -> Boolean): Boolean { - for (element in this) if (predicate(element)) return true - return false -} - -/** - * Returns a list containing all elements not matching the given [predicate]. - */ -public inline fun Iterable.filterNot(predicate: (T) -> Boolean): List { - return filterNotTo(ArrayList(), predicate) -} - -/** - * Returns a list containing all elements that are not `null`. - */ -public fun Iterable.filterNotNull(): List { - return filterNotNullTo(ArrayList()) -} - -/** - * Appends all elements that are not `null` to the given [destination]. - */ -public fun , T : Any> Iterable.filterNotNullTo(destination: C): C { - for (element in this) if (element != null) destination.add(element) - return destination -} - -/** - * Appends all elements not matching the given [predicate] to the given [destination]. - */ -public inline fun > Iterable.filterNotTo(destination: C, predicate: (T) -> Boolean): C { - for (element in this) if (!predicate(element)) destination.add(element) - return destination -} - +@Fixme fun Array.asList(): List { // TODO: consider making lighter list over an array. val result = ArrayList(this.size) @@ -230,6 +179,7 @@ fun Array.toSet(): Set { return result } +@FixmeVariance public fun > Iterable.toCollection(destination: C): C { for (item in this) { destination.add(item) @@ -237,7 +187,260 @@ public fun > Iterable.toCollection(destina return destination } +@Fixme +internal fun List.optimizeReadOnlyList() = this + // From generated _Collections.kt. +///////// + +/** + * Returns 1st *element* from the collection. + */ +@kotlin.internal.InlineOnly +public inline operator fun List.component1(): T { + return get(0) +} + +/** + * Returns 2nd *element* from the collection. + */ +@kotlin.internal.InlineOnly +public inline operator fun List.component2(): T { + return get(1) +} + +/** + * Returns 3rd *element* from the collection. + */ +@kotlin.internal.InlineOnly +public inline operator fun List.component3(): T { + return get(2) +} + +/** + * Returns 4th *element* from the collection. + */ +@kotlin.internal.InlineOnly +public inline operator fun List.component4(): T { + return get(3) +} + +/** + * Returns 5th *element* from the collection. + */ +@kotlin.internal.InlineOnly +public inline operator fun List.component5(): T { + return get(4) +} + +/** + * Returns `true` if [element] is found in the collection. + */ +public operator fun <@kotlin.internal.OnlyInputTypes T> Iterable.contains(element: T): Boolean { + if (this is Collection) + return contains(element) + return indexOf(element) >= 0 +} + +/** + * Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this collection. + */ +public fun Iterable.elementAt(index: Int): T { + if (this is List) + return get(index) + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Collection doesn't contain element at index $index.") } +} + +/** + * Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this list. + */ +@kotlin.internal.InlineOnly +public inline fun List.elementAt(index: Int): T { + return get(index) +} + +/** + * Returns an element at the given [index] or the result of calling the [defaultValue] function if the [index] is out of bounds of this collection. + */ +public fun Iterable.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + if (this is List) + return this.getOrElse(index, defaultValue) + if (index < 0) + return defaultValue(index) + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return defaultValue(index) +} + +/** + * Returns an element at the given [index] or the result of calling the [defaultValue] function if the [index] is out of bounds of this list. + */ +@kotlin.internal.InlineOnly +public inline fun List.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns an element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun Iterable.elementAtOrNull(index: Int): T? { + if (this is List) + return this.getOrNull(index) + if (index < 0) + return null + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null +} + +/** + * Returns an element at the given [index] or `null` if the [index] is out of bounds of this list. + */ +@kotlin.internal.InlineOnly +public inline fun List.elementAtOrNull(index: Int): T? { + return this.getOrNull(index) +} + +/** + * Returns the first element matching the given [predicate], or `null` if no such element was found. + */ +@kotlin.internal.InlineOnly +public inline fun Iterable.find(predicate: (T) -> Boolean): T? { + return firstOrNull(predicate) +} + +/** + * Returns the last element matching the given [predicate], or `null` if no such element was found. + */ +@kotlin.internal.InlineOnly +public inline fun Iterable.findLast(predicate: (T) -> Boolean): T? { + return lastOrNull(predicate) +} + +/** + * Returns the last element matching the given [predicate], or `null` if no such element was found. + */ +@kotlin.internal.InlineOnly +public inline fun List.findLast(predicate: (T) -> Boolean): T? { + return lastOrNull(predicate) +} + +/** + * Returns first element. + * @throws [NoSuchElementException] if the collection is empty. + */ +public fun Iterable.first(): T { + when (this) { + is List -> return this.first() + else -> { + val iterator = iterator() + if (!iterator.hasNext()) + throw NoSuchElementException("Collection is empty.") + return iterator.next() + } + } +} + +/** + * Returns first element. + * @throws [NoSuchElementException] if the list is empty. + */ +public fun List.first(): T { + if (isEmpty()) + throw NoSuchElementException("List is empty.") + return this[0] +} + +/** + * Returns the first element matching the given [predicate]. + * @throws [NoSuchElementException] if no such element is found. + */ +public inline fun Iterable.first(predicate: (T) -> Boolean): T { + for (element in this) if (predicate(element)) return element + throw NoSuchElementException("Collection contains no element matching the predicate.") +} + +/** + * Returns the first element, or `null` if the collection is empty. + */ +public fun Iterable.firstOrNull(): T? { + when (this) { + is List -> { + if (isEmpty()) + return null + else + return this[0] + } + else -> { + val iterator = iterator() + if (!iterator.hasNext()) + return null + return iterator.next() + } + } +} + +/** + * Returns the first element, or `null` if the list is empty. + */ +public fun List.firstOrNull(): T? { + return if (isEmpty()) null else this[0] +} + +/** + * Returns the first element matching the given [predicate], or `null` if element was not found. + */ +public inline fun Iterable.firstOrNull(predicate: (T) -> Boolean): T? { + for (element in this) if (predicate(element)) return element + return null +} + +/** + * Returns an element at the given [index] or the result of calling the [defaultValue] function if the [index] is out of bounds of this list. + */ +@kotlin.internal.InlineOnly +public inline fun List.getOrElse(index: Int, defaultValue: (Int) -> T): T { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns an element at the given [index] or `null` if the [index] is out of bounds of this list. + */ +public fun List.getOrNull(index: Int): T? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns first index of [element], or -1 if the collection does not contain element. + */ +public fun <@kotlin.internal.OnlyInputTypes T> Iterable.indexOf(element: T): Int { + if (this is List) return this.indexOf(element) + var index = 0 + for (item in this) { + if (element == item) + return index + index++ + } + return -1 +} + +/** + * Returns first index of [element], or -1 if the list does not contain element. + */ +public fun <@kotlin.internal.OnlyInputTypes T> List.indexOf(element: T): Int { + return indexOf(element) +} + /** * Returns index of the first element matching the given [predicate], or -1 if the collection does not contain such element. */ @@ -290,3 +493,1815 @@ public inline fun List.indexOfLast(predicate: (T) -> Boolean): Int { } return -1 } + +/** + * Returns the last element. + * @throws [NoSuchElementException] if the collection is empty. + */ +public fun Iterable.last(): T { + when (this) { + is List -> return this.last() + else -> { + val iterator = iterator() + if (!iterator.hasNext()) + throw NoSuchElementException("Collection is empty.") + var last = iterator.next() + while (iterator.hasNext()) + last = iterator.next() + return last + } + } +} + +/** + * Returns the last element. + * @throws [NoSuchElementException] if the list is empty. + */ +public fun List.last(): T { + if (isEmpty()) + throw NoSuchElementException("List is empty.") + return this[lastIndex] +} + +/** + * Returns the last element matching the given [predicate]. + * @throws [NoSuchElementException] if no such element is found. + */ +public inline fun Iterable.last(predicate: (T) -> Boolean): T { + var last: T? = null + var found = false + for (element in this) { + if (predicate(element)) { + last = element + found = true + } + } + if (!found) throw NoSuchElementException("Collection contains no element matching the predicate.") + return last as T +} + +/** + * Returns the last element matching the given [predicate]. + * @throws [NoSuchElementException] if no such element is found. + */ +public inline fun List.last(predicate: (T) -> Boolean): T { + val iterator = this.listIterator(size) + while (iterator.hasPrevious()) { + val element = iterator.previous() + if (predicate(element)) return element + } + throw NoSuchElementException("List contains no element matching the predicate.") +} + +/** + * Returns last index of [element], or -1 if the collection does not contain element. + */ +public fun <@kotlin.internal.OnlyInputTypes T> Iterable.lastIndexOf(element: T): Int { + if (this is List) return this.lastIndexOf(element) + var lastIndex = -1 + var index = 0 + for (item in this) { + if (element == item) + lastIndex = index + index++ + } + return lastIndex +} + +/** + * Returns last index of [element], or -1 if the list does not contain element. + */ +public fun <@kotlin.internal.OnlyInputTypes T> List.lastIndexOf(element: T): Int { + return lastIndexOf(element) +} + +/** + * Returns the last element, or `null` if the collection is empty. + */ +public fun Iterable.lastOrNull(): T? { + when (this) { + is List -> return if (isEmpty()) null else this[size - 1] + else -> { + val iterator = iterator() + if (!iterator.hasNext()) + return null + var last = iterator.next() + while (iterator.hasNext()) + last = iterator.next() + return last + } + } +} + +/** + * Returns the last element, or `null` if the list is empty. + */ +public fun List.lastOrNull(): T? { + return if (isEmpty()) null else this[size - 1] +} + +/** + * Returns the last element matching the given [predicate], or `null` if no such element was found. + */ +public inline fun Iterable.lastOrNull(predicate: (T) -> Boolean): T? { + var last: T? = null + for (element in this) { + if (predicate(element)) { + last = element + } + } + return last +} + +/** + * Returns the last element matching the given [predicate], or `null` if no such element was found. + */ +public inline fun List.lastOrNull(predicate: (T) -> Boolean): T? { + val iterator = this.listIterator(size) + while (iterator.hasPrevious()) { + val element = iterator.previous() + if (predicate(element)) return element + } + return null +} + +/** + * Returns the single element, or throws an exception if the collection is empty or has more than one element. + */ +public fun Iterable.single(): T { + when (this) { + is List -> return this.single() + else -> { + val iterator = iterator() + if (!iterator.hasNext()) + throw NoSuchElementException("Collection is empty.") + val single = iterator.next() + if (iterator.hasNext()) + throw IllegalArgumentException("Collection has more than one element.") + return single + } + } +} + +/** + * Returns the single element, or throws an exception if the list is empty or has more than one element. + */ +public fun List.single(): T { + return when (size) { + 0 -> throw NoSuchElementException("List is empty.") + 1 -> this[0] + else -> throw IllegalArgumentException("List has more than one element.") + } +} + +/** + * Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element. + */ +public inline fun Iterable.single(predicate: (T) -> Boolean): T { + var single: T? = null + var found = false + for (element in this) { + if (predicate(element)) { + if (found) throw IllegalArgumentException("Collection contains more than one matching element.") + single = element + found = true + } + } + if (!found) throw NoSuchElementException("Collection contains no element matching the predicate.") + return single as T +} + +/** + * Returns single element, or `null` if the collection is empty or has more than one element. + */ +public fun Iterable.singleOrNull(): T? { + when (this) { + is List -> return if (size == 1) this[0] else null + else -> { + val iterator = iterator() + if (!iterator.hasNext()) + return null + val single = iterator.next() + if (iterator.hasNext()) + return null + return single + } + } +} + +/** + * Returns single element, or `null` if the list is empty or has more than one element. + */ +public fun List.singleOrNull(): T? { + return if (size == 1) this[0] else null +} + +/** + * Returns the single element matching the given [predicate], or `null` if element was not found or more than one element was found. + */ +public inline fun Iterable.singleOrNull(predicate: (T) -> Boolean): T? { + var single: T? = null + var found = false + for (element in this) { + if (predicate(element)) { + if (found) return null + single = element + found = true + } + } + if (!found) return null + return single +} + +/** + * Returns a list containing all elements except first [n] elements. + */ +public fun Iterable.drop(n: Int): List { + require(n >= 0) { "Requested element count $n is less than zero." } + if (n == 0) return toList() + val list: ArrayList + if (this is Collection<*>) { + val resultSize = size - n + if (resultSize <= 0) + return emptyList() + if (resultSize == 1) + return listOf(last()) + list = ArrayList(resultSize) + if (this is List) { + if (this is RandomAccess) { + for (index in n..size - 1) + list.add(this[index]) + } else { + for (item in this.listIterator(n)) + list.add(item) + } + return list + } + } + else { + list = ArrayList() + } + var count = 0 + for (item in this) { + if (count++ >= n) list.add(item) + } + return list.optimizeReadOnlyList() +} + +/** + * Returns a list containing all elements except last [n] elements. + */ +public fun List.dropLast(n: Int): List { + require(n >= 0) { "Requested element count $n is less than zero." } + return take((size - n).coerceAtLeast(0)) +} + +/** + * Returns a list containing all elements except last elements that satisfy the given [predicate]. + */ +public inline fun List.dropLastWhile(predicate: (T) -> Boolean): List { + if (!isEmpty()) { + val iterator = this.listIterator(size) + while (iterator.hasPrevious()) { + if (!predicate(iterator.previous())) { + return take(iterator.nextIndex() + 1) + } + } + } + return emptyList() +} + +/** + * Returns a list containing all elements except first elements that satisfy the given [predicate]. + */ +public inline fun Iterable.dropWhile(predicate: (T) -> Boolean): List { + var yielding = false + val list = ArrayList() + for (item in this) + if (yielding) + list.add(item) + else if (!predicate(item)) { + list.add(item) + yielding = true + } + return list +} + +/** + * Returns a list containing only elements matching the given [predicate]. + */ +public inline fun Iterable.filter(predicate: (T) -> Boolean): List { + return filterTo(ArrayList(), predicate) +} + +/** + * Returns a list containing only elements matching the given [predicate]. + * @param [predicate] function that takes the index of an element and the element itself + * and returns the result of predicate evaluation on the element. + */ +public inline fun Iterable.filterIndexed(predicate: (Int, T) -> Boolean): List { + return filterIndexedTo(ArrayList(), predicate) +} + +/** + * Appends all elements matching the given [predicate] to the given [destination]. + * @param [predicate] function that takes the index of an element and the element itself + * and returns the result of predicate evaluation on the element. + */ +public inline fun > Iterable.filterIndexedTo(destination: C, predicate: (Int, T) -> Boolean): C { + forEachIndexed { index, element -> + if (predicate(index, element)) destination.add(element) + } + return destination +} + +/** + * Returns a list containing all elements that are instances of specified type parameter R. + */ +/* +@FixmeReified +public inline fun Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer R> { + return filterIsInstanceTo(ArrayList()) +} + +/** + * Appends all elements that are instances of specified type parameter R to the given [destination]. + */ +public inline fun > Iterable<*>.filterIsInstanceTo(destination: C): C { + for (element in this) if (element is R) destination.add(element) + return destination +} +*/ + +/** + * Returns a list containing all elements not matching the given [predicate]. + */ +public inline fun Iterable.filterNot(predicate: (T) -> Boolean): List { + return filterNotTo(ArrayList(), predicate) +} + +/** + * Returns a list containing all elements that are not `null`. + */ +public fun Iterable.filterNotNull(): List { + return filterNotNullTo(ArrayList()) +} + +/** + * Appends all elements that are not `null` to the given [destination]. + */ +public fun , T : Any> Iterable.filterNotNullTo(destination: C): C { + for (element in this) if (element != null) destination.add(element) + return destination +} + +/** + * Appends all elements not matching the given [predicate] to the given [destination]. + */ +public inline fun > Iterable.filterNotTo(destination: C, predicate: (T) -> Boolean): C { + for (element in this) if (!predicate(element)) destination.add(element) + return destination +} + +/** + * Appends all elements matching the given [predicate] to the given [destination]. + */ +public inline fun > Iterable.filterTo(destination: C, predicate: (T) -> Boolean): C { + for (element in this) if (predicate(element)) destination.add(element) + return destination +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun List.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return this.subList(indices.start, indices.endInclusive + 1).toList() +} + +/** + * Returns a list containing elements at specified [indices]. + */ +public fun List.slice(indices: Iterable): List { + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return emptyList() + val list = ArrayList(size) + for (index in indices) { + list.add(get(index)) + } + return list +} + +/** + * Returns a list containing first [n] elements. + */ +public fun Iterable.take(n: Int): List { + require(n >= 0) { "Requested element count $n is less than zero." } + if (n == 0) return emptyList() + if (this is Collection) { + if (n >= size) return toList() + if (n == 1) return listOf(first()) + } + var count = 0 + val list = ArrayList(n) + for (item in this) { + if (count++ == n) + break + list.add(item) + } + return list.optimizeReadOnlyList() +} + +/** + * Returns a list containing last [n] elements. + */ +public fun List.takeLast(n: Int): List { + require(n >= 0) { "Requested element count $n is less than zero." } + if (n == 0) return emptyList() + val size = size + if (n >= size) return toList() + if (n == 1) return listOf(last()) + val list = ArrayList(n) + if (this is RandomAccess) { + for (index in size - n .. size - 1) + list.add(this[index]) + } else { + for (item in this.listIterator(n)) + list.add(item) + } + return list +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun List.takeLastWhile(predicate: (T) -> Boolean): List { + if (isEmpty()) + return emptyList() + val iterator = this.listIterator(size) + while (iterator.hasPrevious()) { + if (!predicate(iterator.previous())) { + iterator.next() + val expectedSize = size - iterator.nextIndex() + if (expectedSize == 0) return emptyList() + return ArrayList(expectedSize).apply { + while (iterator.hasNext()) + add(iterator.next()) + } + } + } + return toList() +} + +/** + * Returns a list containing first elements satisfying the given [predicate]. + */ +public inline fun Iterable.takeWhile(predicate: (T) -> Boolean): List { + val list = ArrayList() + for (item in this) { + if (!predicate(item)) + break + list.add(item) + } + return list +} + +/** + * Reverses elements in the list in-place. + */ +@Fixme +public fun MutableList.reverse(): Unit { + //java.util.Collections.reverse(this) + TODO() +} + +/** + * Returns a list with elements in reversed order. + */ +public fun Iterable.reversed(): List { + if (this is Collection && size <= 1) return toList() + val list = toMutableList() + list.reverse() + return list +} + +/** + * Sorts elements in the list in-place according to natural sort order of the value returned by specified [selector] function. + */ +public inline fun > MutableList.sortBy(crossinline selector: (T) -> R?): Unit { + if (size > 1) sortWith(compareBy(selector)) +} + +/** + * Sorts elements in the list in-place descending according to natural sort order of the value returned by specified [selector] function. + */ +public inline fun > MutableList.sortByDescending(crossinline selector: (T) -> R?): Unit { + if (size > 1) sortWith(compareByDescending(selector)) +} + +/** + * Sorts elements in the list in-place descending according to their natural sort order. + */ +public fun > MutableList.sortDescending(): Unit { + sortWith(reverseOrder()) +} + +/** + * Returns a list of all elements sorted according to their natural sort order. + */ +@FixmeSorting +public fun > Iterable.sorted(): List { + TODO() + //if (this is Collection) { + // if (size <= 1) return this.toList() + // @Suppress("UNCHECKED_CAST") + // return (toTypedArray>() as Array).apply { sort() }.asList() + //} + //return toMutableList().apply { sort() } +} + +/** + * Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function. + */ +public inline fun > Iterable.sortedBy(crossinline selector: (T) -> R?): List { + return sortedWith(compareBy(selector)) +} + +/** + * Returns a list of all elements sorted descending according to natural sort order of the value returned by specified [selector] function. + */ +public inline fun > Iterable.sortedByDescending(crossinline selector: (T) -> R?): List { + return sortedWith(compareByDescending(selector)) +} + +/** + * Returns a list of all elements sorted descending according to their natural sort order. + */ +public fun > Iterable.sortedDescending(): List { + return sortedWith(reverseOrder()) +} + +/** + * Returns a list of all elements sorted according to the specified [comparator]. + */ +@FixmeSorting +public fun Iterable.sortedWith(comparator: Comparator): List { + TODO() + //if (this is Collection) { + // if (size <= 1) return this.toList() + // @Suppress("UNCHECKED_CAST") + // return (toTypedArray() as Array).apply { sortWith(comparator) }.asList() + //} + //return toMutableList().apply { sortWith(comparator) } +} + +/** + * Returns an array of Boolean containing all of the elements of this collection. + */ +public fun Collection.toBooleanArray(): BooleanArray { + val result = BooleanArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Byte containing all of the elements of this collection. + */ +public fun Collection.toByteArray(): ByteArray { + val result = ByteArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Char containing all of the elements of this collection. + */ +public fun Collection.toCharArray(): CharArray { + val result = CharArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Double containing all of the elements of this collection. + */ +public fun Collection.toDoubleArray(): DoubleArray { + val result = DoubleArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Float containing all of the elements of this collection. + */ +public fun Collection.toFloatArray(): FloatArray { + val result = FloatArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Int containing all of the elements of this collection. + */ +public fun Collection.toIntArray(): IntArray { + val result = IntArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Long containing all of the elements of this collection. + */ +public fun Collection.toLongArray(): LongArray { + val result = LongArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns an array of Short containing all of the elements of this collection. + */ +public fun Collection.toShortArray(): ShortArray { + val result = ShortArray(size) + var index = 0 + for (element in this) + result[index++] = element + return result +} + +/** + * Returns a [Map] containing key-value pairs provided by [transform] function + * applied to elements of the given collection. + * + * If any of two pairs would have the same key the last one gets added to the map. + * + * The returned map preserves the entry iteration order of the original collection. + */ +public inline fun Iterable.associate(transform: (T) -> Pair): Map { + val capacity = @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16) + return associateTo(LinkedHashMap(capacity), transform) +} + +/** + * Returns a [Map] containing the elements from the given collection indexed by the key + * returned from [keySelector] function applied to each element. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + * + * The returned map preserves the entry iteration order of the original collection. + */ +public inline fun Iterable.associateBy(keySelector: (T) -> K): Map { + val capacity = @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16) + return associateByTo(LinkedHashMap(capacity), keySelector) +} + +/** + * Returns a [Map] containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to elements of the given collection. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + * + * The returned map preserves the entry iteration order of the original collection. + */ +public inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map { + val capacity = @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16) + return associateByTo(LinkedHashMap(capacity), keySelector, valueTransform) +} + +/** + * Populates and returns the [destination] mutable map with key-value pairs, + * where key is provided by the [keySelector] function applied to each element of the given collection + * and value is the element itself. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + */ +public inline fun > Iterable.associateByTo(destination: M, keySelector: (T) -> K): M { + for (element in this) { + destination.put(keySelector(element), element) + } + return destination +} + +/** + * Populates and returns the [destination] mutable map with key-value pairs, + * where key is provided by the [keySelector] function and + * and value is provided by the [valueTransform] function applied to elements of the given collection. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + */ +public inline fun > Iterable.associateByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { + for (element in this) { + destination.put(keySelector(element), valueTransform(element)) + } + return destination +} + +/** + * Populates and returns the [destination] mutable map with key-value pairs + * provided by [transform] function applied to each element of the given collection. + * + * If any of two pairs would have the same key the last one gets added to the map. + */ +public inline fun > Iterable.associateTo(destination: M, transform: (T) -> Pair): M { + for (element in this) { + destination += transform(element) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > Iterable.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun Iterable.toHashSet(): HashSet { + return toCollection(HashSet(mapCapacity(collectionSizeOrDefault(12)))) +} + +/** + * Returns a [List] containing all elements. + */ +public fun Iterable.toList(): List { + if (this is Collection) { + return when (size) { + 0 -> emptyList() + 1 -> listOf(if (this is List) get(0) else iterator().next()) + else -> this.toMutableList() + } + } + return this.toMutableList().optimizeReadOnlyList() +} + +/** + * Returns a [MutableList] filled with all elements of this collection. + */ +public fun Iterable.toMutableList(): MutableList { + if (this is Collection) + return this.toMutableList() + return toCollection(ArrayList()) +} + +/** + * Returns a [MutableList] filled with all elements of this collection. + */ +public fun Collection.toMutableList(): MutableList { + return ArrayList(this) +} + +/** + * Returns a [Set] of all elements. + * + * The returned set preserves the element iteration order of the original collection. + */ +public fun Iterable.toSet(): Set { + if (this is Collection) { + return when (size) { + 0 -> emptySet() + 1 -> setOf(if (this is List) this[0] else iterator().next()) + else -> toCollection(LinkedHashSet(mapCapacity(size))) + } + } + return toCollection(LinkedHashSet()).optimizeReadOnlySet() +} + +/** + * Returns a [SortedSet] of all elements. + */ +//public fun > Iterable.toSortedSet(): SortedSet { +// return toCollection(TreeSet()) +//} + +/** + * Returns a [SortedSet] of all elements. + * + * Elements in the set returned are sorted according to the given [comparator]. + */ +//public fun Iterable.toSortedSet(comparator: Comparator): SortedSet { +// return toCollection(TreeSet(comparator)) +//} + +/** + * Returns a single list of all elements yielded from results of [transform] function being invoked on each element of original collection. + */ +public inline fun Iterable.flatMap(transform: (T) -> Iterable): List { + return flatMapTo(ArrayList(), transform) +} + +/** + * Appends all elements yielded from results of [transform] function being invoked on each element of original collection, to the given [destination]. + */ +public inline fun > Iterable.flatMapTo(destination: C, transform: (T) -> Iterable): C { + for (element in this) { + val list = transform(element) + destination.addAll(list) + } + return destination +} + +/** + * Groups elements of the original collection by the key returned by the given [keySelector] function + * applied to each element and returns a map where each group key is associated with a list of corresponding elements. + * + * The returned map preserves the entry iteration order of the keys produced from the original collection. + * + * @sample samples.collections.Collections.Transformations.groupBy + */ +public inline fun Iterable.groupBy(keySelector: (T) -> K): Map> { + return groupByTo(LinkedHashMap>(), keySelector) +} + +/** + * Groups values returned by the [valueTransform] function applied to each element of the original collection + * by the key returned by the given [keySelector] function applied to the element + * and returns a map where each group key is associated with a list of corresponding values. + * + * The returned map preserves the entry iteration order of the keys produced from the original collection. + * + * @sample samples.collections.Collections.Transformations.groupByKeysAndValues + */ +public inline fun Iterable.groupBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map> { + return groupByTo(LinkedHashMap>(), keySelector, valueTransform) +} + +/** + * Groups elements of the original collection by the key returned by the given [keySelector] function + * applied to each element and puts to the [destination] map each group key associated with a list of corresponding elements. + * + * @return The [destination] map. + * + * @sample samples.collections.Collections.Transformations.groupBy + */ +public inline fun >> Iterable.groupByTo(destination: M, keySelector: (T) -> K): M { + for (element in this) { + val key = keySelector(element) + val list = destination.getOrPut(key) { ArrayList() } + list.add(element) + } + return destination +} + +/** + * Groups values returned by the [valueTransform] function applied to each element of the original collection + * by the key returned by the given [keySelector] function applied to the element + * and puts to the [destination] map each group key associated with a list of corresponding values. + * + * @return The [destination] map. + * + * @sample samples.collections.Collections.Transformations.groupByKeysAndValues + */ +public inline fun >> Iterable.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { + for (element in this) { + val key = keySelector(element) + val list = destination.getOrPut(key) { ArrayList() } + list.add(valueTransform(element)) + } + return destination +} + +/** + * Returns a list containing the results of applying the given [transform] function + * to each element in the original collection. + */ +public inline fun Iterable.map(transform: (T) -> R): List { + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + return mapTo(ArrayList(collectionSizeOrDefault(10)), transform) +} + +/** + * Returns a list containing the results of applying the given [transform] function + * to each element and its index in the original collection. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +public inline fun Iterable.mapIndexed(transform: (Int, T) -> R): List { + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + return mapIndexedTo(ArrayList(collectionSizeOrDefault(10)), transform) +} + +/** + * Returns a list containing only the non-null results of applying the given [transform] function + * to each element and its index in the original collection. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +public inline fun Iterable.mapIndexedNotNull(transform: (Int, T) -> R?): List { + return mapIndexedNotNullTo(ArrayList(), transform) +} + +/** + * Applies the given [transform] function to each element and its index in the original collection + * and appends only the non-null results to the given [destination]. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +public inline fun > Iterable.mapIndexedNotNullTo(destination: C, transform: (Int, T) -> R?): C { + forEachIndexed { index, element -> transform(index, element)?.let { destination.add(it) } } + return destination +} + +/** + * Applies the given [transform] function to each element and its index in the original collection + * and appends the results to the given [destination]. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +public inline fun > Iterable.mapIndexedTo(destination: C, transform: (Int, T) -> R): C { + var index = 0 + for (item in this) + destination.add(transform(index++, item)) + return destination +} + +/** + * Returns a list containing only the non-null results of applying the given [transform] function + * to each element in the original collection. + */ +public inline fun Iterable.mapNotNull(transform: (T) -> R?): List { + return mapNotNullTo(ArrayList(), transform) +} + +/** + * Applies the given [transform] function to each element in the original collection + * and appends only the non-null results to the given [destination]. + */ +public inline fun > Iterable.mapNotNullTo(destination: C, transform: (T) -> R?): C { + forEach { element -> transform(element)?.let { destination.add(it) } } + return destination +} + +/** + * Applies the given [transform] function to each element of the original collection + * and appends the results to the given [destination]. + */ +public inline fun > Iterable.mapTo(destination: C, transform: (T) -> R): C { + for (item in this) + destination.add(transform(item)) + return destination +} + +/** + * Returns a lazy [Iterable] of [IndexedValue] for each element of the original collection. + */ +public fun Iterable.withIndex(): Iterable> { + return IndexingIterable { iterator() } +} + +/** + * Returns a list containing only distinct elements from the given collection. + * + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public fun Iterable.distinct(): List { + return this.toMutableSet().toList() +} + +/** + * Returns a list containing only elements from the given collection + * having distinct keys returned by the given [selector] function. + * + * The elements in the resulting list are in the same order as they were in the source collection. + */ +public inline fun Iterable.distinctBy(selector: (T) -> K): List { + val set = HashSet() + val list = ArrayList() + for (e in this) { + val key = selector(e) + if (set.add(key)) + list.add(e) + } + return list +} + +/** + * Returns a set containing all elements that are contained by both this set and the specified collection. + * + * The returned set preserves the element iteration order of the original collection. + */ +public infix fun Iterable.intersect(other: Iterable): Set { + val set = this.toMutableSet() + set.retainAll(other) + return set +} + +/** + * Returns a set containing all elements that are contained by this collection and not contained by the specified collection. + * + * The returned set preserves the element iteration order of the original collection. + */ +public infix fun Iterable.subtract(other: Iterable): Set { + val set = this.toMutableSet() + set.removeAll(other) + return set +} + +/** + * Returns a mutable set containing all distinct elements from the given collection. + * + * The returned set preserves the element iteration order of the original collection. + */ +public fun Iterable.toMutableSet(): MutableSet { + return when (this) { + is Collection -> LinkedHashSet(this) + else -> toCollection(LinkedHashSet()) + } +} + +/** + * Returns a set containing all distinct elements from both collections. + * + * The returned set preserves the element iteration order of the original collection. + * Those elements of the [other] collection that are unique are iterated in the end + * in the order of the [other] collection. + */ +public infix fun Iterable.union(other: Iterable): Set { + val set = this.toMutableSet() + set.addAll(other) + return set +} + +/** + * Returns `true` if all elements match the given [predicate]. + */ +public inline fun Iterable.all(predicate: (T) -> Boolean): Boolean { + for (element in this) if (!predicate(element)) return false + return true +} + +/** + * Returns `true` if collection has at least one element. + */ +public fun Iterable.any(): Boolean { + for (element in this) return true + return false +} + +/** + * Returns `true` if at least one element matches the given [predicate]. + */ +public inline fun Iterable.any(predicate: (T) -> Boolean): Boolean { + for (element in this) if (predicate(element)) return true + return false +} + +/** + * Returns the number of elements in this collection. + */ +public fun Iterable.count(): Int { + var count = 0 + for (element in this) count++ + return count +} + +/** + * Returns the number of elements in this collection. + */ +@kotlin.internal.InlineOnly +public inline fun Collection.count(): Int { + return size +} + +/** + * Returns the number of elements matching the given [predicate]. + */ +public inline fun Iterable.count(predicate: (T) -> Boolean): Int { + var count = 0 + for (element in this) if (predicate(element)) count++ + return count +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element. + */ +public inline fun Iterable.fold(initial: R, operation: (R, T) -> R): R { + var accumulator = initial + for (element in this) accumulator = operation(accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original collection. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + */ +public inline fun Iterable.foldIndexed(initial: R, operation: (Int, R, T) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. + */ +public inline fun List.foldRight(initial: R, operation: (T, R) -> R): R { + var accumulator = initial + if (!isEmpty()) { + val iterator = this.listIterator(size) + while (iterator.hasPrevious()) { + accumulator = operation(iterator.previous(), accumulator) + } + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original list and current accumulator value. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + */ +public inline fun List.foldRightIndexed(initial: R, operation: (Int, T, R) -> R): R { + var accumulator = initial + if (!isEmpty()) { + val iterator = this.listIterator(size) + while (iterator.hasPrevious()) { + val index = iterator.previousIndex() + accumulator = operation(index, iterator.previous(), accumulator) + } + } + return accumulator +} + +/** + * Performs the given [action] on each element. + */ +@kotlin.internal.HidesMembers +public inline fun Iterable.forEach(action: (T) -> Unit): Unit { + for (element in this) action(element) +} + +/** + * Performs the given [action] on each element, providing sequential index with the element. + * @param [action] function that takes the index of an element and the element itself + * and performs the desired action on the element. + */ +public inline fun Iterable.forEachIndexed(action: (Int, T) -> Unit): Unit { + var index = 0 + for (item in this) action(index++, item) +} + +/** + * Returns the largest element or `null` if there are no elements. + */ +public fun > Iterable.max(): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var max = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (max < e) max = e + } + return max +} + +/** + * Returns the first element yielding the largest value of the given function or `null` if there are no elements. + */ +public inline fun > Iterable.maxBy(selector: (T) -> R): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var maxElem = iterator.next() + var maxValue = selector(maxElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = selector(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + +/** + * Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements. + */ +public fun Iterable.maxWith(comparator: Comparator): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var max = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (comparator.compare(max, e) < 0) max = e + } + return max +} + +/** + * Returns the smallest element or `null` if there are no elements. + */ +public fun > Iterable.min(): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var min = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (min > e) min = e + } + return min +} + +/** + * Returns the first element yielding the smallest value of the given function or `null` if there are no elements. + */ +public inline fun > Iterable.minBy(selector: (T) -> R): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var minElem = iterator.next() + var minValue = selector(minElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = selector(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + +/** + * Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements. + */ +public fun Iterable.minWith(comparator: Comparator): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var min = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (comparator.compare(min, e) > 0) min = e + } + return min +} + +/** + * Returns `true` if the collection has no elements. + */ +public fun Iterable.none(): Boolean { + for (element in this) return false + return true +} + +/** + * Returns `true` if no elements match the given [predicate]. + */ +public inline fun Iterable.none(predicate: (T) -> Boolean): Boolean { + for (element in this) if (predicate(element)) return false + return true +} + +/** + * Performs the given [action] on each element and returns the collection itself afterwards. + */ +@SinceKotlin("1.1") +public inline fun > C.onEach(action: (T) -> Unit): C { + return apply { for (element in this) action(element) } +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. + */ +public inline fun Iterable.reduce(operation: (S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.") + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original collection. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself and calculates the next accumulator value. + */ +public inline fun Iterable.reduceIndexed(operation: (Int, S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.") + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value. + */ +public inline fun List.reduceRight(operation: (T, S) -> S): S { + 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 +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original list and current accumulator value. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + */ +public inline fun List.reduceRightIndexed(operation: (Int, T, S) -> S): S { + val iterator = this.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 +} + +/** + * Returns the sum of all values produced by [selector] function applied to each element in the collection. + */ +public inline fun Iterable.sumBy(selector: (T) -> Int): Int { + var sum: Int = 0 + for (element in this) { + sum += selector(element) + } + return sum +} + +/** + * Returns the sum of all values produced by [selector] function applied to each element in the collection. + */ +public inline fun Iterable.sumByDouble(selector: (T) -> Double): Double { + var sum: Double = 0.0 + for (element in this) { + sum += selector(element) + } + return sum +} + +/** + * Returns an original collection containing all the non-`null` elements, throwing an [IllegalArgumentException] if there are any `null` elements. + */ +public fun Iterable.requireNoNulls(): Iterable { + for (element in this) { + if (element == null) { + throw IllegalArgumentException("null element found in $this.") + } + } + @Suppress("UNCHECKED_CAST") + return this as Iterable +} + +/** + * Returns an original collection containing all the non-`null` elements, throwing an [IllegalArgumentException] if there are any `null` elements. + */ +public fun List.requireNoNulls(): List { + for (element in this) { + if (element == null) { + throw IllegalArgumentException("null element found in $this.") + } + } + @Suppress("UNCHECKED_CAST") + return this as List +} + +/** + * Returns a list containing all elements of the original collection without the first occurrence of the given [element]. + */ +public operator fun Iterable.minus(element: T): List { + val result = ArrayList(collectionSizeOrDefault(10)) + var removed = false + return this.filterTo(result) { if (!removed && it == element) { removed = true; false } else true } +} + +/** + * Returns a list containing all elements of the original collection except the elements contained in the given [elements] array. + */ +public operator fun Iterable.minus(elements: Array): List { + if (elements.isEmpty()) return this.toList() + val other = elements.toHashSet() + return this.filterNot { it in other } +} + +/** + * Returns a list containing all elements of the original collection except the elements contained in the given [elements] collection. + */ +public operator fun Iterable.minus(elements: Iterable): List { + val other = elements.convertToSetForSetOperationWith(this) + if (other.isEmpty()) + return this.toList() + return this.filterNot { it in other } +} + +/** + * Returns a list containing all elements of the original collection except the elements contained in the given [elements] sequence. + */ +public operator fun Iterable.minus(elements: Sequence): List { + val other = elements.toHashSet() + if (other.isEmpty()) + return this.toList() + return this.filterNot { it in other } +} + +/** + * Returns a list containing all elements of the original collection without the first occurrence of the given [element]. + */ +@kotlin.internal.InlineOnly +public inline fun Iterable.minusElement(element: T): List { + return minus(element) +} + +/** + * Splits the original collection into pair of lists, + * where *first* list contains elements for which [predicate] yielded `true`, + * while *second* list contains elements for which [predicate] yielded `false`. + */ +public inline fun Iterable.partition(predicate: (T) -> Boolean): Pair, List> { + val first = ArrayList() + val second = ArrayList() + for (element in this) { + if (predicate(element)) { + first.add(element) + } else { + second.add(element) + } + } + return Pair(first, second) +} + +/** + * Returns a list containing all elements of the original collection and then the given [element]. + */ +public operator fun Iterable.plus(element: T): List { + if (this is Collection) return this.plus(element) + val result = ArrayList() + result.addAll(this) + result.add(element) + return result +} + +/** + * Returns a list containing all elements of the original collection and then the given [element]. + */ +public operator fun Collection.plus(element: T): List { + val result = ArrayList(size + 1) + result.addAll(this) + result.add(element) + return result +} + +/** + * Returns a list containing all elements of the original collection and then all elements of the given [elements] array. + */ +public operator fun Iterable.plus(elements: Array): List { + if (this is Collection) return this.plus(elements) + val result = ArrayList() + result.addAll(this) + result.addAll(elements) + return result +} + +/** + * Returns a list containing all elements of the original collection and then all elements of the given [elements] array. + */ +public operator fun Collection.plus(elements: Array): List { + val result = ArrayList(this.size + elements.size) + result.addAll(this) + result.addAll(elements) + return result +} + +/** + * Returns a list containing all elements of the original collection and then all elements of the given [elements] collection. + */ +public operator fun Iterable.plus(elements: Iterable): List { + if (this is Collection) return this.plus(elements) + val result = ArrayList() + result.addAll(this) + result.addAll(elements) + return result +} + +/** + * Returns a list containing all elements of the original collection and then all elements of the given [elements] collection. + */ +public operator fun Collection.plus(elements: Iterable): List { + if (elements is Collection) { + val result = ArrayList(this.size + elements.size) + result.addAll(this) + result.addAll(elements) + return result + } else { + val result = ArrayList(this) + result.addAll(elements) + return result + } +} + +/** + * Returns a list containing all elements of the original collection and then all elements of the given [elements] sequence. + */ +public operator fun Iterable.plus(elements: Sequence): List { + val result = ArrayList() + result.addAll(this) + result.addAll(elements) + return result +} + +/** + * Returns a list containing all elements of the original collection and then all elements of the given [elements] sequence. + */ +public operator fun Collection.plus(elements: Sequence): List { + val result = ArrayList(this.size + 10) + result.addAll(this) + result.addAll(elements) + return result +} + +/** + * Returns a list containing all elements of the original collection and then the given [element]. + */ +@kotlin.internal.InlineOnly +public inline fun Iterable.plusElement(element: T): List { + return plus(element) +} + +/** + * Returns a list containing all elements of the original collection and then the given [element]. + */ +@kotlin.internal.InlineOnly +public inline fun Collection.plusElement(element: T): List { + return plus(element) +} + +/** + * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. + */ +public infix fun Iterable.zip(other: Array): List> { + return zip(other) { t1, t2 -> t1 to t2 } +} + +inline fun min(x1: Int, x2: Int) = if (x1 < x2) x1 else x2 + +/** + * 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.zip(other: Array, transform: (T, R) -> V): List { + val arraySize = other.size + val list = ArrayList(min(collectionSizeOrDefault(10), arraySize)) + var i = 0 + for (element in this) { + if (i >= arraySize) break + list.add(transform(element, other[i++])) + } + return list +} + +/** + * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. + */ +public infix fun Iterable.zip(other: Iterable): List> { + return zip(other) { t1, t2 -> t1 to t2 } +} + +/** + * 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.zip(other: Iterable, transform: (T, R) -> V): List { + val first = iterator() + val second = other.iterator() + val list = ArrayList(min(collectionSizeOrDefault(10), other.collectionSizeOrDefault(10))) + while (first.hasNext() && second.hasNext()) { + list.add(transform(first.next(), second.next())) + } + return list +} + +/** + * Appends the string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied. + * + * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit] + * elements will be appended, followed by the [truncated] string (which defaults to "..."). + */ +public fun Iterable.joinTo(buffer: A, separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): A { + buffer.append(prefix) + var count = 0 + for (element in this) { + if (++count > 1) buffer.append(separator) + if (limit < 0 || count <= limit) { + if (transform != null) + buffer.append(transform(element)) + else + buffer.append(if (element == null) "null" else element.toString()) + } else break + } + if (limit >= 0 && count > limit) buffer.append(truncated) + buffer.append(postfix) + return buffer +} + +/** + * Creates a string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied. + * + * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit] + * elements will be appended, followed by the [truncated] string (which defaults to "..."). + */ +public fun Iterable.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { + return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString() +} + +/** + * Returns this collection as an [Iterable]. + */ +@kotlin.internal.InlineOnly +public inline fun Iterable.asIterable(): Iterable { + return this +} + +/** + * Creates a [Sequence] instance that wraps the original collection returning its elements when being iterated. + */ +@FixmeSequences +public fun Iterable.asSequence(): Sequence { + //return Sequence { this.iterator() } + TODO() +} + +/** + * Returns a list containing all elements that are instances of specified class. + */ +//public fun Iterable<*>.filterIsInstance(klass: Class): List { +// return filterIsInstanceTo(ArrayList(), klass) +//} + +/** + * Returns an average value of elements in the collection. + */ +public fun Iterable.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the collection. + */ +public fun Iterable.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the collection. + */ +public fun Iterable.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the collection. + */ +public fun Iterable.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the collection. + */ +public fun Iterable.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the collection. + */ +public fun Iterable.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns the sum of all elements in the collection. + */ +public fun Iterable.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the collection. + */ +public fun Iterable.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the collection. + */ +public fun Iterable.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the collection. + */ +public fun Iterable.sum(): Long { + var sum: Long = 0L + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the collection. + */ +public fun Iterable.sum(): Float { + var sum: Float = 0.0f + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the collection. + */ +public fun Iterable.sum(): Double { + var sum: Double = 0.0 + for (element in this) { + sum += element + } + return sum +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/collections/HashMap.kt b/runtime/src/main/kotlin/kotlin/collections/HashMap.kt index 46d155a9752..a91e9a29281 100644 --- a/runtime/src/main/kotlin/kotlin/collections/HashMap.kt +++ b/runtime/src/main/kotlin/kotlin/collections/HashMap.kt @@ -670,4 +670,7 @@ internal class HashMapEntrySet internal constructor( @Suppress("UNCHECKED_CAST") // todo: get rid of unchecked cast here somehow return size == other.size && backing.containsAllEntries(other as Collection>) } -} \ No newline at end of file +} + +// This hash map keeps insertion order. +typealias LinkedHashMap = HashMap \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/collections/HashSet.kt b/runtime/src/main/kotlin/kotlin/collections/HashSet.kt index 90b326ae970..faa477b5e7a 100644 --- a/runtime/src/main/kotlin/kotlin/collections/HashSet.kt +++ b/runtime/src/main/kotlin/kotlin/collections/HashSet.kt @@ -82,4 +82,7 @@ class HashSet internal constructor( // ---------------------------- private ---------------------------- private fun contentEquals(other: Set): Boolean = size == other.size && containsAll(other) -} \ No newline at end of file +} + +// This hash set keeps insertion order. +typealias LinkedHashSet = HashSet \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/collections/IndexedValue.kt b/runtime/src/main/kotlin/kotlin/collections/IndexedValue.kt new file mode 100644 index 00000000000..7259c82a2b4 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/collections/IndexedValue.kt @@ -0,0 +1,9 @@ +package kotlin.collections + +/** + * Data class representing a value from a collection or sequence, along with its index in that collection or sequence. + * + * @property value the underlying value. + * @property index the index of the value in the collection or sequence. + */ +public data class IndexedValue(public val index: Int, public val value: T) diff --git a/runtime/src/main/kotlin/kotlin/collections/Iterables.kt b/runtime/src/main/kotlin/kotlin/collections/Iterables.kt new file mode 100644 index 00000000000..5cc6005f25a --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/collections/Iterables.kt @@ -0,0 +1,82 @@ +package kotlin.collections + +/** + * Given an [iterator] function constructs an [Iterable] instance that returns values through the [Iterator] + * provided by that function. + */ +@kotlin.internal.InlineOnly +public inline fun Iterable(crossinline iterator: () -> Iterator): Iterable = object : Iterable { + override fun iterator(): Iterator = iterator() +} + +/** + * A wrapper over another [Iterable] (or any other object that can produce an [Iterator]) that returns + * an indexing iterator. + */ +internal class IndexingIterable(private val iteratorFactory: () -> Iterator) : Iterable> { + override fun iterator(): Iterator> = IndexingIterator(iteratorFactory()) +} + + +/** + * Returns the size of this iterable if it is known, or `null` otherwise. + */ +@PublishedApi +internal fun Iterable.collectionSizeOrNull(): Int? = if (this is Collection<*>) this.size else null + +/** + * Returns the size of this iterable if it is known, or the specified [default] value otherwise. + */ +@PublishedApi +internal fun Iterable.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) this.size else default + +/** Returns true when it's safe to convert this collection to a set without changing contains method behavior. */ +private fun Collection.safeToConvertToSet() = size > 2 && this is ArrayList + +/** Converts this collection to a set, when it's worth so and it doesn't change contains method behavior. */ +internal fun Iterable.convertToSetForSetOperationWith(source: Iterable): Collection = + when(this) { + is Set -> this + is Collection -> + when { + source is Collection && source.size < 2 -> this + else -> if (this.safeToConvertToSet()) toHashSet() else this + } + else -> toHashSet() + } + +/** Converts this collection to a set, when it's worth so and it doesn't change contains method behavior. */ +internal fun Iterable.convertToSetForSetOperation(): Collection = + when(this) { + is Set -> this + is Collection -> if (this.safeToConvertToSet()) toHashSet() else this + else -> toHashSet() + } + + +/** + * Returns a single list of all elements from all collections in the given collection. + */ +public fun Iterable>.flatten(): List { + val result = ArrayList() + for (element in this) { + result.addAll(element) + } + return result +} + +/** + * Returns a pair of lists, where + * *first* list is built from the first values of each pair from this collection, + * *second* list is built from the second values of each pair from this collection. + */ +public fun Iterable>.unzip(): Pair, List> { + val expectedSize = collectionSizeOrDefault(10) + val listT = ArrayList(expectedSize) + val listR = ArrayList(expectedSize) + for (pair in this) { + listT.add(pair.first) + listR.add(pair.second) + } + return listT to listR +} diff --git a/runtime/src/main/kotlin/kotlin/collections/Iterators.kt b/runtime/src/main/kotlin/kotlin/collections/Iterators.kt index 286b4fabab5..dbf0c4d7aeb 100644 --- a/runtime/src/main/kotlin/kotlin/collections/Iterators.kt +++ b/runtime/src/main/kotlin/kotlin/collections/Iterators.kt @@ -63,3 +63,31 @@ public abstract class BooleanIterator : Iterator { /** Returns the next value in the sequence without boxing. */ public abstract fun nextBoolean(): Boolean } + +/** + * Returns the given iterator itself. This allows to use an instance of iterator in a `for` loop. + */ +@kotlin.internal.InlineOnly +public inline operator fun Iterator.iterator(): Iterator = this + +/** + * Returns an [Iterator] wrapping each value produced by this [Iterator] with the [IndexedValue], + * containing value and it's index. + */ +public fun Iterator.withIndex(): Iterator> = IndexingIterator(this) + +/** + * Performs the given [operation] on each element of this [Iterator]. + */ +public inline fun Iterator.forEach(operation: (T) -> Unit) : Unit { + for (element in this) operation(element) +} + +/** + * Iterator transforming original `iterator` into iterator of [IndexedValue], counting index from zero. + */ +internal class IndexingIterator(private val iterator: Iterator) : Iterator> { + private var index = 0 + final override fun hasNext(): Boolean = iterator.hasNext() + final override fun next(): IndexedValue = IndexedValue(index++, iterator.next()) +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/collections/Maps.kt b/runtime/src/main/kotlin/kotlin/collections/Maps.kt index 20272206cc3..86f9f3ad9c2 100644 --- a/runtime/src/main/kotlin/kotlin/collections/Maps.kt +++ b/runtime/src/main/kotlin/kotlin/collections/Maps.kt @@ -97,8 +97,7 @@ internal fun mapCapacity(expectedSize: Int): Int { return Int.MAX_VALUE // any large value } -@Fixme -private const val INT_MAX_POWER_OF_TWO: Int = 0x40000000 // Int.MAX_VALUE / 2 + 1 +private const val INT_MAX_POWER_OF_TWO: Int = Int.MAX_VALUE / 2 + 1 /** Returns `true` if this map is not empty. */ @kotlin.internal.InlineOnly @@ -192,19 +191,14 @@ public inline fun Map.Entry.toPair(): Pair = Pair(key, value) public inline fun Map.getOrElse(key: K, defaultValue: () -> V): V = get(key) ?: defaultValue() -@Fixme internal inline fun Map.getOrElseNullable(key: K, defaultValue: () -> V): V { - TODO() + val value = get(key) + if (value == null && !containsKey(key)) { + return defaultValue() + } else { + return value as V + } } -// val value = get(key) -// if (value == null && !containsKey(key)) { -// return defaultValue() -// } else { -// return value as V -// } -//} - - /** * Returns the value for the given key. If the key is not found in the map, calls the [defaultValue] function, @@ -242,11 +236,9 @@ public inline operator fun MutableMap.iterator(): MutableIterator> Map.mapValuesTo(destination: M, transform: (Map.Entry) -> R): M { - TODO() -// return entries.associateByTo(destination, { it.key }, transform) + return entries.associateByTo(destination, { it.key }, transform) } /** @@ -258,8 +250,7 @@ public inline fun > Map.mapValuesT */ @kotlin.internal.InlineOnly public inline fun > Map.mapKeysTo(destination: M, transform: (Map.Entry) -> R): M { - TODO() -// return entries.associateByTo(destination, transform, { it.value }) + return entries.associateByTo(destination, transform, { it.value }) } /** @@ -297,9 +288,12 @@ public fun MutableMap.putAll(pairs: Sequence>): Uni * * @sample samples.collections.Maps.Transforms.mapValues */ -//public inline fun Map.mapValues(transform: (Map.Entry) -> R): Map { -// return mapValuesTo(HashMap(mapCapacity(size)), transform) // .optimizeReadOnlyMap() -//} +public inline fun Map.mapValues(transform: (Map.Entry) -> R): Map { + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + return mapValuesTo(HashMap( + mapCapacity(size)), + transform).optimizeReadOnlyMap() +} /** * Returns a new Map with entries having the keys obtained by applying the [transform] function to each entry in this @@ -312,9 +306,12 @@ public fun MutableMap.putAll(pairs: Sequence>): Uni * * @sample samples.collections.Maps.Transforms.mapKeys */ -//public inline fun Map.mapKeys(transform: (Map.Entry) -> R): Map { -// return mapKeysTo(HashMap(mapCapacity(size)), transform) // .optimizeReadOnlyMap() -//} +public inline fun Map.mapKeys(transform: (Map.Entry) -> R): Map { + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") + return mapKeysTo(HashMap( + mapCapacity(size)), + transform).optimizeReadOnlyMap() +} /** * Returns a map containing all key-value pairs with keys matching the given [predicate]. @@ -412,6 +409,7 @@ public fun Iterable>.toMap(): Map { /** * Populates and returns the [destination] mutable map with key-value pairs from the given collection of pairs. */ +@Fixme public fun > Iterable>.toMap(destination: M): M { for (pair in this) { destination.put(pair.first, pair.second) @@ -434,6 +432,7 @@ public fun Array>.toMap(): Map = when(size) { /** * Populates and returns the [destination] mutable map with key-value pairs from the given array of pairs. */ +@Fixme public fun > Array>.toMap(destination: M): M { // = destination.apply { putAll(this@toMap) } for (pair in this) { @@ -452,6 +451,7 @@ public fun Sequence>.toMap(): Map = toMap(HashMap( /** * Populates and returns the [destination] mutable map with key-value pairs from the given sequence of pairs. */ +@Fixme public fun > Sequence>.toMap(destination: M): M { for (pair in this) { destination.put(pair.first, pair.second) @@ -484,15 +484,15 @@ public fun Map.toMutableMap(): MutableMap = HashMap(t public fun > Map.toMap(destination: M): M = destination.apply { putAll(this@toMap) } -// TODO: fix me, once have correct type variance in HashMap. /** * Creates a new read-only map by replacing or adding an entry to this map from a given key-value [pair]. * * The returned map preserves the entry iteration order of the original map. * The [pair] is iterated in the end if it has a unique key. */ -// public operator fun Map.plus(pair: Pair): Map -// = if (this.isEmpty()) mapOf(pair) else HashMap(this).apply { put(pair.first, pair.second) } +@FixmeVariance +public operator fun Map.plus(pair: Pair): Map + = if (this.isEmpty()) mapOf(pair) else HashMap(this).apply { put(pair.first, pair.second) } /** * Creates a new read-only map by replacing or adding entries to this map from a given collection of key-value [pairs]. @@ -500,8 +500,9 @@ public fun > Map.toMap(destination: M * The returned map preserves the entry iteration order of the original map. * Those [pairs] with unique keys are iterated in the end in the order of [pairs] collection. */ -//public operator fun Map.plus(pairs: Iterable>): Map -// = if (this.isEmpty()) pairs.toMap() else HashMap(this).apply { putAll(pairs) } +@FixmeVariance +public operator fun Map.plus(pairs: Iterable>): Map + = if (this.isEmpty()) pairs.toMap() else HashMap(this).apply { putAll(pairs) } /** * Creates a new read-only map by replacing or adding entries to this map from a given array of key-value [pairs]. @@ -509,8 +510,9 @@ public fun > Map.toMap(destination: M * The returned map preserves the entry iteration order of the original map. * Those [pairs] with unique keys are iterated in the end in the order of [pairs] array. */ -//public operator fun Map.plus(pairs: Array>): Map -// = if (this.isEmpty()) pairs.toMap() else HashMap(this).apply { putAll(pairs) } +@FixmeVariance +public operator fun Map.plus(pairs: Array>): Map + = if (this.isEmpty()) pairs.toMap() else HashMap(this).apply { putAll(pairs) } /** * Creates a new read-only map by replacing or adding entries to this map from a given sequence of key-value [pairs]. @@ -518,8 +520,8 @@ public fun > Map.toMap(destination: M * The returned map preserves the entry iteration order of the original map. * Those [pairs] with unique keys are iterated in the end in the order of [pairs] sequence. */ -//public operator fun Map.plus(pairs: Sequence>): Map -// = HashMap(this).apply { putAll(pairs) }.optimizeReadOnlyMap() +public operator fun Map.plus(pairs: Sequence>): Map + = HashMap(this).apply { putAll(pairs) }.optimizeReadOnlyMap() /** * Creates a new read-only map by replacing or adding entries to this map from another [map]. @@ -527,8 +529,9 @@ public fun > Map.toMap(destination: M * The returned map preserves the entry iteration order of the original map. * Those entries of another [map] that are missing in this map are iterated in the end in the order of that [map]. */ -//public operator fun Map.plus(map: Map): Map -// = HashMap(this).apply { putAll(map) } +@FixmeVariance +public operator fun Map.plus(map: Map): Map + = HashMap(this).apply { putAll(map) } /** * Appends or replaces the given [pair] in this mutable map. diff --git a/runtime/src/main/kotlin/kotlin/collections/MutableCollections.kt b/runtime/src/main/kotlin/kotlin/collections/MutableCollections.kt index 1713e0e769b..4a934ea582e 100644 --- a/runtime/src/main/kotlin/kotlin/collections/MutableCollections.kt +++ b/runtime/src/main/kotlin/kotlin/collections/MutableCollections.kt @@ -1,5 +1,7 @@ package kotlin.collections +import kotlin.comparisons.* + /** * Removes a single instance of the specified element from this * collection, if it is present. @@ -171,11 +173,7 @@ public fun MutableList.removeAll(predicate: (T) -> Boolean): Boolean = fi */ public fun MutableList.retainAll(predicate: (T) -> Boolean): Boolean = filterInPlace(predicate, false) -@Fixme private fun MutableList.filterInPlace(predicate: (T) -> Boolean, predicateResultToRemove: Boolean): Boolean { - TODO() -} -/* TODO: fix downTo, RandomAccess if (this !is RandomAccess) return (this as MutableIterable).filterInPlace(predicate, predicateResultToRemove) @@ -199,97 +197,68 @@ private fun MutableList.filterInPlace(predicate: (T) -> Boolean, predicat else { return false } -} */ +} /** * Removes all elements from this [MutableCollection] that are also contained in the given [elements] collection. */ -@Fixme public fun MutableCollection.removeAll(elements: Iterable): Boolean { - // TODO: add convertToSetForSetOperationWith - // return removeAll(elements.convertToSetForSetOperationWith(this)) - var removed = false - for (e in elements) { - removed = removed or remove(e) - } - return removed + return removeAll(elements.convertToSetForSetOperationWith(this)) } /** * Removes all elements from this [MutableCollection] that are also contained in the given [elements] sequence. */ -@Fixme public fun MutableCollection.removeAll(elements: Sequence): Boolean { - // TODO: add toHashSet() - //val set = elements.toHashSet() - // return set.isNotEmpty() && removeAll(set) - var removed = false - for (e in elements) { - removed = removed or remove(e) - } - return removed + val set = elements.toHashSet() + return set.isNotEmpty() && removeAll(set) } /** * Removes all elements from this [MutableCollection] that are also contained in the given [elements] array. */ -@Fixme public fun MutableCollection.removeAll(elements: Array): Boolean { - // TODO: add toHashSet() - // return elements.isNotEmpty() && removeAll(elements.toHashSet()) - var removed = false - for (e in elements) { - removed = removed or remove(e) - } - return removed + return elements.isNotEmpty() && removeAll(elements.toHashSet()) } /** * Retains only elements of this [MutableCollection] that are contained in the given [elements] collection. */ -@Fixme public fun MutableCollection.retainAll(elements: Iterable): Boolean { - TODO() - //return retainAll(elements.convertToSetForSetOperationWith(this)) + return retainAll(elements.convertToSetForSetOperationWith(this)) } /** * Retains only elements of this [MutableCollection] that are contained in the given [elements] array. */ -@Fixme public fun MutableCollection.retainAll(elements: Array): Boolean { - TODO() - //if (elements.isNotEmpty()) - // return retainAll(elements.toHashSet()) - //else - // return retainNothing() + if (elements.isNotEmpty()) + return retainAll(elements.toHashSet()) + else + return retainNothing() } /** * Retains only elements of this [MutableCollection] that are contained in the given [elements] sequence. */ -@Fixme public fun MutableCollection.retainAll(elements: Sequence): Boolean { - TODO() - //val set = elements.toHashSet() - //if (set.isNotEmpty()) - // return retainAll(set) - //else - // return retainNothing() + val set = elements.toHashSet() + if (set.isNotEmpty()) + return retainAll(set) + else + return retainNothing() } -@Fixme private fun MutableCollection<*>.retainNothing(): Boolean { - TODO() - //val result = isNotEmpty() - //clear() - //return result + val result = isNotEmpty() + clear() + return result } /** * Sorts elements in the list in-place according to their natural sort order. */ -@Fixme +@FixmeSorting public fun > MutableList.sort(): Unit { TODO() //if (size > 1) java.util.Collections.sort(this) @@ -298,6 +267,8 @@ public fun > MutableList.sort(): Unit { /** * Sorts elements in the list in-place according to the order specified with [comparator]. */ -//public fun MutableList.sortWith(comparator: Comparator): Unit { -//if (size > 1) java.util.Collections.sort(this, comparator) -//} +@FixmeSorting +public fun MutableList.sortWith(comparator: Comparator): Unit { + TODO() + //if (size > 1) java.util.Collections.sort(this, comparator) +} diff --git a/runtime/src/main/kotlin/kotlin/collections/RandomAccess.kt b/runtime/src/main/kotlin/kotlin/collections/RandomAccess.kt new file mode 100644 index 00000000000..78bb8027619 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/collections/RandomAccess.kt @@ -0,0 +1,3 @@ +package kotlin.collections + +public interface RandomAccess diff --git a/runtime/src/main/kotlin/kotlin/comparisons/Comparisons.kt b/runtime/src/main/kotlin/kotlin/comparisons/Comparisons.kt new file mode 100644 index 00000000000..7611c0b2448 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/comparisons/Comparisons.kt @@ -0,0 +1,300 @@ +package kotlin.comparisons + +interface Comparator { + fun compare(a: T, b: T): Int +} + +/** + * Compares two values using the specified functions [selectors] to calculate the result of the comparison. + * The functions are called sequentially, receive the given values [a] and [b] and return [Comparable] + * objects. As soon as the [Comparable] instances returned by a function for [a] and [b] values do not + * compare as equal, the result of that comparison is returned. + */ +public fun compareValuesBy(a: T, b: T, vararg selectors: (T) -> Comparable<*>?): Int { + require(selectors.size > 0) + for (fn in selectors) { + val v1 = fn(a) + val v2 = fn(b) + val diff = compareValues(v1, v2) + if (diff != 0) return diff + } + return 0 +} + +/** + * Compares two values using the specified [selector] function to calculate the result of the comparison. + * The function is applied to the given values [a] and [b] and return [Comparable] objects. + * The result of comparison of these [Comparable] instances is returned. + */ +@kotlin.internal.InlineOnly +public inline fun compareValuesBy(a: T, b: T, selector: (T) -> Comparable<*>?): Int { + return compareValues(selector(a), selector(b)) +} + +/** + * Compares two values using the specified [selector] function to calculate the result of the comparison. + * The function is applied to the given values [a] and [b] and return objects of type K which are then being + * compared with the given [comparator]. + */ +@kotlin.internal.InlineOnly +public inline fun compareValuesBy(a: T, b: T, comparator: Comparator, selector: (T) -> K): Int { + return comparator.compare(selector(a), selector(b)) +} + +//// Not so useful without type inference for receiver of expression +//// compareValuesWith(v1, v2, compareBy { it.prop1 } thenByDescending { it.prop2 }) +///** +// * Compares two values using the specified [comparator]. +// */ +//@Suppress("NOTHING_TO_INLINE") +//public inline fun compareValuesWith(a: T, b: T, comparator: Comparator): Int = comparator.compare(a, b) +// + + +/** + * Compares two nullable [Comparable] values. Null is considered less than any value. + */ +public fun > compareValues(a: T?, b: T?): Int { + if (a === b) return 0 + if (a == null) return -1 + if (b == null) return 1 + + @Suppress("UNCHECKED_CAST") + return (a as Comparable).compareTo(b) +} + +/** + * Creates a comparator using the sequence of functions to calculate a result of comparison. + * The functions are called sequentially, receive the given values `a` and `b` and return [Comparable] + * objects. As soon as the [Comparable] instances returned by a function for `a` and `b` values do not + * compare as equal, the result of that comparison is returned from the [Comparator]. + */ +public fun compareBy(vararg selectors: (T) -> Comparable<*>?): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int = compareValuesBy(a, b, *selectors) + } +} + + + +/** + * Creates a comparator using the function to transform value to a [Comparable] instance for comparison. + */ +@kotlin.internal.InlineOnly +public inline fun compareBy(crossinline selector: (T) -> Comparable<*>?): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int = compareValuesBy(a, b, selector) + } +} + +/** + * Creates a comparator using the [selector] function to transform values being compared and then applying + * the specified [comparator] to compare transformed values. + */ +@kotlin.internal.InlineOnly +public inline fun compareBy(comparator: Comparator, crossinline selector: (T) -> K): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int = compareValuesBy(a, b, comparator, selector) + } +} + +/** + * Creates a descending comparator using the function to transform value to a [Comparable] instance for comparison. + */ +@kotlin.internal.InlineOnly +public inline fun compareByDescending(crossinline selector: (T) -> Comparable<*>?): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int = compareValuesBy(b, a, selector) + } +} + +/** + * Creates a descending comparator using the [selector] function to transform values being compared and then applying + * the specified [comparator] to compare transformed values. + * + * Note that an order of [comparator] is reversed by this wrapper. + */ +@kotlin.internal.InlineOnly +public inline fun compareByDescending(comparator: Comparator, crossinline selector: (T) -> K): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int = compareValuesBy(b, a, comparator, selector) + } +} + +/** + * Creates a comparator comparing values after the primary comparator defined them equal. It uses + * the function to transform value to a [Comparable] instance for comparison. + */ +@kotlin.internal.InlineOnly +public inline fun Comparator.thenBy(crossinline selector: (T) -> Comparable<*>?): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@thenBy.compare(a, b) + return if (previousCompare != 0) previousCompare else compareValuesBy(a, b, selector) + } + } +} + +/** + * Creates a comparator comparing values after the primary comparator defined them equal. It uses + * the [selector] function to transform values and then compares them with the given [comparator]. + */ +@kotlin.internal.InlineOnly +public inline fun Comparator.thenBy(comparator: Comparator, crossinline selector: (T) -> K): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@thenBy.compare(a, b) + return if (previousCompare != 0) previousCompare else compareValuesBy(a, b, comparator, selector) + } + } +} + +/** + * Creates a descending comparator using the primary comparator and + * the function to transform value to a [Comparable] instance for comparison. + */ +@kotlin.internal.InlineOnly +public inline fun Comparator.thenByDescending(crossinline selector: (T) -> Comparable<*>?): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@thenByDescending.compare(a, b) + return if (previousCompare != 0) previousCompare else compareValuesBy(b, a, selector) + } + } +} + +/** + * Creates a descending comparator comparing values after the primary comparator defined them equal. It uses + * the [selector] function to transform values and then compares them with the given [comparator]. + */ +@kotlin.internal.InlineOnly +public inline fun Comparator.thenByDescending(comparator: Comparator, crossinline selector: (T) -> K): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@thenByDescending.compare(a, b) + return if (previousCompare != 0) previousCompare else compareValuesBy(b, a, comparator, selector) + } + } +} + + +/** + * Creates a comparator using the primary comparator and function to calculate a result of comparison. + */ +@kotlin.internal.InlineOnly +public inline fun Comparator.thenComparator(crossinline comparison: (T, T) -> Int): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@thenComparator.compare(a, b) + return if (previousCompare != 0) previousCompare else comparison(a, b) + } + } +} + +/** + * Combines this comparator and the given [comparator] such that the latter is applied only + * when the former considered values equal. + */ +public infix fun Comparator.then(comparator: Comparator): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@then.compare(a, b) + return if (previousCompare != 0) previousCompare else comparator.compare(a, b) + } + } +} + +/** + * Combines this comparator and the given [comparator] such that the latter is applied only + * when the former considered values equal. + */ +public infix fun Comparator.thenDescending(comparator: Comparator): Comparator { + return object : Comparator { + public override fun compare(a: T, b: T): Int { + val previousCompare = this@thenDescending.compare(a, b) + return if (previousCompare != 0) previousCompare else comparator.compare(b, a) + } + } +} + +// Not so useful without type inference for receiver of expression +/** + * Extends the given [comparator] of non-nullable values to a comparator of nullable values + * considering `null` value less than any other value. + */ +public fun nullsFirst(comparator: Comparator): Comparator { + return object: Comparator { + override fun compare(a: T?, b: T?): Int { + if (a === b) return 0 + if (a == null) return -1 + if (b == null) return 1 + return comparator.compare(a, b) + } + } +} + +/** + * Provides a comparator of nullable [Comparable] values + * considering `null` value less than any other value. + */ +@kotlin.internal.InlineOnly +public inline fun > nullsFirst(): Comparator = nullsFirst(naturalOrder()) + +/** + * Extends the given [comparator] of non-nullable values to a comparator of nullable values + * considering `null` value greater than any other value. + */ +public fun nullsLast(comparator: Comparator): Comparator { + return object: Comparator { + override fun compare(a: T?, b: T?): Int { + if (a === b) return 0 + if (a == null) return 1 + if (b == null) return -1 + return comparator.compare(a, b) + } + } +} + +/** + * Provides a comparator of nullable [Comparable] values + * considering `null` value greater than any other value. + */ +@kotlin.internal.InlineOnly +public inline fun > nullsLast(): Comparator = nullsLast(naturalOrder()) + +/** + * Returns a comparator that compares [Comparable] objects in natural order. + */ +public fun > naturalOrder(): Comparator = @Suppress("UNCHECKED_CAST") (NaturalOrderComparator as Comparator) + +/** + * Returns a comparator that compares [Comparable] objects in reversed natural order. + */ +public fun > reverseOrder(): Comparator = @Suppress("UNCHECKED_CAST") (ReverseOrderComparator as Comparator) + +/** Returns a comparator that imposes the reverse ordering of this comparator. */ +public fun Comparator.reversed(): Comparator = when (this) { + is ReversedComparator -> this.comparator + NaturalOrderComparator -> @Suppress("UNCHECKED_CAST") (ReverseOrderComparator as Comparator) + ReverseOrderComparator -> @Suppress("UNCHECKED_CAST") (NaturalOrderComparator as Comparator) + else -> ReversedComparator(this) +} + + +private class ReversedComparator(public val comparator: Comparator): Comparator { + override fun compare(a: T, b: T): Int = comparator.compare(b, a) + @Suppress("VIRTUAL_MEMBER_HIDDEN") + fun reversed(): Comparator = comparator +} + +private object NaturalOrderComparator : Comparator> { + override fun compare(a: Comparable, b: Comparable): Int = a.compareTo(b) + @Suppress("VIRTUAL_MEMBER_HIDDEN") + fun reversed(): Comparator> = ReverseOrderComparator +} + +private object ReverseOrderComparator: Comparator> { + override fun compare(a: Comparable, b: Comparable): Int = b.compareTo(a) + @Suppress("VIRTUAL_MEMBER_HIDDEN") + fun reversed(): Comparator> = NaturalOrderComparator +} diff --git a/runtime/src/main/kotlin/kotlin/ranges/Ranges.kt b/runtime/src/main/kotlin/kotlin/ranges/Ranges.kt index 768cb33ef48..12096e272d4 100644 --- a/runtime/src/main/kotlin/kotlin/ranges/Ranges.kt +++ b/runtime/src/main/kotlin/kotlin/ranges/Ranges.kt @@ -333,3 +333,12 @@ public fun Long.coerceIn(range: ClosedRange): Long { public fun IntProgression.reversed(): IntProgression { return IntProgression.fromClosedRange(last, first, -step) } + +/** + * Returns a progression from this value down to the specified [to] value with the step -1. + * + * The [to] value has to be less than this value. + */ +public infix fun Int.downTo(to: Int): IntProgression { + return IntProgression.fromClosedRange(this, to, -1) +} diff --git a/runtime/src/main/kotlin/kotlin/collections/Sequence.kt b/runtime/src/main/kotlin/kotlin/sequences/Sequence.kt similarity index 66% rename from runtime/src/main/kotlin/kotlin/collections/Sequence.kt rename to runtime/src/main/kotlin/kotlin/sequences/Sequence.kt index 5ac63d3354d..3cdeee1c228 100644 --- a/runtime/src/main/kotlin/kotlin/collections/Sequence.kt +++ b/runtime/src/main/kotlin/kotlin/sequences/Sequence.kt @@ -21,3 +21,22 @@ public interface Sequence { */ public operator fun iterator(): Iterator } + +/** + * A sequence that supports drop(n) and take(n) operations + */ +internal interface DropTakeSequence : Sequence { + fun drop(n: Int): Sequence + fun take(n: Int): Sequence +} + +/** + * Returns an empty sequence. + */ +public fun emptySequence(): Sequence = EmptySequence + +private object EmptySequence : Sequence, DropTakeSequence { + override fun iterator(): Iterator = EmptyIterator + override fun drop(n: Int) = EmptySequence + override fun take(n: Int) = EmptySequence +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/sequences/Sequences.kt b/runtime/src/main/kotlin/kotlin/sequences/Sequences.kt new file mode 100644 index 00000000000..fe304bbf4e2 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/sequences/Sequences.kt @@ -0,0 +1,1527 @@ +package kotlin.sequences + +import kotlin.comparisons.* + +/** + * Returns `true` if [element] is found in the sequence. + */ +public operator fun <@kotlin.internal.OnlyInputTypes T> Sequence.contains(element: T): Boolean { + return indexOf(element) >= 0 +} + +/** + * Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this sequence. + */ +public fun Sequence.elementAt(index: Int): T { + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Sequence doesn't contain element at index $index.") } +} + +/** + * Returns an element at the given [index] or the result of calling the [defaultValue] function if the [index] is out of bounds of this sequence. + */ +public fun Sequence.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + if (index < 0) + return defaultValue(index) + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return defaultValue(index) +} + +/** + * Returns an element at the given [index] or `null` if the [index] is out of bounds of this sequence. + */ +public fun Sequence.elementAtOrNull(index: Int): T? { + if (index < 0) + return null + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null +} + +/** + * Returns the first element matching the given [predicate], or `null` if no such element was found. + */ +@kotlin.internal.InlineOnly +public inline fun Sequence.find(predicate: (T) -> Boolean): T? { + return firstOrNull(predicate) +} + +/** + * Returns the last element matching the given [predicate], or `null` if no such element was found. + */ +@kotlin.internal.InlineOnly +public inline fun Sequence.findLast(predicate: (T) -> Boolean): T? { + return lastOrNull(predicate) +} + +/** + * Returns first element. + * @throws [NoSuchElementException] if the sequence is empty. + */ +public fun Sequence.first(): T { + val iterator = iterator() + if (!iterator.hasNext()) + throw NoSuchElementException("Sequence is empty.") + return iterator.next() +} + +/** + * Returns the first element matching the given [predicate]. + * @throws [NoSuchElementException] if no such element is found. + */ +public inline fun Sequence.first(predicate: (T) -> Boolean): T { + for (element in this) if (predicate(element)) return element + throw NoSuchElementException("Sequence contains no element matching the predicate.") +} + +/** + * Returns the first element, or `null` if the sequence is empty. + */ +public fun Sequence.firstOrNull(): T? { + val iterator = iterator() + if (!iterator.hasNext()) + return null + return iterator.next() +} + +/** + * Returns the first element matching the given [predicate], or `null` if element was not found. + */ +public inline fun Sequence.firstOrNull(predicate: (T) -> Boolean): T? { + for (element in this) if (predicate(element)) return element + return null +} + +/** + * Returns first index of [element], or -1 if the sequence does not contain element. + */ +public fun <@kotlin.internal.OnlyInputTypes T> Sequence.indexOf(element: T): Int { + var index = 0 + for (item in this) { + if (element == item) + return index + index++ + } + return -1 +} + +/** + * Returns index of the first element matching the given [predicate], or -1 if the sequence does not contain such element. + */ +public inline fun Sequence.indexOfFirst(predicate: (T) -> Boolean): Int { + var index = 0 + for (item in this) { + if (predicate(item)) + return index + index++ + } + return -1 +} + +/** + * Returns index of the last element matching the given [predicate], or -1 if the sequence does not contain such element. + */ +public inline fun Sequence.indexOfLast(predicate: (T) -> Boolean): Int { + var lastIndex = -1 + var index = 0 + for (item in this) { + if (predicate(item)) + lastIndex = index + index++ + } + return lastIndex +} + +/** + * Returns the last element. + * @throws [NoSuchElementException] if the sequence is empty. + */ +public fun Sequence.last(): T { + val iterator = iterator() + if (!iterator.hasNext()) + throw NoSuchElementException("Sequence is empty.") + var last = iterator.next() + while (iterator.hasNext()) + last = iterator.next() + return last +} + +/** + * Returns the last element matching the given [predicate]. + * @throws [NoSuchElementException] if no such element is found. + */ +public inline fun Sequence.last(predicate: (T) -> Boolean): T { + var last: T? = null + var found = false + for (element in this) { + if (predicate(element)) { + last = element + found = true + } + } + if (!found) throw NoSuchElementException("Sequence contains no element matching the predicate.") + return last as T +} + +/** + * Returns last index of [element], or -1 if the sequence does not contain element. + */ +public fun <@kotlin.internal.OnlyInputTypes T> Sequence.lastIndexOf(element: T): Int { + var lastIndex = -1 + var index = 0 + for (item in this) { + if (element == item) + lastIndex = index + index++ + } + return lastIndex +} + +/** + * Returns the last element, or `null` if the sequence is empty. + */ +public fun Sequence.lastOrNull(): T? { + val iterator = iterator() + if (!iterator.hasNext()) + return null + var last = iterator.next() + while (iterator.hasNext()) + last = iterator.next() + return last +} + +/** + * Returns the last element matching the given [predicate], or `null` if no such element was found. + */ +public inline fun Sequence.lastOrNull(predicate: (T) -> Boolean): T? { + var last: T? = null + for (element in this) { + if (predicate(element)) { + last = element + } + } + return last +} + +/** + * Returns the single element, or throws an exception if the sequence is empty or has more than one element. + */ +public fun Sequence.single(): T { + val iterator = iterator() + if (!iterator.hasNext()) + throw NoSuchElementException("Sequence is empty.") + val single = iterator.next() + if (iterator.hasNext()) + throw IllegalArgumentException("Sequence has more than one element.") + return single +} + +/** + * Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element. + */ +public inline fun Sequence.single(predicate: (T) -> Boolean): T { + var single: T? = null + var found = false + for (element in this) { + if (predicate(element)) { + if (found) throw IllegalArgumentException("Sequence contains more than one matching element.") + single = element + found = true + } + } + if (!found) throw NoSuchElementException("Sequence contains no element matching the predicate.") + return single as T +} + +/** + * Returns single element, or `null` if the sequence is empty or has more than one element. + */ +public fun Sequence.singleOrNull(): T? { + val iterator = iterator() + if (!iterator.hasNext()) + return null + val single = iterator.next() + if (iterator.hasNext()) + return null + return single +} + +/** + * Returns the single element matching the given [predicate], or `null` if element was not found or more than one element was found. + */ +public inline fun Sequence.singleOrNull(predicate: (T) -> Boolean): T? { + var single: T? = null + var found = false + for (element in this) { + if (predicate(element)) { + if (found) return null + single = element + found = true + } + } + if (!found) return null + return single +} + +/** + * Returns a sequence containing all elements except first [n] elements. + */ +@FixmeSequences +public fun Sequence.drop(n: Int): Sequence { + require(n >= 0) { "Requested element count $n is less than zero." } + TODO() + //return when { + // n == 0 -> this + // this is DropTakeSequence -> this.drop(n) + // else -> DropSequence(this, n) + //} +} + +/** + * Returns a sequence containing all elements except first elements that satisfy the given [predicate]. + */ +@FixmeSequences +public fun Sequence.dropWhile(predicate: (T) -> Boolean): Sequence { + TODO() + //return DropWhileSequence(this, predicate) +} + +/** + * A sequence that returns the values from the underlying [sequence] that either match or do not match + * the specified [predicate]. + * + * @param sendWhen If `true`, values for which the predicate returns `true` are returned. Otherwise, + * values for which the predicate returns `false` are returned + */ +internal class FilteringSequence(private val sequence: Sequence, + private val sendWhen: Boolean = true, + private val predicate: (T) -> Boolean +) : Sequence { + + override fun iterator(): Iterator = object : Iterator { + val iterator = sequence.iterator() + var nextState: Int = -1 // -1 for unknown, 0 for done, 1 for continue + var nextItem: T? = null + + private fun calcNext() { + while (iterator.hasNext()) { + val item = iterator.next() + if (predicate(item) == sendWhen) { + nextItem = item + nextState = 1 + return + } + } + nextState = 0 + } + + override fun next(): T { + if (nextState == -1) + calcNext() + if (nextState == 0) + throw NoSuchElementException() + val result = nextItem + nextItem = null + nextState = -1 + return result as T + } + + override fun hasNext(): Boolean { + if (nextState == -1) + calcNext() + return nextState == 1 + } + } +} + +/** + * Returns a sequence containing only elements matching the given [predicate]. + */ +public fun Sequence.filter(predicate: (T) -> Boolean): Sequence { + return FilteringSequence(this, true, predicate) +} + +/** + * Returns a sequence containing only elements matching the given [predicate]. + * @param [predicate] function that takes the index of an element and the element itself + * and returns the result of predicate evaluation on the element. + */ +@Fixme +public fun Sequence.filterIndexed(predicate: (Int, T) -> Boolean): Sequence { + TODO() + // TODO: Rewrite with generalized MapFilterIndexingSequence + // return TransformingSequence(FilteringSequence(IndexingSequence(this), true, { predicate(it.index, it.value) }), { it.value }) +} + +/** + * Appends all elements matching the given [predicate] to the given [destination]. + * @param [predicate] function that takes the index of an element and the element itself + * and returns the result of predicate evaluation on the element. + */ +public inline fun > Sequence.filterIndexedTo(destination: C, predicate: (Int, T) -> Boolean): C { + forEachIndexed { index, element -> + if (predicate(index, element)) destination.add(element) + } + return destination +} + +/** + * Returns a sequence containing all elements that are instances of specified type parameter R. + */ +@FixmeReified +public inline fun Sequence<*>.filterIsInstance(): Sequence<@kotlin.internal.NoInfer R> { + //@Suppress("UNCHECKED_CAST") + //return filter { it is R } as Sequence + TODO() +} + +/** + * Appends all elements that are instances of specified type parameter R to the given [destination]. + */ +@FixmeReified +public inline fun > Sequence<*>.filterIsInstanceTo(destination: C): C { + //for (element in this) if (element is R) destination.add(element) + //return destination + TODO() +} + +/** + * Returns a sequence containing all elements not matching the given [predicate]. + */ +public fun Sequence.filterNot(predicate: (T) -> Boolean): Sequence { + return FilteringSequence(this, false, predicate) +} + +/** + * Returns a sequence containing all elements that are not `null`. + */ +public fun Sequence.filterNotNull(): Sequence { + @Suppress("UNCHECKED_CAST") + return filterNot { it == null } as Sequence +} + +/** + * Appends all elements that are not `null` to the given [destination]. + */ +public fun , T : Any> Sequence.filterNotNullTo(destination: C): C { + for (element in this) if (element != null) destination.add(element) + return destination +} + +/** + * Appends all elements not matching the given [predicate] to the given [destination]. + */ +public inline fun > Sequence.filterNotTo(destination: C, predicate: (T) -> Boolean): C { + for (element in this) if (!predicate(element)) destination.add(element) + return destination +} + +/** + * Appends all elements matching the given [predicate] to the given [destination]. + */ +public inline fun > Sequence.filterTo(destination: C, predicate: (T) -> Boolean): C { + for (element in this) if (predicate(element)) destination.add(element) + return destination +} + +/** + * Returns a sequence containing first [n] elements. + */ +@FixmeSequences +public fun Sequence.take(n: Int): Sequence { + //require(n >= 0) { "Requested element count $n is less than zero." } + //return when { + // n == 0 -> emptySequence() + // this is DropTakeSequence -> this.take(n) + // else -> TakeSequence(this, n) + //} + TODO() +} + +/** + * Returns a sequence containing first elements satisfying the given [predicate]. + */ +@FixmeSequences +public fun Sequence.takeWhile(predicate: (T) -> Boolean): Sequence { + // return TakeWhileSequence(this, predicate) + TODO() +} + +/** + * Returns a sequence that yields elements of this sequence sorted according to their natural sort order. + */ +public fun > Sequence.sorted(): Sequence { + return object : Sequence { + override fun iterator(): Iterator { + val sortedList = this@sorted.toMutableList() + sortedList.sort() + return sortedList.iterator() + } + } +} + +/** + * Returns a sequence that yields elements of this sequence sorted according to natural sort order of the value returned by specified [selector] function. + */ +public inline fun > Sequence.sortedBy(crossinline selector: (T) -> R?): Sequence { + return sortedWith(compareBy(selector)) +} + +/** + * Returns a sequence that yields elements of this sequence sorted descending according to natural sort order of the value returned by specified [selector] function. + */ +public inline fun > Sequence.sortedByDescending(crossinline selector: (T) -> R?): Sequence { + return sortedWith(compareByDescending(selector)) +} + +/** + * Returns a sequence that yields elements of this sequence sorted descending according to their natural sort order. + */ +public fun > Sequence.sortedDescending(): Sequence { + return sortedWith(reverseOrder()) +} + +/** + * Returns a sequence that yields elements of this sequence sorted according to the specified [comparator]. + */ +public fun Sequence.sortedWith(comparator: Comparator): Sequence { + return object : Sequence { + override fun iterator(): Iterator { + val sortedList = this@sortedWith.toMutableList() + sortedList.sortWith(comparator) + return sortedList.iterator() + } + } +} + +/** + * Returns a [Map] containing key-value pairs provided by [transform] function + * applied to elements of the given sequence. + * + * If any of two pairs would have the same key the last one gets added to the map. + * + * The returned map preserves the entry iteration order of the original sequence. + */ +public inline fun Sequence.associate(transform: (T) -> Pair): Map { + return associateTo(LinkedHashMap(), transform) +} + +/** + * Returns a [Map] containing the elements from the given sequence indexed by the key + * returned from [keySelector] function applied to each element. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + * + * The returned map preserves the entry iteration order of the original sequence. + */ +public inline fun Sequence.associateBy(keySelector: (T) -> K): Map { + return associateByTo(LinkedHashMap(), keySelector) +} + +/** + * Returns a [Map] containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to elements of the given sequence. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + * + * The returned map preserves the entry iteration order of the original sequence. + */ +public inline fun Sequence.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map { + return associateByTo(LinkedHashMap(), keySelector, valueTransform) +} + +/** + * Populates and returns the [destination] mutable map with key-value pairs, + * where key is provided by the [keySelector] function applied to each element of the given sequence + * and value is the element itself. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + */ +public inline fun > Sequence.associateByTo(destination: M, keySelector: (T) -> K): M { + for (element in this) { + destination.put(keySelector(element), element) + } + return destination +} + +/** + * Populates and returns the [destination] mutable map with key-value pairs, + * where key is provided by the [keySelector] function and + * and value is provided by the [valueTransform] function applied to elements of the given sequence. + * + * If any two elements would have the same key returned by [keySelector] the last one gets added to the map. + */ +public inline fun > Sequence.associateByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { + for (element in this) { + destination.put(keySelector(element), valueTransform(element)) + } + return destination +} + +/** + * Populates and returns the [destination] mutable map with key-value pairs + * provided by [transform] function applied to each element of the given sequence. + * + * If any of two pairs would have the same key the last one gets added to the map. + */ +public inline fun > Sequence.associateTo(destination: M, transform: (T) -> Pair): M { + for (element in this) { + destination += transform(element) + } + return destination +} + +/** + * Appends all elements to the given [destination] collection. + */ +public fun > Sequence.toCollection(destination: C): C { + for (item in this) { + destination.add(item) + } + return destination +} + +/** + * Returns a [HashSet] of all elements. + */ +public fun Sequence.toHashSet(): HashSet { + return toCollection(HashSet()) +} + +/** + * Returns a [List] containing all elements. + */ +public fun Sequence.toList(): List { + return this.toMutableList().optimizeReadOnlyList() +} + +/** + * Returns a [MutableList] filled with all elements of this sequence. + */ +public fun Sequence.toMutableList(): MutableList { + return toCollection(ArrayList()) +} + +/** + * Returns a [Set] of all elements. + * + * The returned set preserves the element iteration order of the original sequence. + */ +public fun Sequence.toSet(): Set { + return toCollection(LinkedHashSet()).optimizeReadOnlySet() +} + +/** + * Returns a single sequence of all elements from results of [transform] function being invoked on each element of original sequence. + */ +@FixmeSequences +public fun Sequence.flatMap(transform: (T) -> Sequence): Sequence { + // return FlatteningSequence(this, transform, { it.iterator() }) + TODO() +} + +/** + * Appends all elements yielded from results of [transform] function being invoked on each element of original sequence, to the given [destination]. + */ +public inline fun > Sequence.flatMapTo(destination: C, transform: (T) -> Sequence): C { + for (element in this) { + val list = transform(element) + destination.addAll(list) + } + return destination +} + +/** + * Groups elements of the original sequence by the key returned by the given [keySelector] function + * applied to each element and returns a map where each group key is associated with a list of corresponding elements. + * + * The returned map preserves the entry iteration order of the keys produced from the original sequence. + * + * @sample samples.collections.Collections.Transformations.groupBy + */ +public inline fun Sequence.groupBy(keySelector: (T) -> K): Map> { + return groupByTo(LinkedHashMap>(), keySelector) +} + +/** + * Groups values returned by the [valueTransform] function applied to each element of the original sequence + * by the key returned by the given [keySelector] function applied to the element + * and returns a map where each group key is associated with a list of corresponding values. + * + * The returned map preserves the entry iteration order of the keys produced from the original sequence. + * + * @sample samples.collections.Collections.Transformations.groupByKeysAndValues + */ +public inline fun Sequence.groupBy(keySelector: (T) -> K, valueTransform: (T) -> V): Map> { + return groupByTo(LinkedHashMap>(), keySelector, valueTransform) +} + +/** + * Groups elements of the original sequence by the key returned by the given [keySelector] function + * applied to each element and puts to the [destination] map each group key associated with a list of corresponding elements. + * + * @return The [destination] map. + * + * @sample samples.collections.Collections.Transformations.groupBy + */ +public inline fun >> Sequence.groupByTo(destination: M, keySelector: (T) -> K): M { + for (element in this) { + val key = keySelector(element) + val list = destination.getOrPut(key) { ArrayList() } + list.add(element) + } + return destination +} + +/** + * Groups values returned by the [valueTransform] function applied to each element of the original sequence + * by the key returned by the given [keySelector] function applied to the element + * and puts to the [destination] map each group key associated with a list of corresponding values. + * + * @return The [destination] map. + * + * @sample samples.collections.Collections.Transformations.groupByKeysAndValues + */ +public inline fun >> Sequence.groupByTo(destination: M, keySelector: (T) -> K, valueTransform: (T) -> V): M { + for (element in this) { + val key = keySelector(element) + val list = destination.getOrPut(key) { ArrayList() } + list.add(valueTransform(element)) + } + return destination +} + +/** + * Creates a [Grouping] source from a sequence to be used later with one of group-and-fold operations + * using the specified [keySelector] function to extract a key from each element. + */ +// @Fixme +// public inline fun Sequence.groupingBy(crossinline keySelector: (T) -> K): Grouping { +// TODO() + //return object : Grouping { + // override fun sourceIterator(): Iterator = this@groupingBy.iterator() + // override fun keyOf(element: T): K = keySelector(element) + //} +//} + +/** + * Returns a sequence containing the results of applying the given [transform] function + * to each element in the original sequence. + */ +@FixmeSequences +public fun Sequence.map(transform: (T) -> R): Sequence { + // return TransformingSequence(this, transform) + TODO() +} + +/** + * Returns a sequence containing the results of applying the given [transform] function + * to each element and its index in the original sequence. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +@FixmeSequences +public fun Sequence.mapIndexed(transform: (Int, T) -> R): Sequence { + TODO() + //return TransformingIndexedSequence(this, transform) +} + +/** + * Returns a sequence containing only the non-null results of applying the given [transform] function + * to each element and its index in the original sequence. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +@FixmeSequences +public fun Sequence.mapIndexedNotNull(transform: (Int, T) -> R?): Sequence { + TODO() + //return TransformingIndexedSequence(this, transform).filterNotNull() +} + +/** + * Applies the given [transform] function to each element and its index in the original sequence + * and appends only the non-null results to the given [destination]. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +public inline fun > Sequence.mapIndexedNotNullTo(destination: C, transform: (Int, T) -> R?): C { + forEachIndexed { index, element -> transform(index, element)?.let { destination.add(it) } } + return destination +} + +/** + * Applies the given [transform] function to each element and its index in the original sequence + * and appends the results to the given [destination]. + * @param [transform] function that takes the index of an element and the element itself + * and returns the result of the transform applied to the element. + */ +public inline fun > Sequence.mapIndexedTo(destination: C, transform: (Int, T) -> R): C { + var index = 0 + for (item in this) + destination.add(transform(index++, item)) + return destination +} + +/** + * Returns a sequence containing only the non-null results of applying the given [transform] function + * to each element in the original sequence. + */ +@FixmeSequences +public fun Sequence.mapNotNull(transform: (T) -> R?): Sequence { + // return TransformingSequence(this, transform).filterNotNull() + TODO() +} + +/** + * Applies the given [transform] function to each element in the original sequence + * and appends only the non-null results to the given [destination]. + */ +public inline fun > Sequence.mapNotNullTo(destination: C, transform: (T) -> R?): C { + forEach { element -> transform(element)?.let { destination.add(it) } } + return destination +} + +/** + * Applies the given [transform] function to each element of the original sequence + * and appends the results to the given [destination]. + */ +public inline fun > Sequence.mapTo(destination: C, transform: (T) -> R): C { + for (item in this) + destination.add(transform(item)) + return destination +} + +/** + * Returns a sequence of [IndexedValue] for each element of the original sequence. + */ +@Fixme +public fun Sequence.withIndex(): Sequence> { + // return IndexingSequence(this) + TODO() +} + +/** + * Returns a sequence containing only distinct elements from the given sequence. + * + * The elements in the resulting sequence are in the same order as they were in the source sequence. + */ +public fun Sequence.distinct(): Sequence { + return this.distinctBy { it } +} + +/** + * Returns a sequence containing only elements from the given sequence + * having distinct keys returned by the given [selector] function. + * + * The elements in the resulting sequence are in the same order as they were in the source sequence. + */ +@FixmeSequences +public fun Sequence.distinctBy(selector: (T) -> K): Sequence { + // return DistinctSequence(this, selector) + TODO() +} + +/** + * Returns a mutable set containing all distinct elements from the given sequence. + * + * The returned set preserves the element iteration order of the original sequence. + */ +public fun Sequence.toMutableSet(): MutableSet { + val set = LinkedHashSet() + for (item in this) set.add(item) + return set +} + +/** + * Returns `true` if all elements match the given [predicate]. + */ +public inline fun Sequence.all(predicate: (T) -> Boolean): Boolean { + for (element in this) if (!predicate(element)) return false + return true +} + +/** + * Returns `true` if sequence has at least one element. + */ +public fun Sequence.any(): Boolean { + for (element in this) return true + return false +} + +/** + * Returns `true` if at least one element matches the given [predicate]. + */ +public inline fun Sequence.any(predicate: (T) -> Boolean): Boolean { + for (element in this) if (predicate(element)) return true + return false +} + +/** + * Returns the number of elements in this sequence. + */ +public fun Sequence.count(): Int { + var count = 0 + for (element in this) count++ + return count +} + +/** + * Returns the number of elements matching the given [predicate]. + */ +public inline fun Sequence.count(predicate: (T) -> Boolean): Int { + var count = 0 + for (element in this) if (predicate(element)) count++ + return count +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element. + */ +public inline fun Sequence.fold(initial: R, operation: (R, T) -> R): R { + var accumulator = initial + for (element in this) accumulator = operation(accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original sequence. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + */ +public inline fun Sequence.foldIndexed(initial: R, operation: (Int, R, T) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Performs the given [action] on each element. + */ +public inline fun Sequence.forEach(action: (T) -> Unit): Unit { + for (element in this) action(element) +} + +/** + * Performs the given [action] on each element, providing sequential index with the element. + * @param [action] function that takes the index of an element and the element itself + * and performs the desired action on the element. + */ +public inline fun Sequence.forEachIndexed(action: (Int, T) -> Unit): Unit { + var index = 0 + for (item in this) action(index++, item) +} + +/** + * Returns the largest element or `null` if there are no elements. + * + * If any of elements is `NaN` returns `NaN`. + */ +public fun Sequence.max(): Double? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var max = iterator.next() + if (max.isNaN()) return max + while (iterator.hasNext()) { + val e = iterator.next() + if (e.isNaN()) return e + if (max < e) max = e + } + return max +} + +/** + * Returns the largest element or `null` if there are no elements. + * + * If any of elements is `NaN` returns `NaN`. + */ +public fun Sequence.max(): Float? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var max = iterator.next() + if (max.isNaN()) return max + while (iterator.hasNext()) { + val e = iterator.next() + if (e.isNaN()) return e + if (max < e) max = e + } + return max +} + +/** + * Returns the largest element or `null` if there are no elements. + */ +public fun > Sequence.max(): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var max = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (max < e) max = e + } + return max +} + +/** + * Returns the first element yielding the largest value of the given function or `null` if there are no elements. + */ +public inline fun > Sequence.maxBy(selector: (T) -> R): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var maxElem = iterator.next() + var maxValue = selector(maxElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = selector(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem +} + +/** + * Returns the first element having the largest value according to the provided [comparator] or `null` if there are no elements. + */ +public fun Sequence.maxWith(comparator: Comparator): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var max = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (comparator.compare(max, e) < 0) max = e + } + return max +} + +/** + * Returns the smallest element or `null` if there are no elements. + * + * If any of elements is `NaN` returns `NaN`. + */ +public fun Sequence.min(): Double? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var min = iterator.next() + if (min.isNaN()) return min + while (iterator.hasNext()) { + val e = iterator.next() + if (e.isNaN()) return e + if (min > e) min = e + } + return min +} + +/** + * Returns the smallest element or `null` if there are no elements. + * + * If any of elements is `NaN` returns `NaN`. + */ +public fun Sequence.min(): Float? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var min = iterator.next() + if (min.isNaN()) return min + while (iterator.hasNext()) { + val e = iterator.next() + if (e.isNaN()) return e + if (min > e) min = e + } + return min +} + +/** + * Returns the smallest element or `null` if there are no elements. + */ +public fun > Sequence.min(): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var min = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (min > e) min = e + } + return min +} + +/** + * Returns the first element yielding the smallest value of the given function or `null` if there are no elements. + */ +public inline fun > Sequence.minBy(selector: (T) -> R): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var minElem = iterator.next() + var minValue = selector(minElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = selector(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem +} + +/** + * Returns the first element having the smallest value according to the provided [comparator] or `null` if there are no elements. + */ +public fun Sequence.minWith(comparator: Comparator): T? { + val iterator = iterator() + if (!iterator.hasNext()) return null + var min = iterator.next() + while (iterator.hasNext()) { + val e = iterator.next() + if (comparator.compare(min, e) > 0) min = e + } + return min +} + +/** + * Returns `true` if the sequence has no elements. + */ +public fun Sequence.none(): Boolean { + for (element in this) return false + return true +} + +/** + * Returns `true` if no elements match the given [predicate]. + */ +public inline fun Sequence.none(predicate: (T) -> Boolean): Boolean { + for (element in this) if (predicate(element)) return false + return true +} + +/** + * Returns a sequence which performs the given [action] on each element of the original sequence as they pass though it. + */ +public fun Sequence.onEach(action: (T) -> Unit): Sequence { + return map { + action(it) + it + } +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. + */ +public inline fun Sequence.reduce(operation: (S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty sequence can't be reduced.") + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(accumulator, iterator.next()) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original sequence. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself and calculates the next accumulator value. + */ +public inline fun Sequence.reduceIndexed(operation: (Int, S, T) -> S): S { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty sequence can't be reduced.") + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + } + return accumulator +} + +/** + * Returns the sum of all values produced by [selector] function applied to each element in the sequence. + */ +public inline fun Sequence.sumBy(selector: (T) -> Int): Int { + var sum: Int = 0 + for (element in this) { + sum += selector(element) + } + return sum +} + +/** + * Returns the sum of all values produced by [selector] function applied to each element in the sequence. + */ +public inline fun Sequence.sumByDouble(selector: (T) -> Double): Double { + var sum: Double = 0.0 + for (element in this) { + sum += selector(element) + } + return sum +} + +/** + * Returns an original collection containing all the non-`null` elements, throwing an [IllegalArgumentException] if there are any `null` elements. + */ +public fun Sequence.requireNoNulls(): Sequence { + return map { it ?: throw IllegalArgumentException("null element found in $this.") } +} + +/** + * Returns a sequence containing all elements of the original sequence without the first occurrence of the given [element]. + */ +public operator fun Sequence.minus(element: T): Sequence { + return object: Sequence { + override fun iterator(): Iterator { + var removed = false + return this@minus.filter { if (!removed && it == element) { removed = true; false } else true }.iterator() + } + } +} + +/** + * Returns a sequence containing all elements of original sequence except the elements contained in the given [elements] array. + * + * Note that the source sequence and the array being subtracted are iterated only when an `iterator` is requested from + * the resulting sequence. Changing any of them between successive calls to `iterator` may affect the result. + */ +public operator fun Sequence.minus(elements: Array): Sequence { + if (elements.isEmpty()) return this + return object: Sequence { + override fun iterator(): Iterator { + val other = elements.toHashSet() + return this@minus.filterNot { it in other }.iterator() + } + } +} + +/** + * Returns a sequence containing all elements of original sequence except the elements contained in the given [elements] collection. + * + * Note that the source sequence and the collection being subtracted are iterated only when an `iterator` is requested from + * the resulting sequence. Changing any of them between successive calls to `iterator` may affect the result. + */ +public operator fun Sequence.minus(elements: Iterable): Sequence { + return object: Sequence { + override fun iterator(): Iterator { + val other = elements.convertToSetForSetOperation() + if (other.isEmpty()) + return this@minus.iterator() + else + return this@minus.filterNot { it in other }.iterator() + } + } +} + +/** + * Returns a sequence containing all elements of original sequence except the elements contained in the given [elements] sequence. + * + * Note that the source sequence and the sequence being subtracted are iterated only when an `iterator` is requested from + * the resulting sequence. Changing any of them between successive calls to `iterator` may affect the result. + */ +public operator fun Sequence.minus(elements: Sequence): Sequence { + return object: Sequence { + override fun iterator(): Iterator { + val other = elements.toHashSet() + if (other.isEmpty()) + return this@minus.iterator() + else + return this@minus.filterNot { it in other }.iterator() + } + } +} + +/** + * Returns a sequence containing all elements of the original sequence without the first occurrence of the given [element]. + */ +@kotlin.internal.InlineOnly +public inline fun Sequence.minusElement(element: T): Sequence { + return minus(element) +} + +/** + * Splits the original sequence into pair of lists, + * where *first* list contains elements for which [predicate] yielded `true`, + * while *second* list contains elements for which [predicate] yielded `false`. + */ +public inline fun Sequence.partition(predicate: (T) -> Boolean): Pair, List> { + val first = ArrayList() + val second = ArrayList() + for (element in this) { + if (predicate(element)) { + first.add(element) + } else { + second.add(element) + } + } + return Pair(first, second) +} + +/** + * Returns a sequence containing all elements of the original sequence and then the given [element]. + */ +@FixmeSequences +public operator fun Sequence.plus(element: T): Sequence { + TODO() + // return sequenceOf(this, sequenceOf(element)).flatten() +} + +/** + * Returns a sequence containing all elements of original sequence and then all elements of the given [elements] array. + * + * Note that the source sequence and the array being added are iterated only when an `iterator` is requested from + * the resulting sequence. Changing any of them between successive calls to `iterator` may affect the result. + */ +public operator fun Sequence.plus(elements: Array): Sequence { + return this.plus(elements.asList()) +} + +/** + * Returns a sequence containing all elements of original sequence and then all elements of the given [elements] collection. + * + * Note that the source sequence and the collection being added are iterated only when an `iterator` is requested from + * the resulting sequence. Changing any of them between successive calls to `iterator` may affect the result. + */ +@FixmeSequences +public operator fun Sequence.plus(elements: Iterable): Sequence { + // return sequenceOf(this, elements.asSequence()).flatten() + TODO() +} + +/** + * Returns a sequence containing all elements of original sequence and then all elements of the given [elements] sequence. + * + * Note that the source sequence and the sequence being added are iterated only when an `iterator` is requested from + * the resulting sequence. Changing any of them between successive calls to `iterator` may affect the result. + */ +@FixmeSequences +public operator fun Sequence.plus(elements: Sequence): Sequence { + //return sequenceOf(this, elements).flatten() + TODO() +} + +/** + * Returns a sequence containing all elements of the original sequence and then the given [element]. + */ +@kotlin.internal.InlineOnly +public inline fun Sequence.plusElement(element: T): Sequence { + return plus(element) +} + +/** + * Returns a sequence of pairs built from elements of both sequences with same indexes. + * Resulting sequence has length of shortest input sequence. + */ +@FixmeSequences +public infix fun Sequence.zip(other: Sequence): Sequence> { + TODO() + //return MergingSequence(this, other) { t1, t2 -> t1 to t2 } +} + +/** + * Returns a sequence of values built from elements of both collections with same indexes using provided [transform]. Resulting sequence has length of shortest input sequences. + */ +@FixmeSequences +public fun Sequence.zip(other: Sequence, transform: (T, R) -> V): Sequence { + // return MergingSequence(this, other, transform) + TODO() +} + +/** + * Appends the string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied. + * + * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit] + * elements will be appended, followed by the [truncated] string (which defaults to "..."). + */ +@FixmeSequences +public fun Sequence.joinTo(buffer: A, separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): A { + TODO() + /* + buffer.append(prefix) + var count = 0 + for (element in this) { + if (++count > 1) buffer.append(separator) + if (limit < 0 || count <= limit) { + buffer.appendElement(element, transform) + } else break + } + if (limit >= 0 && count > limit) buffer.append(truncated) + buffer.append(postfix) + return buffer */ +} + +/** + * Creates a string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied. + * + * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit] + * elements will be appended, followed by the [truncated] string (which defaults to "..."). + */ +public fun Sequence.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String { + return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString() +} + +/** + * Creates an [Iterable] instance that wraps the original sequence returning its elements when being iterated. + */ +public fun Sequence.asIterable(): Iterable { + return Iterable { this.iterator() } +} + +/** + * Returns this sequence as a [Sequence]. + */ +@kotlin.internal.InlineOnly +public inline fun Sequence.asSequence(): Sequence { + return this +} + +/** + * Returns an average value of elements in the sequence. + */ +public fun Sequence.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the sequence. + */ +public fun Sequence.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the sequence. + */ +public fun Sequence.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the sequence. + */ +public fun Sequence.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the sequence. + */ +public fun Sequence.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns an average value of elements in the sequence. + */ +public fun Sequence.average(): Double { + var sum: Double = 0.0 + var count: Int = 0 + for (element in this) { + sum += element + count += 1 + } + return if (count == 0) 0.0 else sum / count +} + +/** + * Returns the sum of all elements in the sequence. + */ +public fun Sequence.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the sequence. + */ +public fun Sequence.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the sequence. + */ +public fun Sequence.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the sequence. + */ +public fun Sequence.sum(): Long { + var sum: Long = 0L + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the sequence. + */ +public fun Sequence.sum(): Float { + var sum: Float = 0.0f + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the sequence. + */ +public fun Sequence.sum(): Double { + var sum: Double = 0.0 + for (element in this) { + sum += element + } + return sum +} + diff --git a/runtime/src/main/kotlin/kotlin/text/Appendable.kt b/runtime/src/main/kotlin/kotlin/text/Appendable.kt new file mode 100644 index 00000000000..3addc63d33f --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/text/Appendable.kt @@ -0,0 +1,7 @@ +package kotlin.text + +interface Appendable { + fun append(c: Char): Appendable + fun append(csq: CharSequence?): Appendable + fun append(csq: CharSequence?, start: Int, end: Int): Appendable +} diff --git a/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt b/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt index fbc2dcb04ed..cd31b4d4d82 100644 --- a/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt +++ b/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt @@ -13,7 +13,7 @@ external fun toCharArray(string: String) : CharArray class StringBuilder private constructor ( private var array: CharArray -) : CharSequence { +) : CharSequence, Appendable { constructor() : this(10) constructor(capacity: Int) : this(CharArray(capacity)) @@ -57,11 +57,17 @@ class StringBuilder private constructor ( } } - fun append(it: Char) { + // Of Appenable. + override fun append(c: Char) : Appendable { ensureExtraCapacity(1) - array[length++] = it + array[length++] = c + return this } + override fun append(csq: CharSequence?): Appendable = TODO() + + override fun append(csq: CharSequence?, start: Int, end: Int): Appendable = TODO() + fun append(it: CharArray) { ensureExtraCapacity(it.size) for (c in it) diff --git a/runtime/src/main/kotlin/kotlin/util/Preconditions.kt b/runtime/src/main/kotlin/kotlin/util/Preconditions.kt new file mode 100644 index 00000000000..d7dd0290437 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/util/Preconditions.kt @@ -0,0 +1,98 @@ +package kotlin + +/** + * Throws an [IllegalArgumentException] if the [value] is false. + * + * @sample samples.misc.Preconditions.failRequireWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun require(value: Boolean): Unit = require(value) { "Failed requirement." } + +/** + * Throws an [IllegalArgumentException] with the result of calling [lazyMessage] if the [value] is false. + * + * @sample samples.misc.Preconditions.failRequireWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit { + if (!value) { + val message = lazyMessage() + throw IllegalArgumentException(message.toString()) + } +} + +/** + * Throws an [IllegalArgumentException] if the [value] is null. Otherwise returns the not null value. + */ +@kotlin.internal.InlineOnly +public inline fun requireNotNull(value: T?): T = requireNotNull(value) { "Required value was null." } + +/** + * Throws an [IllegalArgumentException] with the result of calling [lazyMessage] if the [value] is null. Otherwise + * returns the not null value. + * + * @sample samples.misc.Preconditions.failRequireWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun requireNotNull(value: T?, lazyMessage: () -> Any): T { + if (value == null) { + val message = lazyMessage() + throw IllegalArgumentException(message.toString()) + } else { + return value + } +} + +/** + * Throws an [IllegalStateException] if the [value] is false. + * + * @sample samples.misc.Preconditions.failCheckWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun check(value: Boolean): Unit = check(value) { "Check failed." } + +/** + * Throws an [IllegalStateException] with the result of calling [lazyMessage] if the [value] is false. + * + * @sample samples.misc.Preconditions.failCheckWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun check(value: Boolean, lazyMessage: () -> Any): Unit { + if (!value) { + val message = lazyMessage() + throw IllegalStateException(message.toString()) + } +} + +/** + * Throws an [IllegalStateException] if the [value] is null. Otherwise + * returns the not null value. + * + * @sample samples.misc.Preconditions.failCheckWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun checkNotNull(value: T?): T = checkNotNull(value) { "Required value was null." } + +/** + * Throws an [IllegalStateException] with the result of calling [lazyMessage] if the [value] is null. Otherwise + * returns the not null value. + * + * @sample samples.misc.Preconditions.failCheckWithLazyMessage + */ +@kotlin.internal.InlineOnly +public inline fun checkNotNull(value: T?, lazyMessage: () -> Any): T { + if (value == null) { + val message = lazyMessage() + throw IllegalStateException(message.toString()) + } else { + return value + } +} + +/** + * Throws an [IllegalStateException] with the given [message]. + * + * @sample samples.misc.Preconditions.failWithError + */ +@kotlin.internal.InlineOnly +public inline fun error(message: Any): Nothing = throw IllegalStateException(message.toString())