String <-> CharArray, ByteArray conversions (#2973)

This commit is contained in:
ilya-g
2019-05-15 13:35:06 +03:00
committed by Nikolay Igotti
parent 9d207ed7b7
commit 470c0efb26
14 changed files with 236 additions and 70 deletions
+2 -2
View File
@@ -3472,10 +3472,10 @@ task coverage_basic_library(type: RunStandaloneKonanTest) {
task buildKonanStdlibTests(type: BuildKonanTest) {
outputSourceSetName = "testOutputStdlib"
flags = [ "-Xmulti-platform", "-friend-modules", project.rootProject.file("${project.properties['konan.home']}/klib/common/stdlib") ]
flags = [ "-Xmulti-platform", '-Xuse-experimental=kotlin.ExperimentalStdlibApi', "-friend-modules", project.rootProject.file("${project.properties['konan.home']}/klib/common/stdlib") ]
def testSources = externalStdlibTestsDir.absolutePath
compileList = [ "$testSources/stdlib/test", "$testSources/stdlib/common",
"stdlib_external/utils.kt", "stdlib_external/jsCollectionFactoriesActuals.kt" ]
"stdlib_external/utils.kt", "stdlib_external/text/StringEncodingTestNative.kt", "stdlib_external/jsCollectionFactoriesActuals.kt" ]
excludeList = [ "$testSources/stdlib/test/internalAnnotations.kt" ]
}
+7 -9
View File
@@ -66,7 +66,7 @@ fun <T: Any> checkThrows(e: KClass<T>, string: String, action: () -> Unit) {
assertTrue(e.isInstance(exception),"""
Wrong exception was thrown for string: $string
Expected: ${e.qualifiedName}
Actual: ${exception::class.qualifiedName}
Actual: ${exception::class.qualifiedName}: $exception}
""".trimIndent())
}
@@ -197,7 +197,7 @@ fun test16to8CustomBorders() {
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(-1, 4)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(5, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(2, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8(3, -2)}
checkThrows(IllegalArgumentException::class, "Hello") { "Hello".toUtf8(3, -2)}
// Test manual conversion with an exception if an input is invalid and custom borders.
@@ -228,7 +228,7 @@ fun test16to8CustomBorders() {
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(-1, 4)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(5, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(2, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { "Hello".toUtf8OrThrow(3, -2)}
checkThrows(IllegalArgumentException::class, "Hello") { "Hello".toUtf8OrThrow(3, -2)}
}
fun testPrint() {
@@ -294,8 +294,6 @@ fun test8to16CustomBorders() {
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 3, 2)
checkUtf8to16Replacing("",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 0)
checkUtf8to16Replacing("",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 10, 0)
checkUtf8to16Replacing("\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
@@ -323,7 +321,8 @@ fun test8to16CustomBorders() {
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(-1, 4)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(5, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(2, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(3, -2)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8(10, 0)}
checkThrows(IllegalArgumentException::class, "Hello") { helloArray.stringFromUtf8(3, -2)}
// Conversion with throwing
checkUtf8to16Throwing("He",
@@ -334,8 +333,6 @@ fun test8to16CustomBorders() {
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 3, 2)
checkUtf8to16Throwing("",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 0)
checkUtf8to16Throwing("",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 10, 0)
checkUtf8to16Throwing("\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
@@ -361,7 +358,8 @@ fun test8to16CustomBorders() {
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(-1, 4)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(5, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(2, 10)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(3, -2)}
checkThrows(IndexOutOfBoundsException::class, "Hello") { helloArray.stringFromUtf8OrThrow(10, 0)}
checkThrows(IllegalArgumentException::class, "Hello") { helloArray.stringFromUtf8OrThrow(3, -2)}
}
// endregion
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package test.text
internal actual val surrogateCodePointDecoding: String = "\uFFFD".repeat(3)
internal actual val surrogateCharEncoding: ByteArray = byteArrayOf(0xEF.toByte(), 0xBF.toByte(), 0xBD.toByte())
@@ -17,3 +17,7 @@ public actual fun assertTypeEquals(expected: Any?, actual: Any?) {
}
internal actual fun String.removeLeadingPlusOnJava6(): String = this
internal actual inline fun testOnNonJvm6And7(f: () -> Unit) {
f()
}
+3 -3
View File
@@ -18,9 +18,9 @@
buildKotlinVersion=1.3.40-dev-2251
buildKotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_Compiler),number:1.3.40-dev-2251,pinned:true/artifacts/content/maven
remoteRoot=konan_tests
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_Compiler),number:1.3.40-dev-2423,branch:default:true,pinned:true/artifacts/content/maven
kotlinVersion=1.3.40-dev-2423
testKotlinVersion=1.3.40-dev-2423
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_Compiler),number:1.3.50-dev-44,branch:default:true,pinned:true/artifacts/content/maven
kotlinVersion=1.3.50-dev-44
testKotlinVersion=1.3.50-dev-44
# See https://teamcity.jetbrains.com/project.html?projectId=Kotlin_KotlinNativeShared&tab=projectOverview
sharedRepo=https://dl.bintray.com/jetbrains/kotlin-native-dependencies
sharedVersion=1.0-dev-57
+2 -2
View File
@@ -52,8 +52,8 @@ void RUNTIME_NORETURN ThrowNumberFormatException();
void RUNTIME_NORETURN ThrowOutOfMemoryError();
// Throws not implemented error.
void RUNTIME_NORETURN ThrowNotImplementedError();
// Throws illegal character conversion exception (used in UTF8/UTF16 conversions).
void RUNTIME_NORETURN ThrowIllegalCharacterConversionException();
// Throws character coding exception (used in UTF8/UTF16 conversions).
void RUNTIME_NORETURN ThrowCharacterCodingException();
void RUNTIME_NORETURN ThrowIllegalArgumentException();
void RUNTIME_NORETURN ThrowIllegalStateException();
void RUNTIME_NORETURN ThrowInvalidMutabilityException(KConstRef where);
+8 -16
View File
@@ -35,7 +35,7 @@ typedef KStdStringInserter utf16to8(const KChar*,const KChar*, KStdStringInserte
KStdStringInserter utf16toUtf8OrThrow(const KChar* start, const KChar* end, KStdStringInserter result) {
TRY_CATCH(result = utf8::utf16to8(start, end, result),
result = utf8::unchecked::utf16to8(start, end, result),
ThrowIllegalCharacterConversionException());
ThrowCharacterCodingException());
return result;
}
@@ -67,7 +67,7 @@ OBJ_GETTER(utf8ToUtf16OrThrow, const char* rawString, size_t rawStringLength) {
uint32_t charCount;
TRY_CATCH(charCount = utf8::utf16_length(rawString, end),
charCount = utf8::unchecked::utf16_length(rawString, end),
ThrowIllegalCharacterConversionException());
ThrowCharacterCodingException());
RETURN_RESULT_OF(utf8ToUtf16Impl<utf8::unchecked::utf8to16>, rawString, end, charCount);
}
@@ -787,11 +787,7 @@ OBJ_GETTER(Kotlin_ByteArray_stringFromUtf8OrThrow, KConstRef thiz, KInt start, K
RETURN_RESULT_OF0(TheEmptyString);
}
const char* rawString = byteArrayAsCString(thiz, start, size);
KInt realSize = 0;
while (rawString[realSize] != 0 && realSize < size) {
realSize++;
}
RETURN_RESULT_OF(utf8ToUtf16OrThrow, rawString, realSize);
RETURN_RESULT_OF(utf8ToUtf16OrThrow, rawString, size);
}
OBJ_GETTER(Kotlin_ByteArray_stringFromUtf8, KConstRef thiz, KInt start, KInt size) {
@@ -799,11 +795,7 @@ OBJ_GETTER(Kotlin_ByteArray_stringFromUtf8, KConstRef thiz, KInt start, KInt siz
RETURN_RESULT_OF0(TheEmptyString);
}
const char* rawString = byteArrayAsCString(thiz, start, size);
KInt realSize = 0;
while (rawString[realSize] != 0 && realSize < size) {
realSize++;
}
RETURN_RESULT_OF(utf8ToUtf16, rawString, realSize);
RETURN_RESULT_OF(utf8ToUtf16, rawString, size);
}
OBJ_GETTER(Kotlin_String_toUtf8, KString thiz, KInt start, KInt size) {
@@ -833,12 +825,12 @@ OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef thiz, KInt start, KInt size) {
RETURN_OBJ(result->obj());
}
OBJ_GETTER(Kotlin_String_toCharArray, KString string) {
OBJ_GETTER(Kotlin_String_toCharArray, KString string, KInt start, KInt size) {
ArrayHeader* result = AllocArrayInstance(
theCharArrayTypeInfo, string->count_, OBJ_RESULT)->array();
theCharArrayTypeInfo, size, OBJ_RESULT)->array();
memcpy(CharArrayAddressOfElementAt(result, 0),
CharArrayAddressOfElementAt(string, 0),
string->count_ * sizeof(KChar));
CharArrayAddressOfElementAt(string, start),
size * sizeof(KChar));
RETURN_OBJ(result->obj());
}
+28 -17
View File
@@ -89,10 +89,16 @@ namespace internal
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_out_of_unicode_domain(u32 cp)
{
return cp > CODE_POINT_MAX;
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
return (!utf8::internal::is_out_of_unicode_domain(cp) && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
@@ -146,7 +152,9 @@ namespace internal
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
#define UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(CP, LENGTH) {if (utf8::internal::is_overlong_sequence(CP, LENGTH)) return OVERLONG_SEQUENCE;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
@@ -172,6 +180,8 @@ namespace internal
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 2)
return UTF8_OK;
}
@@ -187,6 +197,11 @@ namespace internal
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
if (utf8::internal::is_surrogate(code_point))
return INVALID_CODE_POINT;
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 3)
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
@@ -206,6 +221,11 @@ namespace internal
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
if (utf8::internal::is_out_of_unicode_domain(code_point))
return INVALID_CODE_POINT;
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 4)
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
@@ -251,23 +271,14 @@ namespace internal
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
// Decoding succeeded.
code_point = cp;
++it;
} else {
// Failure branch - restore the original value of the iterator
it = original_it;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
+3 -3
View File
@@ -37,13 +37,13 @@ uint32_t next(octet_iterator &it, const octet_iterator end, uint32_t replacement
case internal::UTF8_OK :
return cp;
case internal::INVALID_LEAD :
case internal::INVALID_CODE_POINT :
case internal::OVERLONG_SEQUENCE :
it++;
return replacement;
case internal::NOT_ENOUGH_ROOM :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
case internal::INVALID_CODE_POINT :
// The whole invalid sequence is replaced with one replacement codepoint.
// The whole incomplete sequence is replaced with one replacement codepoint.
for (it++; it < end && utf8::internal::is_trail(*it); it++);
return replacement;
}
@@ -166,6 +166,7 @@ public actual open class NumberFormatException : IllegalArgumentException {
actual constructor(message: String?) : super(message)
}
// TODO: Deprecate and replace with CharacterCodingException
public open class IllegalCharacterConversionException : IllegalArgumentException {
constructor(): super()
+39 -12
View File
@@ -8,40 +8,67 @@ package kotlin.native
/**
* Converts an UTF-8 array into a [String]. Replaces invalid input sequences with a default character.
*/
public fun ByteArray.stringFromUtf8(start: Int = 0, size: Int = this.size) : String =
stringFromUtf8Impl(start, size)
public fun ByteArray.stringFromUtf8(start: Int = 0, size: Int = this.size) : String {
checkBoundsIndexes(start, start + size, this.size)
return stringFromUtf8Impl(start, size)
}
@SymbolName("Kotlin_ByteArray_stringFromUtf8")
private external fun ByteArray.stringFromUtf8Impl(start: Int, size: Int) : String
internal external fun ByteArray.stringFromUtf8Impl(start: Int, size: Int) : String
/**
* Converts an UTF-8 array into a [String].
* @throws [IllegalCharacterConversionException] if the input is invalid.
*/
public fun ByteArray.stringFromUtf8OrThrow(start: Int = 0, size: Int = this.size) : String =
stringFromUtf8OrThrowImpl(start, size)
@UseExperimental(ExperimentalStdlibApi::class)
public fun ByteArray.stringFromUtf8OrThrow(start: Int = 0, size: Int = this.size) : String {
checkBoundsIndexes(start, start + size, this.size)
try {
return stringFromUtf8OrThrowImpl(start, size)
} catch (e: CharacterCodingException) {
throw IllegalCharacterConversionException()
}
}
@SymbolName("Kotlin_ByteArray_stringFromUtf8OrThrow")
private external fun ByteArray.stringFromUtf8OrThrowImpl(start: Int, size: Int) : String
internal external fun ByteArray.stringFromUtf8OrThrowImpl(start: Int, size: Int) : String
/**
* Converts a [String] into an UTF-8 array. Replaces invalid input sequences with a default character.
*/
public fun String.toUtf8(start: Int = 0, size: Int = this.length) : ByteArray =
toUtf8Impl(start, size)
public fun String.toUtf8(start: Int = 0, size: Int = this.length) : ByteArray {
checkBoundsIndexes(start, start + size, this.length)
return toUtf8Impl(start, size)
}
@SymbolName("Kotlin_String_toUtf8")
private external fun String.toUtf8Impl(start: Int, size: Int) : ByteArray
internal external fun String.toUtf8Impl(start: Int, size: Int) : ByteArray
/**
* Converts a [String] into an UTF-8 array.
* @throws [IllegalCharacterConversionException] if the input is invalid.
*/
public fun String.toUtf8OrThrow(start: Int = 0, size: Int = this.length) : ByteArray =
toUtf8OrThrowImpl(start, size)
@UseExperimental(ExperimentalStdlibApi::class)
public fun String.toUtf8OrThrow(start: Int = 0, size: Int = this.length) : ByteArray {
checkBoundsIndexes(start, start + size, this.length)
try {
return toUtf8OrThrowImpl(start, size)
} catch (e: CharacterCodingException) {
throw IllegalCharacterConversionException()
}
}
internal fun checkBoundsIndexes(startIndex: Int, endIndex: Int, size: Int) {
if (startIndex < 0 || endIndex > size) {
throw IndexOutOfBoundsException("startIndex: $startIndex, endIndex: $endIndex, size: $size")
}
if (startIndex > endIndex) {
throw IllegalArgumentException("startIndex: $startIndex > endIndex: $endIndex")
}
}
@SymbolName("Kotlin_String_toUtf8OrThrow")
private external fun String.toUtf8OrThrowImpl(start: Int, size: Int) : ByteArray
internal external fun String.toUtf8OrThrowImpl(start: Int, size: Int) : ByteArray
@SymbolName("Kotlin_String_fromCharArray")
internal external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
@@ -70,8 +70,9 @@ internal fun ThrowNotImplementedError(): Nothing {
}
@ExportForCppRuntime
internal fun ThrowIllegalCharacterConversionException(): Nothing {
throw IllegalCharacterConversionException()
internal fun ThrowCharacterCodingException(): Nothing {
@UseExperimental(ExperimentalStdlibApi::class)
throw CharacterCodingException()
}
@ExportForCppRuntime
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.text
/**
* The exception thrown when a character encoding or decoding error occurs.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual open class CharacterCodingException(message: String?) : Exception(message) {
actual constructor() : this(null)
}
+110 -4
View File
@@ -175,10 +175,12 @@ public actual external fun String.toUpperCase(): String
public actual external fun String.toLowerCase(): String
/**
* Returns a new character array containing the characters from this string.
* Returns a [CharArray] containing characters of this string.
*/
public actual fun String.toCharArray(): CharArray = toCharArray(this, 0, length)
@SymbolName("Kotlin_String_toCharArray")
public external fun String.toCharArray(): CharArray
private external fun toCharArray(string: String, start: Int, size: Int): CharArray
/**
* Returns a copy of this string having its first letter uppercased, or the original string,
@@ -228,7 +230,111 @@ public actual fun String(chars: CharArray): String = fromCharArray(chars, 0, cha
* @throws IndexOutOfBoundsException if either [offset] or [length] are less than zero
* or `offset + length` is out of [chars] array bounds.
*/
public actual fun String(chars: CharArray, offset: Int, length: Int): String = fromCharArray(chars, offset, length)
public actual fun String(chars: CharArray, offset: Int, length: Int): String {
if (offset < 0 || length < 0 || offset + length > chars.size)
throw ArrayIndexOutOfBoundsException()
return fromCharArray(chars, offset, length)
}
/**
* Concatenates characters in this [CharArray] into a String.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun CharArray.concatToString(): String = fromCharArray(this, 0, size)
/**
* Concatenates characters in this [CharArray] or its subrange into a String.
*
* @param startIndex the beginning (inclusive) of the subrange of characters, 0 by default.
* @param endIndex the end (exclusive) of the subrange of characters, size of this array by default.
*
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the size of this array.
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun CharArray.concatToString(startIndex: Int, endIndex: Int): String {
checkBoundsIndexes(startIndex, endIndex, size)
return fromCharArray(this, startIndex, endIndex - startIndex)
}
/**
* Returns a [CharArray] containing characters of this string or its substring.
*
* @param startIndex the beginning (inclusive) of the substring, 0 by default.
* @param endIndex the end (exclusive) of the substring, length of this string by default.
*
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the length of this string.
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun String.toCharArray(startIndex: Int, endIndex: Int): CharArray {
checkBoundsIndexes(startIndex, endIndex, length)
return toCharArray(this, startIndex, endIndex - startIndex)
}
/**
* Decodes a string from the bytes in UTF-8 encoding in this array.
*
* Malformed byte sequences are replaced by the replacement char `\uFFFD`.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun ByteArray.decodeToString(): String = stringFromUtf8Impl(0, size)
/**
* Decodes a string from the bytes in UTF-8 encoding in this array or its subrange.
*
* @param startIndex the beginning (inclusive) of the subrange to decode, 0 by default.
* @param endIndex the end (exclusive) of the subrange to decode, size of this array by default.
* @param throwOnInvalidSequence specifies whether to throw an exception on malformed byte sequence or replace it by the replacement char `\uFFFD`.
*
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the size of this array.
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
* @throws CharacterCodingException if the byte array contains malformed UTF-8 byte sequence and [throwOnInvalidSequence] is true.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun ByteArray.decodeToString(startIndex: Int, endIndex: Int, throwOnInvalidSequence: Boolean): String {
checkBoundsIndexes(startIndex, endIndex, size)
return if (throwOnInvalidSequence)
stringFromUtf8OrThrowImpl(startIndex, endIndex - startIndex)
else
stringFromUtf8Impl(startIndex, endIndex - startIndex)
}
/**
* Encodes this string to an array of bytes in UTF-8 encoding.
*
* Any malformed char sequence is replaced by the replacement byte sequence.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun String.encodeToByteArray(): ByteArray = toUtf8Impl(0, length)
/**
* Encodes this string or its substring to an array of bytes in UTF-8 encoding.
*
* @param startIndex the beginning (inclusive) of the substring to encode, 0 by default.
* @param endIndex the end (exclusive) of the substring to encode, length of this string by default.
* @param throwOnInvalidSequence specifies whether to throw an exception on malformed char sequence or replace.
*
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or [endIndex] is greater than the length of this string.
* @throws IllegalArgumentException if [startIndex] is greater than [endIndex].
* @throws CharacterCodingException if this string contains malformed char sequence and [throwOnInvalidSequence] is true.
*/
@SinceKotlin("1.3")
@ExperimentalStdlibApi
public actual fun String.encodeToByteArray(startIndex: Int, endIndex: Int, throwOnInvalidSequence: Boolean): ByteArray {
checkBoundsIndexes(startIndex, endIndex, length)
return if (throwOnInvalidSequence)
toUtf8OrThrowImpl(startIndex, endIndex - startIndex)
else
toUtf8Impl(startIndex, endIndex - startIndex)
}
@SymbolName("Kotlin_String_compareToIgnoreCase")
internal external fun compareToIgnoreCase(thiz: String, other: String): Int
@@ -241,4 +347,4 @@ public actual fun String.compareTo(other: String, ignoreCase: Boolean): Int {
private val STRING_CASE_INSENSITIVE_ORDER = Comparator<String> { a, b -> a.compareTo(b, ignoreCase = true) }
public actual val String.Companion.CASE_INSENSITIVE_ORDER: Comparator<String>
get() = STRING_CASE_INSENSITIVE_ORDER
get() = STRING_CASE_INSENSITIVE_ORDER