Skip to content

Commit adbc5d9

Browse files
authored
Merge pull request #12 from JakeWharton/jw.to-chars.2023-01-23
Add `CodePoints.toChars` functions
2 parents de0ed20 + f780240 commit adbc5d9

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-0
lines changed

src/commonImplementation/kotlin/CodePoints.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,12 @@ actual object CodePoints {
4646
actual inline fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
4747
return CommonCodePoints.toCodePoint(highSurrogate, lowSurrogate)
4848
}
49+
50+
actual inline fun toChars(codePoint: Int): CharArray {
51+
return CommonCodePoints.toChars(codePoint)
52+
}
53+
54+
actual inline fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
55+
return CommonCodePoints.toChars(codePoint, destination, offset)
56+
}
4957
}

src/commonImplementation/kotlin/CommonCodePoints.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,29 @@ object CommonCodePoints {
5858
fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
5959
return (highSurrogate.code shl 10) + lowSurrogate.code + SURROGATE_DECODE_OFFSET
6060
}
61+
62+
fun toChars(codePoint: Int): CharArray {
63+
return if (isBmpCodePoint(codePoint)) {
64+
charArrayOf(codePoint.toChar())
65+
} else {
66+
charArrayOf(highSurrogate(codePoint), lowSurrogate(codePoint))
67+
}
68+
}
69+
70+
fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
71+
val size = destination.size
72+
if (offset >= 0) {
73+
if (isBmpCodePoint(codePoint)) {
74+
if (offset < size) {
75+
destination[offset] = codePoint.toChar()
76+
return 1
77+
}
78+
} else if (offset < size - 1) {
79+
destination[offset] = highSurrogate(codePoint)
80+
destination[offset + 1] = lowSurrogate(codePoint)
81+
return 2
82+
}
83+
}
84+
throw IndexOutOfBoundsException("Size: $size, offset: $offset")
85+
}
6186
}

src/commonMain/kotlin/CodePoints.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,20 @@ expect object CodePoints {
101101
* if necessary.
102102
*/
103103
fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int
104+
105+
/**
106+
* Converts the specified character (Unicode code point) to its UTF-16 representation stored in a char array.
107+
* If the specified code point is a BMP (Basic Multilingual Plane or Plane 0) value, the resulting char array has
108+
* the same value as [codePoint]. If the specified code point is a supplementary code point, the resulting char
109+
* array has the corresponding surrogate pair.
110+
*/
111+
fun toChars(codePoint: Int): CharArray
112+
113+
/**
114+
* Converts the specified character (Unicode code point) to its UTF-16 representation. If the specified code point
115+
* is a BMP (Basic Multilingual Plane or Plane 0) value, the same value is stored in `destination[offset]`,
116+
* and 1 is returned. If the specified code point is a supplementary character, its surrogate values are stored in
117+
* `destination[offset]` (high-surrogate) and `destination[offset+1]` (low-surrogate), and 2 is returned.
118+
*/
119+
fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int
104120
}

src/commonTest/kotlin/CodePointsTest.kt

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package de.cketti.codepoints
22

33
import kotlin.test.Test
4+
import kotlin.test.assertContentEquals
45
import kotlin.test.assertEquals
6+
import kotlin.test.assertFailsWith
57
import kotlin.test.assertFalse
68
import kotlin.test.assertTrue
79

@@ -120,4 +122,75 @@ class CodePointsTest {
120122
fun toCodePoint() {
121123
assertEquals(0x1F995, CodePoints.toCodePoint('\uD83E', '\uDD95'))
122124
}
125+
126+
@Test
127+
fun toChars() {
128+
assertContentEquals(charArrayOf('a'), CodePoints.toChars('a'.code))
129+
assertContentEquals(charArrayOf('\uFFFF'), CodePoints.toChars(0xFFFF))
130+
assertContentEquals(charArrayOf('\uD83E', '\uDD95'), CodePoints.toChars("\uD83E\uDD95".codePointAt(0)))
131+
}
132+
133+
@Test
134+
fun toCharsDestination() {
135+
val chars = charArrayOf('z', 'z', 'z')
136+
137+
CodePoints.toChars('a'.code, chars, 0)
138+
assertContentEquals(charArrayOf('a', 'z', 'z'), chars)
139+
140+
CodePoints.toChars('a'.code, chars, 2)
141+
assertContentEquals(charArrayOf('a', 'z', 'a'), chars)
142+
143+
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 0)
144+
assertContentEquals(charArrayOf('\uD83E', '\uDD95', 'a'), chars)
145+
146+
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 1)
147+
assertContentEquals(charArrayOf('\uD83E', '\uD83E', '\uDD95'), chars)
148+
}
149+
150+
@Test
151+
fun toCharsDestinationTooSmall() {
152+
val chars = charArrayOf()
153+
154+
assertFailsWith<IndexOutOfBoundsException> {
155+
CodePoints.toChars('a'.code, chars, 0)
156+
}
157+
assertFailsWith<IndexOutOfBoundsException> {
158+
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 0)
159+
}
160+
}
161+
162+
@Test
163+
fun toCharsDestinationOffsetInvalid() {
164+
val chars = charArrayOf('z', 'z')
165+
166+
assertFailsWith<IndexOutOfBoundsException> {
167+
CodePoints.toChars('a'.code, chars, 2)
168+
}
169+
assertContentEquals(charArrayOf('z', 'z'), chars)
170+
171+
assertFailsWith<IndexOutOfBoundsException> {
172+
CodePoints.toChars('a'.code, chars, -1)
173+
}
174+
assertContentEquals(charArrayOf('z', 'z'), chars)
175+
176+
assertFailsWith<IndexOutOfBoundsException> {
177+
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 2)
178+
}
179+
assertContentEquals(charArrayOf('z', 'z'), chars)
180+
181+
assertFailsWith<IndexOutOfBoundsException> {
182+
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, -1)
183+
}
184+
assertContentEquals(charArrayOf('z', 'z'), chars)
185+
}
186+
187+
@Test
188+
fun toCharsDestinationOffsetTooSmall() {
189+
val chars = charArrayOf('z', 'z')
190+
191+
assertFailsWith<IndexOutOfBoundsException> {
192+
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 1)
193+
}
194+
assertContentEquals(charArrayOf('z', 'z'), chars)
195+
}
123196
}

src/jvmMain/kotlin/CodePoints.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,12 @@ actual object CodePoints {
4646
actual inline fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
4747
return Character.toCodePoint(highSurrogate, lowSurrogate)
4848
}
49+
50+
actual inline fun toChars(codePoint: Int): CharArray {
51+
return Character.toChars(codePoint)
52+
}
53+
54+
actual inline fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
55+
return Character.toChars(codePoint, destination, offset)
56+
}
4957
}

0 commit comments

Comments
 (0)