refactoring [fleet, codepoints]: get rid of the external library for handling unicode surrogates

GitOrigin-RevId: d937ebff4de4b43ce4c8904acdca5d2bbc5b2370
This commit is contained in:
Alexander Zolotov
2025-11-14 20:37:35 +00:00
committed by intellij-monorepo-bot
parent abc33e8fe5
commit ca057d0754
15 changed files with 206 additions and 100 deletions
@@ -1,18 +0,0 @@
<component name="libraryTable">
<library name="de.cketti.unicode.kotlin.codepoints.jvm" type="repository">
<properties include-transitive-deps="false" maven-id="de.cketti.unicode:kotlin-codepoints-jvm:0.9.0">
<verification>
<artifact url="file://$MAVEN_REPOSITORY$/de/cketti/unicode/kotlin-codepoints-jvm/0.9.0/kotlin-codepoints-jvm-0.9.0.jar">
<sha256sum>d642f145f6123739e779d4156145cc5fe7c2173bb58d437b813961a31c337ff9</sha256sum>
</artifact>
</verification>
</properties>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/de/cketti/unicode/kotlin-codepoints-jvm/0.9.0/kotlin-codepoints-jvm-0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/de/cketti/unicode/kotlin-codepoints-jvm/0.9.0/kotlin-codepoints-jvm-0.9.0-sources.jar!/" />
</SOURCES>
</library>
</component>
+8 -3
View File
@@ -1,6 +1,6 @@
### auto-generated section `build fleet.util.codepoints` start
load("//build:compiler-options.bzl", "create_kotlinc_options")
load("@rules_jvm//:jvm.bzl", "jvm_library", "resourcegroup")
load("@rules_jvm//:jvm.bzl", "jvm_library", "jvm_provided_library", "resourcegroup")
create_kotlinc_options(
name = "custom_codepoints",
@@ -15,17 +15,22 @@ resourcegroup(
strip_prefix = "resources"
)
jvm_provided_library(
name = "fleet_util_multiplatform_provided",
lib = "//fleet/util/multiplatform"
)
jvm_library(
name = "codepoints",
module_name = "fleet.util.codepoints",
visibility = ["//visibility:public"],
srcs = glob(["srcCommonMain/**/*.kt", "srcCommonMain/**/*.java", "srcCommonMain/**/*.form"], allow_empty = True, exclude = ["**/module-info.java"]),
srcs = glob(["srcCommonMain/**/*.kt", "srcCommonMain/**/*.java", "srcCommonMain/**/*.form", "srcJvmMain/**/*.kt", "srcJvmMain/**/*.java", "srcJvmMain/**/*.form"], allow_empty = True, exclude = ["**/module-info.java"]),
resources = [":codepoints_resources"],
kotlinc_opts = ":custom_codepoints",
deps = [
"@lib//:kotlin-stdlib",
"//fleet/util/core",
"@lib//:de-cketti-unicode-kotlin-codepoints-jvm",
":fleet_util_multiplatform_provided",
]
)
### auto-generated section `build fleet.util.codepoints` end
@@ -12,6 +12,11 @@
<stringArg name="apiVersion" arg="2.2" />
<stringArg name="languageVersion" arg="2.2" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>$MAVEN_REPOSITORY$/jetbrains/fleet/expects-compiler-plugin/2.2.21-RC2-0.1/expects-compiler-plugin-2.2.21-RC2-0.1.jar</args>
</arrayArg>
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
@@ -21,11 +26,12 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/srcCommonMain" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/srcJvmMain" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="module" module-name="fleet.util.core" />
<orderEntry type="library" name="de.cketti.unicode.kotlin.codepoints.jvm" level="project" />
<orderEntry type="module" module-name="fleet.util.multiplatform" scope="PROVIDED" />
</component>
</module>
@@ -12,6 +12,7 @@ plugins {
alias(libs.plugins.dokka)
// GRADLE_PLUGINS__MARKER_START
id("fleet-module")
alias(jps.plugins.expects)
// GRADLE_PLUGINS__MARKER_END
}
@@ -57,10 +58,13 @@ kotlin {
implementation(jps.org.jetbrains.kotlin.kotlin.stdlib1993400674.get().let { "${it.group}:${it.name}:${it.version}" }) {
exclude(group = "org.jetbrains", module = "annotations")
}
implementation(jps.de.cketti.unicode.kotlin.codepoints.jvm1960123061.get().let { "${it.group}:kotlin-codepoints:${it.version}" }) {
isTransitive = false
}
implementation(project(":fleet.util.core"))
}
sourceSets.jvmMain.dependencies {
compileOnly(project(":fleet.util.multiplatform"))
}
sourceSets.wasmJsMain.dependencies {
implementation(project(":fleet.util.multiplatform"))
}
// KOTLIN__MARKER_END
}
+1 -4
View File
@@ -1,6 +1,3 @@
- name: dist.all/lib/fleet.util.codepoints.jar
modules:
- name: fleet.util.codepoints
library: de.cketti.unicode.kotlin.codepoints.jvm
files:
- name: $MAVEN_REPOSITORY$/de/cketti/unicode/kotlin-codepoints-jvm/0/kotlin-codepoints-jvm-0.jar
- name: fleet.util.codepoints
@@ -0,0 +1,12 @@
package fleet.codepoints
fun <T : Appendable> T.appendCodePoint(codepoint: Codepoint): T {
if (codepoint.isBmpCodePoint()) {
append(codepoint.codepoint.toChar())
}
else {
append(highSurrogatePlatformSpecific(codepoint.codepoint))
append(lowSurrogatePlatformSpecific(codepoint.codepoint))
}
return this
}
@@ -0,0 +1,73 @@
package fleet.codepoints
fun CharSequence.codePointAt(index: Int): Codepoint {
if (index !in indices) throw IndexOutOfBoundsException("Index out of range: $index, size: $length")
val firstChar = this[index]
if (firstChar.isHighSurrogate() && index + 1 < length) {
val secondChar = this[index + 1]
if (secondChar.isLowSurrogate()) {
return Codepoint.fromChars(firstChar, secondChar)
}
}
return Codepoint(firstChar.code)
}
fun CharSequence.codePointBefore(index: Int): Codepoint {
val startIndex = index - 1
if (startIndex < 0 || index !in indices) throw IndexOutOfBoundsException("Index out of range: $index, size: $length")
val secondChar = this[startIndex]
if (secondChar.isLowSurrogate() && startIndex - 1 >= 0) {
val firstChar = this[startIndex - 1]
if (firstChar.isHighSurrogate()) {
return Codepoint.fromChars(firstChar, secondChar)
}
}
return Codepoint(secondChar.code)
}
fun CharSequence.codepoints(offset: Int, direction: Direction = Direction.FORWARD): Iterator<Codepoint> =
when (direction) {
Direction.FORWARD -> iterator {
var i = offset
val len = length
while (i < len) {
val c1 = get(i++)
if (c1.isHighSurrogate()) {
if (i < len) {
val c2 = get(i++)
if (c2.isLowSurrogate()) {
yield(Codepoint.fromChars(c1, c2))
}
}
}
else {
yield(Codepoint(c1.code))
}
}
}
Direction.BACKWARD -> iterator {
var i = offset - 1
while (i >= 0) {
val c2 = get(i--)
if (c2.isLowSurrogate()) {
if (i >= 0) {
val c1 = get(i--)
if (c1.isHighSurrogate()) {
yield(Codepoint.fromChars(c1, c2))
}
}
}
else {
yield(Codepoint(c2.code))
}
}
}
}
enum class Direction {
FORWARD,
BACKWARD,
}
@@ -1,14 +1,19 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package fleet.codepoints
import de.cketti.codepoints.CodePoints
import kotlin.jvm.JvmInline
@JvmInline
value class Codepoint(val codepoint: Int) {
val charCount: Int get() = CodePoints.charCount(codepoint)
val charCount: Int
get() = if (codepoint < MIN_SUPPLEMENTARY_CODE_POINT) 1 else 2
fun asString(): String = toString(codepoint)
internal fun isBmpCodePoint(): Boolean = codepoint ushr 16 == 0
companion object {
fun fromChars(highSurrogate: Char, lowSurrogate: Char ): Codepoint = codepointOfPlatformSpecific(highSurrogate, lowSurrogate)
fun isUnicodeIdentifierStart(codepoint: Int): Boolean = isCodepointInRanges(codepoint, unicodeIdStartRanges)
fun isUnicodeIdentifierPart(codepoint: Int): Boolean = isCodepointInRanges(codepoint, unicodeIdContinueRanges)
fun isIdentifierIgnorable(codepoint: Int): Boolean = isCodepointInRanges(codepoint, identifierIgnorableRanges)
@@ -39,51 +44,7 @@ value class Codepoint(val codepoint: Int) {
}
fun toString(codepoint: Int): String {
return CodePoints.toString(codepoint)
return codePointsToStringPlatformSpecific(codepoint)
}
}
}
fun CharSequence.codepoints(offset: Int, direction: Direction = Direction.FORWARD): Iterator<Codepoint> =
when (direction) {
Direction.FORWARD -> iterator {
var i = offset
val len = length
while (i < len) {
val c1 = get(i++)
if (c1.isHighSurrogate()) {
if (i < len) {
val c2 = get(i++)
if (c2.isLowSurrogate()) {
yield(Codepoint(CodePoints.toCodePoint(c1, c2)))
}
}
}
else {
yield(Codepoint(c1.code))
}
}
}
Direction.BACKWARD -> iterator {
var i = offset - 1
while (i >= 0) {
val c2 = get(i--)
if (c2.isLowSurrogate()) {
if (i >= 0) {
val c1 = get(i--)
if (c1.isHighSurrogate()) {
yield(Codepoint(CodePoints.toCodePoint(c1, c2)))
}
}
}
else {
yield(Codepoint(c2.code))
}
}
}
}
enum class Direction {
FORWARD,
BACKWARD,
}
@@ -0,0 +1,37 @@
package fleet.codepoints
import fleet.util.multiplatform.linkToActual
internal const val MIN_SUPPLEMENTARY_CODE_POINT = 0x10000
private const val MIN_HIGH_SURROGATE = 0xD800
private const val MIN_LOW_SURROGATE = 0xDC00
private const val SURROGATE_DECODE_OFFSET = MIN_SUPPLEMENTARY_CODE_POINT - (MIN_HIGH_SURROGATE shl 10) - MIN_LOW_SURROGATE
private const val HIGH_SURROGATE_ENCODE_OFFSET = (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT ushr 10))
internal fun codePointsToStringPlatformSpecific(vararg codepoints: Int): String = linkToActual()
internal fun codePointsToStringMultiplatform(vararg codepoints: Int): String {
return buildString(capacity = codepoints.size * 2) {
for (codePoint in codepoints) {
appendCodePoint(Codepoint(codePoint))
}
}
}
internal fun codepointOfPlatformSpecific(highSurrogate: Char, lowSurrogate: Char): Codepoint = linkToActual()
internal fun codepointOfMultiplatform(highSurrogate: Char, lowSurrogate: Char): Codepoint {
return Codepoint((highSurrogate.code shl 10) + lowSurrogate.code + SURROGATE_DECODE_OFFSET)
}
internal fun highSurrogatePlatformSpecific(codepoint: Int): Char = linkToActual()
internal fun highSurrogateMultiplatform(codepoint: Int): Char {
return ((codepoint ushr 10) + HIGH_SURROGATE_ENCODE_OFFSET).toChar()
}
internal fun lowSurrogatePlatformSpecific(codepoint: Int): Char = linkToActual()
internal fun lowSurrogateMultiplatform(codepoint: Int): Char {
return ((codepoint and 0x3FF) + MIN_LOW_SURROGATE).toChar()
}
@@ -0,0 +1,19 @@
package fleet.codepoints
import fleet.util.multiplatform.Actual
@Actual
internal fun codePointsToStringPlatformSpecificJvm(vararg codepoints: Int): String {
return String(codepoints, 0, codepoints.size)
}
@Actual
internal fun codepointOfPlatformSpecificJvm(highSurrogate: Char, lowSurrogate: Char): Codepoint {
return Codepoint(Character.toCodePoint(highSurrogate, lowSurrogate))
}
@Actual
internal fun highSurrogatePlatformSpecificJvm(codepoint: Int): Char = Character.highSurrogate(codepoint)
@Actual
internal fun lowSurrogatePlatformSpecificJvm(codepoint: Int): Char = Character.lowSurrogate(codepoint)
@@ -0,0 +1,17 @@
package fleet.codepoints
@fleet.util.multiplatform.Actual
internal fun codePointsToStringPlatformSpecificNative(vararg codepoints: Int): String {
return codePointsToStringMultiplatform(*codepoints)
}
@fleet.util.multiplatform.Actual
internal fun codepointOfPlatformSpecificNative(highSurrogate: Char, lowSurrogate: Char): Codepoint {
return codepointOfMultiplatform(highSurrogate, lowSurrogate)
}
@fleet.util.multiplatform.Actual
internal fun highSurrogatePlatformSpecificNative(codepoint: Int): Char = highSurrogateMultiplatform(codepoint)
@fleet.util.multiplatform.Actual
internal fun lowSurrogatePlatformSpecificNative(codepoint: Int): Char = lowSurrogateMultiplatform(codepoint
@@ -0,0 +1,17 @@
package fleet.codepoints
@fleet.util.multiplatform.Actual
internal fun codePointsToStringPlatformSpecificWasmJs(vararg codepoints: Int): String {
return codePointsToStringMultiplatform(*codepoints)
}
@fleet.util.multiplatform.Actual
internal fun codepointOfPlatformSpecificWasmJs(highSurrogate: Char, lowSurrogate: Char): Codepoint {
return codepointOfMultiplatform(highSurrogate, lowSurrogate)
}
@fleet.util.multiplatform.Actual
internal fun highSurrogatePlatformSpecificWasmJs(codepoint: Int): Char = highSurrogateMultiplatform(codepoint)
@fleet.util.multiplatform.Actual
internal fun lowSurrogatePlatformSpecificWasmJs(codepoint: Int): Char = lowSurrogateMultiplatform(codepoint)
-7
View File
@@ -1074,13 +1074,6 @@ jvm_import(
visibility = ["//visibility:public"]
)
jvm_import(
name = "de-cketti-unicode-kotlin-codepoints-jvm",
jar = "@de_cketti_unicode-kotlin-codepoints-jvm-0_9_0_http//file",
source_jar = "@de_cketti_unicode-kotlin-codepoints-jvm-0_9_0-sources_http//file",
visibility = ["//visibility:public"]
)
jvm_import(
name = "download-pgp-verifier",
jar = "@com_jetbrains_infra-download-pgp-verifier-1_1_4_http//file",
-14
View File
@@ -1322,20 +1322,6 @@ http_file(
downloaded_file_path = "cucumber-jvm-deps-1.0.5-sources.jar"
)
http_file(
name = "de_cketti_unicode-kotlin-codepoints-jvm-0_9_0_http",
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/de/cketti/unicode/kotlin-codepoints-jvm/0.9.0/kotlin-codepoints-jvm-0.9.0.jar",
sha256 = "d642f145f6123739e779d4156145cc5fe7c2173bb58d437b813961a31c337ff9",
downloaded_file_path = "kotlin-codepoints-jvm-0.9.0.jar"
)
http_file(
name = "de_cketti_unicode-kotlin-codepoints-jvm-0_9_0-sources_http",
url = "https://cache-redirector.jetbrains.com/repo1.maven.org/maven2/de/cketti/unicode/kotlin-codepoints-jvm/0.9.0/kotlin-codepoints-jvm-0.9.0-sources.jar",
sha256 = "713ed1a4bf439eda3a304bce8a713380fc60221dbd34c49bcda0999f4cdf6937",
downloaded_file_path = "kotlin-codepoints-jvm-0.9.0-sources.jar"
)
http_file(
name = "com_jetbrains_infra-download-pgp-verifier-1_1_4_http",
url = "https://cache-redirector.jetbrains.com/packages.jetbrains.team/maven/p/ij/intellij-dependencies/com/jetbrains/infra/download-pgp-verifier/1.1.4/download-pgp-verifier-1.1.4.jar",
@@ -792,9 +792,6 @@ object CommunityLibraryLicenses {
.apache("https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt")
.suppliedByOrganizations(Suppliers.JETBRAINS),
LibraryLicense("kotlin-codepoints", libraryName = "de.cketti.unicode.kotlin.codepoints.jvm", url = "https://github.com/cketti/kotlin-codepoints")
.mit("https://github.com/cketti/kotlin-codepoints/blob/main/LICENSE"),
LibraryLicense("kotlin-metadata", libraryName = "kotlin-metadata", url = "https://github.com/JetBrains/kotlin")
.apache("https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt")
.suppliedByOrganizations(Suppliers.JETBRAINS),