diff --git a/libraries/stdlib/src/generated/_Elements.kt b/libraries/stdlib/src/generated/_Elements.kt index f70c09381f9..cb10a8ecddb 100644 --- a/libraries/stdlib/src/generated/_Elements.kt +++ b/libraries/stdlib/src/generated/_Elements.kt @@ -453,111 +453,176 @@ public fun Stream.contains(element: T): Boolean { } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun Array.elementAt(index: Int): T { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun BooleanArray.elementAt(index: Int): Boolean { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun ByteArray.elementAt(index: Int): Byte { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun CharArray.elementAt(index: Int): Char { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun DoubleArray.elementAt(index: Int): Double { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun FloatArray.elementAt(index: Int): Float { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun IntArray.elementAt(index: Int): Int { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun LongArray.elementAt(index: Int): Long { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun ShortArray.elementAt(index: Int): Short { return get(index) } /** - * Returns element at given *index* + * Returns 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) as T - val iterator = iterator() - var count = 0 - while (iterator.hasNext()) { - val element = iterator.next() - if (index == count++) - return element - } - throw IndexOutOfBoundsException("Collection doesn't contain element at index") + if (this is List) + return get(index) + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Collection doesn't contain element at index $index") } } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun List.elementAt(index: Int): T { return get(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun Sequence.elementAt(index: Int): T { - val iterator = iterator() - var count = 0 - while (iterator.hasNext()) { - val element = iterator.next() - if (index == count++) - return element - } - throw IndexOutOfBoundsException("Collection doesn't contain element at index") + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Sequence doesn't contain element at index $index") } } deprecated("Migrate to using Sequence and respective functions") /** - * Returns element at given *index* + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. */ public fun Stream.elementAt(index: Int): T { + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Stream doesn't contain element at index $index") } +} + +/** + * Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection. + */ +public fun String.elementAt(index: Int): Char { + return get(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun Array.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun BooleanArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Boolean): Boolean { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun ByteArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Byte): Byte { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun CharArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Char): Char { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun DoubleArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Double): Double { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun FloatArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Float): Float { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun IntArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Int): Int { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun LongArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Long): Long { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun ShortArray.elementAtOrElse(index: Int, defaultValue: (Int) -> Short): Short { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun Iterable.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + if (this is List) + return this.elementAtOrElse(index, defaultValue) val iterator = iterator() var count = 0 while (iterator.hasNext()) { @@ -565,14 +630,174 @@ public fun Stream.elementAt(index: Int): T { if (index == count++) return element } - throw IndexOutOfBoundsException("Collection doesn't contain element at index") + return defaultValue(index) } /** - * Returns element at given *index* + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. */ -public fun String.elementAt(index: Int): Char { - return get(index) +public inline fun List.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun Sequence.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return defaultValue(index) +} + + +deprecated("Migrate to using Sequence and respective functions") +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun Stream.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T { + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return defaultValue(index) +} + +/** + * Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection. + */ +public inline fun String.elementAtOrElse(index: Int, defaultValue: (Int) -> Char): Char { + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun Array.elementAtOrNull(index: Int): T? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun BooleanArray.elementAtOrNull(index: Int): Boolean? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun ByteArray.elementAtOrNull(index: Int): Byte? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun CharArray.elementAtOrNull(index: Int): Char? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun DoubleArray.elementAtOrNull(index: Int): Double? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun FloatArray.elementAtOrNull(index: Int): Float? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun IntArray.elementAtOrNull(index: Int): Int? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun LongArray.elementAtOrNull(index: Int): Long? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun ShortArray.elementAtOrNull(index: Int): Short? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns 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.elementAtOrNull(index) + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun List.elementAtOrNull(index: Int): T? { + return if (index >= 0 && index <= lastIndex) get(index) else null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun Sequence.elementAtOrNull(index: Int): T? { + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null +} + + +deprecated("Migrate to using Sequence and respective functions") +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun Stream.elementAtOrNull(index: Int): T? { + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null +} + +/** + * Returns element at the given [index] or `null` if the [index] is out of bounds of this collection. + */ +public fun String.elementAtOrNull(index: Int): Char? { + return if (index >= 0 && index <= lastIndex) get(index) else null } /** diff --git a/libraries/stdlib/test/collections/IterableTests.kt b/libraries/stdlib/test/collections/IterableTests.kt index 1eac9153059..ea6a4608283 100644 --- a/libraries/stdlib/test/collections/IterableTests.kt +++ b/libraries/stdlib/test/collections/IterableTests.kt @@ -54,6 +54,14 @@ abstract class OrderedIterableTests>(data: T, empty: T) : I fails { data.elementAt(2) } fails { data.elementAt(-1) } fails { empty.elementAt(0) } + + expect("foo") { data.elementAtOrElse(0, {""} )} + expect("zoo") { data.elementAtOrElse(-1, { "zoo" })} + expect("zoo") { data.elementAtOrElse(2, { "zoo" })} + expect("zoo") { empty.elementAtOrElse(0) { "zoo" }} + + expect(null) { empty.elementAtOrNull(0) } + } Test fun first() { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt index cfe1a79d19d..e0eee2af93a 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt @@ -176,12 +176,37 @@ fun elements(): List { } templates add f("elementAt(index: Int)") { - doc { "Returns element at given *index*" } + val index = '$' + "index" + doc { "Returns element at the given [index] or throws an IndexOutOfBoundsException if the [index] is out of bounds of this collection." } returns("T") body { """ - if (this is List<*>) - return get(index) as T + if (this is List) + return get(index) + + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Collection doesn't contain element at index $index") } + """ + } + body(Sequences) { + """ + return elementAtOrElse(index) { throw IndexOutOfBoundsException("Sequence doesn't contain element at index $index") } + """ + } + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { + """ + return get(index) + """ + } + } + + templates add f("elementAtOrElse(index: Int, defaultValue: (Int) -> T)") { + doc { "Returns element at the given [index] or calls [defaultValue] and returns its result if the [index] is out of bounds of this collection." } + returns("T") + inline(true) + body { + """ + if (this is List) + return this.elementAtOrElse(index, defaultValue) val iterator = iterator() var count = 0 while (iterator.hasNext()) { @@ -189,7 +214,7 @@ fun elements(): List { if (index == count++) return element } - throw IndexOutOfBoundsException("Collection doesn't contain element at index") + return defaultValue(index) """ } body(Sequences) { @@ -201,12 +226,49 @@ fun elements(): List { if (index == count++) return element } - throw IndexOutOfBoundsException("Collection doesn't contain element at index") + return defaultValue(index) """ } body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ - return get(index) + return if (index >= 0 && index <= lastIndex) get(index) else defaultValue(index) + """ + } + } + + + templates add f("elementAtOrNull(index: Int)") { + doc { "Returns element at the given [index] or `null` if the [index] is out of bounds of this collection." } + returns("T?") + body { + """ + if (this is List) + return this.elementAtOrNull(index) + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null + """ + } + body(Sequences) { + """ + val iterator = iterator() + var count = 0 + while (iterator.hasNext()) { + val element = iterator.next() + if (index == count++) + return element + } + return null + """ + } + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { + """ + return if (index >= 0 && index <= lastIndex) get(index) else null """ } }