improvements to addInt and $ for integer types (#18592)

* improvements to $(SomeInteger) and addInt
* remove mIntToStr, mInt64ToStr
* improvements
* fix tests/pragmas/tinjectstmt.nim; the diff is harmless, cgen code is identical with -d:danger or debug mode
* rm tests/system/tstrmantle.nim
* revert compiler/jsgen.nim for -d:nimVersion140
This commit is contained in:
Timothee Cour 2021-08-19 02:33:52 -07:00 • committed by GitHub
commit 394f4ac7bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 162 additions and 186 deletions

View file

@ -29,18 +29,34 @@ const
# 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 addIntImpl*(result: var string, origin: uint64) =
when defined(js):
proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".}
func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} =
let old = result.len
result.setLen old + n
template impl =
for i in 0..<n: result[old + i] = x[start + i]
when nimvm: impl
else:
when defined(js) or defined(nimscript): impl
else:
{.noSideEffect.}:
copyMem result[old].addr, x[start].unsafeAddr, n
func addChars[T](result: var string, x: T) {.inline.} =
addChars(result, x, 0, x.len)
func addIntImpl(result: var string, x: uint64) {.inline.} =
var tmp {.noinit.}: array[24, char]
var num = origin
var num = x
var next = tmp.len - 1
const nbatch = 100
@ -60,17 +76,39 @@ func addIntImpl*(result: var string, origin: uint64) =
tmp[next] = digits100[index + 1]
tmp[next - 1] = digits100[index]
dec next
let n = result.len
let length = tmp.len - next
result.setLen n + length
when nimvm:
for i in 0..<length:
result[n+i] = tmp[next+i]
else:
when defined(js) or defined(nimscript):
for i in 0..<length:
result[n+i] = tmp[next+i]
else:
{.noSideEffect.}:
copyMem result[n].addr, tmp[next].addr, length
addChars(result, tmp, next, tmp.len - next)
func addInt*(result: var string, x: uint64) =
when nimvm: addIntImpl(result, x)
else:
when not defined(js): addIntImpl(result, x)
else:
addChars(result, numToString(x))
proc addInt*(result: var string; x: int64) =
## Converts integer to its string representation and appends it to `result`.
runnableExamples:
var s = "foo"
s.addInt(45)
assert s == "foo45"
template impl =
var num: uint64
if x < 0:
if x == low(int64):
num = uint64(x)
else:
num = uint64(-x)
let base = result.len
setLen(result, base + 1)
result[base] = '-'
else:
num = uint64(x)
addInt(result, num)
when nimvm: impl()
else:
when defined(js):
addChars(result, numToString(x))
else: impl()
proc addInt*(result: var string; x: int) {.inline.} =
addInt(result, int64(x))

View file

@ -1,3 +1,5 @@
from std/private/digitsutils import addInt
template toLocation*(result: var string, file: string | cstring, line: int, col: int) =
## avoids spurious allocations
# Hopefully this can be re-used everywhere so that if a user needs to customize,
@ -5,11 +7,8 @@ template toLocation*(result: var string, file: string | cstring, line: int, col:
result.add file
if line > 0:
result.add "("
# simplify this after moving moving `include strmantle` above import assertions`
when declared(addInt): result.addInt line
else: result.add $line
addInt(result, line)
if col > 0:
result.add ", "
when declared(addInt): result.addInt col
else: result.add $col
addInt(result, col)
result.add ")"

View file

@ -2463,14 +2463,13 @@ when notJSnotNims:
else:
{.error: "Only closure iterator is allowed!".}
from std/private/digitsutils import addInt
export addInt
when defined(js):
include "system/jssys"
include "system/reprjs"
when defined(js) or defined(nimscript):
proc addInt*(result: var string; x: int64) =
result.add $x
proc quit*(errormsg: string, errorcode = QuitFailure) {.noreturn.} =
## A shorthand for `echo(errormsg); quit(errorcode)`.
when defined(nimscript) or defined(js) or (hostOS == "standalone"):
@ -2918,7 +2917,7 @@ proc addQuoted*[T](s: var string, x: T) =
s.addEscapedChar(x)
s.add("'")
# prevent temporary string allocation
elif T is SomeSignedInt:
elif T is SomeInteger:
s.addInt(x)
elif T is SomeFloat:
s.addFloat(x)

View file

@ -12,7 +12,6 @@ import std/private/miscdollars
type InstantiationInfo = tuple[filename: string, line: int, column: int]
proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.}
proc `$`(info: InstantiationInfo): string =
# The +1 is needed here
# instead of overriding `$` (and changing its meaning), consider explicit name.
@ -108,7 +107,9 @@ template doAssertRaises*(exception: typedesc, code: untyped) =
wrong = true
except exception:
discard
except Exception as e: raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd)
except Exception as e:
mixin `$` # alternatively, we could define $cstring in this module
raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd)
except: raisedForeign()
if wrong:
raiseAssert(begin & " nothing was raised" & msgEnd)

View file

@ -1,45 +1,31 @@
## `$` is Nim's general way of spelling `toString`:idx:.
runnableExamples:
assert $0.1 == "0.1"
assert $(-2*3) == "-6"
import std/private/digitsutils
import system/formatfloat
export addFloat
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
## spelling `toString`:idx:.
proc `$`*(x: int): string {.raises: [].} =
## Outplace version of `addInt`.
result.addInt(x)
template dollarImpl(x: uint | uint64, result: var string) =
addIntImpl(result, x)
proc `$`*(x: int64): string {.raises: [].} =
## Outplace version of `addInt`.
result.addInt(x)
when defined(js):
import std/private/since
since (1, 3):
proc `$`*(x: uint): string =
## Caveat: currently implemented as $(cast[int](x)), tied to current
## semantics of js' Number type.
# for c, see strmantle.`$`
when nimvm:
dollarImpl(x, result)
else:
result = $(int(x))
proc `$`*(x: uint64): string {.raises: [].} =
## Outplace version of `addInt`.
addInt(result, x)
proc `$`*(x: uint64): string =
## Compatibility note:
## the results may change in future releases if/when js target implements
## 64bit ints.
# pending https://github.com/nim-lang/RFCs/issues/187
when nimvm:
dollarImpl(x, result)
else:
result = $(cast[int](x))
else:
proc `$`*(x: uint64): string {.noSideEffect, raises: [].} =
## The stringify operator for an unsigned integer argument. Returns `x`
## converted to a decimal string.
dollarImpl(x, result)
proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
## The stringify operator for an integer argument. Returns `x`
## converted to a decimal string.
# same as old `ctfeWhitelist` behavior, whether or not this is a good idea.
template gen(T) =
# xxx simplify this by supporting this in compiler: int{lit} | uint64{lit} | int64{lit}
func `$`*(x: T{lit}): string {.compileTime.} = result.addInt(x)
gen(int)
gen(uint64)
gen(int64)
func `$`*(x: float | float32): string =
## Outplace version of `addFloat`.

View file

@ -8,18 +8,17 @@ proc distinctBase(T: typedesc, recursive: static bool = true): typedesc {.magic:
proc repr*(x: NimNode): string {.magic: "Repr", noSideEffect.}
proc repr*(x: int): string {.magic: "IntToStr", noSideEffect.}
## repr for an integer argument. Returns `x`
## converted to a decimal string.
proc repr*(x: int): string =
## Same as $x
$x
proc repr*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
## repr for an integer argument. Returns `x`
## converted to a decimal string.
proc repr*(x: int64): string =
## Same as $x
$x
proc repr*(x: uint64): string {.noSideEffect.} =
## repr for an unsigned integer argument. Returns `x`
## converted to a decimal string.
$x #Calls `$` from system/strmantle.nim
## Same as $x
$x
proc repr*(x: float): string =
## Same as $x

View file

@ -43,32 +43,6 @@ proc hashString(s: string): int {.compilerproc.} =
h = h + h shl 15
result = cast[int](h)
proc addInt*(result: var string; x: int64) =
## Converts integer to its string representation and appends it to `result`.
##
## .. code-block:: Nim
## var
## a = "123"
## b = 45
## a.addInt(b) # a <- "12345"
var num: uint64
if x < 0:
if x == low(int64):
num = uint64(x)
else:
num = uint64(-x)
let base = result.len
setLen(result, base + 1)
result[base] = '-'
else:
num = uint64(x)
addIntImpl(result, num)
proc nimIntToStr(x: int): string {.compilerRtl.} =
result = newStringOfCap(sizeof(x)*4)
result.addInt x
proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
importc: "strtod", header: "<stdlib.h>", noSideEffect.}
@ -240,10 +214,6 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
when defined(nimHasInvariant):
{.pop.} # staticBoundChecks
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
result = newStringOfCap(sizeof(x)*4)
result.addInt x
proc nimBoolToStr(x: bool): string {.compilerRtl.} =
return if x: "true" else: "false"