diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-08-19 02:33:52 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-19 11:33:52 +0200 |
commit | 394f4ac7bb92fe5aaf902495c6b43b3451667602 (patch) | |
tree | 8957f2337957a2c28d152490d07be106b1dd2994 /lib | |
parent | 7b58dc2de0f606b757a558dfdda9d930ae63f41a (diff) | |
download | Nim-394f4ac7bb92fe5aaf902495c6b43b3451667602.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/std/private/digitsutils.nim | 68 | ||||
-rw-r--r-- | lib/std/private/miscdollars.nim | 9 | ||||
-rw-r--r-- | lib/system.nim | 9 | ||||
-rw-r--r-- | lib/system/assertions.nim | 5 | ||||
-rw-r--r-- | lib/system/dollars.nim | 62 | ||||
-rw-r--r-- | lib/system/repr_v2.nim | 17 | ||||
-rw-r--r-- | lib/system/strmantle.nim | 30 |
7 files changed, 96 insertions, 104 deletions
diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index 7aefc36bc..268a3ba7d 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -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] + addChars(result, tmp, next, tmp.len - next) + +func addInt*(result: var string, x: uint64) = + when nimvm: addIntImpl(result, x) else: - when defined(js) or defined(nimscript): - for i in 0..<length: - result[n+i] = tmp[next+i] + when not defined(js): addIntImpl(result, x) else: - {.noSideEffect.}: - copyMem result[n].addr, tmp[next].addr, length + 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)) diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim index a41cf1bc1..840fedf54 100644 --- a/lib/std/private/miscdollars.nim +++ b/lib/std/private/miscdollars.nim @@ -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 ")" diff --git a/lib/system.nim b/lib/system.nim index e6a2439df..740c4419f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -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) diff --git a/lib/system/assertions.nim b/lib/system/assertions.nim index cd789845b..6f64a55b7 100644 --- a/lib/system/assertions.nim +++ b/lib/system/assertions.nim @@ -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) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 8634db382..46085d2aa 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -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:. - -template dollarImpl(x: uint | uint64, result: var string) = - addIntImpl(result, 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 = - ## 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. +proc `$`*(x: int): string {.raises: [].} = + ## Outplace version of `addInt`. + result.addInt(x) + +proc `$`*(x: int64): string {.raises: [].} = + ## Outplace version of `addInt`. + result.addInt(x) + +proc `$`*(x: uint64): string {.raises: [].} = + ## Outplace version of `addInt`. + addInt(result, x) + +# 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`. diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index ba94b881d..6ab5f3c3f 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -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 diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index f55168c01..9cf4f9e55 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -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" |