diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index 23c3a418d07..904825f0b85 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -15,6 +15,8 @@ import java.util.Collections // TODO: it's temporary while we have java.util.Col */ public fun Array.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -29,6 +31,8 @@ public fun Array.drop(n: Int): List { */ public fun BooleanArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -43,6 +47,8 @@ public fun BooleanArray.drop(n: Int): List { */ public fun ByteArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -57,6 +63,8 @@ public fun ByteArray.drop(n: Int): List { */ public fun CharArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -71,6 +79,8 @@ public fun CharArray.drop(n: Int): List { */ public fun DoubleArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -85,6 +95,8 @@ public fun DoubleArray.drop(n: Int): List { */ public fun FloatArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -99,6 +111,8 @@ public fun FloatArray.drop(n: Int): List { */ public fun IntArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -113,6 +127,8 @@ public fun IntArray.drop(n: Int): List { */ public fun LongArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -127,6 +143,8 @@ public fun LongArray.drop(n: Int): List { */ public fun ShortArray.drop(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() val list = ArrayList(size() - n) @@ -141,6 +159,7 @@ public fun ShortArray.drop(n: Int): List { */ 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 @@ -169,7 +188,7 @@ public fun Iterable.drop(n: Int): List { */ public fun Sequence.drop(n: Int): Sequence { require(n >= 0, { "Requested element count $n is less than zero." }) - return DropSequence(this, n) + return if (n == 0) this else DropSequence(this, n) } @@ -179,7 +198,7 @@ deprecated("Migrate to using Sequence and respective functions") */ public fun Stream.drop(n: Int): Stream { require(n >= 0, { "Requested element count $n is less than zero." }) - return DropStream(this, n) + return if (n == 0) this else DropStream(this, n) } /** @@ -189,6 +208,94 @@ public fun String.drop(n: Int): String { return substring(Math.min(n, length())) } +/** + * Returns a list containing all elements except last [n] elements. + */ +public fun Array.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 [n] elements. + */ +public fun BooleanArray.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 [n] elements. + */ +public fun ByteArray.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 [n] elements. + */ +public fun CharArray.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 [n] elements. + */ +public fun DoubleArray.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 [n] elements. + */ +public fun FloatArray.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 [n] elements. + */ +public fun IntArray.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 [n] elements. + */ +public fun LongArray.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 [n] elements. + */ +public fun ShortArray.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 [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 string with the last [n] characters removed. + */ +public fun String.dropLast(n: Int): String { + require(n >= 0, { "Requested element count $n is less than zero." }) + return take((length() - n).coerceAtLeast(0)) +} + /** * Returns a list containing all elements except last elements that satisfy the given [predicate]. */ @@ -1090,11 +1197,12 @@ public fun String.slice(indices: Iterable): String { */ public fun Array.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1106,11 +1214,12 @@ public fun Array.take(n: Int): List { */ public fun BooleanArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1122,11 +1231,12 @@ public fun BooleanArray.take(n: Int): List { */ public fun ByteArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1138,11 +1248,12 @@ public fun ByteArray.take(n: Int): List { */ public fun CharArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1154,11 +1265,12 @@ public fun CharArray.take(n: Int): List { */ public fun DoubleArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1170,11 +1282,12 @@ public fun DoubleArray.take(n: Int): List { */ public fun FloatArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1186,11 +1299,12 @@ public fun FloatArray.take(n: Int): List { */ public fun IntArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1202,11 +1316,12 @@ public fun IntArray.take(n: Int): List { */ public fun LongArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1218,11 +1333,12 @@ public fun LongArray.take(n: Int): List { */ public fun ShortArray.take(n: Int): List { require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -1234,8 +1350,10 @@ public fun ShortArray.take(n: Int): List { */ 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 && n >= size()) return toList() var count = 0 - val list = ArrayList(Math.min(n, collectionSizeOrDefault(n))) + val list = ArrayList(n) for (item in this) { if (count++ == n) break @@ -1249,7 +1367,7 @@ public fun Iterable.take(n: Int): List { */ public fun Sequence.take(n: Int): Sequence { require(n >= 0, { "Requested element count $n is less than zero." }) - return TakeSequence(this, n) + return if (n == 0) emptySequence() else TakeSequence(this, n) } @@ -1259,7 +1377,7 @@ deprecated("Migrate to using Sequence and respective functions") */ public fun Stream.take(n: Int): Stream { require(n >= 0, { "Requested element count $n is less than zero." }) - return TakeStream(this, n) + return if (n == 0) emptyStream() else TakeStream(this, n) } /** @@ -1275,10 +1393,11 @@ public fun String.take(n: Int): String { */ public fun Array.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1288,10 +1407,11 @@ public fun Array.takeLast(n: Int): List { */ public fun BooleanArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1301,10 +1421,11 @@ public fun BooleanArray.takeLast(n: Int): List { */ public fun ByteArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1314,10 +1435,11 @@ public fun ByteArray.takeLast(n: Int): List { */ public fun CharArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1327,10 +1449,11 @@ public fun CharArray.takeLast(n: Int): List { */ public fun DoubleArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1340,10 +1463,11 @@ public fun DoubleArray.takeLast(n: Int): List { */ public fun FloatArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1353,10 +1477,11 @@ public fun FloatArray.takeLast(n: Int): List { */ public fun IntArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1366,10 +1491,11 @@ public fun IntArray.takeLast(n: Int): List { */ public fun LongArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1379,10 +1505,11 @@ public fun LongArray.takeLast(n: Int): List { */ public fun ShortArray.takeLast(n: Int): List { require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1392,10 +1519,11 @@ public fun ShortArray.takeLast(n: Int): List { */ 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() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list } @@ -1409,6 +1537,138 @@ public fun String.takeLast(n: Int): String { return substring(length - Math.min(n, length), length) } +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun Array.takeLastWhile(predicate: (T) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun BooleanArray.takeLastWhile(predicate: (Boolean) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun ByteArray.takeLastWhile(predicate: (Byte) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun CharArray.takeLastWhile(predicate: (Char) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun DoubleArray.takeLastWhile(predicate: (Double) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun FloatArray.takeLastWhile(predicate: (Float) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun IntArray.takeLastWhile(predicate: (Int) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun LongArray.takeLastWhile(predicate: (Long) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun ShortArray.takeLastWhile(predicate: (Short) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a list containing last elements satisfying the given [predicate]. + */ +public inline fun List.takeLastWhile(predicate: (T) -> Boolean): List { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() +} + +/** + * Returns a string containing last characters that satisfy the given [predicate]. + */ +public inline fun String.takeLastWhile(predicate: (Char) -> Boolean): String { + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return substring(index + 1) + } + } + return this +} + /** * Returns a list containing first elements satisfying the given [predicate]. */ diff --git a/libraries/stdlib/src/kotlin/collections/Sequence.kt b/libraries/stdlib/src/kotlin/collections/Sequence.kt index 9326514dec7..0cd77f967fa 100644 --- a/libraries/stdlib/src/kotlin/collections/Sequence.kt +++ b/libraries/stdlib/src/kotlin/collections/Sequence.kt @@ -70,6 +70,9 @@ public fun sequenceOf(progression: Progression): Sequence = object : S */ public fun emptySequence(): Sequence = EmptySequence +deprecated("Remove in M13 with streams.") +private fun emptyStream(): Stream = EmptySequence + private object EmptySequence : Sequence { override fun iterator(): Iterator = EmptyIterator } diff --git a/libraries/stdlib/test/collections/ArraysJVMTest.kt b/libraries/stdlib/test/collections/ArraysJVMTest.kt index 79c8203c4d4..6605aa45b5a 100644 --- a/libraries/stdlib/test/collections/ArraysJVMTest.kt +++ b/libraries/stdlib/test/collections/ArraysJVMTest.kt @@ -233,6 +233,24 @@ class ArraysJVMTest { } } + test fun dropLast() { + expect(listOf(), { intArrayOf().dropLast(1) }) + expect(listOf(), { intArrayOf(1).dropLast(1) }) + expect(listOf(1), { intArrayOf(1).dropLast(0) }) + expect(listOf(2), { intArrayOf(2, 3).dropLast(1) }) + expect(listOf(3000000000000), { longArrayOf(3000000000000, 2000000000000).dropLast(1) }) + expect(listOf(2.toByte()), { byteArrayOf(2, 3).dropLast(1) }) + expect(listOf(2.toShort()), { shortArrayOf(2, 3).dropLast(1) }) + expect(listOf(2.0f), { floatArrayOf(2f, 3f).dropLast(1) }) + expect(listOf(2.0), { doubleArrayOf(2.0, 3.0).dropLast(1) }) + expect(listOf(true), { booleanArrayOf(true, false).dropLast(1) }) + expect(listOf('a'), { charArrayOf('a', 'b').dropLast(1) }) + expect(listOf("a"), { arrayOf("a", "b").dropLast(1) }) + fails { + listOf(1).dropLast(-1) + } + } + test fun dropWhile() { expect(listOf(), { intArrayOf().dropWhile { it < 3 } }) expect(listOf(), { intArrayOf(1).dropWhile { it < 3 } }) @@ -247,6 +265,20 @@ class ArraysJVMTest { expect(listOf("b", "a"), { arrayOf("a", "b", "a").dropWhile { it < "b" } }) } + test fun dropLastWhile() { + expect(listOf(), { intArrayOf().dropLastWhile { it < 3 } }) + expect(listOf(), { intArrayOf(1).dropLastWhile { it < 3 } }) + expect(listOf(2, 3), { intArrayOf(2, 3, 1).dropLastWhile { it < 3 } }) + expect(listOf(3000000000000), { longArrayOf(3000000000000, 2000000000000).dropLastWhile { it < 3000000000000 } }) + expect(listOf(2.toByte(), 3.toByte()), { byteArrayOf(2, 3, 1).dropLastWhile { it < 3 } }) + expect(listOf(2.toShort(), 3.toShort()), { shortArrayOf(2, 3, 1).dropLastWhile { it < 3 } }) + expect(listOf(2f, 3f), { floatArrayOf(2f, 3f, 1f).dropLastWhile { it < 3 } }) + expect(listOf(2.0, 3.0), { doubleArrayOf(2.0, 3.0, 1.0).dropLastWhile { it < 3 } }) + expect(listOf(true, false), { booleanArrayOf(true, false, true).dropLastWhile { it } }) + expect(listOf('a', 'b'), { charArrayOf('a', 'b', 'a').dropLastWhile { it < 'b' } }) + expect(listOf("a", "b"), { arrayOf("a", "b", "a").dropLastWhile { it < "b" } }) + } + test fun take() { expect(listOf(), { intArrayOf().take(1) }) expect(listOf(), { intArrayOf(1).take(0) }) @@ -293,8 +325,22 @@ class ArraysJVMTest { expect(listOf(2f), { floatArrayOf(2f, 3f, 1f).takeWhile { it < 3 } }) expect(listOf(2.0), { doubleArrayOf(2.0, 3.0, 1.0).takeWhile { it < 3 } }) expect(listOf(true), { booleanArrayOf(true, false, true).takeWhile { it } }) - expect(listOf('a'), { charArrayOf('a', 'b', 'a').takeWhile { it < 'b' } }) - expect(listOf("a"), { arrayOf("a", "b", "a").takeWhile { it < "b" } }) + expect(listOf('a'), { charArrayOf('a', 'c', 'b').takeWhile { it < 'c' } }) + expect(listOf("a"), { arrayOf("a", "c", "b").takeWhile { it < "c" } }) + } + + test fun takeLastWhile() { + expect(listOf(), { intArrayOf().takeLastWhile { it < 3 } }) + expect(listOf(1), { intArrayOf(1).takeLastWhile { it < 3 } }) + expect(listOf(1), { intArrayOf(2, 3, 1).takeLastWhile { it < 3 } }) + expect(listOf(2000000000000), { longArrayOf(3000000000000, 2000000000000).takeLastWhile { it < 3000000000000 } }) + expect(listOf(1.toByte()), { byteArrayOf(2, 3, 1).takeLastWhile { it < 3 } }) + expect(listOf(1.toShort()), { shortArrayOf(2, 3, 1).takeLastWhile { it < 3 } }) + expect(listOf(1f), { floatArrayOf(2f, 3f, 1f).takeLastWhile { it < 3 } }) + expect(listOf(1.0), { doubleArrayOf(2.0, 3.0, 1.0).takeLastWhile { it < 3 } }) + expect(listOf(true), { booleanArrayOf(true, false, true).takeLastWhile { it } }) + expect(listOf('b'), { charArrayOf('a', 'c', 'b').takeLastWhile { it < 'c' } }) + expect(listOf("b"), { arrayOf("a", "c", "b").takeLastWhile { it < "c" } }) } test fun filter() { diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 9d34f3c3fc9..7cc82c6bfaf 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -273,6 +273,17 @@ class CollectionTest { assertEquals(listOf("bar", "abc"), coll.dropWhile { it.startsWith("f") }) } + test fun dropLast() { + val coll = listOf("foo", "bar", "abc") + assertEquals(coll, coll.dropLast(0)) + assertEquals(emptyList(), coll.dropLast(coll.size())) + assertEquals(emptyList(), coll.dropLast(coll.size() + 1)) + assertEquals(listOf("foo", "bar"), coll.dropLast(1)) + assertEquals(listOf("foo"), coll.dropLast(2)) + + fails { coll.dropLast(-1) } + } + test fun dropLastWhile() { val coll = listOf("Foo", "bare", "abc" ) assertEquals(coll, coll.dropLastWhile { false }) @@ -283,16 +294,43 @@ class CollectionTest { test fun take() { val coll = listOf("foo", "bar", "abc") + assertEquals(emptyList(), coll.take(0)) assertEquals(listOf("foo"), coll.take(1)) assertEquals(listOf("foo", "bar"), coll.take(2)) + assertEquals(coll, coll.take(coll.size())) + assertEquals(coll, coll.take(coll.size() + 1)) + + fails { coll.take(-1) } } test fun takeWhile() { val coll = listOf("foo", "bar", "abc") + assertEquals(emptyList(), coll.takeWhile { false }) + assertEquals(coll, coll.takeWhile { true }) assertEquals(listOf("foo"), coll.takeWhile { it.startsWith("f") }) assertEquals(listOf("foo", "bar", "abc"), coll.takeWhile { it.length() == 3 }) } + test fun takeLast() { + val coll = listOf("foo", "bar", "abc") + + assertEquals(emptyList(), coll.takeLast(0)) + assertEquals(listOf("abc"), coll.takeLast(1)) + assertEquals(listOf("bar", "abc"), coll.takeLast(2)) + assertEquals(coll, coll.takeLast(coll.size())) + assertEquals(coll, coll.takeLast(coll.size() + 1)) + + fails { coll.takeLast(-1) } + } + + test fun takeLastWhile() { + val coll = listOf("foo", "bar", "abc") + assertEquals(emptyList(), coll.takeLastWhile { false }) + assertEquals(coll, coll.takeLastWhile { true }) + assertEquals(listOf("abc"), coll.takeLastWhile { it.startsWith("a") }) + assertEquals(listOf("bar", "abc"), coll.takeLastWhile { it[0] < 'c' }) + } + test fun copyToArray() { val data = listOf("foo", "bar") val arr = data.toTypedArray() diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index fb9b9980279..8f1b5b12778 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -12,6 +12,7 @@ fun filtering(): List { body { """ 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 @@ -42,7 +43,7 @@ fun filtering(): List { body(Sequences) { """ require(n >= 0, { "Requested element count $n is less than zero." }) - return DropSequence(this, n) + return if (n == 0) this else DropSequence(this, n) """ } @@ -53,6 +54,8 @@ fun filtering(): List { body(ArraysOfObjects, ArraysOfPrimitives) { """ require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) + return toList() if (n >= size()) return emptyList() @@ -72,8 +75,10 @@ fun filtering(): List { body { """ require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() + if (this is Collection && n >= size()) return toList() var count = 0 - val list = ArrayList(Math.min(n, collectionSizeOrDefault(n))) + val list = ArrayList(n) for (item in this) { if (count++ == n) break @@ -97,18 +102,19 @@ fun filtering(): List { body(Sequences) { """ require(n >= 0, { "Requested element count $n is less than zero." }) - return TakeSequence(this, n) + return if (n == 0) emptySequence() else TakeSequence(this, n) """ } body(ArraysOfObjects, ArraysOfPrimitives) { """ require(n >= 0, "Requested element count $n is less than zero.") + if (n == 0) return emptyList() + if (n >= size()) return toList() var count = 0 - val realN = Math.min(n, size()) - val list = ArrayList(realN) + val list = ArrayList(n) for (item in this) { - if (count++ == realN) + if (count++ == n) break; list.add(item) } @@ -117,6 +123,29 @@ fun filtering(): List { } } + templates add f("dropLast(n: Int)") { + val n = "\$n" + only(Lists, ArraysOfObjects, ArraysOfPrimitives, Strings) + + doc { "Returns a list containing all elements except last [n] elements." } + returns("List") + body { + """ + require(n >= 0, { "Requested element count $n is less than zero." }) + return take((size() - n).coerceAtLeast(0)) + """ + } + + doc(Strings) { "Returns a string with the last [n] characters removed." } + returns("String", Strings) + body(Strings) { + """ + require(n >= 0, { "Requested element count $n is less than zero." }) + return take((length() - n).coerceAtLeast(0)) + """ + } + } + templates add f("takeLast(n: Int)") { val n = "\$n" doc { "Returns a list containing last [n] elements." } @@ -136,10 +165,11 @@ fun filtering(): List { body(Lists, ArraysOfObjects, ArraysOfPrimitives) { """ require(n >= 0, { "Requested element count $n is less than zero." }) + if (n == 0) return emptyList() val size = size() - val realN = Math.min(n, size) - val list = ArrayList(realN) - for (index in size - realN .. size - 1) + if (n >= size) return toList() + val list = ArrayList(n) + for (index in size - n .. size - 1) list.add(this[index]) return list """ @@ -250,6 +280,37 @@ fun filtering(): List { } } + templates add f("takeLastWhile(predicate: (T) -> Boolean)") { + inline(true) + only(Lists, ArraysOfObjects, ArraysOfPrimitives, Strings) + doc { "Returns a list containing last elements satisfying the given [predicate]."} + returns("List") + + body { + """ + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return drop(index + 1) + } + } + return toList() + """ + } + + doc(Strings) { "Returns a string containing last characters that satisfy the given [predicate]." } + returns("String", Strings) + body(Strings) { + """ + for (index in lastIndex downTo 0) { + if (!predicate(this[index])) { + return substring(index + 1) + } + } + return this + """ + } + } + templates add f("filter(predicate: (T) -> Boolean)") { inline(true)