From 05fd2b012afc865c03c002ee2517885170624928 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 4 Nov 2015 06:02:54 +0300 Subject: [PATCH] Provide overloads both for Strings and CharSequences of filter, filterNot, reversed and partition --- libraries/stdlib/src/generated/_Strings.kt | 71 ++++++++++++------- libraries/stdlib/test/text/StringTest.kt | 43 ++++++++--- .../src/templates/Filtering.kt | 40 +++++------ .../src/templates/Generators.kt | 16 ++--- .../src/templates/Ordering.kt | 11 ++- 5 files changed, 106 insertions(+), 75 deletions(-) diff --git a/libraries/stdlib/src/generated/_Strings.kt b/libraries/stdlib/src/generated/_Strings.kt index 211517c455e..b1e840aa995 100644 --- a/libraries/stdlib/src/generated/_Strings.kt +++ b/libraries/stdlib/src/generated/_Strings.kt @@ -504,31 +504,29 @@ public inline fun String.dropWhile(predicate: (Char) -> Boolean): String { } /** - * Returns a string containing only those characters from the original string that match the given [predicate]. + * Returns a char sequence containing only those characters from the original char sequence that match the given [predicate]. */ -public inline fun CharSequence.filter(predicate: (Char) -> Boolean): String { - return filterTo(StringBuilder(), predicate).toString() +public inline fun CharSequence.filter(predicate: (Char) -> Boolean): CharSequence { + return filterTo(StringBuilder(), predicate) } /** - * Returns a list containing all elements matching the given [predicate]. + * Returns a string containing only those characters from the original string that match the given [predicate]. */ -@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) public inline fun String.filter(predicate: (Char) -> Boolean): String { return filterTo(StringBuilder(), predicate).toString() } /** - * Returns a string containing only those characters from the original string that do not match the given [predicate]. + * Returns a char sequence containing only those characters from the original char sequence that do not match the given [predicate]. */ -public inline fun CharSequence.filterNot(predicate: (Char) -> Boolean): String { - return filterNotTo(StringBuilder(), predicate).toString() +public inline fun CharSequence.filterNot(predicate: (Char) -> Boolean): CharSequence { + return filterNotTo(StringBuilder(), predicate) } /** - * Returns a list containing all elements not matching the given [predicate]. + * Returns a string containing only those characters from the original string that do not match the given [predicate]. */ -@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) public inline fun String.filterNot(predicate: (Char) -> Boolean): String { return filterNotTo(StringBuilder(), predicate).toString() } @@ -574,7 +572,15 @@ public inline fun String.filterTo(destination: C, predicate: (C } /** - * Returns a string containing characters at indices at the specified [indices]. + * Returns a char sequence containing characters of the original char sequence at the specified range of [indices]. + */ +public fun CharSequence.slice(indices: IntRange): CharSequence { + if (indices.isEmpty()) return "" + return subSequence(indices) +} + +/** + * Returns a string containing characters of the original string at the specified range of [indices]. */ public fun String.slice(indices: IntRange): String { if (indices.isEmpty()) return "" @@ -582,7 +588,20 @@ public fun String.slice(indices: IntRange): String { } /** - * Returns a string containing characters at specified [indices]. + * Returns a char sequence containing characters of the original char sequence at specified [indices]. + */ +public fun CharSequence.slice(indices: Iterable): CharSequence { + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return "" + val result = StringBuilder(size) + for (i in indices) { + result.append(get(i)) + } + return result +} + +/** + * Returns a string containing characters of the original string at specified [indices]. */ public fun String.slice(indices: Iterable): String { val size = indices.collectionSizeOrDefault(10) @@ -675,18 +694,17 @@ public inline fun String.takeWhile(predicate: (Char) -> Boolean): String { } /** - * Returns a string with characters in reversed order. + * Returns a char sequence with characters in reversed order. */ -public fun CharSequence.reversed(): String { - return StringBuilder().append(this).reverse().toString() +public fun CharSequence.reversed(): CharSequence { + return StringBuilder(this).reverse() } /** - * Returns a list with elements in reversed order. + * Returns a string with characters in reversed order. */ -@Deprecated("Provided for binary compatibility", level = DeprecationLevel.HIDDEN) public fun String.reversed(): String { - return StringBuilder().append(this).reverse().toString() + return StringBuilder(this).reverse().toString() } /** @@ -1450,11 +1468,11 @@ public inline fun String.sumByDouble(transform: (Char) -> Double): Double { } /** - * Splits the original char sequence into pair of strings, - * where *first* string contains characters for which [predicate] yielded `true`, - * while *second* string contains characters for which [predicate] yielded `false`. + * Splits the original char sequence into pair of char sequences, + * where *first* char sequence contains characters for which [predicate] yielded `true`, + * while *second* char sequence contains characters for which [predicate] yielded `false`. */ -public inline fun CharSequence.partition(predicate: (Char) -> Boolean): Pair { +public inline fun CharSequence.partition(predicate: (Char) -> Boolean): Pair { val first = StringBuilder() val second = StringBuilder() for (element in this) { @@ -1464,15 +1482,14 @@ public inline fun CharSequence.partition(predicate: (Char) -> Boolean): Pair Boolean): Pair { val first = StringBuilder() val second = StringBuilder() diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index e5bf5d29b65..2c61cf5c2dd 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -216,14 +216,20 @@ class StringTest { assertEquals("aDAB", data.slice(iter).toString()) } - @test fun reverse() = withOneCharSequenceArg { arg1 -> - fun String.reversed(): String = arg1(this).reversed() - + @test fun reverse() { assertEquals("dcba", "abcd".reversed()) assertEquals("4321", "1234".reversed()) assertEquals("", "".reversed()) } + @test fun reverseCharSequence() = withOneCharSequenceArg { arg1 -> + fun String.reversedCs(): CharSequence = arg1(this).reversed() + + assertContentEquals("dcba", "abcd".reversedCs()) + assertContentEquals("4321", "1234".reversedCs()) + assertContentEquals("", "".reversedCs()) + } + @test fun indices() = withOneCharSequenceArg { arg1 -> fun String.indices(): IntRange = arg1(this).indices @@ -716,14 +722,24 @@ class StringTest { } - @test fun filter() = withOneCharSequenceArg { arg1 -> - assertEquals("acdca", arg1("abcdcba").filter { !it.equals('b') }) - assertEquals("1234", arg1("a1b2c3d4").filter { it.isAsciiDigit() }) + @test fun filter() { + assertEquals("acdca", ("abcdcba").filter { !it.equals('b') }) + assertEquals("1234", ("a1b2c3d4").filter { it.isAsciiDigit() }) } - @test fun filterNot() = withOneCharSequenceArg { arg1 -> - assertEquals("acdca", arg1("abcdcba").filterNot { it.equals('b') }) - assertEquals("abcd", arg1("a1b2c3d4").filterNot { it.isAsciiDigit() }) + @test fun filterCharSequence() = withOneCharSequenceArg { arg1 -> + assertContentEquals("acdca", arg1("abcdcba").filter { !it.equals('b') }) + assertContentEquals("1234", arg1("a1b2c3d4").filter { it.isAsciiDigit() }) + } + + @test fun filterNot() { + assertEquals("acdca", ("abcdcba").filterNot { it.equals('b') }) + assertEquals("abcd", ("a1b2c3d4").filterNot { it.isAsciiDigit() }) + } + + @test fun filterNotCharSequence() = withOneCharSequenceArg { arg1 -> + assertContentEquals("acdca", arg1("abcdcba").filterNot { it.equals('b') }) + assertContentEquals("abcd", arg1("a1b2c3d4").filterNot { it.isAsciiDigit() }) } @test fun all() = withOneCharSequenceArg("AbCd") { data -> @@ -754,12 +770,19 @@ class StringTest { assertNull(data.filterNot { it.isAsciiLetter() || it.isAsciiDigit() }.firstOrNull()) } - @test fun partition() = withOneCharSequenceArg("a1b2c3") { data -> + @test fun partition() { + val data = "a1b2c3" val pair = data.partition { it.isAsciiDigit() } assertEquals("123", pair.first, "pair.first") assertEquals("abc", pair.second, "pair.second") } + @test fun partitionCharSequence() = withOneCharSequenceArg("a1b2c3") { data -> + val pair = data.partition { it.isAsciiDigit() } + assertContentEquals("123", pair.first, "pair.first") + assertContentEquals("abc", pair.second, "pair.second") + } + @test fun map() = withOneCharSequenceArg { arg1 -> assertEquals(listOf('a', 'b', 'c'), arg1("abc").map { it }) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index b6fbe072d84..3bcb88471bd 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -1,6 +1,8 @@ package templates import templates.Family.* +import templates.DocExtensions.collection +import templates.DocExtensions.element fun filtering(): List { val templates = arrayListOf() @@ -357,14 +359,9 @@ fun filtering(): List { """ } - deprecate(Strings) { forBinaryCompatibility } - doc(CharSequences) { "Returns a string containing only those characters from the original string that match the given [predicate]." } - returns(CharSequences, Strings) { "String" } - body(CharSequences, Strings) { - """ - return filterTo(StringBuilder(), predicate).toString() - """ - } + doc(CharSequences, Strings) { f -> "Returns a ${f.collection} containing only those characters from the original ${f.collection} that match the given [predicate]." } + returns(CharSequences, Strings) { "SELF" } + body(CharSequences, Strings) { f -> """return filterTo(StringBuilder(), predicate)${toResult(f)}""" } inline(false, Sequences) doc(Sequences) { "Returns a sequence containing all elements matching the given [predicate]." } @@ -414,14 +411,9 @@ fun filtering(): List { """ } - deprecate(Strings) { forBinaryCompatibility } - doc(CharSequences) { "Returns a string containing only those characters from the original string that do not match the given [predicate]." } - returns(CharSequences, Strings) { "String" } - body(CharSequences, Strings) { - """ - return filterNotTo(StringBuilder(), predicate).toString() - """ - } + doc(CharSequences, Strings) { f -> "Returns a ${f.collection} containing only those characters from the original ${f.collection} that do not match the given [predicate]." } + returns(CharSequences, Strings) { "SELF" } + body(CharSequences, Strings) { f -> """return filterNotTo(StringBuilder(), predicate)${toResult(f)}""" } inline(false, Sequences) doc(Sequences) { "Returns a sequence containing all elements not matching the given [predicate]." } @@ -509,9 +501,9 @@ fun filtering(): List { """ } - doc(Strings) { "Returns a string containing characters at specified [indices]." } - returns(Strings) { "String" } - body(Strings) { + doc(CharSequences, Strings) { f -> "Returns a ${f.collection} containing ${f.element}s of the original ${f.collection} at specified [indices]." } + returns(CharSequences, Strings) { "SELF" } + body(CharSequences, Strings) { f -> """ val size = indices.collectionSizeOrDefault(10) if (size == 0) return "" @@ -519,7 +511,7 @@ fun filtering(): List { for (i in indices) { result.append(get(i)) } - return result.toString() + return result${toResult(f)} """ } } @@ -541,12 +533,12 @@ fun filtering(): List { """ } - doc(Strings) { "Returns a string containing characters at indices at the specified [indices]." } - returns(Strings) { "String" } - body(Strings) { + doc(CharSequences, Strings) { f -> "Returns a ${f.collection} containing ${f.element}s of the original ${f.collection} at the specified range of [indices]." } + returns(CharSequences, Strings) { "SELF" } + body(CharSequences, Strings) { f -> """ if (indices.isEmpty()) return "" - return substring(indices) + return ${ mapOf(Strings to "substring", CharSequences to "subSequence")[f]}(indices) """ } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt index 08ec47e6b3e..04700cb3c64 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt @@ -420,16 +420,16 @@ fun generators(): List { """ } - deprecate(Strings) { forBinaryCompatibility } - doc(CharSequences) { + doc(CharSequences, Strings) { f -> """ - Splits the original char sequence into pair of strings, - where *first* string contains characters for which [predicate] yielded `true`, - while *second* string contains characters for which [predicate] yielded `false`. + Splits the original ${f.collection} into pair of ${f.collection}s, + where *first* ${f.collection} contains characters for which [predicate] yielded `true`, + while *second* ${f.collection} contains characters for which [predicate] yielded `false`. """ } - returns(CharSequences, Strings) { "Pair" } - body(CharSequences, Strings) { + returns(CharSequences, Strings) { "Pair" } + body(CharSequences, Strings) { f -> + val toString = if (f == Strings) ".toString()" else "" """ val first = StringBuilder() val second = StringBuilder() @@ -440,7 +440,7 @@ fun generators(): List { second.append(element) } } - return Pair(first.toString(), second.toString()) + return Pair(first$toString, second$toString) """ } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt index 9377ddbce38..2fb41c324e1 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt @@ -1,6 +1,7 @@ package templates import templates.Family.* +import templates.DocExtensions.collection fun ordering(): List { val templates = arrayListOf() @@ -39,13 +40,11 @@ fun ordering(): List { """ } - deprecate(Strings) { forBinaryCompatibility } - doc(CharSequences) { "Returns a string with characters in reversed order." } - returns(CharSequences, Strings) { "String" } - body(CharSequences, Strings) { - // TODO: Replace with StringBuilder(this) when JS can handle it + doc(CharSequences, Strings) { f -> "Returns a ${f.collection} with characters in reversed order." } + returns(CharSequences, Strings) { "SELF" } + body(CharSequences, Strings) { f -> """ - return StringBuilder().append(this).reverse().toString() + return StringBuilder(this).reverse()${ if (f == Strings) ".toString()" else "" } """ }