stdlib: Improve character API.
The patch adds methods for surrogate characters processing and Unicode category support needed for regular expression library.
This commit is contained in:
@@ -163,7 +163,6 @@ enum CharacterClass {
|
||||
OTHER_SYMBOL = 28,
|
||||
/**
|
||||
* Unicode category constant Pi.
|
||||
*
|
||||
*/
|
||||
INITIAL_QUOTE_PUNCTUATION = 29,
|
||||
/**
|
||||
@@ -973,6 +972,10 @@ KChar Kotlin_Char_toUpperCase(KChar ch) {
|
||||
return towupper_Konan(ch);
|
||||
}
|
||||
|
||||
KInt Kotlin_Char_getType(KChar ch) {
|
||||
return getType(ch);
|
||||
}
|
||||
|
||||
constexpr KInt digits[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
-1, -1, -1, -1, -1, -1, -1,
|
||||
|
||||
@@ -172,6 +172,12 @@ external public fun String.toUpperCase(): String
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
external public inline fun String.toLowerCase(): String
|
||||
|
||||
/**
|
||||
* Returns an array containing all characters of the specified string.
|
||||
*/
|
||||
@SymbolName("Kotlin_String_toCharArray")
|
||||
external public fun String.toCharArray() : CharArray
|
||||
|
||||
/**
|
||||
* Returns a copy of this string having its first letter uppercased, or the original string,
|
||||
* if it's empty or already starts with an upper case letter.
|
||||
|
||||
@@ -106,6 +106,21 @@ public final class Char : Comparable<Char> {
|
||||
*/
|
||||
public const val MAX_SURROGATE: Char = MAX_LOW_SURROGATE
|
||||
|
||||
/**
|
||||
* The minimum value of a supplementary code point, `\u0x10000`. Kotlin/Native specific.
|
||||
*/
|
||||
public const val MIN_SUPPLEMENTARY_CODE_POINT: Int = 0x10000
|
||||
|
||||
/**
|
||||
* The minimum value of a Unicode code point. Kotlin/Native specific.
|
||||
*/
|
||||
public const val MIN_CODE_POINT = 0x000000
|
||||
|
||||
/**
|
||||
* The maximum value of a Unicode code point. Kotlin/Native specific.
|
||||
*/
|
||||
public const val MAX_CODE_POINT = 0X10FFFF
|
||||
|
||||
/**
|
||||
* The minimum radix available for conversion to and from strings.
|
||||
*/
|
||||
|
||||
@@ -1275,6 +1275,17 @@ public fun <T : Comparable<T>> MutableList<T>.sortDescending(): Unit {
|
||||
sortWith(reverseOrder())
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces each element in the list with a result of a transformation specified.
|
||||
*/
|
||||
public fun <T> MutableList<T>.replaceAll(transformation: (T) -> T) {
|
||||
val it = listIterator()
|
||||
while (it.hasNext()) {
|
||||
val element = it.next()
|
||||
it.set(transformation(element))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all elements sorted according to their natural sort order.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package kotlin.text
|
||||
|
||||
import kotlin.IllegalArgumentException
|
||||
|
||||
/**
|
||||
* Returns `true` if this character (Unicode code point) is defined in Unicode.
|
||||
*/
|
||||
@@ -102,6 +104,15 @@ internal fun digitOf(char: Char, radix: Int): Int = digitOfChecked(char, checkRa
|
||||
@SymbolName("Kotlin_Char_digitOfChecked")
|
||||
external internal fun digitOfChecked(char: Char, radix: Int): Int
|
||||
|
||||
/**
|
||||
* Returns a value indicating a character's general category.
|
||||
*/
|
||||
public val Char.category: CharCategory get() = CharCategory.valueOf(getType())
|
||||
|
||||
/** Retrun a Unicode category of the character as an Int. */
|
||||
@SymbolName("Kotlin_Char_getType")
|
||||
external internal fun Char.getType(): Int
|
||||
|
||||
/**
|
||||
* Checks whether the given [radix] is valid radix for string to number and number to string conversion.
|
||||
*/
|
||||
@@ -112,3 +123,48 @@ internal fun checkRadix(radix: Int): Int {
|
||||
}
|
||||
return radix
|
||||
}
|
||||
|
||||
// Char.Compaion methods. Konan specific.
|
||||
|
||||
// TODO: Make public when supplementary codepoints are supported.
|
||||
/** Converts a unicode code point to lower case. */
|
||||
internal fun Char.Companion.toLowerCase(codePoint: Int): Int =
|
||||
if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
codePoint.toChar().toLowerCase().toInt()
|
||||
} else {
|
||||
codePoint // TODO: Implement this transformation for supplementary codepoints.
|
||||
}
|
||||
|
||||
/** Converts a unicode code point to upper case. */
|
||||
internal fun Char.Companion.toUpperCase(codePoint: Int): Int =
|
||||
if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
codePoint.toChar().toUpperCase().toInt()
|
||||
} else {
|
||||
codePoint // TODO: Implement this transformation for supplementary codepoints.
|
||||
}
|
||||
|
||||
/** Converts a surrogate pair to a unicode code point. Doesn't validate that the characters are a valid surrogate pair. */
|
||||
public fun Char.Companion.toCodePoint(high: Char, low: Char): Int =
|
||||
(((high - MIN_HIGH_SURROGATE) shl 10) or (low - MIN_LOW_SURROGATE)) + 0x10000
|
||||
|
||||
/** Checks if the codepoint specified is a supplementary codepoint or not. */
|
||||
public fun Char.Companion.isSupplementaryCodePoint(codepoint: Int): Boolean =
|
||||
codepoint in MIN_SUPPLEMENTARY_CODE_POINT..MAX_CODE_POINT
|
||||
|
||||
public fun Char.Companion.isSurrogatePair(high: Char, low: Char): Boolean = high.isHighSurrogate() && low.isLowSurrogate()
|
||||
|
||||
/**
|
||||
* Converts the codepoint specified to a char array. If the codepoint is not supplementary, the method will
|
||||
* return an array with one element otherwise it will return an array A with a high surrogate in A[0] and
|
||||
* a low surrogate in A[1].
|
||||
*/
|
||||
public fun Char.Companion.toChars(codePoint: Int): CharArray =
|
||||
when {
|
||||
codePoint in 0 until MIN_SUPPLEMENTARY_CODE_POINT -> charArrayOf(codePoint.toChar())
|
||||
codePoint in MIN_SUPPLEMENTARY_CODE_POINT..MAX_CODE_POINT -> {
|
||||
val low = ((codePoint - 0x10000) and 0x3FF) + MIN_LOW_SURROGATE.toInt()
|
||||
val high = (((codePoint - 0x10000) ushr 10) and 0x3FF) + MIN_HIGH_SURROGATE.toInt()
|
||||
charArrayOf(high.toChar(), low.toChar())
|
||||
}
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package kotlin.text
|
||||
|
||||
// The values duplicate constants defined in KString.cpp.
|
||||
/**
|
||||
* Represents the character general category in the Unicode specification.
|
||||
*/
|
||||
public enum class CharCategory(public val value: Int, public val code: String) {
|
||||
/**
|
||||
* General category "Cn" in the Unicode specification.
|
||||
*/
|
||||
UNASSIGNED(0, "Cn"),
|
||||
|
||||
/**
|
||||
* General category "Lu" in the Unicode specification.
|
||||
*/
|
||||
UPPERCASE_LETTER(1, "Lu"),
|
||||
|
||||
/**
|
||||
* General category "Ll" in the Unicode specification.
|
||||
*/
|
||||
LOWERCASE_LETTER(2, "Ll"),
|
||||
|
||||
/**
|
||||
* General category "Lt" in the Unicode specification.
|
||||
*/
|
||||
TITLECASE_LETTER(3, "Lt"),
|
||||
|
||||
/**
|
||||
* General category "Lm" in the Unicode specification.
|
||||
*/
|
||||
MODIFIER_LETTER(4, "Lm"),
|
||||
|
||||
/**
|
||||
* General category "Lo" in the Unicode specification.
|
||||
*/
|
||||
OTHER_LETTER(5, "Lo"),
|
||||
|
||||
/**
|
||||
* General category "Mn" in the Unicode specification.
|
||||
*/
|
||||
NON_SPACING_MARK(6, "Mn"),
|
||||
|
||||
/**
|
||||
* General category "Me" in the Unicode specification.
|
||||
*/
|
||||
ENCLOSING_MARK(7, "Me"),
|
||||
|
||||
/**
|
||||
* General category "Mc" in the Unicode specification.
|
||||
*/
|
||||
COMBINING_SPACING_MARK(8, "Mc"),
|
||||
|
||||
/**
|
||||
* General category "Nd" in the Unicode specification.
|
||||
*/
|
||||
DECIMAL_DIGIT_NUMBER(9, "Nd"),
|
||||
|
||||
/**
|
||||
* General category "Nl" in the Unicode specification.
|
||||
*/
|
||||
LETTER_NUMBER(10, "Nl"),
|
||||
|
||||
/**
|
||||
* General category "No" in the Unicode specification.
|
||||
*/
|
||||
OTHER_NUMBER(11, "No"),
|
||||
|
||||
/**
|
||||
* General category "Zs" in the Unicode specification.
|
||||
*/
|
||||
SPACE_SEPARATOR(12, "Zs"),
|
||||
|
||||
/**
|
||||
* General category "Zl" in the Unicode specification.
|
||||
*/
|
||||
LINE_SEPARATOR(13, "Zl"),
|
||||
|
||||
/**
|
||||
* General category "Zp" in the Unicode specification.
|
||||
*/
|
||||
PARAGRAPH_SEPARATOR(14, "Zp"),
|
||||
|
||||
/**
|
||||
* General category "Cc" in the Unicode specification.
|
||||
*/
|
||||
CONTROL(15, "Cc"),
|
||||
|
||||
/**
|
||||
* General category "Cf" in the Unicode specification.
|
||||
*/
|
||||
FORMAT(16, "Cf"),
|
||||
|
||||
/**
|
||||
* General category "Co" in the Unicode specification.
|
||||
*/
|
||||
PRIVATE_USE(18, "Co"),
|
||||
|
||||
/**
|
||||
* General category "Cs" in the Unicode specification.
|
||||
*/
|
||||
SURROGATE(19, "Cs"),
|
||||
|
||||
/**
|
||||
* General category "Pd" in the Unicode specification.
|
||||
*/
|
||||
DASH_PUNCTUATION(20, "Pd"),
|
||||
|
||||
/**
|
||||
* General category "Ps" in the Unicode specification.
|
||||
*/
|
||||
START_PUNCTUATION(21, "Ps"),
|
||||
|
||||
/**
|
||||
* General category "Pe" in the Unicode specification.
|
||||
*/
|
||||
END_PUNCTUATION(22, "Pe"),
|
||||
|
||||
/**
|
||||
* General category "Pc" in the Unicode specification.
|
||||
*/
|
||||
CONNECTOR_PUNCTUATION(23, "Pc"),
|
||||
|
||||
/**
|
||||
* General category "Po" in the Unicode specification.
|
||||
*/
|
||||
OTHER_PUNCTUATION(24, "Po"),
|
||||
|
||||
/**
|
||||
* General category "Sm" in the Unicode specification.
|
||||
*/
|
||||
MATH_SYMBOL(25, "Sm"),
|
||||
|
||||
/**
|
||||
* General category "Sc" in the Unicode specification.
|
||||
*/
|
||||
CURRENCY_SYMBOL(26, "Sc"),
|
||||
|
||||
/**
|
||||
* General category "Sk" in the Unicode specification.
|
||||
*/
|
||||
MODIFIER_SYMBOL(27, "Sk"),
|
||||
|
||||
/**
|
||||
* General category "So" in the Unicode specification.
|
||||
*/
|
||||
OTHER_SYMBOL(28, "So"),
|
||||
|
||||
/**
|
||||
* General category "Pi" in the Unicode specification.
|
||||
*/
|
||||
INITIAL_QUOTE_PUNCTUATION(29, "Pi"),
|
||||
|
||||
/**
|
||||
* General category "Pf" in the Unicode specification.
|
||||
*/
|
||||
FINAL_QUOTE_PUNCTUATION(30, "Pf");
|
||||
|
||||
/**
|
||||
* Returns `true` if [char] character belongs to this category.
|
||||
*/
|
||||
public operator fun contains(char: Char): Boolean = char.getType() == this.value
|
||||
|
||||
public companion object {
|
||||
public fun valueOf(category: Int): CharCategory =
|
||||
when {
|
||||
category >=0 && category <= 16 -> values()[category]
|
||||
category >= 18 && category <= 30 -> values()[category - 1]
|
||||
else -> throw IllegalArgumentException("Category #$category is not defined.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,9 +26,6 @@ external fun toUtf8Array(string: String, start: Int, size: Int) : ByteArray
|
||||
@SymbolName("Kotlin_String_fromCharArray")
|
||||
external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
|
||||
|
||||
@SymbolName("Kotlin_String_toCharArray")
|
||||
external fun toCharArray(string: String) : CharArray
|
||||
|
||||
/**
|
||||
* Builds new string by populating newly created [StringBuilder] using provided [builderAction]
|
||||
* and then converting it to [String].
|
||||
@@ -59,7 +56,7 @@ class StringBuilder private constructor (
|
||||
|
||||
constructor(capacity: Int) : this(CharArray(capacity))
|
||||
|
||||
constructor(string: String) : this(toCharArray(string)) {
|
||||
constructor(string: String) : this(string.toCharArray()) {
|
||||
length = array.size
|
||||
}
|
||||
|
||||
@@ -217,7 +214,7 @@ class StringBuilder private constructor (
|
||||
return this
|
||||
}
|
||||
|
||||
fun insert(index: Int, string: String): StringBuilder = insert(index, toCharArray(string))
|
||||
fun insert(index: Int, string: String): StringBuilder = insert(index, string.toCharArray())
|
||||
|
||||
fun insert(index: Int, value: Boolean) = insert(index, value.toString())
|
||||
fun insert(index: Int, value: Byte) = insert(index, value.toString())
|
||||
@@ -260,7 +257,7 @@ class StringBuilder private constructor (
|
||||
return this
|
||||
}
|
||||
|
||||
fun append(it: String): StringBuilder = append(toCharArray(it))
|
||||
fun append(it: String): StringBuilder = append(it.toCharArray())
|
||||
|
||||
fun append(it: Boolean) = append(it.toString())
|
||||
fun append(it: Byte) = append(it.toString())
|
||||
|
||||
Reference in New Issue
Block a user