Skip to content

Commit

Permalink
Merge pull request #12 from JakeWharton/jw.to-chars.2023-01-23
Browse files Browse the repository at this point in the history
Add `CodePoints.toChars` functions
  • Loading branch information
cketti authored Jan 23, 2023
2 parents de0ed20 + f780240 commit adbc5d9
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/commonImplementation/kotlin/CodePoints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,12 @@ actual object CodePoints {
actual inline fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
return CommonCodePoints.toCodePoint(highSurrogate, lowSurrogate)
}

actual inline fun toChars(codePoint: Int): CharArray {
return CommonCodePoints.toChars(codePoint)
}

actual inline fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
return CommonCodePoints.toChars(codePoint, destination, offset)
}
}
25 changes: 25 additions & 0 deletions src/commonImplementation/kotlin/CommonCodePoints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,29 @@ object CommonCodePoints {
fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
return (highSurrogate.code shl 10) + lowSurrogate.code + SURROGATE_DECODE_OFFSET
}

fun toChars(codePoint: Int): CharArray {
return if (isBmpCodePoint(codePoint)) {
charArrayOf(codePoint.toChar())
} else {
charArrayOf(highSurrogate(codePoint), lowSurrogate(codePoint))
}
}

fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
val size = destination.size
if (offset >= 0) {
if (isBmpCodePoint(codePoint)) {
if (offset < size) {
destination[offset] = codePoint.toChar()
return 1
}
} else if (offset < size - 1) {
destination[offset] = highSurrogate(codePoint)
destination[offset + 1] = lowSurrogate(codePoint)
return 2
}
}
throw IndexOutOfBoundsException("Size: $size, offset: $offset")
}
}
16 changes: 16 additions & 0 deletions src/commonMain/kotlin/CodePoints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,20 @@ expect object CodePoints {
* if necessary.
*/
fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int

/**
* Converts the specified character (Unicode code point) to its UTF-16 representation stored in a char array.
* If the specified code point is a BMP (Basic Multilingual Plane or Plane 0) value, the resulting char array has
* the same value as [codePoint]. If the specified code point is a supplementary code point, the resulting char
* array has the corresponding surrogate pair.
*/
fun toChars(codePoint: Int): CharArray

/**
* Converts the specified character (Unicode code point) to its UTF-16 representation. If the specified code point
* is a BMP (Basic Multilingual Plane or Plane 0) value, the same value is stored in `destination[offset]`,
* and 1 is returned. If the specified code point is a supplementary character, its surrogate values are stored in
* `destination[offset]` (high-surrogate) and `destination[offset+1]` (low-surrogate), and 2 is returned.
*/
fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int
}
73 changes: 73 additions & 0 deletions src/commonTest/kotlin/CodePointsTest.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package de.cketti.codepoints

import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue

Expand Down Expand Up @@ -120,4 +122,75 @@ class CodePointsTest {
fun toCodePoint() {
assertEquals(0x1F995, CodePoints.toCodePoint('\uD83E', '\uDD95'))
}

@Test
fun toChars() {
assertContentEquals(charArrayOf('a'), CodePoints.toChars('a'.code))
assertContentEquals(charArrayOf('\uFFFF'), CodePoints.toChars(0xFFFF))
assertContentEquals(charArrayOf('\uD83E', '\uDD95'), CodePoints.toChars("\uD83E\uDD95".codePointAt(0)))
}

@Test
fun toCharsDestination() {
val chars = charArrayOf('z', 'z', 'z')

CodePoints.toChars('a'.code, chars, 0)
assertContentEquals(charArrayOf('a', 'z', 'z'), chars)

CodePoints.toChars('a'.code, chars, 2)
assertContentEquals(charArrayOf('a', 'z', 'a'), chars)

CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 0)
assertContentEquals(charArrayOf('\uD83E', '\uDD95', 'a'), chars)

CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 1)
assertContentEquals(charArrayOf('\uD83E', '\uD83E', '\uDD95'), chars)
}

@Test
fun toCharsDestinationTooSmall() {
val chars = charArrayOf()

assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars('a'.code, chars, 0)
}
assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 0)
}
}

@Test
fun toCharsDestinationOffsetInvalid() {
val chars = charArrayOf('z', 'z')

assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars('a'.code, chars, 2)
}
assertContentEquals(charArrayOf('z', 'z'), chars)

assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars('a'.code, chars, -1)
}
assertContentEquals(charArrayOf('z', 'z'), chars)

assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 2)
}
assertContentEquals(charArrayOf('z', 'z'), chars)

assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, -1)
}
assertContentEquals(charArrayOf('z', 'z'), chars)
}

@Test
fun toCharsDestinationOffsetTooSmall() {
val chars = charArrayOf('z', 'z')

assertFailsWith<IndexOutOfBoundsException> {
CodePoints.toChars("\uD83E\uDD95".codePointAt(0), chars, 1)
}
assertContentEquals(charArrayOf('z', 'z'), chars)
}
}
8 changes: 8 additions & 0 deletions src/jvmMain/kotlin/CodePoints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,12 @@ actual object CodePoints {
actual inline fun toCodePoint(highSurrogate: Char, lowSurrogate: Char): Int {
return Character.toCodePoint(highSurrogate, lowSurrogate)
}

actual inline fun toChars(codePoint: Int): CharArray {
return Character.toChars(codePoint)
}

actual inline fun toChars(codePoint: Int, destination: CharArray, offset: Int): Int {
return Character.toChars(codePoint, destination, offset)
}
}

0 comments on commit adbc5d9

Please sign in to comment.