Skip to content

Commit bb929ac

Browse files
committed
Inline implementations in actuals
With the dedicated platform testing gone, this indirection is no longer needed. The common tests still validate behavioral conformity across all platforms.
1 parent df119f7 commit bb929ac

File tree

6 files changed

+129
-207
lines changed

6 files changed

+129
-207
lines changed
Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,77 @@
1-
@file:Suppress("NOTHING_TO_INLINE")
2-
31
package de.cketti.codepoints
42

5-
import de.cketti.codepoints.internal.charCount as commonCharCount
6-
import de.cketti.codepoints.internal.highSurrogate as commonHighSurrogate
7-
import de.cketti.codepoints.internal.isBmpCodePoint as commonIsBmpCodePoint
8-
import de.cketti.codepoints.internal.isSupplementaryCodePoint as commonIsSupplementaryCodePoint
9-
import de.cketti.codepoints.internal.isSurrogatePair as commonIsSurrogatePair
10-
import de.cketti.codepoints.internal.isValidCodePoint as commonIsValidCodePoint
11-
import de.cketti.codepoints.internal.lowSurrogate as commonLowSurrogate
12-
import de.cketti.codepoints.internal.toChars as commonToChars
13-
import de.cketti.codepoints.internal.toCodePoint as commonToCodePoint
14-
153
actual object CodePoints {
4+
private const val MIN_SUPPLEMENTARY_CODE_POINT = 0x10000
5+
private const val MAX_CODE_POINT = 0x10FFFF
6+
7+
private const val MIN_HIGH_SURROGATE = 0xD800
8+
private const val MIN_LOW_SURROGATE = 0xDC00
9+
10+
private const val SURROGATE_DECODE_OFFSET =
11+
MIN_SUPPLEMENTARY_CODE_POINT - (MIN_HIGH_SURROGATE shl 10) - MIN_LOW_SURROGATE
12+
13+
private const val HIGH_SURROGATE_ENCODE_OFFSET =
14+
(MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT ushr 10))
15+
1616
actual fun isValidCodePoint(codePoint: Int): Boolean {
17-
return commonIsValidCodePoint(codePoint)
17+
return codePoint in 0..MAX_CODE_POINT
1818
}
1919

2020
actual fun isBmpCodePoint(codePoint: Int): Boolean {
21-
return commonIsBmpCodePoint(codePoint)
21+
return codePoint ushr 16 == 0
2222
}
2323

2424
actual fun isSupplementaryCodePoint(codePoint: Int): Boolean {
25-
return commonIsSupplementaryCodePoint(codePoint)
25+
return codePoint in MIN_SUPPLEMENTARY_CODE_POINT..MAX_CODE_POINT
2626
}
2727

2828
actual fun charCount(codePoint: Int): Int {
29-
return commonCharCount(codePoint)
29+
return if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) 1 else 2
3030
}
3131

3232
actual fun isSurrogatePair(highSurrogate: Char, lowSurrogate: Char): Boolean {
33-
return commonIsSurrogatePair(highSurrogate, lowSurrogate)
33+
return highSurrogate.isHighSurrogate() && lowSurrogate.isLowSurrogate()
3434
}
3535

3636
actual fun highSurrogate(codePoint: Int): Char {
37-
return commonHighSurrogate(codePoint)
37+
return ((codePoint ushr 10) + HIGH_SURROGATE_ENCODE_OFFSET).toChar()
3838
}
3939

4040
actual fun lowSurrogate(codePoint: Int): Char {
41-
return commonLowSurrogate(codePoint)
41+
return ((codePoint and 0x3FF) + MIN_LOW_SURROGATE).toChar()
4242
}
4343

4444
actual fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
45-
return commonToCodePoint(highSurrogate, lowSurrogate)
45+
return (highSurrogate.code shl 10) + lowSurrogate.code + SURROGATE_DECODE_OFFSET
4646
}
4747

4848
actual fun toChars(codePoint: Int): CharArray {
49-
return commonToChars(codePoint)
49+
return if (isBmpCodePoint(codePoint)) {
50+
charArrayOf(codePoint.toChar())
51+
} else {
52+
charArrayOf(highSurrogate(codePoint), lowSurrogate(codePoint))
53+
}
5054
}
5155

5256
actual fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
53-
return commonToChars(codePoint, destination, offset)
57+
if (isBmpCodePoint(codePoint)) {
58+
destination.setSafe(offset, codePoint.toChar())
59+
return 1
60+
} else {
61+
// When writing the low surrogate succeeds but writing the high surrogate fails (offset = -1), the
62+
// destination will be modified even though the method throws. This feels wrong, but matches the behavior
63+
// of the Java stdlib implementation.
64+
destination.setSafe(offset + 1, lowSurrogate(codePoint))
65+
destination.setSafe(offset, highSurrogate(codePoint))
66+
return 2
67+
}
68+
}
69+
70+
private fun CharArray.setSafe(index: Int, value: Char) {
71+
if (index !in this.indices) {
72+
throw IndexOutOfBoundsException("Size: $size, offset: $index")
73+
}
74+
75+
this[index] = value
5476
}
5577
}
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
package de.cketti.codepoints
22

3+
import de.cketti.codepoints.CodePoints.highSurrogate
4+
import de.cketti.codepoints.CodePoints.isBmpCodePoint
5+
import de.cketti.codepoints.CodePoints.lowSurrogate
36
import kotlin.text.StringBuilder
4-
import de.cketti.codepoints.internal.appendCodePoint as commonAppendCodePoint
57

68
actual fun StringBuilder.appendCodePoint(codePoint: Int): StringBuilder = apply {
7-
commonAppendCodePoint(this, codePoint)
9+
if (isBmpCodePoint(codePoint)) {
10+
append(codePoint.toChar())
11+
} else {
12+
append(highSurrogate(codePoint))
13+
append(lowSurrogate(codePoint))
14+
}
815
}
Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,90 @@
1-
@file:Suppress("NOTHING_TO_INLINE")
2-
31
package de.cketti.codepoints
42

5-
import de.cketti.codepoints.internal.codePointAt as commonCodePointAt
6-
import de.cketti.codepoints.internal.codePointBefore as commonCodePointBefore
7-
import de.cketti.codepoints.internal.codePointCount as commonCodePointCount
8-
import de.cketti.codepoints.internal.offsetByCodePoints as commonOffsetByCodePoints
3+
import de.cketti.codepoints.CodePoints.toCodePoint
94

105
actual fun String.codePointAt(index: Int): Int {
11-
return commonCodePointAt(this, index)
6+
if (index !in indices) throw IndexOutOfBoundsException()
7+
8+
val firstChar = this[index]
9+
if (firstChar.isHighSurrogate() && index + 1 < length) {
10+
val nextChar = this[index + 1]
11+
if (nextChar.isLowSurrogate()) {
12+
return toCodePoint(firstChar, nextChar)
13+
}
14+
}
15+
16+
return firstChar.code
1217
}
1318

1419
actual fun String.codePointBefore(index: Int): Int {
15-
return commonCodePointBefore(this, index)
20+
val startIndex = index - 1
21+
if (startIndex !in indices) throw IndexOutOfBoundsException()
22+
23+
val firstChar = this[startIndex]
24+
if (firstChar.isLowSurrogate() && startIndex - 1 >= 0) {
25+
val previousChar = this[startIndex - 1]
26+
if (previousChar.isHighSurrogate()) {
27+
return toCodePoint(previousChar, firstChar)
28+
}
29+
}
30+
31+
return firstChar.code
1632
}
1733

1834
actual fun String.codePointCount(beginIndex: Int, endIndex: Int): Int {
19-
return commonCodePointCount(this, beginIndex, endIndex)
35+
if (beginIndex < 0 || endIndex > length || beginIndex > endIndex) throw IndexOutOfBoundsException()
36+
37+
var index = beginIndex
38+
var count = 0
39+
do {
40+
val firstChar = this[index]
41+
index++
42+
if (firstChar.isHighSurrogate() && index < endIndex) {
43+
val nextChar = this[index]
44+
if (nextChar.isLowSurrogate()) {
45+
index++
46+
}
47+
}
48+
49+
count++
50+
} while (index < endIndex)
51+
52+
return count
2053
}
2154

2255
actual fun String.offsetByCodePoints(index: Int, codePointOffset: Int): Int {
23-
return commonOffsetByCodePoints(this, index, codePointOffset)
56+
if (index !in 0..length) throw IndexOutOfBoundsException()
57+
if (codePointOffset == 0) return index
58+
59+
if (codePointOffset > 0) {
60+
var currentIndex = index
61+
repeat(codePointOffset) {
62+
if (currentIndex > lastIndex) throw IndexOutOfBoundsException()
63+
val firstChar = this[currentIndex]
64+
currentIndex++
65+
if (firstChar.isHighSurrogate() && currentIndex <= lastIndex) {
66+
val nextChar = this[currentIndex]
67+
if (nextChar.isLowSurrogate()) {
68+
currentIndex++
69+
}
70+
}
71+
}
72+
73+
return currentIndex
74+
} else {
75+
var currentIndex = index - 1
76+
repeat(-codePointOffset) {
77+
if (currentIndex < 0) throw IndexOutOfBoundsException()
78+
val firstChar = this[currentIndex]
79+
currentIndex--
80+
if (firstChar.isLowSurrogate() && currentIndex >= 0) {
81+
val previousChar = this[currentIndex]
82+
if (previousChar.isHighSurrogate()) {
83+
currentIndex--
84+
}
85+
}
86+
}
87+
88+
return currentIndex + 1
89+
}
2490
}

src/commonImplementation/kotlin/internal/CommonCodePoints.kt

Lines changed: 0 additions & 75 deletions
This file was deleted.

src/commonImplementation/kotlin/internal/CommonStringBuilderFunctions.kt

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/commonImplementation/kotlin/internal/CommonStringFunctions.kt

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)