From cbc0e6404ef30b437698c3540c850ec17ce30da7 Mon Sep 17 00:00:00 2001 From: Ilya Ryzhenkov Date: Tue, 8 Apr 2014 15:40:53 +0400 Subject: [PATCH] Support String in generators, and migrate generated functions. --- libraries/stdlib/src/generated/_Aggregates.kt | 198 ++++++++ libraries/stdlib/src/generated/_Elements.kt | 84 ++++ libraries/stdlib/src/generated/_Filtering.kt | 86 ++++ libraries/stdlib/src/generated/_Generators.kt | 101 +++- libraries/stdlib/src/generated/_Mapping.kt | 70 ++- libraries/stdlib/src/generated/_Ordering.kt | 8 + libraries/stdlib/src/generated/_Snapshots.kt | 60 +++ libraries/stdlib/src/generated/_SpecialJVM.kt | 17 + libraries/stdlib/src/generated/_Streams.kt | 8 + libraries/stdlib/src/generated/_Strings.kt | 32 ++ libraries/stdlib/src/kotlin/text/Strings.kt | 54 +- .../stdlib/src/kotlin/text/StringsJVM.kt | 460 ++++-------------- libraries/stdlib/test/text/StringJVMTest.kt | 29 +- libraries/stdlib/test/text/StringTest.kt | 15 + .../src/templates/Aggregates.kt | 6 +- .../src/templates/Elements.kt | 19 +- .../kotlin-stdlib-gen/src/templates/Engine.kt | 22 +- .../src/templates/Filtering.kt | 88 +++- .../src/templates/Generators.kt | 46 +- .../kotlin-stdlib-gen/src/templates/Guards.kt | 2 +- .../src/templates/Mapping.kt | 6 +- .../src/templates/Ordering.kt | 14 + 22 files changed, 971 insertions(+), 454 deletions(-) diff --git a/libraries/stdlib/src/generated/_Aggregates.kt b/libraries/stdlib/src/generated/_Aggregates.kt index 5275e5bb3e6..aedd06d709b 100644 --- a/libraries/stdlib/src/generated/_Aggregates.kt +++ b/libraries/stdlib/src/generated/_Aggregates.kt @@ -115,6 +115,15 @@ public inline fun Stream.all(predicate: (T) -> Boolean) : Boolean { } +/** + * Returns *true* if all elements match the given *predicate* + */ +public inline fun String.all(predicate: (Char) -> Boolean) : Boolean { + for (element in this) if (!predicate(element)) return false + return true + +} + /** * Returns *true* if collection has at least one element */ @@ -223,6 +232,15 @@ public fun Stream.any() : Boolean { } +/** + * Returns *true* if collection has at least one element + */ +public fun String.any() : Boolean { + for (element in this) return true + return false + +} + /** * Returns *true* if any element matches the given *predicate* */ @@ -331,6 +349,15 @@ public inline fun Stream.any(predicate: (T) -> Boolean) : Boolean { } +/** + * Returns *true* if any element matches the given *predicate* + */ +public inline fun String.any(predicate: (Char) -> Boolean) : Boolean { + for (element in this) if (predicate(element)) return true + return false + +} + /** * Returns the number of elements */ @@ -428,6 +455,13 @@ public fun Stream.count() : Int { } +/** + * Returns the number of elements + */ +public fun String.count() : Int { + return size +} + /** * Returns the number of elements matching the given *predicate* */ @@ -548,6 +582,16 @@ public inline fun Stream.count(predicate: (T) -> Boolean) : Int { } +/** + * Returns the number of elements matching the given *predicate* + */ +public inline fun String.count(predicate: (Char) -> 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 */ @@ -658,6 +702,16 @@ public inline fun Stream.fold(initial: R, operation: (R, T) -> R) : R } +/** + * Accumulates value starting with *initial* value and applying *operation* from left to right to current accumulator value and each element + */ +public inline fun String.fold(initial: R, operation: (R, Char) -> 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 right to left to each element and current accumulator value */ @@ -788,6 +842,19 @@ public inline fun List.foldRight(initial: R, operation: (T, R) -> R) : } +/** + * Accumulates value starting with *initial* value and applying *operation* from right to left to each element and current accumulator value + */ +public inline fun String.foldRight(initial: R, operation: (Char, R) -> R) : R { + var index = size - 1 + var accumulator = initial + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator + +} + /** * Performs the given *operation* on each element */ @@ -884,6 +951,14 @@ public inline fun Stream.forEach(operation: (T) -> Unit) : Unit { } +/** + * Performs the given *operation* on each element + */ +public inline fun String.forEach(operation: (Char) -> Unit) : Unit { + for (element in this) operation(element) + +} + /** * Returns the largest element or null if there are no elements */ @@ -1036,6 +1111,22 @@ public fun > Stream.max() : T? { } +/** + * Returns the largest element or null if there are no elements + */ +public fun String.max() : Char? { + 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 */ @@ -1258,6 +1349,27 @@ public inline fun , T: Any> Stream.maxBy(f: (T) -> R) : T? { } +/** + * Returns the first element yielding the largest value of the given function or null if there are no elements + */ +public inline fun > String.maxBy(f: (Char) -> R) : Char? { + val iterator = iterator() + if (!iterator.hasNext()) return null + + var maxElem = iterator.next() + var maxValue = f(maxElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = f(e) + if (maxValue < v) { + maxElem = e + maxValue = v + } + } + return maxElem + +} + /** * Returns the first element yielding the largest value of the given function or null if there are no elements */ @@ -1423,6 +1535,22 @@ public fun > Stream.min() : T? { } +/** + * Returns the smallest element or null if there are no elements + */ +public fun String.min() : Char? { + 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 */ @@ -1645,6 +1773,27 @@ public inline fun , T: Any> Stream.minBy(f: (T) -> R) : T? { } +/** + * Returns the first element yielding the smallest value of the given function or null if there are no elements + */ +public inline fun > String.minBy(f: (Char) -> R) : Char? { + val iterator = iterator() + if (!iterator.hasNext()) return null + + var minElem = iterator.next() + var minValue = f(minElem) + while (iterator.hasNext()) { + val e = iterator.next() + val v = f(e) + if (minValue > v) { + minElem = e + minValue = v + } + } + return minElem + +} + /** * Returns the first element yielding the smallest value of the given function or null if there are no elements */ @@ -1774,6 +1923,15 @@ public fun Stream.none() : Boolean { } +/** + * Returns *true* if collection has no elements + */ +public fun String.none() : Boolean { + for (element in this) return false + return true + +} + /** * Returns *true* if no elements match the given *predicate* */ @@ -1882,6 +2040,15 @@ public inline fun Stream.none(predicate: (T) -> Boolean) : Boolean { } +/** + * Returns *true* if no elements match the given *predicate* + */ +public inline fun String.none(predicate: (Char) -> Boolean) : Boolean { + for (element in this) if (predicate(element)) return false + return true + +} + /** * Accumulates value starting with the first element and applying *operation* from left to right to current accumulator value and each element */ @@ -2047,6 +2214,21 @@ public inline fun Stream.reduce(operation: (T, T) -> T) : T { } +/** + * Accumulates value starting with the first element and applying *operation* from left to right to current accumulator value and each element + */ +public inline fun String.reduce(operation: (Char, Char) -> Char) : Char { + val iterator = this.iterator() + if (!iterator.hasNext()) throw UnsupportedOperationException("Empty iterable can't be reduced") + + var accumulator = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(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 */ @@ -2207,3 +2389,19 @@ public inline fun List.reduceRight(operation: (T, T) -> T) : T { } +/** + * Accumulates value starting with last element and applying *operation* from right to left to each element and current accumulator value + */ +public inline fun String.reduceRight(operation: (Char, Char) -> Char) : Char { + var index = size - 1 + if (index < 0) throw UnsupportedOperationException("Empty iterable can't be reduced") + + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + + return accumulator + +} + diff --git a/libraries/stdlib/src/generated/_Elements.kt b/libraries/stdlib/src/generated/_Elements.kt index a010a3816a4..ca2ca13e777 100644 --- a/libraries/stdlib/src/generated/_Elements.kt +++ b/libraries/stdlib/src/generated/_Elements.kt @@ -211,6 +211,14 @@ public fun Stream.elementAt(index : Int) : T { } +/** + * Returns element at given *index* + */ +public fun String.elementAt(index : Int) : Char { + return get(index) + +} + /** * Returns first element */ @@ -351,6 +359,16 @@ public fun Stream.first(): T { } } +/** + * Returns first element + */ +public fun String.first() : Char { + if (size == 0) + throw IllegalArgumentException("Collection is empty") + return this[0] + +} + /** * Returns first element matching the given *predicate* */ @@ -450,6 +468,15 @@ public inline fun Stream.first(predicate: (T) -> Boolean) : T { } +/** + * Returns first element matching the given *predicate* + */ +public inline fun String.first(predicate: (Char) -> Boolean) : Char { + for (element in this) if (predicate(element)) return element + throw IllegalArgumentException("No element matching predicate was found") + +} + /** * Returns first elementm, or null if collection is empty */ @@ -570,6 +597,14 @@ public fun Stream.firstOrNull(): T? { } } +/** + * Returns first elementm, or null if collection is empty + */ +public fun String.firstOrNull() : Char? { + return if (size > 0) this[0] else null + +} + /** * Returns first element matching the given *predicate*, or *null* if element was not found */ @@ -669,6 +704,15 @@ public inline fun Stream.firstOrNull(predicate: (T) -> Boolean) : T? { } +/** + * Returns first element matching the given *predicate*, or *null* if element was not found + */ +public inline fun String.firstOrNull(predicate: (Char) -> Boolean) : Char? { + for (element in this) if (predicate(element)) return element + return null + +} + /** * Returns first index of *element*, or -1 if the collection does not contain element */ @@ -966,6 +1010,16 @@ public fun Stream.last() : T { } +/** + * Returns last element + */ +public fun String.last() : Char { + if (size == 0) + throw IllegalArgumentException("Collection is empty") + return this[size - 1] + +} + /** * Returns last element matching the given *predicate* */ @@ -1464,6 +1518,14 @@ public fun Stream.lastOrNull() : T? { } +/** + * Returns last element, or null if collection is empty + */ +public fun String.lastOrNull() : Char? { + return if (size > 0) this[size - 1] else null + +} + /** * Returns last element matching the given *predicate*, or null if element was not found */ @@ -1770,6 +1832,16 @@ public fun Stream.single() : T { } +/** + * Returns single element, or throws exception if there is no or more than one element + */ +public fun String.single() : Char { + if (size != 1) + throw IllegalArgumentException("Collection has $size elements") + return this[0] + +} + /** * Returns single element matching the given *predicate*, or throws exception if there is no or more than one element */ @@ -2144,6 +2216,18 @@ public fun Stream.singleOrNull() : T? { } +/** + * Returns single element, or null if collection is empty, or throws exception if there is more than one element + */ +public fun String.singleOrNull() : Char? { + if (size == 0) + return null + if (size != 1) + throw IllegalArgumentException("Collection has $size elements") + return this[0] + +} + /** * Returns single element matching the given *predicate*, or null if element was not found or more than one elements were found */ diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index 720e985fced..2d0ba33ecd5 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -189,6 +189,13 @@ public fun Stream.drop(n: Int) : Stream { } +/** + * Returns a list containing all elements except first *n* elements + */ +public fun String.drop(n: Int) : String { + return substring(Math.min(n, size)) +} + /** * Returns a list containing all elements except first elements that satisfy the given *predicate* */ @@ -376,6 +383,18 @@ public fun Stream.dropWhile(predicate: (T)->Boolean) : Stream { } +/** + * Returns a list containing all elements except first elements that satisfy the given *predicate* + */ +public inline fun String.dropWhile(predicate: (Char) -> Boolean): String { + for (index in 0..length) + if (!predicate(get(index))) { + return substring(index) + } + return "" + +} + /** * Returns a list containing all elements matching the given *predicate* */ @@ -472,6 +491,14 @@ public fun Stream.filter(predicate: (T)->Boolean) : Stream { } +/** + * Returns a list containing all elements matching the given *predicate* + */ +public inline fun String.filter(predicate: (Char)->Boolean) : String { + return filterTo(StringBuilder(), predicate).toString() + +} + /** * Returns a list containing all elements not matching the given *predicate* */ @@ -568,6 +595,14 @@ public fun Stream.filterNot(predicate: (T)->Boolean) : Stream { } +/** + * Returns a list containing all elements not matching the given *predicate* + */ +public inline fun String.filterNot(predicate: (Char)->Boolean) : String { + return filterNotTo(StringBuilder(), predicate).toString() + +} + /** * Returns a list containing all elements that are not null */ @@ -727,6 +762,15 @@ public inline fun > Stream.filterNotTo(collecti } +/** + * Appends all characters not matching the given *predicate* to the given *collection* + */ +public inline fun String.filterNotTo(collection: C, predicate: (Char) -> Boolean) : C { + for (element in this) if (!predicate(element)) collection.append(element) + return collection + +} + /** * Appends all elements matching the given *predicate* into the given *collection* */ @@ -835,6 +879,17 @@ public inline fun > Stream.filterTo(collection: } +/** + * Appends all characters matching the given *predicate* to the given *collection* + */ +public inline fun String.filterTo(destination: C, predicate: (Char) -> Boolean): C { + for (index in 0..length - 1) { + val element = get(index) + if (predicate(element)) destination.append(element) + } + return destination +} + /** * Returns a list containing elements at specified positions */ @@ -955,6 +1010,18 @@ public fun List.slice(indices: Iterable) : List { } +/** + * Returns a list containing elements at specified positions + */ +public fun String.slice(indices: Iterable) : String { + val result = StringBuilder() + for (i in indices) { + result.append(get(i)) + } + return result.toString() + +} + /** * Returns a list containing first *n* elements */ @@ -1139,6 +1206,13 @@ public fun Stream.take(n: Int) : Stream { } +/** + * Returns a list containing first *n* elements + */ +public fun String.take(n: Int) : String { + return substring(0, Math.min(n, size)) +} + /** * Returns a list containing first elements satisfying the given *predicate* */ @@ -1287,3 +1361,15 @@ public fun Stream.takeWhile(predicate: (T)->Boolean) : Stream { } +/** + * Returns a list containing first elements satisfying the given *predicate* + */ +public inline fun String.takeWhile(predicate: (Char) -> Boolean): String { + for (index in 0..length) + if (!predicate(get(index))) { + return substring(0, index) + } + return "" + +} + diff --git a/libraries/stdlib/src/generated/_Generators.kt b/libraries/stdlib/src/generated/_Generators.kt index 84cace31caa..4d63d414119 100644 --- a/libraries/stdlib/src/generated/_Generators.kt +++ b/libraries/stdlib/src/generated/_Generators.kt @@ -216,6 +216,25 @@ public inline fun Stream.partition(predicate: (T) -> Boolean) : Pair Boolean) : Pair { + val first = StringBuilder() + val second = StringBuilder() + for (element in this) { + if (predicate(element)) { + first.append(element) + } else { + second.append(element) + } + } + return Pair(first.toString(), second.toString()) + +} + /** * Returns a list containing all elements of original collection and then all elements of the given *collection* */ @@ -683,9 +702,37 @@ public fun Iterable.zip(array: Array) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun Array.zip(collection: Iterable) : List> { +public fun String.zip(array: Array) : List> { val first = iterator() - val second = collection.iterator() + val second = array.iterator() + val list = ArrayList>() + while (first.hasNext() && second.hasNext()) { + list.add(first.next() to second.next()) + } + return list + +} + +/** + * Returns a list of pairs built from characters of both strings with same indexes. List has length of shortest collection. + */ +public fun String.zip(other : String) : List> { + val first = iterator() + val second = other.iterator() + val list = ArrayList>() + while (first.hasNext() && second.hasNext()) { + list.add(first.next() to second.next()) + } + return list + +} + +/** + * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. + */ +public fun Array.zip(other: Iterable) : List> { + val first = iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -697,9 +744,9 @@ public fun Array.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun BooleanArray.zip(collection: Iterable) : List> { +public fun BooleanArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -711,9 +758,9 @@ public fun BooleanArray.zip(collection: Iterable) : List> /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun ByteArray.zip(collection: Iterable) : List> { +public fun ByteArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -725,9 +772,9 @@ public fun ByteArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun CharArray.zip(collection: Iterable) : List> { +public fun CharArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -739,9 +786,9 @@ public fun CharArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun DoubleArray.zip(collection: Iterable) : List> { +public fun DoubleArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -753,9 +800,9 @@ public fun DoubleArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun FloatArray.zip(collection: Iterable) : List> { +public fun FloatArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -767,9 +814,9 @@ public fun FloatArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun IntArray.zip(collection: Iterable) : List> { +public fun IntArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -781,9 +828,9 @@ public fun IntArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun LongArray.zip(collection: Iterable) : List> { +public fun LongArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -795,9 +842,9 @@ public fun LongArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun ShortArray.zip(collection: Iterable) : List> { +public fun ShortArray.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -809,9 +856,9 @@ public fun ShortArray.zip(collection: Iterable) : List> { /** * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ -public fun Iterable.zip(collection: Iterable) : List> { +public fun Iterable.zip(other: Iterable) : List> { val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -820,6 +867,20 @@ public fun Iterable.zip(collection: Iterable) : List> { } +/** + * Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection. + */ +public fun String.zip(other: Iterable) : List> { + val first = iterator() + val second = other.iterator() + val list = ArrayList>() + while (first.hasNext() && second.hasNext()) { + list.add(first.next() to second.next()) + } + return list + +} + /** * Returns a stream of pairs built from elements of both collections with same indexes. List has length of shortest collection. */ diff --git a/libraries/stdlib/src/generated/_Mapping.kt b/libraries/stdlib/src/generated/_Mapping.kt index c51012a638f..733f9f9cc82 100644 --- a/libraries/stdlib/src/generated/_Mapping.kt +++ b/libraries/stdlib/src/generated/_Mapping.kt @@ -84,6 +84,13 @@ public inline fun Map.flatMap(transform: (Map.Entry)-> Itera return flatMapTo(ArrayList(), transform) } +/** + * Returns a single list of all elements yielded from results of *transform* function being invoked on each element of original collection + */ +public inline fun String.flatMap(transform: (Char)-> Iterable) : List { + return flatMapTo(ArrayList(), transform) +} + /** * Returns a single stream of all elements streamed from results of *transform* function being invoked on each element of original stream */ @@ -223,6 +230,18 @@ public inline fun > Map.flatMapTo(colle } +/** + * Appends all elements yielded from results of *transform* function being invoked on each element of original collection, to the given *collection* + */ +public inline fun > String.flatMapTo(collection: C, transform: (Char) -> Iterable) : C { + for (element in this) { + val list = transform(element) + collection.addAll(list) + } + return collection + +} + /** * Appends all elements yielded from results of *transform* function being invoked on each element of original stream, to the given *collection* */ @@ -319,6 +338,13 @@ public inline fun Stream.groupBy(toKey: (T) -> K) : Map> { return groupByTo(HashMap>(), toKey) } +/** + * Returns a map of the elements in original collection grouped by the result of given *toKey* function + */ +public inline fun String.groupBy(toKey: (Char) -> K) : Map> { + return groupByTo(HashMap>(), toKey) +} + /** * Appends elements from original collection grouped by the result of given *toKey* function to the given *map* */ @@ -475,6 +501,19 @@ public inline fun Stream.groupByTo(map: MutableMap>, } +/** + * Appends elements from original collection grouped by the result of given *toKey* function to the given *map* + */ +public inline fun String.groupByTo(map: MutableMap>, toKey: (Char) -> K) : Map> { + for (element in this) { + val key = toKey(element) + val list = map.getOrPut(key) { ArrayList() } + list.add(element) + } + return map + +} + /** * Returns a list containing the results of applying the given *transform* function to each element of the original collection */ @@ -559,10 +598,17 @@ public fun Stream.map(transform : (T) -> R) : Stream { return TransformingStream(this, transform) } +/** + * Returns a list containing the results of applying the given *transform* function to each element of the original collection + */ +public inline fun String.map(transform : (Char) -> R) : List { + return mapTo(ArrayList(), transform) +} + /** * Returns a list containing the results of applying the given *transform* function to each non-null element of the original collection */ -public fun Array.mapNotNull(transform : (T) -> R) : List { +public inline fun Array.mapNotNull(transform : (T) -> R) : List { return mapNotNullTo(ArrayList(), transform) } @@ -570,7 +616,7 @@ public fun Array.mapNotNull(transform : (T) -> R) : List { /** * Returns a list containing the results of applying the given *transform* function to each non-null element of the original collection */ -public fun Iterable.mapNotNull(transform : (T) -> R) : List { +public inline fun Iterable.mapNotNull(transform : (T) -> R) : List { return mapNotNullTo(ArrayList(), transform) } @@ -757,6 +803,17 @@ public inline fun > Stream.mapTo(collection: } +/** + * Appends transformed elements of original collection using the given *transform* function + * to the given *collection* + */ +public inline fun > String.mapTo(collection: C, transform : (Char) -> R) : C { + for (item in this) + collection.add(transform(item)) + return collection + +} + /** * Returns a list containing pairs of each element of the original collection and their index */ @@ -856,3 +913,12 @@ public fun Stream.withIndices() : Stream> { } +/** + * Returns a list containing pairs of each element of the original collection and their index + */ +public fun String.withIndices() : List> { + var index = 0 + return mapTo(ArrayList>(), { index++ to it }) + +} + diff --git a/libraries/stdlib/src/generated/_Ordering.kt b/libraries/stdlib/src/generated/_Ordering.kt index 5a40c899da7..c6a9d7e3aac 100644 --- a/libraries/stdlib/src/generated/_Ordering.kt +++ b/libraries/stdlib/src/generated/_Ordering.kt @@ -107,6 +107,14 @@ public fun Iterable.reverse() : List { } +/** + * Returns a string with characters in reversed order + */ +public fun String.reverse() : String { + return StringBuilder().append(this).reverse().toString() + +} + /** * Returns a sorted list of all elements */ diff --git a/libraries/stdlib/src/generated/_Snapshots.kt b/libraries/stdlib/src/generated/_Snapshots.kt index 1ba2e79513c..c384f451e82 100644 --- a/libraries/stdlib/src/generated/_Snapshots.kt +++ b/libraries/stdlib/src/generated/_Snapshots.kt @@ -111,6 +111,13 @@ public fun Stream.toArrayList() : ArrayList { return toCollection(ArrayList()) } +/** + * Returns an ArrayList of all elements + */ +public fun String.toArrayList() : ArrayList { + return toCollection(ArrayList()) +} + /** * Appends all elements to the given *collection* */ @@ -232,6 +239,17 @@ public fun > Stream.toCollection(collection : } +/** + * Appends all elements to the given *collection* + */ +public fun > String.toCollection(collection : C) : C { + for (item in this) { + collection.add(item) + } + return collection + +} + /** * Returns a HashSet of all elements */ @@ -309,6 +327,13 @@ public fun Stream.toHashSet() : HashSet { return toCollection(HashSet()) } +/** + * Returns a HashSet of all elements + */ +public fun String.toHashSet() : HashSet { + return toCollection(HashSet()) +} + /** * Returns a LinkedList containing all elements */ @@ -386,6 +411,13 @@ public fun Stream.toLinkedList() : LinkedList { return toCollection(LinkedList()) } +/** + * Returns a LinkedList containing all elements + */ +public fun String.toLinkedList() : LinkedList { + return toCollection(LinkedList()) +} + /** * Returns a List containing all elements */ @@ -487,6 +519,13 @@ public fun Stream.toList() : List { return toCollection(ArrayList()) } +/** + * Returns a List containing all elements + */ +public fun String.toList() : List { + return toCollection(ArrayList()) +} + /** * Returns a Set of all elements */ @@ -564,6 +603,13 @@ public fun Stream.toSet() : Set { return toCollection(LinkedHashSet()) } +/** + * Returns a Set of all elements + */ +public fun String.toSet() : Set { + return toCollection(LinkedHashSet()) +} + /** * Returns a sorted list of all elements */ @@ -641,6 +687,13 @@ public fun > Stream.toSortedList() : List { return toArrayList().sort() } +/** + * Returns a sorted list of all elements + */ +public fun String.toSortedList() : List { + return toArrayList().sort() +} + /** * Returns a SortedSet of all elements */ @@ -718,3 +771,10 @@ public fun Stream.toSortedSet() : SortedSet { return toCollection(TreeSet()) } +/** + * Returns a SortedSet of all elements + */ +public fun String.toSortedSet() : SortedSet { + return toCollection(TreeSet()) +} + diff --git a/libraries/stdlib/src/generated/_SpecialJVM.kt b/libraries/stdlib/src/generated/_SpecialJVM.kt index d87041b41f6..2c2e7d5a02b 100644 --- a/libraries/stdlib/src/generated/_SpecialJVM.kt +++ b/libraries/stdlib/src/generated/_SpecialJVM.kt @@ -357,6 +357,14 @@ public fun Stream.filterIsInstance(klass: Class) : Stream { } +/** + * Returns a list containing all elements that are instances of specified class + */ +public fun String.filterIsInstance(klass: Class) : List { + return filterIsInstanceTo(ArrayList(), klass) + +} + /** * Appends all elements that are instances of specified class into the given *collection* */ @@ -384,6 +392,15 @@ public fun , R: T> Stream.filterIsInstanceTo(co } +/** + * Appends all elements that are instances of specified class into the given *collection* + */ +public fun , R: Char> String.filterIsInstanceTo(collection: C, klass: Class) : C { + for (element in this) if (klass.isInstance(element)) collection.add(element as R) + return collection + +} + /** * Sorts array or range in array inplace */ diff --git a/libraries/stdlib/src/generated/_Streams.kt b/libraries/stdlib/src/generated/_Streams.kt index 9ae2d8fd31d..28b4e1b0866 100644 --- a/libraries/stdlib/src/generated/_Streams.kt +++ b/libraries/stdlib/src/generated/_Streams.kt @@ -95,3 +95,11 @@ public fun Stream.stream() : Stream { } +/** + * Returns a stream from the given collection + */ +public fun String.stream() : Stream { + return object : Stream { override fun iterator() : Iterator { return this@stream.iterator() } } + +} + diff --git a/libraries/stdlib/src/generated/_Strings.kt b/libraries/stdlib/src/generated/_Strings.kt index 14f6820c860..8e45c36f041 100644 --- a/libraries/stdlib/src/generated/_Strings.kt +++ b/libraries/stdlib/src/generated/_Strings.kt @@ -227,6 +227,26 @@ public fun Stream.appendString(buffer: Appendable, separator: String = ", } +/** + * Appends the string from all the elements separated using the *separator* and using the given *prefix* and *postfix* if supplied + * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will + * a special *truncated* separator (which defaults to "..." + */ +public fun String.appendString(buffer: Appendable, separator: String = ", ", prefix: String ="", postfix: String = "", limit: Int = -1, truncated: String = "...") : Unit { + buffer.append(prefix) + var count = 0 + for (element in this) { + if (++count > 1) buffer.append(separator) + if (limit < 0 || count <= limit) { + val text = if (element == null) "null" else element.toString() + buffer.append(text) + } else break + } + if (limit >= 0 && count > limit) buffer.append(truncated) + buffer.append(postfix) + +} + /** * Creates a string from all the elements separated using the *separator* and using the given *prefix* and *postfix* if supplied. * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will @@ -359,3 +379,15 @@ public fun Stream.makeString(separator: String = ", ", prefix: String = " } +/** + * Creates a string from all the elements separated using the *separator* and using the given *prefix* and *postfix* if supplied. + * If a collection could be huge you can specify a non-negative value of *limit* which will only show a subset of the collection then it will + * a special *truncated* separator (which defaults to "..." + */ +public fun String.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "...") : String { + val buffer = StringBuilder() + appendString(buffer, separator, prefix, postfix, limit, truncated) + return buffer.toString() + +} + diff --git a/libraries/stdlib/src/kotlin/text/Strings.kt b/libraries/stdlib/src/kotlin/text/Strings.kt index f0e8513495e..5b6f6b1c2b9 100644 --- a/libraries/stdlib/src/kotlin/text/Strings.kt +++ b/libraries/stdlib/src/kotlin/text/Strings.kt @@ -1,21 +1,10 @@ package kotlin -import java.util.ArrayList -import java.util.HashMap -import java.util.HashSet -import java.util.LinkedList - /** Returns the string with leading and trailing text matching the given string removed */ -public fun String.trim(text: String) : String = trimLeading(text).trimTrailing(text) - -/** Returns the first character */ -public fun String.first() : Char = this[0] - -/** Returns the last character */ -public fun String.last() : Char = this[length - 1] +public fun String.trim(text: String): String = trimLeading(text).trimTrailing(text) /** Returns the string with the prefix and postfix text trimmed */ -public fun String.trim(prefix: String, postfix: String) : String = trimLeading(prefix).trimTrailing(postfix) +public fun String.trim(prefix: String, postfix: String): String = trimLeading(prefix).trimTrailing(postfix) /** Returns the string with the leading prefix of this string removed */ public fun String.trimLeading(prefix: String): String { @@ -36,12 +25,12 @@ public fun String.trimTrailing(postfix: String): String { } /** Returns true if the string is not null and not empty */ -public fun String?.isNotEmpty() : Boolean = this != null && this.length() > 0 +public fun String?.isNotEmpty(): Boolean = this != null && this.length() > 0 /** -Iterator for characters of given CharSequence -*/ -public fun CharSequence.iterator() : CharIterator = object : CharIterator() { + * Iterator for characters of given CharSequence + */ +public fun CharSequence.iterator(): CharIterator = object : CharIterator() { private var index = 0 public override fun nextChar(): Char = get(index++) @@ -55,20 +44,27 @@ public fun String?.orEmpty(): String = this ?: "" // "Extension functions" for CharSequence -val CharSequence.size : Int -get() = this.length +public val CharSequence.size: Int + get() = this.length + +public val String.size: Int + get() = length() + +public val String.indices : IntRange + get() = 0..size /** - * Counts the number of characters which match the given predicate - * - * @includeFunctionBody ../../test/text/StringTest.kt count + * Returns a subsequence specified by given set of indices. */ -public inline fun String.count(predicate: (Char) -> Boolean): Int { - var answer = 0 - for (c in this) { - if (predicate(c)) { - answer++ - } +public fun CharSequence.slice(indices: Iterable): CharSequence { + val result = StringBuilder() + for (i in indices) { + result.append(get(i)) } - return answer + return result.toString() } + +/** + * Returns a substring specified by given range + */ +public fun String.substring(range: IntRange): String = substring(range.start, range.end + 1) diff --git a/libraries/stdlib/src/kotlin/text/StringsJVM.kt b/libraries/stdlib/src/kotlin/text/StringsJVM.kt index 774636c705a..a0011d3d1ad 100644 --- a/libraries/stdlib/src/kotlin/text/StringsJVM.kt +++ b/libraries/stdlib/src/kotlin/text/StringsJVM.kt @@ -8,173 +8,174 @@ import java.util.LinkedList import java.util.Locale import java.nio.charset.Charset -public inline fun String.lastIndexOf(str: String) : Int = (this as java.lang.String).lastIndexOf(str) +public fun String.lastIndexOf(str: String): Int = (this as java.lang.String).lastIndexOf(str) -public inline fun String.lastIndexOf(ch: Char) : Int = (this as java.lang.String).lastIndexOf(ch.toString()) +public fun String.lastIndexOf(ch: Char): Int = (this as java.lang.String).lastIndexOf(ch.toString()) -public inline fun String.equalsIgnoreCase(anotherString: String) : Boolean = (this as java.lang.String).equalsIgnoreCase(anotherString) +public fun String.equalsIgnoreCase(anotherString: String): Boolean = (this as java.lang.String).equalsIgnoreCase(anotherString) -public inline fun String.hashCode() : Int = (this as java.lang.String).hashCode() +public fun String.hashCode(): Int = (this as java.lang.String).hashCode() -public inline fun String.indexOf(str : String) : Int = (this as java.lang.String).indexOf(str) +public fun String.indexOf(str: String): Int = (this as java.lang.String).indexOf(str) -public inline fun String.indexOf(str : String, fromIndex : Int) : Int = (this as java.lang.String).indexOf(str, fromIndex) +public fun String.indexOf(str: String, fromIndex: Int): Int = (this as java.lang.String).indexOf(str, fromIndex) -public inline fun String.replace(oldChar: Char, newChar : Char) : String = (this as java.lang.String).replace(oldChar, newChar) +public fun String.replace(oldChar: Char, newChar: Char): String = (this as java.lang.String).replace(oldChar, newChar) -public inline fun String.replaceAll(regex: String, replacement : String) : String = (this as java.lang.String).replaceAll(regex, replacement) +public fun String.replaceAll(regex: String, replacement: String): String = (this as java.lang.String).replaceAll(regex, replacement) -public inline fun String.trim() : String = (this as java.lang.String).trim() +public fun String.trim(): String = (this as java.lang.String).trim() -public inline fun String.toUpperCase() : String = (this as java.lang.String).toUpperCase() +public fun String.toUpperCase(): String = (this as java.lang.String).toUpperCase() -public inline fun String.toLowerCase() : String = (this as java.lang.String).toLowerCase() +public fun String.toLowerCase(): String = (this as java.lang.String).toLowerCase() -public inline fun String.length() : Int = (this as java.lang.String).length() +public fun String.length(): Int = (this as java.lang.String).length() -public inline fun String.getBytes() : ByteArray = (this as java.lang.String).getBytes() +public fun String.getBytes(): ByteArray = (this as java.lang.String).getBytes() -public inline fun String.toCharArray() : CharArray = (this as java.lang.String).toCharArray() +public fun String.toCharArray(): CharArray = (this as java.lang.String).toCharArray() -public fun String.toCharList(): List = toCharArray().toList() +public fun String.format(vararg args: Any?): String = java.lang.String.format(this, *args) -public inline fun String.format(vararg args : Any?) : String = java.lang.String.format(this, *args) +public fun String.format(locale: Locale, vararg args : Any?) : String = java.lang.String.format(locale, this, *args) -public inline fun String.format(locale: Locale, vararg args : Any?) : String = java.lang.String.format(locale, this, *args) +public fun String.split(regex: String): Array = (this as java.lang.String).split(regex) -public inline fun String.split(regex : String) : Array = (this as java.lang.String).split(regex) +public fun String.split(ch: Char): Array = (this as java.lang.String).split(java.util.regex.Pattern.quote(ch.toString())) -public inline fun String.split(ch : Char) : Array = (this as java.lang.String).split(java.util.regex.Pattern.quote(ch.toString())) +public fun String.substring(beginIndex: Int): String = (this as java.lang.String).substring(beginIndex) -public inline fun String.substring(beginIndex : Int) : String = (this as java.lang.String).substring(beginIndex) +public fun String.substring(beginIndex: Int, endIndex: Int): String = (this as java.lang.String).substring(beginIndex, endIndex) -public inline fun String.substring(beginIndex : Int, endIndex : Int) : String = (this as java.lang.String).substring(beginIndex, endIndex) +public fun String.startsWith(prefix: String): Boolean = (this as java.lang.String).startsWith(prefix) -public inline fun String.startsWith(prefix: String) : Boolean = (this as java.lang.String).startsWith(prefix) +public fun String.startsWith(prefix: String, toffset: Int): Boolean = (this as java.lang.String).startsWith(prefix, toffset) -public inline fun String.startsWith(prefix: String, toffset: Int) : Boolean = (this as java.lang.String).startsWith(prefix, toffset) +public fun String.startsWith(ch: Char): Boolean = (this as java.lang.String).startsWith(ch.toString()) -public inline fun String.startsWith(ch: Char) : Boolean = (this as java.lang.String).startsWith(ch.toString()) +public fun String.contains(seq: CharSequence): Boolean = (this as java.lang.String).contains(seq) -public inline fun String.contains(seq: CharSequence) : Boolean = (this as java.lang.String).contains(seq) +public fun String.endsWith(suffix: String): Boolean = (this as java.lang.String).endsWith(suffix) -public inline fun String.endsWith(suffix: String) : Boolean = (this as java.lang.String).endsWith(suffix) - -public inline fun String.endsWith(ch: Char) : Boolean = (this as java.lang.String).endsWith(ch.toString()) +public fun String.endsWith(ch: Char): Boolean = (this as java.lang.String).endsWith(ch.toString()) // "constructors" for String -public inline fun String(bytes : ByteArray, offset : Int, length : Int, charsetName : String) : String = java.lang.String(bytes, offset, length, charsetName) as String +public fun String(bytes: ByteArray, offset: Int, length: Int, charsetName: String): String = java.lang.String(bytes, offset, length, charsetName) as String -public inline fun String(bytes : ByteArray, offset : Int, length : Int, charset : Charset) : String = java.lang.String(bytes, offset, length, charset) as String +public fun String(bytes: ByteArray, offset: Int, length: Int, charset: Charset): String = java.lang.String(bytes, offset, length, charset) as String -public inline fun String(bytes : ByteArray, charsetName : String) : String = java.lang.String(bytes, charsetName) as String +public fun String(bytes: ByteArray, charsetName: String): String = java.lang.String(bytes, charsetName) as String -public inline fun String(bytes : ByteArray, charset : Charset) : String = java.lang.String(bytes, charset) as String +public fun String(bytes: ByteArray, charset: Charset): String = java.lang.String(bytes, charset) as String -public inline fun String(bytes : ByteArray, i : Int, i1 : Int) : String = java.lang.String(bytes, i, i1) as String +public fun String(bytes: ByteArray, i: Int, i1: Int): String = java.lang.String(bytes, i, i1) as String -public inline fun String(bytes : ByteArray) : String = java.lang.String(bytes) as String +public fun String(bytes: ByteArray): String = java.lang.String(bytes) as String -public inline fun String(chars : CharArray) : String = java.lang.String(chars) as String +public fun String(chars: CharArray): String = java.lang.String(chars) as String -public inline fun String(stringBuffer : java.lang.StringBuffer) : String = java.lang.String(stringBuffer) as String +public fun String(stringBuffer: java.lang.StringBuffer): String = java.lang.String(stringBuffer) as String -public inline fun String(stringBuilder : java.lang.StringBuilder) : String = java.lang.String(stringBuilder) as String +public fun String(stringBuilder: java.lang.StringBuilder): String = java.lang.String(stringBuilder) as String -public inline fun String.replaceFirst(regex : String, replacement : String) : String = (this as java.lang.String).replaceFirst(regex, replacement) +public fun String.replaceFirst(regex: String, replacement: String): String = (this as java.lang.String).replaceFirst(regex, replacement) -public inline fun String.charAt(index : Int) : Char = (this as java.lang.String).charAt(index) +public fun String.charAt(index: Int): Char = (this as java.lang.String).charAt(index) -public inline fun String.split(regex : String, limit : Int) : Array = (this as java.lang.String).split(regex, limit) +public fun String.split(regex: String, limit: Int): Array = (this as java.lang.String).split(regex, limit) -public inline fun String.codePointAt(index : Int) : Int = (this as java.lang.String).codePointAt(index) +public fun String.codePointAt(index: Int): Int = (this as java.lang.String).codePointAt(index) -public inline fun String.codePointBefore(index : Int) : Int = (this as java.lang.String).codePointBefore(index) +public fun String.codePointBefore(index: Int): Int = (this as java.lang.String).codePointBefore(index) -public inline fun String.codePointCount(beginIndex : Int, endIndex : Int) : Int = (this as java.lang.String).codePointCount(beginIndex, endIndex) +public fun String.codePointCount(beginIndex: Int, endIndex: Int): Int = (this as java.lang.String).codePointCount(beginIndex, endIndex) -public inline fun String.compareToIgnoreCase(str : String) : Int = (this as java.lang.String).compareToIgnoreCase(str) +public fun String.compareToIgnoreCase(str: String): Int = (this as java.lang.String).compareToIgnoreCase(str) -public inline fun String.concat(str : String) : String = (this as java.lang.String).concat(str) +public fun String.concat(str: String): String = (this as java.lang.String).concat(str) -public inline fun String.contentEquals(cs : CharSequence) : Boolean = (this as java.lang.String).contentEquals(cs) +public fun String.contentEquals(cs: CharSequence): Boolean = (this as java.lang.String).contentEquals(cs) -public inline fun String.contentEquals(sb : StringBuffer) : Boolean = (this as java.lang.String).contentEquals(sb) +public fun String.contentEquals(sb: StringBuffer): Boolean = (this as java.lang.String).contentEquals(sb) -public inline fun String.getBytes(charset : Charset) : ByteArray = (this as java.lang.String).getBytes(charset) +public fun String.getBytes(charset: Charset): ByteArray = (this as java.lang.String).getBytes(charset) -public inline fun String.getBytes(charsetName : String) : ByteArray = (this as java.lang.String).getBytes(charsetName) +public fun String.getBytes(charsetName: String): ByteArray = (this as java.lang.String).getBytes(charsetName) -public inline fun String.getChars(srcBegin : Int, srcEnd : Int, dst : CharArray, dstBegin : Int) : Unit = (this as java.lang.String).getChars(srcBegin, srcEnd, dst, dstBegin) +public fun String.getChars(srcBegin: Int, srcEnd: Int, dst: CharArray, dstBegin: Int): Unit = (this as java.lang.String).getChars(srcBegin, srcEnd, dst, dstBegin) -public inline fun String.indexOf(ch : Char) : Int = (this as java.lang.String).indexOf(ch.toString()) +public fun String.indexOf(ch: Char): Int = (this as java.lang.String).indexOf(ch.toString()) -public inline fun String.indexOf(ch : Char, fromIndex : Int) : Int = (this as java.lang.String).indexOf(ch.toString(), fromIndex) +public fun String.indexOf(ch: Char, fromIndex: Int): Int = (this as java.lang.String).indexOf(ch.toString(), fromIndex) -public inline fun String.intern() : String = (this as java.lang.String).intern() +public fun String.intern(): String = (this as java.lang.String).intern() -public inline fun String.isEmpty() : Boolean = (this as java.lang.String).isEmpty() +public fun String.isEmpty(): Boolean = (this as java.lang.String).isEmpty() -public inline fun String.lastIndexOf(ch : Char, fromIndex : Int) : Int = (this as java.lang.String).lastIndexOf(ch.toString(), fromIndex) +public fun String.lastIndexOf(ch: Char, fromIndex: Int): Int = (this as java.lang.String).lastIndexOf(ch.toString(), fromIndex) -public inline fun String.lastIndexOf(str : String, fromIndex : Int) : Int = (this as java.lang.String).lastIndexOf(str, fromIndex) +public fun String.lastIndexOf(str: String, fromIndex: Int): Int = (this as java.lang.String).lastIndexOf(str, fromIndex) -public inline fun String.matches(regex : String) : Boolean = (this as java.lang.String).matches(regex) +public fun String.matches(regex: String): Boolean = (this as java.lang.String).matches(regex) -public inline fun String.offsetByCodePoints(index : Int, codePointOffset : Int) : Int = (this as java.lang.String).offsetByCodePoints(index, codePointOffset) +public fun String.offsetByCodePoints(index: Int, codePointOffset: Int): Int = (this as java.lang.String).offsetByCodePoints(index, codePointOffset) -public inline fun String.regionMatches(ignoreCase : Boolean, toffset : Int, other : String, ooffset : Int, len : Int) : Boolean = (this as java.lang.String).regionMatches(ignoreCase, toffset, other, ooffset, len) +public fun String.regionMatches(ignoreCase: Boolean, toffset: Int, other: String, ooffset: Int, len: Int): Boolean = (this as java.lang.String).regionMatches(ignoreCase, toffset, other, ooffset, len) -public inline fun String.regionMatches(toffset : Int, other : String, ooffset : Int, len : Int) : Boolean = (this as java.lang.String).regionMatches(toffset, other, ooffset, len) +public fun String.regionMatches(toffset: Int, other: String, ooffset: Int, len: Int): Boolean = (this as java.lang.String).regionMatches(toffset, other, ooffset, len) -public inline fun String.replace(target : CharSequence, replacement : CharSequence) : String = (this as java.lang.String).replace(target, replacement) +public fun String.replace(target: CharSequence, replacement: CharSequence): String = (this as java.lang.String).replace(target, replacement) -public inline fun String.subSequence(beginIndex : Int, endIndex : Int) : CharSequence = (this as java.lang.String).subSequence(beginIndex, endIndex) +public fun String.subSequence(beginIndex: Int, endIndex: Int): CharSequence = (this as java.lang.String).subSequence(beginIndex, endIndex) -public inline fun String.toLowerCase(locale : java.util.Locale) : String = (this as java.lang.String).toLowerCase(locale) +public fun String.toLowerCase(locale: java.util.Locale): String = (this as java.lang.String).toLowerCase(locale) -public inline fun String.toUpperCase(locale : java.util.Locale) : String = (this as java.lang.String).toUpperCase(locale) +public fun String.toUpperCase(locale: java.util.Locale): String = (this as java.lang.String).toUpperCase(locale) +public fun CharSequence.charAt(index: Int): Char = (this as java.lang.CharSequence).charAt(index) -public inline fun CharSequence.charAt(index : Int) : Char = (this as java.lang.CharSequence).charAt(index) +public fun CharSequence.subSequence(start: Int, end: Int): CharSequence? = (this as java.lang.CharSequence).subSequence(start, end) -public fun CharSequence.get(index : Int) : Char = charAt(index) +public fun CharSequence.toString(): String? = (this as java.lang.CharSequence).toString() -public inline fun CharSequence.subSequence(start : Int, end : Int) : CharSequence? = (this as java.lang.CharSequence).subSequence(start, end) +public fun CharSequence.length(): Int = (this as java.lang.CharSequence).length() -public fun CharSequence.get(start : Int, end : Int) : CharSequence? = subSequence(start, end) +public fun String.toByteArray(encoding: Charset): ByteArray = (this as java.lang.String).getBytes(encoding) -public inline fun CharSequence.toString() : String? = (this as java.lang.CharSequence).toString() - -public inline fun CharSequence.length() : Int = (this as java.lang.CharSequence).length() +public fun String.toBoolean(): Boolean = java.lang.Boolean.parseBoolean(this) +public fun String.toShort(): Short = java.lang.Short.parseShort(this) +public fun String.toInt(): Int = java.lang.Integer.parseInt(this) +public fun String.toLong(): Long = java.lang.Long.parseLong(this) +public fun String.toFloat(): Float = java.lang.Float.parseFloat(this) +public fun String.toDouble(): Double = java.lang.Double.parseDouble(this) +public fun String.toCharList(): List = toCharArray().toList() +public fun CharSequence.get(index: Int): Char = charAt(index) +public fun CharSequence.get(start: Int, end: Int): CharSequence? = subSequence(start, end) public fun String.toByteArray(encoding: String = Charset.defaultCharset().name()): ByteArray = (this as java.lang.String).getBytes(encoding) -public inline fun String.toByteArray(encoding: Charset): ByteArray = (this as java.lang.String).getBytes(encoding) -public inline fun String.toBoolean() : Boolean = java.lang.Boolean.parseBoolean(this) -public inline fun String.toShort() : Short = java.lang.Short.parseShort(this) -public inline fun String.toInt() : Int = java.lang.Integer.parseInt(this) -public inline fun String.toLong() : Long = java.lang.Long.parseLong(this) -public inline fun String.toFloat() : Float = java.lang.Float.parseFloat(this) -public inline fun String.toDouble() : Double = java.lang.Double.parseDouble(this) +/** + * Returns a subsequence specified by given range. + */ +public fun CharSequence.slice(range: IntRange): CharSequence { + return subSequence(range.start, range.end + 1)!! // inclusive +} + /** * Converts the string into a regular expression [[Pattern]] optionally * with the specified flags from [[Pattern]] or'd together * so that strings can be split or matched on. */ -public fun String.toRegex(flags: Int=0): java.util.regex.Pattern { +public fun String.toRegex(flags: Int = 0): java.util.regex.Pattern { return java.util.regex.Pattern.compile(this, flags) } -val String.reader : StringReader -get() = StringReader(this) - -val String.size : Int -get() = length() - +val String.reader: StringReader + get() = StringReader(this) /** * Returns a copy of this string capitalised if it is not empty or already starting with an uppper case letter, otherwise returns this @@ -200,108 +201,23 @@ public fun String.decapitalize(): String { * @includeFunctionBody ../../test/text/StringTest.kt repeat */ public fun String.repeat(n: Int): String { - require(n >= 0, { "Cannot repeat string $n times" }) + if (n < 0) + throw IllegalArgumentException("Value should be non-negative, but was $n") - var sb = StringBuilder() + val sb = StringBuilder() for (i in 1..n) { sb.append(this) } return sb.toString() } -/** - * Filters characters which match the given predicate into new String object - * - * @includeFunctionBody ../../test/text/StringTest.kt filter - */ -public inline fun String.filter(predicate: (Char) -> Boolean): String = filterTo(StringBuilder(), predicate).toString() - -/** - * Returns an Appendable containing all characters which match the given *predicate* - * - * @includeFunctionBody ../../test/text/StringTest.kt filter - */ -public inline fun String.filterTo(result: T, predicate: (Char) -> Boolean): T -{ - for (с in this) if (predicate(с)) result.append(с) - return result -} - -/** - * Filters characters which match the given predicate into new String object - * - * @includeFunctionBody ../../test/text/StringTest.kt filterNot - */ -public inline fun String.filterNot(predicate: (Char) -> Boolean): String = filterNotTo(StringBuilder(), predicate).toString() - -/** - * Returns an Appendable containing all characters which do not match the given *predicate* - * - * @includeFunctionBody ../../test/text/StringTest.kt filterNot - */ -public inline fun String.filterNotTo(result: T, predicate: (Char) -> Boolean): T { - for (element in this) if (!predicate(element)) result.append(element) - return result -} - -/** - * Reverses order of characters in a string - * - * @includeFunctionBody ../../test/text/StringTest.kt reverse - */ -public fun String.reverse(): String = StringBuilder(this).reverse().toString() - -/** - * Performs the given *operation* on each character - * - * @includeFunctionBody ../../test/text/StringTest.kt forEach - */ -public inline fun String.forEach(operation: (Char) -> Unit) { for(c in this) operation(c) } - -/** - * Returns *true* if all characters match the given *predicate* - * - * @includeFunctionBody ../../test/text/StringTest.kt all - */ -public inline fun String.all(predicate: (Char) -> Boolean): Boolean { - for(c in this) if(!predicate(c)) return false - return true -} - -/** - * Returns *true* if any character matches the given *predicate* - * - * @includeFunctionBody ../../test/text/StringTest.kt any - */ -public inline fun String.any(predicate: (Char) -> Boolean): Boolean { - for (c in this) if (predicate(c)) return true - return false -} - -/** - * Appends the string from all the characters separated using the *separator* and using the given *prefix* and *postfix* if supplied - * - * If a string could be huge you can specify a non-negative value of *limit* which will only show substring then it will - * a special *truncated* separator (which defaults to "..." - * - * @includeFunctionBody ../../test/text/StringTest.kt appendString - */ -public fun String.appendString(buffer: Appendable, separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): Unit { - buffer.append(prefix) - var count = 0 - for (c in this) { - if (++count > 1) buffer.append(separator) - if (limit < 0 || count <= limit) buffer.append(c) else break - } - if (limit >= 0 && count > limit) buffer.append(truncated) - buffer.append(postfix) -} /** * Returns the first character which matches the given *predicate* or *null* if none matched * * @includeFunctionBody ../../test/text/StringTest.kt find */ +deprecated("Use firstOrNull instead") public inline fun String.find(predicate: (Char) -> Boolean): Char? { for (c in this) if (predicate(c)) return c return null @@ -312,150 +228,18 @@ public inline fun String.find(predicate: (Char) -> Boolean): Char? { * * @includeFunctionBody ../../test/text/StringTest.kt findNot */ +deprecated("Use firstOrNull instead") public inline fun String.findNot(predicate: (Char) -> Boolean): Char? { for (c in this) if (!predicate(c)) return c return null } -/** -* Partitions this string into a pair of string -* -* @includeFunctionBody ../../test/text/StringTest.kt partition -*/ -public inline fun String.partition(predicate: (Char) -> Boolean): Pair { - val first = StringBuilder() - val second = StringBuilder() - for (c in this) { - if (predicate(c)) { - first.append(c) - } else { - second.append(c) - } - } - return Pair(first.toString(), second.toString()) -} - -/** - * Returns a new List containing the results of applying the given *transform* function to each character in this string - * - */ -public inline fun String.map(transform: (Char) -> R): List = mapTo(ArrayList(), transform) - -/** - * Transforms each character of this string with the given *transform* function and - * adds each return value to the given *result* collection - * - */ -public inline fun > String.mapTo(result: C, transform: (Char) -> R): C { - for (c in this) result.add(transform(c)) - return result -} - -/** - * Returns the result of transforming each character to one or more values which are concatenated together into a single list - * - * @includeFunctionBody ../../test/text/StringTest.kt flatMap - */ -public inline fun String.flatMap(transform: (Char) -> Collection): Collection = flatMapTo(ArrayList(), transform) - -/** - * Returns the result of transforming each character to one or more values which are concatenated together into a passed list - * - * @includeFunctionBody ../../test/text/StringTest.kt flatMap - */ -public inline fun String.flatMapTo(result: MutableCollection, transform: (Char) -> Collection): Collection { - for (c in this) result.addAll(transform(c)) - return result -} - -/** - * Folds all characters from left to right with the *initial* value to perform the operation on sequential pairs of characters - * - * @includeFunctionBody ../../test/text/StringTest.kt fold - */ -public inline fun String.fold(initial: R, operation: (R, Char) -> R): R { - var answer = initial - for (c in this) answer = operation(answer, c) - return answer -} - -/** - * Folds all characters from right to left with the *initial* value to perform the operation on sequential pairs of characters - * - * @includeFunctionBody ../../test/text/StringTest.kt foldRight - */ -public inline fun String.foldRight(initial: R, operation: (Char, R) -> R): R = reverse().fold(initial, { x, y -> operation(y, x) }) - -/** - * Applies binary operation to all characters in a string, going from left to right. - * Similar to fold function, but uses the first character as initial value - * - * @includeFunctionBody ../../test/text/StringTest.kt reduce - */ -public inline fun String.reduce(operation: (Char, Char) -> Char): Char { - val iterator = this.iterator() - if (!iterator.hasNext()) { - throw UnsupportedOperationException("Empty string can't be reduced") - } - - var result = iterator.next() - while (iterator.hasNext()) { - result = operation(result, iterator.next()) - } - - return result -} - -/** - * Applies binary operation to all characters in a string, going from right to left. - * Similar to foldRight function, but uses the last character as initial value - * - * @includeFunctionBody ../../test/text/StringTest.kt reduceRight - */ -public inline fun String.reduceRight(operation: (Char, Char) -> Char): Char = reverse().reduce { x, y -> operation(y, x) } - - -/** - * Groups the characters in the string into a new [[Map]] using the supplied *toKey* function to calculate the key to group the characters by - * - * @includeFunctionBody ../../test/text/StringTest.kt groupBy - */ -public inline fun String.groupBy(toKey: (Char) -> K): Map = groupByTo(HashMap(), toKey) - -/** - * Groups the characters in the string into the given [[Map]] using the supplied *toKey* function to calculate the key to group the characters by - * - * @includeFunctionBody ../../test/text/StringTest.kt groupBy - */ -public inline fun String.groupByTo(result: MutableMap, toKey: (Char) -> K): Map { - for (c in this) { - val key = toKey(c) - val str = result.getOrElse(key) { "" } - result[key] = str + c - } - return result -} - -/** - * Creates a new string from all the characters separated using the *separator* and using the given *prefix* and *postfix* if supplied. - * - * If a string could be huge you can specify a non-negative value of *limit* which will only show a substring then it will - * a special *truncated* separator (which defaults to "..." - * - * @includeFunctionBody ../../test/text/StringTest.kt makeString - */ -public fun String.makeString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -1, truncated: String = "..."): String { - val buffer = StringBuilder() - appendString(buffer, separator, prefix, postfix, limit, truncated) - return buffer.toString() -} - /** * Returns an Appendable containing the everything but the first characters that satisfy the given *predicate* * * @includeFunctionBody ../../test/text/StringTest.kt dropWhile */ -public inline fun String.dropWhileTo(result: T, predicate: (Char) -> Boolean): T { +public inline fun String.dropWhileTo(result: T, predicate: (Char) -> Boolean): T { var start = true for (element in this) { if (start && predicate(element)) { @@ -468,62 +252,20 @@ public inline fun String.dropWhileTo(result: T, predicate: (Char return result } -/** - * Returns a new String containing the everything but the first characters that satisfy the given *predicate* - * - * @includeFunctionBody ../../test/text/StringTest.kt dropWhile - */ -public inline fun String.dropWhile(predicate: (Char) -> Boolean): String = dropWhileTo(StringBuilder(), predicate).toString() - -/** - * Returns a string containing everything but the first *n* characters - * - * @includeFunctionBody ../../test/text/StringTest.kt drop - */ -public fun String.drop(n: Int): String = substring(Math.min(length, n)) - /** * Returns an Appendable containing the first characters that satisfy the given *predicate* - * + * * @includeFunctionBody ../../test/text/StringTest.kt takeWhile */ -public inline fun String.takeWhileTo(result: T, predicate: (Char) -> Boolean): T { +public inline fun String.takeWhileTo(result: T, predicate: (Char) -> Boolean): T { for (c in this) if (predicate(c)) result.append(c) else break return result } -/** - * Returns a new String containing the first characters that satisfy the given *predicate* - * - * @includeFunctionBody ../../test/text/StringTest.kt takeWhile - */ -public inline fun String.takeWhile(predicate: (Char) -> Boolean): String = takeWhileTo(StringBuilder(), predicate).toString() - -/** - * Returns a string containing the first *n* characters - * - * @includeFunctionBody ../../test/text/StringTest.kt take - */ -public fun String.take(n: Int): String = substring(0, Math.min(length, n)) - -/** Copies all characters into the given collection */ -public fun > String.toCollection(result: C): C { - for (c in this) result.add(c) - return result -} - -/** Copies all characters into a [[LinkedList]] */ -public fun String.toLinkedList(): LinkedList = toCollection(LinkedList()) - -/** Copies all characters into a [[List]] */ -public fun String.toList(): List = toCollection(ArrayList(this.length())) - /** Copies all characters into a [[Collection] */ +deprecated("Use toList() instead.") public fun String.toCollection(): Collection = toCollection(ArrayList(this.length())) -/** Copies all characters into a [[Set]] */ -public fun String.toSet(): Set = toCollection(HashSet()) - /** Returns a new String containing the everything but the leading whitespace characters */ public fun String.trimLeading(): String { var count = 0 @@ -544,11 +286,11 @@ public fun String.trimTrailing(): String { return if (count < this.length) substring(0, count) else this } -/** - * Replaces every *regexp* occurence in the text with the value retruned by the given function *body* that can handle - * particular occurance using [[MatchResult]] provided. - */ -public fun String.replaceAll(regexp: String, body: (java.util.regex.MatchResult) -> String) : String { +/** + * Replaces every *regexp* occurence in the text with the value retruned by the given function *body* that can handle + * particular occurance using [[MatchResult]] provided. + */ +public fun String.replaceAll(regexp: String, body: (java.util.regex.MatchResult) -> String): String { val sb = StringBuilder(this.length()) val p = regexp.toRegex() val m = p.matcher(this) @@ -558,7 +300,7 @@ public fun String.replaceAll(regexp: String, body: (java.util.regex.MatchResult) sb.append(this, lastIdx, m.start()) sb.append(body(m.toMatchResult())) lastIdx = m.end() - } + } if (lastIdx == 0) { return this; diff --git a/libraries/stdlib/test/text/StringJVMTest.kt b/libraries/stdlib/test/text/StringJVMTest.kt index ab3a09bc1ca..b90a9c1ba24 100644 --- a/libraries/stdlib/test/text/StringJVMTest.kt +++ b/libraries/stdlib/test/text/StringJVMTest.kt @@ -84,12 +84,6 @@ class StringJVMTest { assertEquals("abcd", "a1b2c3d4".filterNot { it.isDigit() }) } - test fun reverse() { - assertEquals("dcba", "abcd".reverse()) - assertEquals("4321", "1234".reverse()) - assertEquals("", "".reverse()) - } - test fun forEach() { val data = "abcd1234" var count = 0 @@ -227,11 +221,11 @@ class StringJVMTest { } test fun groupBy() { - // collect similar characters by their int code - val data = "ababaaabcd" - val result = data.groupBy { it.toInt() } - assertEquals(4, result.size) - assertEquals("bbb", result.get('b'.toInt())) + // group characters by their case + val data = "abAbaABcD" + val result = data.groupBy { it.isLowerCase() } + assertEquals(2, result.size) + assertEquals(listOf('a','b','b','a','c'), result.get(true)) } test fun makeString() { @@ -369,4 +363,17 @@ class StringJVMTest { assertEquals("", result) } + + test fun slice() { + val iter = listOf(4, 3, 0, 1) + + val builder = StringBuilder() + builder.append("ABCD") + builder.append("abcd") + // ABCDabcd + // 01234567 + assertEquals("BCDabc", builder.slice(1..6)) + assertEquals("baD", builder.slice(5 downTo 3)) + assertEquals("aDAB", builder.slice(iter)) + } } diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index 4c87bbbbc5a..d4e033de4ec 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -47,4 +47,19 @@ class StringTest { assertEquals("abcd", "Abcd".decapitalize()) assertEquals("uRL", "URL".decapitalize()) } + + test fun slice() { + val iter = listOf(4, 3, 0, 1) + // abcde + // 01234 + assertEquals("bcd", "abcde".substring(1..3)) + assertEquals("dcb", "abcde".slice(3 downTo 1)) + assertEquals("edab", "abcde".slice(iter)) + } + + test fun reverse() { + assertEquals("dcba", "abcd".reverse()) + assertEquals("4321", "1234".reverse()) + assertEquals("", "".reverse()) + } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt index f0a527cfa42..a9df46dace4 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt @@ -95,7 +95,7 @@ fun aggregates(): List { return count """ } - body(Maps, Collections, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Maps, Collections, ArraysOfObjects, ArraysOfPrimitives) { "return size" } } @@ -324,7 +324,7 @@ fun aggregates(): List { templates add f("foldRight(initial: R, operation: (T, R) -> R)") { inline(true) - only(Lists, ArraysOfObjects, ArraysOfPrimitives) + only(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) doc { "Accumulates value starting with *initial* value and applying *operation* from right to left to each element and current accumulator value" } typeParam("R") returns("R") @@ -363,7 +363,7 @@ fun aggregates(): List { templates add f("reduceRight(operation: (T, T) -> T)") { inline(true) - only(Lists, ArraysOfObjects, ArraysOfPrimitives) + only(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) doc { "Accumulates value starting with last element and applying *operation* from right to left to each element and current accumulator value" } returns("T") body { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt index 7cd68dcf92f..f77a9a8a23f 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Elements.kt @@ -15,7 +15,7 @@ fun elements(): List { return indexOf(element) >= 0 """ } - exclude(Lists, Collections) + exclude(Strings, Lists, Collections) body(ArraysOfPrimitives, ArraysOfObjects) { """ return indexOf(element) >= 0 @@ -24,6 +24,7 @@ fun elements(): List { } templates add f("indexOf(element: T)") { + exclude(Strings) doc { "Returns first index of *element*, or -1 if the collection does not contain element" } returns("Int") body { @@ -69,6 +70,7 @@ fun elements(): List { } templates add f("lastIndexOf(element: T)") { + exclude(Strings) // has native implementation doc { "Returns last index of *element*, or -1 if the collection does not contain element" } returns("Int") body { @@ -143,7 +145,7 @@ fun elements(): List { throw IndexOutOfBoundsException("Collection doesn't contain element at index") """ } - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ return get(index) """ @@ -171,7 +173,7 @@ fun elements(): List { } """ } - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ if (size == 0) throw IllegalArgumentException("Collection is empty") @@ -200,7 +202,7 @@ fun elements(): List { } """ } - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ return if (size > 0) this[0] else null """ @@ -255,7 +257,7 @@ fun elements(): List { } """ } - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ if (size == 0) throw IllegalArgumentException("Collection is empty") @@ -283,8 +285,7 @@ fun elements(): List { } """ } - include(Lists) - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ return if (size > 0) this[size - 1] else null """ @@ -348,7 +349,7 @@ fun elements(): List { } """ } - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ if (size != 1) throw IllegalArgumentException("Collection has ${bucks}size elements") @@ -376,7 +377,7 @@ fun elements(): List { } """ } - body(Lists, ArraysOfObjects, ArraysOfPrimitives) { + body(Strings, Lists, ArraysOfObjects, ArraysOfPrimitives) { """ if (size == 0) return null diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt index 42500ccd8b5..deb83614e12 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Engine.kt @@ -15,6 +15,7 @@ enum class Family { Maps ArraysOfObjects ArraysOfPrimitives + Strings } enum class PrimitiveType(val name: String) { @@ -30,7 +31,7 @@ enum class PrimitiveType(val name: String) { class GenericFunction(val signature: String) : Comparable { - val defaultFamilies = array(Iterables, Streams, ArraysOfObjects, ArraysOfPrimitives) + val defaultFamilies = array(Iterables, Streams, ArraysOfObjects, ArraysOfPrimitives, Strings) var toNullableT: Boolean = false @@ -150,10 +151,12 @@ class GenericFunction(val signature: String) : Comparable { Maps -> "Map" Streams -> "Stream" ArraysOfObjects -> "Array" + Strings -> "String" ArraysOfPrimitives -> primitive?.let { it.name() + "Array" } ?: throw IllegalArgumentException("Primitive array should specify primitive type") else -> throw IllegalStateException("Invalid family") } + fun String.renderType(): String { val t = StringTokenizer(this, " \t\n,:()<>?.", true) val answer = StringBuilder() @@ -174,11 +177,18 @@ class GenericFunction(val signature: String) : Comparable { PrimitiveType.Float -> "0.0f" else -> "0" } + "TCollection" -> { + when (f) { + Strings -> "Appendable" + else -> "MutableCollection".renderType() + } + } "T" -> { - if (f == Maps) - "Map.Entry" - else - primitive?.name() ?: token + when (f) { + Strings -> "Char" + Maps -> "Map.Entry" + else -> primitive?.name() ?: token + } } else -> token }) @@ -189,7 +199,7 @@ class GenericFunction(val signature: String) : Comparable { fun effectiveTypeParams(): List { val types = ArrayList(typeParams) - if (primitive == null) { + if (primitive == null && f != Strings) { val implicitTypeParameters = receiver.dropWhile { it != '<' }.drop(1).takeWhile { it != '>' }.split(",") for (implicit in implicitTypeParameters.reverse()) { if (!types.any { it.startsWith(implicit) }) { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index 3672099f5c8..f08090f38cc 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -28,7 +28,9 @@ fun filtering(): List { """ } - include(Collections) + body(Strings) { "return substring(Math.min(n, size))" } + returns(Strings) { "String"} + body(Collections, ArraysOfObjects, ArraysOfPrimitives) { """ if (n >= size) @@ -60,6 +62,9 @@ fun filtering(): List { """ } + body(Strings) { "return substring(0, Math.min(n, size))" } + returns(Strings) { "String"} + doc(Streams) { "Returns a stream containing first *n* elements" } returns(Streams) { "Stream" } body(Streams) { @@ -105,6 +110,17 @@ fun filtering(): List { """ } + returns(Strings) { "String"} + body(Strings) { + """ + for (index in 0..length) + if (!predicate(get(index))) { + return substring(index) + } + return "" + """ + } + inline(false, Streams) doc(Streams) { "Returns a stream containing all elements except first elements that satisfy the given *predicate*" } returns(Streams) { "Stream" } @@ -142,6 +158,17 @@ fun filtering(): List { """ } + returns(Strings) { "String"} + body(Strings) { + """ + for (index in 0..length) + if (!predicate(get(index))) { + return substring(0, index) + } + return "" + """ + } + inline(false, Streams) doc(Streams) { "Returns a stream containing first elements satisfying the given *predicate*" } returns(Streams) { "Stream" } @@ -163,6 +190,13 @@ fun filtering(): List { """ } + returns(Strings) { "String"} + body(Strings) { + """ + return filterTo(StringBuilder(), predicate).toString() + """ + } + inline(false, Streams) doc(Streams) { "Returns a stream containing all elements matching the given *predicate*" } returns(Streams) { "Stream" } @@ -178,7 +212,7 @@ fun filtering(): List { inline(true) doc { "Appends all elements matching the given *predicate* into the given *collection*" } - typeParam("C: MutableCollection") + typeParam("C: TCollection") returns("C") body { @@ -187,6 +221,18 @@ fun filtering(): List { return collection """ } + + doc(Strings) { "Appends all characters matching the given *predicate* to the given *collection*" } + body(Strings) { + """ + for (index in 0..length - 1) { + val element = get(index) + if (predicate(element)) destination.append(element) + } + return destination + """ + } + include(Maps) } @@ -201,6 +247,13 @@ fun filtering(): List { """ } + returns(Strings) { "String"} + body(Strings) { + """ + return filterNotTo(StringBuilder(), predicate).toString() + """ + } + inline(false, Streams) doc(Streams) { "Returns a stream containing all elements not matching the given *predicate*" } returns(Streams) { "Stream" } @@ -216,7 +269,7 @@ fun filtering(): List { inline(true) doc { "Appends all elements not matching the given *predicate* to the given *collection*" } - typeParam("C: MutableCollection") + typeParam("C: TCollection") returns("C") body { @@ -225,11 +278,19 @@ fun filtering(): List { return collection """ } + + doc(Strings) { "Appends all characters not matching the given *predicate* to the given *collection*" } + body(Strings) { + """ + for (element in this) if (!predicate(element)) collection.append(element) + return collection + """ + } include(Maps) } templates add f("filterNotNull()") { - exclude(ArraysOfPrimitives) + exclude(ArraysOfPrimitives, Strings) doc { "Returns a list containing all elements that are not null" } typeParam("T: Any") returns("List") @@ -250,11 +311,11 @@ fun filtering(): List { } templates add f("filterNotNullTo(collection: C)") { - exclude(ArraysOfPrimitives) + exclude(ArraysOfPrimitives, Strings) doc { "Appends all elements that are not null to the given *collection*" } - typeParam("C: MutableCollection") - typeParam("T: Any") returns("C") + typeParam("C: TCollection") + typeParam("T: Any") toNullableT = true body { """ @@ -265,7 +326,7 @@ fun filtering(): List { } templates add f("slice(indices: Iterable)") { - only(Lists, ArraysOfPrimitives, ArraysOfObjects) + only(Strings, Lists, ArraysOfPrimitives, ArraysOfObjects) doc { "Returns a list containing elements at specified positions" } returns("List") body { @@ -277,6 +338,17 @@ fun filtering(): List { return list """ } + + returns(Strings) { "String" } + body(Strings) { + """ + val result = StringBuilder() + for (i in indices) { + result.append(get(i)) + } + return result.toString() + """ + } } return templates diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt index 1bc50a79f5f..89221626d1c 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Generators.kt @@ -6,6 +6,7 @@ fun generators(): List { val templates = arrayListOf() templates add f("plus(element: T)") { + exclude(Strings) doc { "Returns a list containing all elements of original collection and then the given element" } returns("List") body { @@ -26,7 +27,7 @@ fun generators(): List { } templates add f("plus(collection: Iterable)") { - exclude(Streams) + exclude(Strings, Streams) doc { "Returns a list containing all elements of original collection and then all elements of the given *collection*" } returns("List") body { @@ -39,7 +40,7 @@ fun generators(): List { } templates add f("plus(array: Array)") { - exclude(Streams) + exclude(Strings, Streams) doc { "Returns a list containing all elements of original collection and then all elements of the given *collection*" } returns("List") body { @@ -99,9 +100,25 @@ fun generators(): List { return Pair(first, second) """ } + + returns(Strings) { "Pair" } + body(Strings) { + """ + val first = StringBuilder() + val second = StringBuilder() + for (element in this) { + if (predicate(element)) { + first.append(element) + } else { + second.append(element) + } + } + return Pair(first.toString(), second.toString()) + """ + } } - templates add f("zip(collection: Iterable)") { + templates add f("zip(other: Iterable)") { exclude(Streams) doc { """ @@ -113,7 +130,7 @@ fun generators(): List { body { """ val first = iterator() - val second = collection.iterator() + val second = other.iterator() val list = ArrayList>() while (first.hasNext() && second.hasNext()) { list.add(first.next() to second.next()) @@ -123,6 +140,27 @@ fun generators(): List { } } + templates add f("zip(other : String)") { + only(Strings) + doc { + """ + Returns a list of pairs built from characters of both strings with same indexes. List has length of shortest collection. + """ + } + returns("List>") + body { + """ + val first = iterator() + val second = other.iterator() + val list = ArrayList>() + while (first.hasNext() && second.hasNext()) { + list.add(first.next() to second.next()) + } + return list + """ + } + } + templates add f("zip(array: Array)") { exclude(Streams) doc { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Guards.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Guards.kt index 12e811578e9..1fa4fac5914 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Guards.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Guards.kt @@ -10,7 +10,7 @@ fun guards(): List { templates add f("requireNoNulls()") { include(Lists) - exclude(ArraysOfPrimitives) + exclude(Strings, ArraysOfPrimitives) doc { "Returns an original collection containing all the non-*null* elements, throwing an [[IllegalArgumentException]] if there are any null elements" } typeParam("T:Any") toNullableT = true diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt index 206e667edd0..ebaa41ff4cc 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Mapping.kt @@ -45,7 +45,8 @@ fun mapping(): List { } templates add f("mapNotNull(transform : (T) -> R)") { - exclude(ArraysOfPrimitives) + inline(true) + exclude(Strings, ArraysOfPrimitives) doc { "Returns a list containing the results of applying the given *transform* function to each non-null element of the original collection" } typeParam("T: Any") typeParam("R") @@ -59,6 +60,7 @@ fun mapping(): List { doc(Streams) { "Returns a stream containing the results of applying the given *transform* function to each non-null element of the original stream" } returns(Streams) { "Stream" } + inline(false, Streams) body(Streams) { """ return TransformingStream(FilteringStream(this, false, { it != null }) as Stream, transform) @@ -91,7 +93,7 @@ fun mapping(): List { templates add f("mapNotNullTo(collection: C, transform : (T) -> R)") { inline(true) - exclude(ArraysOfPrimitives) + exclude(Strings, ArraysOfPrimitives) doc { """ Appends transformed non-null elements of original collection using the given *transform* function diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt index 4889bf7f05e..a688623d73d 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt @@ -16,6 +16,15 @@ fun ordering(): List { """ } + doc(Strings) { "Returns a string with characters in reversed order" } + returns(Strings) { "String"} + body(Strings) { + // TODO: Replace with StringBuilder(this) when JS can handle it + """ + return StringBuilder().append(this).reverse().toString() + """ + } + exclude(Streams) } @@ -38,6 +47,7 @@ fun ordering(): List { exclude(Streams) exclude(ArraysOfPrimitives) // TODO: resolve collision between inplace sort and this function exclude(ArraysOfObjects) + exclude(Strings) } templates add f("sortDescending()") { @@ -60,6 +70,7 @@ fun ordering(): List { exclude(Streams) exclude(ArraysOfPrimitives) // TODO: resolve collision between inplace sort and this function exclude(ArraysOfObjects) + exclude(Strings) } templates add f("sortBy(order: (T) -> R)") { @@ -83,6 +94,7 @@ fun ordering(): List { exclude(Streams) exclude(ArraysOfPrimitives) + exclude(Strings) } templates add f("sortDescendingBy(order: (T) -> R)") { @@ -106,6 +118,7 @@ fun ordering(): List { exclude(Streams) exclude(ArraysOfPrimitives) + exclude(Strings) } templates add f("sortBy(comparator : Comparator)") { @@ -125,6 +138,7 @@ fun ordering(): List { exclude(Streams) exclude(ArraysOfPrimitives) + exclude(Strings) } return templates