mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-14 23:33:28 +00:00
merge similar procs regarding digits (#18318)
This commit is contained in:
88
lib/std/private/digitsutils.nim
Normal file
88
lib/std/private/digitsutils.nim
Normal file
@@ -0,0 +1,88 @@
|
||||
const
|
||||
trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0]
|
||||
|
||||
digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5',
|
||||
'0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
|
||||
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3',
|
||||
'2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2',
|
||||
'3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
|
||||
'4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0',
|
||||
'5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
||||
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8',
|
||||
'6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7',
|
||||
'7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6',
|
||||
'8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5',
|
||||
'9', '6', '9', '7', '9', '8', '9', '9']
|
||||
|
||||
# Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c
|
||||
# Generates:
|
||||
# .. code-block:: nim
|
||||
# var res = ""
|
||||
# for i in 0 .. 99:
|
||||
# if i < 10:
|
||||
# res.add "0" & $i
|
||||
# else:
|
||||
# res.add $i
|
||||
# doAssert res == digits100
|
||||
|
||||
proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} =
|
||||
assert(digits <= 99)
|
||||
buf[pos] = digits100[2 * digits]
|
||||
buf[pos+1] = digits100[2 * digits + 1]
|
||||
#copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char)))
|
||||
|
||||
proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} =
|
||||
assert(digits <= 99)
|
||||
return trailingZeros100[digits]
|
||||
|
||||
func digits10*(num: uint64): int {.noinline.} =
|
||||
if num < 10'u64:
|
||||
result = 1
|
||||
elif num < 100'u64:
|
||||
result = 2
|
||||
elif num < 1_000'u64:
|
||||
result = 3
|
||||
elif num < 10_000'u64:
|
||||
result = 4
|
||||
elif num < 100_000'u64:
|
||||
result = 5
|
||||
elif num < 1_000_000'u64:
|
||||
result = 6
|
||||
elif num < 10_000_000'u64:
|
||||
result = 7
|
||||
elif num < 100_000_000'u64:
|
||||
result = 8
|
||||
elif num < 1_000_000_000'u64:
|
||||
result = 9
|
||||
elif num < 10_000_000_000'u64:
|
||||
result = 10
|
||||
elif num < 100_000_000_000'u64:
|
||||
result = 11
|
||||
elif num < 1_000_000_000_000'u64:
|
||||
result = 12
|
||||
else:
|
||||
result = 12 + digits10(num div 1_000_000_000_000'u64)
|
||||
|
||||
template numToString*(result: var string, origin: uint64, length: int) =
|
||||
var num = origin
|
||||
var next = length - 1
|
||||
const nbatch = 100
|
||||
|
||||
while num >= nbatch:
|
||||
let originNum = num
|
||||
num = num div nbatch
|
||||
let index = (originNum - num * nbatch) shl 1
|
||||
result[next] = digits100[index + 1]
|
||||
result[next - 1] = digits100[index]
|
||||
dec(next, 2)
|
||||
|
||||
# process last 1-2 digits
|
||||
if num < 10:
|
||||
result[next] = chr(ord('0') + num)
|
||||
else:
|
||||
let index = num * 2
|
||||
result[next] = digits100[index + 1]
|
||||
result[next - 1] = digits100[index]
|
||||
@@ -1,3 +1,6 @@
|
||||
import std/private/digitsutils
|
||||
|
||||
|
||||
proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.}
|
||||
## The stringify operator for an integer argument. Returns `x`
|
||||
## converted to a decimal string. `$` is Nim's general way of
|
||||
@@ -6,22 +9,14 @@ proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.}
|
||||
template dollarImpl(x: uint | uint64, result: var string) =
|
||||
type destTyp = typeof(x)
|
||||
if x == 0:
|
||||
result = "0"
|
||||
else:
|
||||
result = newString(60)
|
||||
var i = 0
|
||||
var n = x
|
||||
while n != 0:
|
||||
let nn = n div destTyp(10)
|
||||
result[i] = char(n - destTyp(10) * nn + ord('0'))
|
||||
inc i
|
||||
n = nn
|
||||
result.setLen i
|
||||
return "0"
|
||||
elif x == 1:
|
||||
return "1"
|
||||
|
||||
let half = i div 2
|
||||
# Reverse
|
||||
for t in 0 .. half-1: swap(result[t], result[i-t-1])
|
||||
let length = digits10(x)
|
||||
setLen(result, length)
|
||||
|
||||
numToString(result, x, length)
|
||||
|
||||
when defined(js):
|
||||
import std/private/since
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
## Note:
|
||||
## This function may temporarily write up to DtoaMinBufferLength characters into the buffer.
|
||||
|
||||
|
||||
import std/private/digitsutils
|
||||
|
||||
|
||||
const
|
||||
dtoaMinBufferLength*: cint = 64
|
||||
|
||||
@@ -1038,34 +1042,6 @@ proc toDecimal64*(ieeeSignificand: uint64; ieeeExponent: uint64): FloatingDecima
|
||||
## ToChars
|
||||
## ==================================================================================================
|
||||
|
||||
proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} =
|
||||
const
|
||||
digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5',
|
||||
'0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
|
||||
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3',
|
||||
'2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2',
|
||||
'3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
|
||||
'4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0',
|
||||
'5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
||||
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8',
|
||||
'6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7',
|
||||
'7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6',
|
||||
'8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5',
|
||||
'9', '6', '9', '7', '9', '8', '9', '9']
|
||||
dragonbox_Assert(digits <= 99)
|
||||
buf[pos] = digits100[2 * digits]
|
||||
buf[pos+1] = digits100[2 * digits + 1]
|
||||
#copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char)))
|
||||
|
||||
proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} =
|
||||
const
|
||||
trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0]
|
||||
dragonbox_Assert(digits <= 99)
|
||||
return trailingZeros100[digits]
|
||||
|
||||
when false:
|
||||
template `+!`(x: cstring; offset: int): cstring = cast[cstring](cast[uint](x) + uint(offset))
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
## https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN
|
||||
## --------------------------------------------------------------------------------------------------
|
||||
|
||||
import std/private/digitsutils
|
||||
|
||||
|
||||
template sf_Assert(x: untyped): untyped =
|
||||
assert(x)
|
||||
|
||||
@@ -233,33 +236,6 @@ proc toDecimal32(ieeeSignificand: uint32; ieeeExponent: uint32): FloatingDecimal
|
||||
## ToChars
|
||||
## ==================================================================================================
|
||||
|
||||
proc utoa2Digits(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} =
|
||||
const
|
||||
digits100: array[200, char] = ['0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5',
|
||||
'0', '6', '0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
|
||||
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3',
|
||||
'2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2',
|
||||
'3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
|
||||
'4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0',
|
||||
'5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
||||
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8',
|
||||
'6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7',
|
||||
'7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6',
|
||||
'8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5',
|
||||
'9', '6', '9', '7', '9', '8', '9', '9']
|
||||
sf_Assert(digits <= 99)
|
||||
buf[pos] = digits100[2 * digits]
|
||||
buf[pos+1] = digits100[2 * digits + 1]
|
||||
|
||||
proc trailingZeros2Digits(digits: uint32): int32 {.inline.} =
|
||||
const
|
||||
trailingZeros100: array[100, int8] = [2'i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0]
|
||||
sf_Assert(digits <= 99)
|
||||
return trailingZeros100[digits]
|
||||
|
||||
proc printDecimalDigitsBackwards(buf: var openArray[char]; pos: int; output: uint32): int32 {.inline.} =
|
||||
var output = output
|
||||
var pos = pos
|
||||
|
||||
@@ -9,72 +9,9 @@
|
||||
|
||||
# Compilerprocs for strings that do not depend on the string implementation.
|
||||
|
||||
const digitsTable = "0001020304050607080910111213141516171819" &
|
||||
"2021222324252627282930313233343536373839" &
|
||||
"4041424344454647484950515253545556575859" &
|
||||
"6061626364656667686970717273747576777879" &
|
||||
"8081828384858687888990919293949596979899"
|
||||
# Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c
|
||||
# Generates:
|
||||
# .. code-block:: nim
|
||||
# var res = ""
|
||||
# for i in 0 .. 99:
|
||||
# if i < 10:
|
||||
# res.add "0" & $i
|
||||
# else:
|
||||
# res.add $i
|
||||
# doAssert res == digitsTable
|
||||
import std/private/digitsutils
|
||||
|
||||
|
||||
func digits10(num: uint64): int {.noinline.} =
|
||||
if num < 10'u64:
|
||||
result = 1
|
||||
elif num < 100'u64:
|
||||
result = 2
|
||||
elif num < 1_000'u64:
|
||||
result = 3
|
||||
elif num < 10_000'u64:
|
||||
result = 4
|
||||
elif num < 100_000'u64:
|
||||
result = 5
|
||||
elif num < 1_000_000'u64:
|
||||
result = 6
|
||||
elif num < 10_000_000'u64:
|
||||
result = 7
|
||||
elif num < 100_000_000'u64:
|
||||
result = 8
|
||||
elif num < 1_000_000_000'u64:
|
||||
result = 9
|
||||
elif num < 10_000_000_000'u64:
|
||||
result = 10
|
||||
elif num < 100_000_000_000'u64:
|
||||
result = 11
|
||||
elif num < 1_000_000_000_000'u64:
|
||||
result = 12
|
||||
else:
|
||||
result = 12 + digits10(num div 1_000_000_000_000'u64)
|
||||
|
||||
template numToString(result: var string, origin: uint64, length: int) =
|
||||
var num = origin
|
||||
var next = length - 1
|
||||
const nbatch = 100
|
||||
|
||||
while num >= nbatch:
|
||||
let originNum = num
|
||||
num = num div nbatch
|
||||
let index = (originNum - num * nbatch) shl 1
|
||||
result[next] = digitsTable[index + 1]
|
||||
result[next - 1] = digitsTable[index]
|
||||
dec(next, 2)
|
||||
|
||||
# process last 1-2 digits
|
||||
if num < 10:
|
||||
result[next] = chr(ord('0') + num)
|
||||
else:
|
||||
let index = num * 2
|
||||
result[next] = digitsTable[index + 1]
|
||||
result[next - 1] = digitsTable[index]
|
||||
|
||||
proc cmpStrings(a, b: string): int {.inline, compilerproc.} =
|
||||
let alen = a.len
|
||||
let blen = b.len
|
||||
|
||||
Reference in New Issue
Block a user