Skip to content

Commit ae64198

Browse files
Migrate NameAllocator from JVM to common (#2024)
* Migrate NameAllocator from JVM to common * CodePoint use unsigned `ushr` Co-authored-by: Jake Wharton <[email protected]> * Remove leading 0 Co-authored-by: Jake Wharton <[email protected]> * Better random tag effect --------- Co-authored-by: Jake Wharton <[email protected]>
1 parent d141589 commit ae64198

File tree

7 files changed

+246
-9
lines changed

7 files changed

+246
-9
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (C) 2024 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.kotlinpoet
17+
18+
import kotlin.jvm.JvmInline
19+
20+
@JvmInline
21+
internal value class CodePoint(val code: Int)
22+
23+
internal expect fun String.codePointAt(index: Int): CodePoint
24+
25+
internal expect fun CodePoint.isLowerCase(): Boolean
26+
internal expect fun CodePoint.isUpperCase(): Boolean
27+
28+
internal expect fun CodePoint.isJavaIdentifierStart(): Boolean
29+
internal expect fun CodePoint.isJavaIdentifierPart(): Boolean
30+
31+
internal expect fun CodePoint.charCount(): Int
32+
33+
internal expect fun StringBuilder.appendCodePoint(codePoint: CodePoint): StringBuilder

kotlinpoet/src/jvmMain/kotlin/com/squareup/kotlinpoet/NameAllocator.kt renamed to kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/NameAllocator.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
*/
1616
package com.squareup.kotlinpoet
1717

18-
import java.util.UUID
18+
import kotlin.jvm.JvmOverloads
19+
import kotlin.random.Random
20+
import kotlin.random.nextULong
1921

2022
/**
2123
* Assigns Kotlin identifier names to avoid collisions, keywords, and invalid characters. To use,
@@ -118,7 +120,8 @@ public class NameAllocator private constructor(
118120
*/
119121
@JvmOverloads public fun newName(
120122
suggestion: String,
121-
tag: Any = UUID.randomUUID().toString(),
123+
// TODO It's possible to use `kotlin.uuid.Uuid` when it's stable
124+
tag: Any = Random.nextULong().toString(16).padStart(16, '0'),
122125
): String {
123126
var result = toJavaIdentifier(suggestion)
124127
while (!allocatedNames.add(result)) {
@@ -154,18 +157,18 @@ private fun toJavaIdentifier(suggestion: String) = buildString {
154157
while (i < suggestion.length) {
155158
val codePoint = suggestion.codePointAt(i)
156159
if (i == 0 &&
157-
!Character.isJavaIdentifierStart(codePoint) &&
158-
Character.isJavaIdentifierPart(codePoint)
160+
!codePoint.isJavaIdentifierStart() &&
161+
codePoint.isJavaIdentifierPart()
159162
) {
160163
append("_")
161164
}
162165

163-
val validCodePoint: Int = if (Character.isJavaIdentifierPart(codePoint)) {
166+
val validCodePoint: CodePoint = if (codePoint.isJavaIdentifierPart()) {
164167
codePoint
165168
} else {
166-
'_'.code
169+
CodePoint('_'.code)
167170
}
168171
appendCodePoint(validCodePoint)
169-
i += Character.charCount(codePoint)
172+
i += codePoint.charCount()
170173
}
171174
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (C) 2024 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.kotlinpoet
17+
18+
internal actual fun String.codePointAt(index: Int): CodePoint {
19+
val code = jsCodePointAt(this, index)
20+
return CodePoint(code)
21+
}
22+
23+
internal actual fun CodePoint.isLowerCase(): Boolean {
24+
// TODO Will there be a problem? Is there a better way?
25+
val str = jsFromCodePoint(this.code)
26+
27+
if (str.length != 1) {
28+
return false
29+
}
30+
31+
return str.first().isLowerCase()
32+
}
33+
34+
internal actual fun CodePoint.isUpperCase(): Boolean {
35+
// TODO Will there be a problem? Is there a better way?
36+
val str = jsFromCodePoint(this.code)
37+
38+
if (str.length != 1) {
39+
return false
40+
}
41+
42+
return str.first().isUpperCase()
43+
}
44+
45+
@Suppress("unused")
46+
private fun jsCodePointAt(str: String, index: Int): Int =
47+
js("str.codePointAt(index)").unsafeCast<Int>()
48+
49+
@Suppress("unused")
50+
private fun jsFromCodePoint(code: Int): String =
51+
js("String.fromCodePoint(code)").toString()

kotlinpoet/src/jvmMain/kotlin/com/squareup/kotlinpoet/ClassName.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,15 @@ public class ClassName internal constructor(
220220

221221
// Add the package name, like "java.util.concurrent", or "" for no package.
222222
var p = 0
223-
while (p < classNameString.length && Character.isLowerCase(classNameString.codePointAt(p))) {
223+
while (p < classNameString.length && classNameString.codePointAt(p).isLowerCase()) {
224224
p = classNameString.indexOf('.', p) + 1
225225
require(p != 0) { "couldn't make a guess for $classNameString" }
226226
}
227227
names += if (p != 0) classNameString.substring(0, p - 1) else ""
228228

229229
// Add the class names, like "Map" and "Entry".
230230
for (part in classNameString.substring(p).split('.')) {
231-
require(part.isNotEmpty() && Character.isUpperCase(part.codePointAt(0))) {
231+
require(part.isNotEmpty() && part.codePointAt(0).isUpperCase()) {
232232
"couldn't make a guess for $classNameString"
233233
}
234234

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (C) 2024 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.kotlinpoet
17+
18+
import kotlin.text.codePointAt as codePointAtKt
19+
20+
internal actual fun String.codePointAt(index: Int): CodePoint =
21+
CodePoint(codePointAtKt(index))
22+
23+
internal actual fun CodePoint.isLowerCase(): Boolean =
24+
Character.isLowerCase(code)
25+
26+
internal actual fun CodePoint.isUpperCase(): Boolean =
27+
Character.isUpperCase(code)
28+
29+
internal actual fun CodePoint.isJavaIdentifierStart(): Boolean =
30+
Character.isJavaIdentifierStart(code)
31+
32+
internal actual fun CodePoint.isJavaIdentifierPart(): Boolean =
33+
Character.isJavaIdentifierPart(code)
34+
35+
internal actual fun CodePoint.charCount(): Int {
36+
return Character.charCount(code)
37+
}
38+
39+
internal actual fun StringBuilder.appendCodePoint(codePoint: CodePoint): StringBuilder {
40+
return appendCodePoint(codePoint.code)
41+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (C) 2024 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.kotlinpoet
17+
18+
/*
19+
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
20+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
21+
*/
22+
internal actual fun StringBuilder.appendCodePoint(codePoint: CodePoint): StringBuilder {
23+
// Copied from StringBuilder.kt,
24+
// TODO Is this correct?
25+
val code = codePoint.code
26+
if (code <= Char.MAX_VALUE.code) {
27+
append(code.toChar())
28+
} else {
29+
append(Char.MIN_HIGH_SURROGATE + ((code - 0x10000) ushr 10))
30+
append(Char.MIN_LOW_SURROGATE + (code and 0x3ff))
31+
}
32+
return this
33+
}
34+
35+
internal actual fun CodePoint.isJavaIdentifierStart(): Boolean {
36+
// TODO How check Java identifier start use code point?
37+
if (charCount() == 1) {
38+
return Char(code).isJavaIdentifierStart()
39+
}
40+
41+
return true
42+
}
43+
44+
internal actual fun CodePoint.isJavaIdentifierPart(): Boolean {
45+
// TODO How check Java identifier part use code point?
46+
if (charCount() == 1) {
47+
return Char(code).isJavaIdentifierPart()
48+
}
49+
50+
return true
51+
}
52+
53+
internal actual fun CodePoint.charCount(): Int {
54+
return if (code >= 0x10000) 2 else 1
55+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) 2024 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.squareup.kotlinpoet
17+
18+
internal actual fun String.codePointAt(index: Int): CodePoint {
19+
val str = this
20+
val code = jsCodePointAt(str, index)
21+
return CodePoint(code)
22+
}
23+
24+
internal actual fun CodePoint.isLowerCase(): Boolean {
25+
// TODO Will there be a problem? Is there a better way?
26+
val code = this.code
27+
val str = jsFromCodePoint(code)
28+
29+
if (str.length != 1) {
30+
return false
31+
}
32+
33+
return str.first().isLowerCase()
34+
}
35+
36+
internal actual fun CodePoint.isUpperCase(): Boolean {
37+
// TODO Will there be a problem? Is there a better way?
38+
val code = this.code
39+
val str = jsFromCodePoint(code)
40+
41+
if (str.length != 1) {
42+
return false
43+
}
44+
45+
return str.first().isUpperCase()
46+
}
47+
48+
@Suppress("UNUSED_PARAMETER")
49+
private fun jsCodePointAt(str: String, index: Int): Int =
50+
js("str.codePointAt(index)")
51+
52+
@Suppress("UNUSED_PARAMETER")
53+
private fun jsFromCodePoint(code: Int): String =
54+
js("String.fromCodePoint(code)")

0 commit comments

Comments
 (0)