Skip to content

Commit

Permalink
Improve algorithm to count digits in Long (#1548)
Browse files Browse the repository at this point in the history
  • Loading branch information
Egorand authored Nov 14, 2024
1 parent 2987a5a commit 935b3f0
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 57 deletions.
86 changes: 29 additions & 57 deletions okio/src/commonMain/kotlin/okio/internal/Buffer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -461,63 +461,7 @@ internal inline fun Buffer.commonWriteDecimalLong(v: Long): Buffer {
negative = true
}

// Binary search for character width which favors matching lower numbers.
var width =
if (v < 100000000L) {
if (v < 10000L) {
if (v < 100L) {
if (v < 10L) {
1
} else {
2
}
} else if (v < 1000L) {
3
} else {
4
}
} else if (v < 1000000L) {
if (v < 100000L) {
5
} else {
6
}
} else if (v < 10000000L) {
7
} else {
8
}
} else if (v < 1000000000000L) {
if (v < 10000000000L) {
if (v < 1000000000L) {
9
} else {
10
}
} else if (v < 100000000000L) {
11
} else {
12
}
} else if (v < 1000000000000000L) {
if (v < 10000000000000L) {
13
} else if (v < 100000000000000L) {
14
} else {
15
}
} else if (v < 100000000000000000L) {
if (v < 10000000000000000L) {
16
} else {
17
}
} else if (v < 1000000000000000000L) {
18
} else {
19
}
var width = countDigitsIn(v)
if (negative) {
++width
}
Expand All @@ -539,6 +483,34 @@ internal inline fun Buffer.commonWriteDecimalLong(v: Long): Buffer {
return this
}

private fun countDigitsIn(v: Long): Int {
val guess = ((64 - v.countLeadingZeroBits()) * 10) ushr 5
return guess + (if (v > DigitCountToLargestValue[guess]) 1 else 0)
}

private val DigitCountToLargestValue = longArrayOf(
-1, // Every value has more than 0 digits.
9L, // For 1 digit (index 1), the largest value is 9.
99L,
999L,
9999L,
99999L,
999999L,
9999999L,
99999999L,
999999999L,
9999999999L,
99999999999L,
999999999999L,
9999999999999L,
99999999999999L,
999999999999999L,
9999999999999999L,
99999999999999999L,
999999999999999999L, // For 18 digits (index 18), the largest value is 999999999999999999.
Long.MAX_VALUE, // For 19 digits (index 19), the largest value is MAX_VALUE.
)

internal inline fun Buffer.commonWriteHexadecimalUnsignedLong(v: Long): Buffer {
var v = v
if (v == 0L) {
Expand Down
36 changes: 36 additions & 0 deletions okio/src/commonTest/kotlin/okio/CommonBufferedSinkTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,42 @@ class CommonBufferedSinkTest(
assertLongDecimalString("10000000000000000", 10000000000000000L)
assertLongDecimalString("100000000000000000", 100000000000000000L)
assertLongDecimalString("1000000000000000000", 1000000000000000000L)
assertLongDecimalString("-9", -9L)
assertLongDecimalString("-99", -99L)
assertLongDecimalString("-999", -999L)
assertLongDecimalString("-9999", -9999L)
assertLongDecimalString("-99999", -99999L)
assertLongDecimalString("-999999", -999999L)
assertLongDecimalString("-9999999", -9999999L)
assertLongDecimalString("-99999999", -99999999L)
assertLongDecimalString("-999999999", -999999999L)
assertLongDecimalString("-9999999999", -9999999999L)
assertLongDecimalString("-99999999999", -99999999999L)
assertLongDecimalString("-999999999999", -999999999999L)
assertLongDecimalString("-9999999999999", -9999999999999L)
assertLongDecimalString("-99999999999999", -99999999999999L)
assertLongDecimalString("-999999999999999", -999999999999999L)
assertLongDecimalString("-9999999999999999", -9999999999999999L)
assertLongDecimalString("-99999999999999999", -99999999999999999L)
assertLongDecimalString("-999999999999999999", -999999999999999999L)
assertLongDecimalString("-10", -10L)
assertLongDecimalString("-100", -100L)
assertLongDecimalString("-1000", -1000L)
assertLongDecimalString("-10000", -10000L)
assertLongDecimalString("-100000", -100000L)
assertLongDecimalString("-1000000", -1000000L)
assertLongDecimalString("-10000000", -10000000L)
assertLongDecimalString("-100000000", -100000000L)
assertLongDecimalString("-1000000000", -1000000000L)
assertLongDecimalString("-10000000000", -10000000000L)
assertLongDecimalString("-100000000000", -100000000000L)
assertLongDecimalString("-1000000000000", -1000000000000L)
assertLongDecimalString("-10000000000000", -10000000000000L)
assertLongDecimalString("-100000000000000", -100000000000000L)
assertLongDecimalString("-1000000000000000", -1000000000000000L)
assertLongDecimalString("-10000000000000000", -10000000000000000L)
assertLongDecimalString("-100000000000000000", -100000000000000000L)
assertLongDecimalString("-1000000000000000000", -1000000000000000000L)
}

private fun assertLongDecimalString(string: String, value: Long) {
Expand Down

0 comments on commit 935b3f0

Please sign in to comment.