Avoid hitting max argument limit in String(chars)
Rewrite CharArray to String conversions to appending chars one by one. Refine parameter checking in String(chars, offset, length) to adhere to the common exception contract and document it. #KT-29003
This commit is contained in:
@@ -100,6 +100,9 @@ public expect fun String(chars: CharArray): String
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the characters from a portion of the specified array to a string.
|
* Converts the characters from a portion of the specified array to a string.
|
||||||
|
*
|
||||||
|
* @throws IndexOutOfBoundsException if either [offset] or [length] are less than zero
|
||||||
|
* or `offset + length` is out of [chars] array bounds.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.2")
|
@SinceKotlin("1.2")
|
||||||
public expect fun String(chars: CharArray, offset: Int, length: Int): String
|
public expect fun String(chars: CharArray, offset: Int, length: Int): String
|
||||||
|
|||||||
@@ -11,17 +11,29 @@ import kotlin.js.RegExp
|
|||||||
* Converts the characters in the specified array to a string.
|
* Converts the characters in the specified array to a string.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.2")
|
@SinceKotlin("1.2")
|
||||||
@kotlin.internal.InlineOnly
|
public actual fun String(chars: CharArray): String {
|
||||||
public actual inline fun String(chars: CharArray): String {
|
var result = ""
|
||||||
return js("String.fromCharCode").apply(null, chars)
|
for (char in chars) {
|
||||||
|
result += char
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the characters from a portion of the specified array to a string.
|
* Converts the characters from a portion of the specified array to a string.
|
||||||
|
*
|
||||||
|
* @throws IndexOutOfBoundsException if either [offset] or [length] are less than zero
|
||||||
|
* or `offset + length` is out of [chars] array bounds.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.2")
|
@SinceKotlin("1.2")
|
||||||
public actual fun String(chars: CharArray, offset: Int, length: Int): String {
|
public actual fun String(chars: CharArray, offset: Int, length: Int): String {
|
||||||
return String(chars.copyOfRange(offset, offset + length))
|
if (offset < 0 || length < 0 || chars.size - offset < length)
|
||||||
|
throw IndexOutOfBoundsException("size: ${chars.size}; offset: $offset; length: $length")
|
||||||
|
var result = ""
|
||||||
|
for (index in offset until offset + length) {
|
||||||
|
result += chars[index]
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -272,6 +272,9 @@ public actual inline fun String(chars: CharArray): String =
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the characters from a portion of the specified array to a string.
|
* Converts the characters from a portion of the specified array to a string.
|
||||||
|
*
|
||||||
|
* @throws IndexOutOfBoundsException if either [offset] or [length] are less than zero
|
||||||
|
* or `offset + length` is out of [chars] array bounds.
|
||||||
*/
|
*/
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public actual inline fun String(chars: CharArray, offset: Int, length: Int): String =
|
public actual inline fun String(chars: CharArray, offset: Int, length: Int): String =
|
||||||
|
|||||||
@@ -53,11 +53,21 @@ class StringTest {
|
|||||||
@Test fun stringFromCharArraySlice() {
|
@Test fun stringFromCharArraySlice() {
|
||||||
val chars: CharArray = charArrayOf('K', 'o', 't', 'l', 'i', 'n', ' ', 'r', 'u', 'l', 'e', 's')
|
val chars: CharArray = charArrayOf('K', 'o', 't', 'l', 'i', 'n', ' ', 'r', 'u', 'l', 'e', 's')
|
||||||
assertEquals("rule", String(chars, 7, 4))
|
assertEquals("rule", String(chars, 7, 4))
|
||||||
|
|
||||||
|
val longChars = CharArray(200_000) { 'k' }
|
||||||
|
val longString = String(longChars, 1000, 190_000)
|
||||||
|
assertEquals(190_000, longString.length)
|
||||||
|
assertTrue(longString.all { it == 'k' })
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun stringFromCharArray() {
|
@Test fun stringFromCharArray() {
|
||||||
val chars: CharArray = charArrayOf('K', 'o', 't', 'l', 'i', 'n')
|
val chars: CharArray = charArrayOf('K', 'o', 't', 'l', 'i', 'n')
|
||||||
assertEquals("Kotlin", String(chars))
|
assertEquals("Kotlin", String(chars))
|
||||||
|
|
||||||
|
val longChars = CharArray(200_000) { 'k' }
|
||||||
|
val longString = String(longChars)
|
||||||
|
assertEquals(200_000, longString.length)
|
||||||
|
assertTrue(longString.all { it == 'k' })
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun stringFromCharArrayUnicodeSurrogatePairs() {
|
@Test fun stringFromCharArrayUnicodeSurrogatePairs() {
|
||||||
@@ -67,6 +77,16 @@ class StringTest {
|
|||||||
assertEquals("Ŭᎍ🀺", String(chars, 3, 4))
|
assertEquals("Ŭᎍ🀺", String(chars, 3, 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun stringFromCharArrayOutOfBounds() {
|
||||||
|
fun test(chars: CharArray) {
|
||||||
|
assertFailsWith<IndexOutOfBoundsException> { String(chars, -1, 1) }
|
||||||
|
assertFailsWith<IndexOutOfBoundsException> { String(chars, 1, -1) }
|
||||||
|
assertFailsWith<IndexOutOfBoundsException> { String(chars, chars.size - 1, 2) }
|
||||||
|
}
|
||||||
|
test(CharArray(16) { 'k' })
|
||||||
|
test(CharArray(160_000) { 'k' })
|
||||||
|
}
|
||||||
|
|
||||||
@Test fun isEmptyAndBlank() = withOneCharSequenceArg { arg1 ->
|
@Test fun isEmptyAndBlank() = withOneCharSequenceArg { arg1 ->
|
||||||
class Case(val value: String?, val isNull: Boolean = false, val isEmpty: Boolean = false, val isBlank: Boolean = false)
|
class Case(val value: String?, val isNull: Boolean = false, val isEmpty: Boolean = false, val isBlank: Boolean = false)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user