Skip to content

Simplify evaluation of hex-encoded number's length #338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions core/common/src/-Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,15 @@ internal fun Long.toHexString(): String {

return result.concatToString(i, result.size)
}

/**
* Returns the number of characters required to encode [v]
* as a hexadecimal number without leading zeros (with `v == 0L` being the only exception,
* `hexNumberLength(0) == 1`).
*/
internal inline fun hexNumberLength(v: Long): Int {
if (v == 0L) return 1
val exactWidth = (Long.SIZE_BITS - v.countLeadingZeroBits())
// Round up to the nearest full nibble
return ((exactWidth + 3) / 4)
}
22 changes: 1 addition & 21 deletions core/common/src/Sinks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -149,27 +149,7 @@ public fun Sink.writeHexadecimalUnsignedLong(long: Long) {
return
}

// Mask every bit below the most significant bit to a 1
// http://aggregate.org/MAGIC/#Most%20Significant%201%20Bit
var x = v
x = x or (x ushr 1)
x = x or (x ushr 2)
x = x or (x ushr 4)
x = x or (x ushr 8)
x = x or (x ushr 16)
x = x or (x ushr 32)

// Count the number of 1s
// http://aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count)
x -= x ushr 1 and 0x5555555555555555
x = (x ushr 2 and 0x3333333333333333) + (x and 0x3333333333333333)
x = (x ushr 4) + x and 0x0f0f0f0f0f0f0f0f
x += x ushr 8
x += x ushr 16
x = (x and 0x3f) + ((x ushr 32) and 0x3f)

// Round up to the nearest full byte
val width = ((x + 3) / 4).toInt()
val width = hexNumberLength(v)

writeToInternalBuffer { buffer ->
val tail = buffer.writableSegment(width)
Expand Down
42 changes: 42 additions & 0 deletions core/common/test/UtilsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/

package kotlinx.io

import kotlin.test.Test
import kotlin.test.assertEquals

class UtilsTest {
@Test
fun hexNumberLength() {
val num2length: Map<Long, Int> = mapOf(
0x1L to 1,
0x10L to 2,
0x100L to 3,
0x1000L to 4,
0x10000L to 5,
0x100000L to 6,
0x1000000L to 7,
0x10000000L to 8,
0x100000000L to 9,
0x1000000000L to 10,
0x10000000000L to 11,
0x100000000000L to 12,
0x1000000000000L to 13,
0x10000000000000L to 14,
0x100000000000000L to 15,
0x1000000000000000L to 16,
-1L to 16,
0x3fL to 2,
0x7fL to 2,
0xffL to 2,
0L to 1
)

num2length.forEach { (num, length) ->
assertEquals(length, hexNumberLength(num), "Wrong length for 0x${num.toString(16)}")
}
}
}