diff --git a/core/common/src/Sinks.kt b/core/common/src/Sinks.kt index c2e87a66..4589daa4 100644 --- a/core/common/src/Sinks.kt +++ b/core/common/src/Sinks.kt @@ -87,35 +87,7 @@ public fun Sink.writeDecimalLong(long: Long) { 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 } @@ -135,6 +107,34 @@ public fun Sink.writeDecimalLong(long: Long) { } } +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. +) + /** * Writes [long] to this sink in hexadecimal form (i.e., as a string in base 16). * diff --git a/core/common/test/AbstractSinkTest.kt b/core/common/test/AbstractSinkTest.kt index f52f5eb7..2c1b57e0 100644 --- a/core/common/test/AbstractSinkTest.kt +++ b/core/common/test/AbstractSinkTest.kt @@ -343,6 +343,42 @@ abstract class AbstractSinkTest internal constructor( 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) {