Skip to content

Commit 4019a7e

Browse files
authored
Simplify evaluation of hex-encoded number's length (#338)
* Simplify evaluation of hex-encoded number's length * Clean up the code, fixed the value returned for `0L`
1 parent 7c4d095 commit 4019a7e

File tree

3 files changed

+55
-21
lines changed

3 files changed

+55
-21
lines changed

core/common/src/-Util.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,15 @@ internal fun Long.toHexString(): String {
171171

172172
return result.concatToString(i, result.size)
173173
}
174+
175+
/**
176+
* Returns the number of characters required to encode [v]
177+
* as a hexadecimal number without leading zeros (with `v == 0L` being the only exception,
178+
* `hexNumberLength(0) == 1`).
179+
*/
180+
internal inline fun hexNumberLength(v: Long): Int {
181+
if (v == 0L) return 1
182+
val exactWidth = (Long.SIZE_BITS - v.countLeadingZeroBits())
183+
// Round up to the nearest full nibble
184+
return ((exactWidth + 3) / 4)
185+
}

core/common/src/Sinks.kt

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -149,27 +149,7 @@ public fun Sink.writeHexadecimalUnsignedLong(long: Long) {
149149
return
150150
}
151151

152-
// Mask every bit below the most significant bit to a 1
153-
// http://aggregate.org/MAGIC/#Most%20Significant%201%20Bit
154-
var x = v
155-
x = x or (x ushr 1)
156-
x = x or (x ushr 2)
157-
x = x or (x ushr 4)
158-
x = x or (x ushr 8)
159-
x = x or (x ushr 16)
160-
x = x or (x ushr 32)
161-
162-
// Count the number of 1s
163-
// http://aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count)
164-
x -= x ushr 1 and 0x5555555555555555
165-
x = (x ushr 2 and 0x3333333333333333) + (x and 0x3333333333333333)
166-
x = (x ushr 4) + x and 0x0f0f0f0f0f0f0f0f
167-
x += x ushr 8
168-
x += x ushr 16
169-
x = (x and 0x3f) + ((x ushr 32) and 0x3f)
170-
171-
// Round up to the nearest full byte
172-
val width = ((x + 3) / 4).toInt()
152+
val width = hexNumberLength(v)
173153

174154
writeToInternalBuffer { buffer ->
175155
val tail = buffer.writableSegment(width)

core/common/test/UtilsTest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
4+
*/
5+
6+
package kotlinx.io
7+
8+
import kotlin.test.Test
9+
import kotlin.test.assertEquals
10+
11+
class UtilsTest {
12+
@Test
13+
fun hexNumberLength() {
14+
val num2length: Map<Long, Int> = mapOf(
15+
0x1L to 1,
16+
0x10L to 2,
17+
0x100L to 3,
18+
0x1000L to 4,
19+
0x10000L to 5,
20+
0x100000L to 6,
21+
0x1000000L to 7,
22+
0x10000000L to 8,
23+
0x100000000L to 9,
24+
0x1000000000L to 10,
25+
0x10000000000L to 11,
26+
0x100000000000L to 12,
27+
0x1000000000000L to 13,
28+
0x10000000000000L to 14,
29+
0x100000000000000L to 15,
30+
0x1000000000000000L to 16,
31+
-1L to 16,
32+
0x3fL to 2,
33+
0x7fL to 2,
34+
0xffL to 2,
35+
0L to 1
36+
)
37+
38+
num2length.forEach { (num, length) ->
39+
assertEquals(length, hexNumberLength(num), "Wrong length for 0x${num.toString(16)}")
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)