diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index dee8dcb45c1..5e2f230caac 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -13,12 +13,12 @@ import java.util.Collections // TODO: it's temporary while we have java.util.Col * Returns a list containing all elements except first [n] elements */ public fun Array.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -27,12 +27,12 @@ public fun Array.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun BooleanArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -41,12 +41,12 @@ public fun BooleanArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun ByteArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -55,12 +55,12 @@ public fun ByteArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun CharArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -69,12 +69,12 @@ public fun CharArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun DoubleArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -83,12 +83,12 @@ public fun DoubleArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun FloatArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -97,12 +97,12 @@ public fun FloatArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun IntArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -111,12 +111,12 @@ public fun IntArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun LongArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -125,12 +125,12 @@ public fun LongArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun ShortArray.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() - var count = 0 val list = ArrayList(size() - n) - for (item in this) { - if (count++ >= n) list.add(item) + for (index in n..size() - 1) { + list.add(this[index]) } return list } @@ -139,6 +139,7 @@ public fun ShortArray.drop(n: Int): List { * Returns a list containing all elements except first [n] elements */ public fun Collection.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() var count = 0 @@ -153,6 +154,7 @@ public fun Collection.drop(n: Int): List { * 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." }) var count = 0 val list = ArrayList() for (item in this) { @@ -161,10 +163,25 @@ public fun Iterable.drop(n: Int): List { return list } +/** + * Returns a list containing all elements except first [n] elements + */ +public fun List.drop(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + if (n >= size()) + return emptyList() + val list = ArrayList(size() - n) + for (index in n..size() - 1) { + list.add(this[index]) + } + return list +} + /** * Returns a sequence containing all elements except first [n] elements */ public fun Sequence.drop(n: Int): Sequence { + require(n >= 0, { "Requested element count $n is less than zero." }) return DropSequence(this, n) } @@ -174,6 +191,7 @@ deprecated("Migrate to using Sequence and respective functions") * Returns a stream containing all elements except first [n] elements */ public fun Stream.drop(n: Int): Stream { + require(n >= 0, { "Requested element count $n is less than zero." }) return DropStream(this, n) } @@ -961,6 +979,7 @@ public fun String.slice(indices: Iterable): String { * Returns a list containing first [n] elements */ public fun Array.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -976,6 +995,7 @@ public fun Array.take(n: Int): List { * Returns a list containing first [n] elements */ public fun BooleanArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -991,6 +1011,7 @@ public fun BooleanArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun ByteArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1006,6 +1027,7 @@ public fun ByteArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun CharArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1021,6 +1043,7 @@ public fun CharArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun DoubleArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1036,6 +1059,7 @@ public fun DoubleArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun FloatArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1051,6 +1075,7 @@ public fun FloatArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun IntArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1066,6 +1091,7 @@ public fun IntArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun LongArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1081,6 +1107,7 @@ public fun LongArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun ShortArray.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1096,6 +1123,7 @@ public fun ShortArray.take(n: Int): List { * Returns a list containing first [n] elements */ public fun Collection.take(n: Int): List { + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -1111,6 +1139,7 @@ public fun Collection.take(n: Int): 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." }) var count = 0 val list = ArrayList(n) for (item in this) { @@ -1125,6 +1154,7 @@ public fun Iterable.take(n: Int): List { * Returns a sequence containing first *n* elements */ public fun Sequence.take(n: Int): Sequence { + require(n >= 0, { "Requested element count $n is less than zero." }) return TakeSequence(this, n) } @@ -1134,6 +1164,7 @@ deprecated("Migrate to using Sequence and respective functions") * Returns a stream containing first *n* elements */ public fun Stream.take(n: Int): Stream { + require(n >= 0, { "Requested element count $n is less than zero." }) return TakeStream(this, n) } @@ -1144,6 +1175,143 @@ public fun String.take(n: Int): String { return substring(0, Math.min(n, length())) } +/** + * Returns a list containing last [n] elements + */ +public fun Array.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun BooleanArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun ByteArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun CharArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun DoubleArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun FloatArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun IntArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun LongArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a list containing last [n] elements + */ +public fun ShortArray.takeLast(n: Int): List { + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * 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." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list +} + +/** + * Returns a string containing the last [n] characters from this string, or the entire string if this string is shorter + */ +public fun String.takeLast(n: Int): String { + return substring(length() - Math.min(n, length()), length()) +} + /** * Returns a list containing first elements satisfying the given [predicate] */ diff --git a/libraries/stdlib/test/collections/ArraysJVMTest.kt b/libraries/stdlib/test/collections/ArraysJVMTest.kt index 0d69356f920..1189c774003 100644 --- a/libraries/stdlib/test/collections/ArraysJVMTest.kt +++ b/libraries/stdlib/test/collections/ArraysJVMTest.kt @@ -216,6 +216,7 @@ class ArraysJVMTest { } test fun drop() { + expect(listOf(1), { intArray(1).drop(0) }) expect(listOf(), { intArray().drop(1) }) expect(listOf(), { intArray(1).drop(1) }) expect(listOf(3), { intArray(2, 3).drop(1) }) @@ -227,6 +228,9 @@ class ArraysJVMTest { expect(listOf(false), { booleanArray(true, false).drop(1) }) expect(listOf('b'), { charArray('a', 'b').drop(1) }) expect(listOf("b"), { array("a", "b").drop(1) }) + fails { + listOf(2).drop(-1) + } } test fun dropWhile() { @@ -245,6 +249,7 @@ class ArraysJVMTest { test fun take() { expect(listOf(), { intArray().take(1) }) + expect(listOf(), { intArray(1).take(0) }) expect(listOf(1), { intArray(1).take(1) }) expect(listOf(2), { intArray(2, 3).take(1) }) expect(listOf(3000000000000), { longArray(3000000000000, 2000000000000).take(1) }) @@ -255,6 +260,27 @@ class ArraysJVMTest { expect(listOf(true), { booleanArray(true, false).take(1) }) expect(listOf('a'), { charArray('a', 'b').take(1) }) expect(listOf("a"), { array("a", "b").take(1) }) + fails { + listOf(1).take(-1) + } + } + + test fun takeLast() { + expect(listOf(), { intArray().takeLast(1) }) + expect(listOf(), { intArray(1).takeLast(0) }) + expect(listOf(1), { intArray(1).takeLast(1) }) + expect(listOf(3), { intArray(2, 3).takeLast(1) }) + expect(listOf(2000000000000), { longArray(3000000000000, 2000000000000).takeLast(1) }) + expect(listOf(3.toByte()), { byteArray(2, 3).takeLast(1) }) + expect(listOf(3.toShort()), { shortArray(2, 3).takeLast(1) }) + expect(listOf(3.0f), { floatArray(2f, 3f).takeLast(1) }) + expect(listOf(3.0), { doubleArray(2.0, 3.0).takeLast(1) }) + expect(listOf(false), { booleanArray(true, false).takeLast(1) }) + expect(listOf('b'), { charArray('a', 'b').takeLast(1) }) + expect(listOf("b"), { array("a", "b").takeLast(1) }) + fails { + listOf(1).takeLast(-1) + } } test fun takeWhile() { diff --git a/libraries/stdlib/test/text/StringJVMTest.kt b/libraries/stdlib/test/text/StringJVMTest.kt index 6bb71f05f45..f7e5703bf9a 100644 --- a/libraries/stdlib/test/text/StringJVMTest.kt +++ b/libraries/stdlib/test/text/StringJVMTest.kt @@ -332,5 +332,12 @@ class StringJVMTest { assertEquals("BCDabc", builder.slice(1..6)) assertEquals("baD", builder.slice(5 downTo 3)) assertEquals("aDAB", builder.slice(iter)) + + fails { + "abc".slice(listOf(1,4)) + } + fails { + builder.slice(listOf(10)) + } } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index 8afe4ac210e..5abba8d820d 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -6,10 +6,12 @@ fun filtering(): List { val templates = arrayListOf() templates add f("drop(n: Int)") { + val n = "\$n" doc { "Returns a list containing all elements except first [n] elements" } returns("List") body { """ + require(n >= 0, { "Requested element count $n is less than zero." }) var count = 0 val list = ArrayList() for (item in this) { @@ -23,6 +25,7 @@ fun filtering(): List { returns(Sequences) { "Sequence" } body(Sequences) { """ + require(n >= 0, { "Requested element count $n is less than zero." }) return DropSequence(this, n) """ } @@ -31,8 +34,9 @@ fun filtering(): List { body(Strings) { "return substring(Math.min(n, length()))" } returns(Strings) { "String" } - body(Collections, ArraysOfObjects, ArraysOfPrimitives) { + body(Collections) { """ + require(n >= 0, { "Requested element count $n is less than zero." }) if (n >= size()) return emptyList() @@ -44,13 +48,29 @@ fun filtering(): List { return list """ } + + body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + """ + require(n >= 0, { "Requested element count $n is less than zero." }) + if (n >= size()) + return emptyList() + + val list = ArrayList(size() - n) + for (index in n..size() - 1) { + list.add(this[index]) + } + return list + """ + } } templates add f("take(n: Int)") { + val n = "\$n" doc { "Returns a list containing first [n] elements" } returns("List") body { """ + require(n >= 0, { "Requested element count $n is less than zero." }) var count = 0 val list = ArrayList(n) for (item in this) { @@ -70,6 +90,7 @@ fun filtering(): List { returns(Sequences) { "Sequence" } body(Sequences) { """ + require(n >= 0, { "Requested element count $n is less than zero." }) return TakeSequence(this, n) """ } @@ -77,6 +98,7 @@ fun filtering(): List { include(Collections) body(Collections, ArraysOfObjects, ArraysOfPrimitives) { """ + require(n >= 0, "Requested element count $n is less than zero.") var count = 0 val realN = if (n > size()) size() else n val list = ArrayList(realN) @@ -90,6 +112,29 @@ fun filtering(): List { } } + templates add f("takeLast(n: Int)") { + val n = "\$n" + doc { "Returns a list containing last [n] elements" } + only(Lists, ArraysOfObjects, ArraysOfPrimitives, Strings) + returns("List") + + doc(Strings) { "Returns a string containing the last [n] characters from this string, or the entire string if this string is shorter"} + body(Strings) { "return substring(length() - Math.min(n, length()), length())" } + returns(Strings) { "String" } + + body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + """ + require(n >= 0, { "Requested element count $n is less than zero." }) + val size = size() + val realN = if (n > size) size else n + val list = ArrayList(realN) + for (index in size - realN .. size - 1) + list.add(this[index]) + return list + """ + } + } + templates add f("dropWhile(predicate: (T) -> Boolean)") { inline(true)