[K/N] Experimental Char code point constants and functions

Internalize WASM Char code point functions.

As a part of efforts to stabilize Native stdlib.
This commit is contained in:
Abduqodiri Qurbonzoda
2023-04-19 15:19:11 +03:00
committed by Space Team
parent c6eaadb44f
commit b25f3be81b
18 changed files with 153 additions and 49 deletions
@@ -234,7 +234,7 @@ internal actual fun checkRadix(radix: Int): Int {
// 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) {
if (codePoint <= MAX_VALUE.code) {
@Suppress("DEPRECATION")
codePoint.toChar().lowercaseChar().toInt()
} else {
@@ -243,40 +243,9 @@ internal fun Char.Companion.toLowerCase(codePoint: Int): Int =
/** Converts a unicode code point to upper case. */
internal fun Char.Companion.toUpperCase(codePoint: Int): Int =
if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) {
if (codePoint <= MAX_VALUE.code) {
@Suppress("DEPRECATION")
codePoint.toChar().uppercaseChar().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. */
// TODO: Consider removing from public API
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. */
// TODO: Consider removing from public API
public fun Char.Companion.isSupplementaryCodePoint(codepoint: Int): Boolean =
codepoint in MIN_SUPPLEMENTARY_CODE_POINT..MAX_CODE_POINT
// TODO: Consider removing from public API
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].
*/
// TODO: Consider removing from public API
@Suppress("DEPRECATION")
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()
}
@@ -23,6 +23,7 @@
@file:Suppress("DEPRECATION") // Char.toInt()
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
import kotlin.collections.associate
import kotlin.native.concurrent.AtomicReference
import kotlin.native.concurrent.freeze
@@ -373,6 +374,8 @@ internal abstract class AbstractCharClass : SpecialToken() {
init {
initValues()
}
@OptIn(ExperimentalNativeApi::class)
override fun computeValue(): AbstractCharClass =
object: AbstractCharClass() {
override fun contains(ch: Int): Boolean = alt xor (ch in start..end)
@@ -22,6 +22,7 @@
@file:Suppress("DEPRECATION") // Char.toInt()
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
import kotlin.native.BitSet
import kotlin.native.ObsoleteNativeApi
@@ -72,6 +73,7 @@ internal class CharClass(val ignoreCase: Boolean = false, negative: Boolean = fa
* We can use this method safely even if nonBitSet != null
* due to specific of range constructions in regular expressions.
*/
@OptIn(ExperimentalNativeApi::class)
fun add(ch: Int): CharClass {
var character = ch
if (ignoreCase) {
@@ -215,6 +217,7 @@ internal class CharClass(val ignoreCase: Boolean = false, negative: Boolean = fa
return this
}
@OptIn(ExperimentalNativeApi::class)
fun add(start: Int, end: Int): CharClass {
if (start > end)
throw IllegalArgumentException("Incorrect range of symbols (start > end)")
@@ -499,7 +502,7 @@ internal class CharClass(val ignoreCase: Boolean = false, negative: Boolean = fa
}
}
@OptIn(ExperimentalStdlibApi::class)
@OptIn(ExperimentalNativeApi::class)
override val instance: AbstractCharClass
get() {
@@ -533,7 +536,7 @@ internal class CharClass(val ignoreCase: Boolean = false, negative: Boolean = fa
}
}
@OptIn(ExperimentalStdlibApi::class)
@OptIn(ExperimentalNativeApi::class)
//for debugging purposes only
override fun toString(): String {
val temp = StringBuilder()
@@ -234,6 +234,7 @@ internal class Lexer(val patternString: String, flags: Int) {
/**
* Returns the next code point in the pattern string.
*/
@OptIn(ExperimentalNativeApi::class)
private fun nextCodePoint(): Int {
val high = pattern[nextIndex()] // nextIndex skips comments and whitespaces if comments flag is on.
if (high.isHighSurrogate()) {
@@ -789,6 +790,7 @@ internal class Lexer(val patternString: String, flags: Int) {
return ch >= 0
}
@OptIn(ExperimentalNativeApi::class)
private fun String.codePointAt(index: Int): Int {
val high = this[index]
if (high.isHighSurrogate() && index + 1 < this.length) {
@@ -841,6 +843,7 @@ internal class Lexer(val patternString: String, flags: Int) {
/**
* Normalize given string.
*/
@OptIn(ExperimentalNativeApi::class)
fun normalize(input: String): String {
val inputChars = input.toCharArray()
val inputLength = inputChars.size
@@ -23,6 +23,8 @@
@file:Suppress("DEPRECATION") // Char.toInt()
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
/** Represents a compiled pattern used by [Regex] for matching, searching, or replacing strings. */
internal class Pattern(val pattern: String, flags: Int = 0) {
@@ -194,6 +196,7 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
/**
* T->aaa
*/
@OptIn(ExperimentalNativeApi::class)
private fun processSequence(): AbstractSet {
val substring = StringBuilder()
while (!lexemes.isEmpty()
@@ -787,6 +790,7 @@ internal class Pattern(val pattern: String, flags: Int = 0) {
return RangeSet(charClass, hasFlag(CASE_INSENSITIVE))
}
@OptIn(ExperimentalNativeApi::class)
private fun processCharSet(ch: Int): AbstractSet {
val isSupplCodePoint = Char.isSupplementaryCodePoint(ch)
@@ -22,6 +22,8 @@
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
/** Represents canonical decomposition of Unicode character. Is used when CANON_EQ flag of Pattern class is specified. */
open internal class DecomposedCharSet(
/** Decomposition of the Unicode codepoint */
@@ -34,6 +36,7 @@ open internal class DecomposedCharSet(
private var readCharsForCodePoint = 1
/** UTF-16 encoding of decomposedChar */
@OptIn(ExperimentalNativeApi::class)
private val decomposedCharUTF16: String by lazy {
val strBuff = StringBuilder()
@@ -122,6 +125,7 @@ open internal class DecomposedCharSet(
get() = "decomposed char: $decomposedChar"
/** Reads Unicode codepoint from [testString] starting from [strIndex] until [rightBound]. */
@OptIn(ExperimentalNativeApi::class)
fun codePointAt(strIndex: Int, testString: CharSequence, rightBound: Int): Int {
var index = strIndex
@@ -22,6 +22,8 @@
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
/**
* Node accepting any character except line terminators.
*/
@@ -34,6 +36,7 @@ internal class DotSet(val lt: AbstractLineTerminator, val matchLineTerminator: B
override val consumesFixedLength: Boolean
get() = true
@OptIn(ExperimentalNativeApi::class)
override fun matches(startIndex: Int, testString: CharSequence, matchResult: MatchResultImpl): Int {
val rightBound = testString.length
if (startIndex >= rightBound) {
@@ -22,6 +22,8 @@
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
/**
* This class represents nodes constructed with character sequences. For
* example, lets consider regular expression: ".*word.*". During regular
@@ -89,6 +91,7 @@ open internal class SequenceSet(substring: CharSequence, val ignoreCase: Boolean
return -1
}
@OptIn(ExperimentalNativeApi::class)
override fun first(set: AbstractSet): Boolean {
if (ignoreCase) {
return super.first(set)
@@ -87,6 +87,8 @@
package kotlin.text.regex
import kotlin.experimental.ExperimentalNativeApi
/**
* Represents node accepting single character from the given char class.
* This character can be supplementary (2 chars needed to represent) or from
@@ -118,6 +120,7 @@ open internal class SupplementaryRangeSet(charClass: AbstractCharClass, val igno
if (index < rightBound) {
val low = testString[index++]
@OptIn(ExperimentalNativeApi::class)
if (Char.isSurrogatePair(high, low) && contains(Char.toCodePoint(high, low))) {
return next.matches(index, testString, matchResult)
}