refactorings in preparations for the new runtime
This commit is contained in:
parent
470949f2e0
commit
ce01472ff3
8 changed files with 311 additions and 304 deletions
|
|
@ -164,7 +164,7 @@ proc canMove(n: PNode): bool =
|
||||||
# result = false
|
# result = false
|
||||||
|
|
||||||
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
if dest.storage == OnStack or not usesNativeGC(p.config):
|
if dest.storage == OnStack or not usesWriteBarrier(p.config):
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
elif dest.storage == OnHeap:
|
elif dest.storage == OnHeap:
|
||||||
# location is on heap
|
# location is on heap
|
||||||
|
|
@ -256,7 +256,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
# (for objects, etc.):
|
# (for objects, etc.):
|
||||||
if needToCopy notin flags or
|
if needToCopy notin flags or
|
||||||
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
||||||
if dest.storage == OnStack or not usesNativeGC(p.config):
|
if dest.storage == OnStack or not usesWriteBarrier(p.config):
|
||||||
useStringh(p.module)
|
useStringh(p.module)
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||||
|
|
@ -290,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
|
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
|
||||||
genRefAssign(p, dest, src, flags)
|
genRefAssign(p, dest, src, flags)
|
||||||
else:
|
else:
|
||||||
if dest.storage == OnStack or not usesNativeGC(p.config):
|
if dest.storage == OnStack or not usesWriteBarrier(p.config):
|
||||||
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
|
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
|
||||||
elif dest.storage == OnHeap:
|
elif dest.storage == OnHeap:
|
||||||
# we use a temporary to care for the dreaded self assignment:
|
# we use a temporary to care for the dreaded self assignment:
|
||||||
|
|
@ -1150,7 +1150,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||||
addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
|
addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
|
||||||
|
|
||||||
let args = [getTypeDesc(p.module, typ), ti, sizeExpr]
|
let args = [getTypeDesc(p.module, typ), ti, sizeExpr]
|
||||||
if a.storage == OnHeap and usesNativeGC(p.config):
|
if a.storage == OnHeap and usesWriteBarrier(p.config):
|
||||||
# use newObjRC1 as an optimization
|
# use newObjRC1 as an optimization
|
||||||
if canFormAcycle(a.t):
|
if canFormAcycle(a.t):
|
||||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
|
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
|
||||||
|
|
@ -1181,7 +1181,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
|
||||||
genTypeInfo(p.module, seqtype, dest.lode.info), length]
|
genTypeInfo(p.module, seqtype, dest.lode.info), length]
|
||||||
var call: TLoc
|
var call: TLoc
|
||||||
initLoc(call, locExpr, dest.lode, OnHeap)
|
initLoc(call, locExpr, dest.lode, OnHeap)
|
||||||
if dest.storage == OnHeap and usesNativeGC(p.config):
|
if dest.storage == OnHeap and usesWriteBarrier(p.config):
|
||||||
if canFormAcycle(dest.t):
|
if canFormAcycle(dest.t):
|
||||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const
|
||||||
# above X strings a hash-switch for strings is generated
|
# above X strings a hash-switch for strings is generated
|
||||||
|
|
||||||
proc registerGcRoot(p: BProc, v: PSym) =
|
proc registerGcRoot(p: BProc, v: PSym) =
|
||||||
if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
|
if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and
|
||||||
containsGarbageCollectedRef(v.loc.t):
|
containsGarbageCollectedRef(v.loc.t):
|
||||||
# we register a specialized marked proc here; this has the advantage
|
# we register a specialized marked proc here; this has the advantage
|
||||||
# that it works out of the box for thread local storage then :-)
|
# that it works out of the box for thread local storage then :-)
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,8 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
|
||||||
of "refc": result = conf.selectedGC == gcRefc
|
of "refc": result = conf.selectedGC == gcRefc
|
||||||
of "v2": result = conf.selectedGC == gcV2
|
of "v2": result = conf.selectedGC == gcV2
|
||||||
of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
|
of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
|
||||||
of "generational": result = conf.selectedGC == gcGenerational
|
of "generational": result = false
|
||||||
|
of "destructors": result = conf.selectedGC == gcDestructors
|
||||||
of "go": result = conf.selectedGC == gcGo
|
of "go": result = conf.selectedGC == gcGo
|
||||||
of "none": result = conf.selectedGC == gcNone
|
of "none": result = conf.selectedGC == gcNone
|
||||||
of "stack", "regions": result = conf.selectedGC == gcRegions
|
of "stack", "regions": result = conf.selectedGC == gcRegions
|
||||||
|
|
@ -435,9 +436,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
of "markandsweep":
|
of "markandsweep":
|
||||||
conf.selectedGC = gcMarkAndSweep
|
conf.selectedGC = gcMarkAndSweep
|
||||||
defineSymbol(conf.symbols, "gcmarkandsweep")
|
defineSymbol(conf.symbols, "gcmarkandsweep")
|
||||||
of "generational":
|
of "destructors":
|
||||||
conf.selectedGC = gcGenerational
|
conf.selectedGC = gcDestructors
|
||||||
defineSymbol(conf.symbols, "gcgenerational")
|
defineSymbol(conf.symbols, "gcdestructors")
|
||||||
of "go":
|
of "go":
|
||||||
conf.selectedGC = gcGo
|
conf.selectedGC = gcGo
|
||||||
defineSymbol(conf.symbols, "gogc")
|
defineSymbol(conf.symbols, "gogc")
|
||||||
|
|
|
||||||
|
|
@ -103,8 +103,8 @@ type
|
||||||
cmdJsonScript # compile a .json build file
|
cmdJsonScript # compile a .json build file
|
||||||
TStringSeq* = seq[string]
|
TStringSeq* = seq[string]
|
||||||
TGCMode* = enum # the selected GC
|
TGCMode* = enum # the selected GC
|
||||||
gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc,
|
gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcDestructors,
|
||||||
gcV2, gcGenerational
|
gcRefc, gcV2
|
||||||
|
|
||||||
IdeCmd* = enum
|
IdeCmd* = enum
|
||||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
|
||||||
|
|
@ -368,7 +368,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
|
proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
|
||||||
proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
|
proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
|
||||||
|
|
||||||
template compilationCachePresent*(conf: ConfigRef): untyped =
|
template compilationCachePresent*(conf: ConfigRef): untyped =
|
||||||
conf.symbolFiles in {v2Sf, writeOnlySf}
|
conf.symbolFiles in {v2Sf, writeOnlySf}
|
||||||
|
|
|
||||||
|
|
@ -179,11 +179,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
|
||||||
if graph.stopCompile(): break
|
if graph.stopCompile(): break
|
||||||
var n = parseTopLevelStmt(p)
|
var n = parseTopLevelStmt(p)
|
||||||
if n.kind == nkEmpty: break
|
if n.kind == nkEmpty: break
|
||||||
#if {sfNoForward, sfReorder} * module.flags != {}:
|
if {sfNoForward, sfReorder} * module.flags != {}:
|
||||||
when true:
|
|
||||||
# we now process the full AST in one go, so that destructor injection for top
|
|
||||||
# level statements works correctly.
|
|
||||||
if graph.stopCompile(): break
|
|
||||||
# read everything, no streaming possible
|
# read everything, no streaming possible
|
||||||
var sl = newNodeI(nkStmtList, n.info)
|
var sl = newNodeI(nkStmtList, n.info)
|
||||||
sl.add n
|
sl.add n
|
||||||
|
|
@ -195,7 +191,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {
|
||||||
sl = reorder(graph, sl, module)
|
sl = reorder(graph, sl, module)
|
||||||
discard processTopLevelStmt(sl, a)
|
discard processTopLevelStmt(sl, a)
|
||||||
break
|
break
|
||||||
#elif not processTopLevelStmt(n, a): break
|
elif not processTopLevelStmt(n, a): break
|
||||||
closeParsers(p)
|
closeParsers(p)
|
||||||
if s.kind != llsStdIn: break
|
if s.kind != llsStdIn: break
|
||||||
closePasses(graph, a)
|
closePasses(graph, a)
|
||||||
|
|
|
||||||
|
|
@ -3264,6 +3264,7 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
{.push stack_trace: off, profiler:off.}
|
{.push stack_trace: off, profiler:off.}
|
||||||
when hasAlloc: include "system/sysstr"
|
when hasAlloc: include "system/sysstr"
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
when hasAlloc: include "system/strmantle"
|
||||||
|
|
||||||
when hostOS != "standalone": include "system/sysio"
|
when hostOS != "standalone": include "system/sysio"
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
|
|
|
||||||
293
lib/system/strmantle.nim
Normal file
293
lib/system/strmantle.nim
Normal file
|
|
@ -0,0 +1,293 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nim's Runtime Library
|
||||||
|
# (c) Copyright 2018 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Compilerprocs for strings that do not depend on the string implementation.
|
||||||
|
|
||||||
|
proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
|
||||||
|
if a == b: return 0
|
||||||
|
when defined(nimNoNil):
|
||||||
|
let alen = if a == nil: 0 else: a.len
|
||||||
|
let blen = if b == nil: 0 else: b.len
|
||||||
|
else:
|
||||||
|
if a == nil: return -1
|
||||||
|
if b == nil: return 1
|
||||||
|
let alen = a.len
|
||||||
|
let blen = b.len
|
||||||
|
let minlen = min(alen, blen)
|
||||||
|
if minlen > 0:
|
||||||
|
result = c_memcmp(addr a.data, addr b.data, minlen.csize)
|
||||||
|
if result == 0:
|
||||||
|
result = alen - blen
|
||||||
|
else:
|
||||||
|
result = alen - blen
|
||||||
|
|
||||||
|
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
||||||
|
if a == b: return true
|
||||||
|
when defined(nimNoNil):
|
||||||
|
let alen = if a == nil: 0 else: a.len
|
||||||
|
let blen = if b == nil: 0 else: b.len
|
||||||
|
else:
|
||||||
|
if a == nil or b == nil: return false
|
||||||
|
let alen = a.len
|
||||||
|
let blen = b.len
|
||||||
|
if alen == blen:
|
||||||
|
if alen == 0: return true
|
||||||
|
return equalMem(addr(a.data), addr(b.data), alen)
|
||||||
|
|
||||||
|
proc hashString(s: string): int {.compilerproc.} =
|
||||||
|
# the compiler needs exactly the same hash function!
|
||||||
|
# this used to be used for efficient generation of string case statements
|
||||||
|
var h = 0
|
||||||
|
for i in 0..len(s)-1:
|
||||||
|
h = h +% ord(s[i])
|
||||||
|
h = h +% h shl 10
|
||||||
|
h = h xor (h shr 6)
|
||||||
|
h = h +% h shl 3
|
||||||
|
h = h xor (h shr 11)
|
||||||
|
h = h +% h shl 15
|
||||||
|
result = h
|
||||||
|
|
||||||
|
proc add*(result: var string; x: int64) =
|
||||||
|
let base = result.len
|
||||||
|
setLen(result, base + sizeof(x)*4)
|
||||||
|
var i = 0
|
||||||
|
var y = x
|
||||||
|
while true:
|
||||||
|
var d = y div 10
|
||||||
|
result[base+i] = chr(abs(int(y - d*10)) + ord('0'))
|
||||||
|
inc(i)
|
||||||
|
y = d
|
||||||
|
if y == 0: break
|
||||||
|
if x < 0:
|
||||||
|
result[base+i] = '-'
|
||||||
|
inc(i)
|
||||||
|
setLen(result, base+i)
|
||||||
|
# mirror the string:
|
||||||
|
for j in 0..i div 2 - 1:
|
||||||
|
swap(result[base+j], result[base+i-j-1])
|
||||||
|
|
||||||
|
proc nimIntToStr(x: int): string {.compilerRtl.} =
|
||||||
|
result = newStringOfCap(sizeof(x)*4)
|
||||||
|
result.add x
|
||||||
|
|
||||||
|
proc add*(result: var string; x: float) =
|
||||||
|
when nimvm:
|
||||||
|
result.add $x
|
||||||
|
else:
|
||||||
|
var buf: array[0..64, char]
|
||||||
|
when defined(nimNoArrayToCstringConversion):
|
||||||
|
var n: int = c_sprintf(addr buf, "%.16g", x)
|
||||||
|
else:
|
||||||
|
var n: int = c_sprintf(buf, "%.16g", x)
|
||||||
|
var hasDot = false
|
||||||
|
for i in 0..n-1:
|
||||||
|
if buf[i] == ',':
|
||||||
|
buf[i] = '.'
|
||||||
|
hasDot = true
|
||||||
|
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
||||||
|
hasDot = true
|
||||||
|
if not hasDot:
|
||||||
|
buf[n] = '.'
|
||||||
|
buf[n+1] = '0'
|
||||||
|
buf[n+2] = '\0'
|
||||||
|
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN'
|
||||||
|
# of '-1.#IND' are produced.
|
||||||
|
# We want to get rid of these here:
|
||||||
|
if buf[n-1] in {'n', 'N', 'D', 'd'}:
|
||||||
|
result.add "nan"
|
||||||
|
elif buf[n-1] == 'F':
|
||||||
|
if buf[0] == '-':
|
||||||
|
result.add "-inf"
|
||||||
|
else:
|
||||||
|
result.add "inf"
|
||||||
|
else:
|
||||||
|
var i = 0
|
||||||
|
while buf[i] != '\0':
|
||||||
|
result.add buf[i]
|
||||||
|
inc i
|
||||||
|
|
||||||
|
proc nimFloatToStr(f: float): string {.compilerproc.} =
|
||||||
|
result = newStringOfCap(8)
|
||||||
|
result.add f
|
||||||
|
|
||||||
|
proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
|
||||||
|
importc: "strtod", header: "<stdlib.h>", noSideEffect.}
|
||||||
|
|
||||||
|
const
|
||||||
|
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
||||||
|
powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
||||||
|
1e20, 1e21, 1e22]
|
||||||
|
|
||||||
|
proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
|
start = 0): int {.compilerProc.} =
|
||||||
|
# This routine attempt to parse float that can parsed quickly.
|
||||||
|
# ie whose integer part can fit inside a 53bits integer.
|
||||||
|
# their real exponent must also be <= 22. If the float doesn't follow
|
||||||
|
# these restrictions, transform the float into this form:
|
||||||
|
# INTEGER * 10 ^ exponent and leave the work to standard `strtod()`.
|
||||||
|
# This avoid the problems of decimal character portability.
|
||||||
|
# see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||||
|
var
|
||||||
|
i = start
|
||||||
|
sign = 1.0
|
||||||
|
kdigits, fdigits = 0
|
||||||
|
exponent: int
|
||||||
|
integer: uint64
|
||||||
|
frac_exponent = 0
|
||||||
|
exp_sign = 1
|
||||||
|
first_digit = -1
|
||||||
|
has_sign = false
|
||||||
|
|
||||||
|
# Sign?
|
||||||
|
if s[i] == '+' or s[i] == '-':
|
||||||
|
has_sign = true
|
||||||
|
if s[i] == '-':
|
||||||
|
sign = -1.0
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
# NaN?
|
||||||
|
if s[i] == 'N' or s[i] == 'n':
|
||||||
|
if s[i+1] == 'A' or s[i+1] == 'a':
|
||||||
|
if s[i+2] == 'N' or s[i+2] == 'n':
|
||||||
|
if s[i+3] notin IdentChars:
|
||||||
|
number = NaN
|
||||||
|
return i+3 - start
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Inf?
|
||||||
|
if s[i] == 'I' or s[i] == 'i':
|
||||||
|
if s[i+1] == 'N' or s[i+1] == 'n':
|
||||||
|
if s[i+2] == 'F' or s[i+2] == 'f':
|
||||||
|
if s[i+3] notin IdentChars:
|
||||||
|
number = Inf*sign
|
||||||
|
return i+3 - start
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if s[i] in {'0'..'9'}:
|
||||||
|
first_digit = (s[i].ord - '0'.ord)
|
||||||
|
# Integer part?
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
inc(kdigits)
|
||||||
|
integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
|
||||||
|
# Fractional part?
|
||||||
|
if s[i] == '.':
|
||||||
|
inc(i)
|
||||||
|
# if no integer part, Skip leading zeros
|
||||||
|
if kdigits <= 0:
|
||||||
|
while s[i] == '0':
|
||||||
|
inc(frac_exponent)
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
|
||||||
|
if first_digit == -1 and s[i] in {'0'..'9'}:
|
||||||
|
first_digit = (s[i].ord - '0'.ord)
|
||||||
|
# get fractional part
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
inc(fdigits)
|
||||||
|
inc(frac_exponent)
|
||||||
|
integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
|
||||||
|
# if has no digits: return error
|
||||||
|
if kdigits + fdigits <= 0 and
|
||||||
|
(i == start or # no char consumed (empty string).
|
||||||
|
(i == start + 1 and has_sign)): # or only '+' or '-
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if s[i] in {'e', 'E'}:
|
||||||
|
inc(i)
|
||||||
|
if s[i] == '+' or s[i] == '-':
|
||||||
|
if s[i] == '-':
|
||||||
|
exp_sign = -1
|
||||||
|
|
||||||
|
inc(i)
|
||||||
|
if s[i] notin {'0'..'9'}:
|
||||||
|
return 0
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
exponent = exponent * 10 + (ord(s[i]) - ord('0'))
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
|
|
||||||
|
var real_exponent = exp_sign*exponent - frac_exponent
|
||||||
|
let exp_negative = real_exponent < 0
|
||||||
|
var abs_exponent = abs(real_exponent)
|
||||||
|
|
||||||
|
# if exponent greater than can be represented: +/- zero or infinity
|
||||||
|
if abs_exponent > 999:
|
||||||
|
if exp_negative:
|
||||||
|
number = 0.0*sign
|
||||||
|
else:
|
||||||
|
number = Inf*sign
|
||||||
|
return i - start
|
||||||
|
|
||||||
|
# if integer is representable in 53 bits: fast path
|
||||||
|
# max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits)
|
||||||
|
let digits = kdigits + fdigits
|
||||||
|
if digits <= 15 or (digits <= 16 and first_digit <= 8):
|
||||||
|
# max float power of ten with set bits above the 53th bit is 10^22
|
||||||
|
if abs_exponent <= 22:
|
||||||
|
if exp_negative:
|
||||||
|
number = sign * integer.float / powtens[abs_exponent]
|
||||||
|
else:
|
||||||
|
number = sign * integer.float * powtens[abs_exponent]
|
||||||
|
return i - start
|
||||||
|
|
||||||
|
# if exponent is greater try to fit extra exponent above 22 by multiplying
|
||||||
|
# integer part is there is space left.
|
||||||
|
let slop = 15 - kdigits - fdigits
|
||||||
|
if abs_exponent <= 22 + slop and not exp_negative:
|
||||||
|
number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop]
|
||||||
|
return i - start
|
||||||
|
|
||||||
|
# if failed: slow path with strtod.
|
||||||
|
var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
||||||
|
var ti = 0
|
||||||
|
let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
||||||
|
|
||||||
|
result = i - start
|
||||||
|
i = start
|
||||||
|
# re-parse without error checking, any error should be handled by the code above.
|
||||||
|
if s[i] == '.': i.inc
|
||||||
|
while s[i] in {'0'..'9','+','-'}:
|
||||||
|
if ti < maxlen:
|
||||||
|
t[ti] = s[i]; inc(ti)
|
||||||
|
inc(i)
|
||||||
|
while s[i] in {'.', '_'}: # skip underscore and decimal point
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
# insert exponent
|
||||||
|
t[ti] = 'E'; inc(ti)
|
||||||
|
t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
|
||||||
|
inc(ti, 3)
|
||||||
|
|
||||||
|
# insert adjusted exponent
|
||||||
|
t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
|
||||||
|
t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
|
||||||
|
t[ti-3] = ('0'.ord + abs_exponent mod 10).char
|
||||||
|
|
||||||
|
when defined(nimNoArrayToCstringConversion):
|
||||||
|
number = c_strtod(addr t, nil)
|
||||||
|
else:
|
||||||
|
number = c_strtod(t, nil)
|
||||||
|
|
||||||
|
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
|
||||||
|
result = newStringOfCap(sizeof(x)*4)
|
||||||
|
result.add x
|
||||||
|
|
||||||
|
proc nimBoolToStr(x: bool): string {.compilerRtl.} =
|
||||||
|
return if x: "true" else: "false"
|
||||||
|
|
||||||
|
proc nimCharToStr(x: char): string {.compilerRtl.} =
|
||||||
|
result = newString(1)
|
||||||
|
result[0] = x
|
||||||
|
|
@ -20,37 +20,6 @@ proc resize(old: int): int {.inline.} =
|
||||||
elif old < 65536: result = old * 2
|
elif old < 65536: result = old * 2
|
||||||
else: result = old * 3 div 2 # for large arrays * 3/2 is better
|
else: result = old * 3 div 2 # for large arrays * 3/2 is better
|
||||||
|
|
||||||
proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
|
|
||||||
if a == b: return 0
|
|
||||||
when defined(nimNoNil):
|
|
||||||
let alen = if a == nil: 0 else: a.len
|
|
||||||
let blen = if b == nil: 0 else: b.len
|
|
||||||
else:
|
|
||||||
if a == nil: return -1
|
|
||||||
if b == nil: return 1
|
|
||||||
let alen = a.len
|
|
||||||
let blen = b.len
|
|
||||||
let minlen = min(alen, blen)
|
|
||||||
if minlen > 0:
|
|
||||||
result = c_memcmp(addr a.data, addr b.data, minlen.csize)
|
|
||||||
if result == 0:
|
|
||||||
result = alen - blen
|
|
||||||
else:
|
|
||||||
result = alen - blen
|
|
||||||
|
|
||||||
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
|
||||||
if a == b: return true
|
|
||||||
when defined(nimNoNil):
|
|
||||||
let alen = if a == nil: 0 else: a.len
|
|
||||||
let blen = if b == nil: 0 else: b.len
|
|
||||||
else:
|
|
||||||
if a == nil or b == nil: return false
|
|
||||||
let alen = a.len
|
|
||||||
let blen = b.len
|
|
||||||
if alen == blen:
|
|
||||||
if alen == 0: return true
|
|
||||||
return equalMem(addr(a.data), addr(b.data), alen)
|
|
||||||
|
|
||||||
when declared(allocAtomic):
|
when declared(allocAtomic):
|
||||||
template allocStr(size: untyped): untyped =
|
template allocStr(size: untyped): untyped =
|
||||||
cast[NimString](allocAtomic(size))
|
cast[NimString](allocAtomic(size))
|
||||||
|
|
@ -162,19 +131,6 @@ proc copyDeepString(src: NimString): NimString {.inline.} =
|
||||||
result.len = src.len
|
result.len = src.len
|
||||||
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
||||||
|
|
||||||
proc hashString(s: string): int {.compilerproc.} =
|
|
||||||
# the compiler needs exactly the same hash function!
|
|
||||||
# this used to be used for efficient generation of string case statements
|
|
||||||
var h = 0
|
|
||||||
for i in 0..len(s)-1:
|
|
||||||
h = h +% ord(s[i])
|
|
||||||
h = h +% h shl 10
|
|
||||||
h = h xor (h shr 6)
|
|
||||||
h = h +% h shl 3
|
|
||||||
h = h xor (h shr 11)
|
|
||||||
h = h +% h shl 15
|
|
||||||
result = h
|
|
||||||
|
|
||||||
proc addChar(s: NimString, c: char): NimString =
|
proc addChar(s: NimString, c: char): NimString =
|
||||||
# is compilerproc!
|
# is compilerproc!
|
||||||
if s == nil:
|
if s == nil:
|
||||||
|
|
@ -246,7 +202,7 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} =
|
||||||
inc(dest.len)
|
inc(dest.len)
|
||||||
|
|
||||||
proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
||||||
var n = max(newLen, 0)
|
let n = max(newLen, 0)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
result = mnewString(newLen)
|
result = mnewString(newLen)
|
||||||
elif n <= s.space:
|
elif n <= s.space:
|
||||||
|
|
@ -340,243 +296,3 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||||
result = cast[PGenericSeq](newSeq(typ, newLen))
|
result = cast[PGenericSeq](newSeq(typ, newLen))
|
||||||
else:
|
else:
|
||||||
result = setLengthSeq(s, typ.base.size, newLen)
|
result = setLengthSeq(s, typ.base.size, newLen)
|
||||||
|
|
||||||
# --------------- other string routines ----------------------------------
|
|
||||||
proc add*(result: var string; x: int64) =
|
|
||||||
let base = result.len
|
|
||||||
setLen(result, base + sizeof(x)*4)
|
|
||||||
var i = 0
|
|
||||||
var y = x
|
|
||||||
while true:
|
|
||||||
var d = y div 10
|
|
||||||
result[base+i] = chr(abs(int(y - d*10)) + ord('0'))
|
|
||||||
inc(i)
|
|
||||||
y = d
|
|
||||||
if y == 0: break
|
|
||||||
if x < 0:
|
|
||||||
result[base+i] = '-'
|
|
||||||
inc(i)
|
|
||||||
setLen(result, base+i)
|
|
||||||
# mirror the string:
|
|
||||||
for j in 0..i div 2 - 1:
|
|
||||||
swap(result[base+j], result[base+i-j-1])
|
|
||||||
|
|
||||||
proc nimIntToStr(x: int): string {.compilerRtl.} =
|
|
||||||
result = newStringOfCap(sizeof(x)*4)
|
|
||||||
result.add x
|
|
||||||
|
|
||||||
proc add*(result: var string; x: float) =
|
|
||||||
when nimvm:
|
|
||||||
result.add $x
|
|
||||||
else:
|
|
||||||
var buf: array[0..64, char]
|
|
||||||
when defined(nimNoArrayToCstringConversion):
|
|
||||||
var n: int = c_sprintf(addr buf, "%.16g", x)
|
|
||||||
else:
|
|
||||||
var n: int = c_sprintf(buf, "%.16g", x)
|
|
||||||
var hasDot = false
|
|
||||||
for i in 0..n-1:
|
|
||||||
if buf[i] == ',':
|
|
||||||
buf[i] = '.'
|
|
||||||
hasDot = true
|
|
||||||
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
|
||||||
hasDot = true
|
|
||||||
if not hasDot:
|
|
||||||
buf[n] = '.'
|
|
||||||
buf[n+1] = '0'
|
|
||||||
buf[n+2] = '\0'
|
|
||||||
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN'
|
|
||||||
# of '-1.#IND' are produced.
|
|
||||||
# We want to get rid of these here:
|
|
||||||
if buf[n-1] in {'n', 'N', 'D', 'd'}:
|
|
||||||
result.add "nan"
|
|
||||||
elif buf[n-1] == 'F':
|
|
||||||
if buf[0] == '-':
|
|
||||||
result.add "-inf"
|
|
||||||
else:
|
|
||||||
result.add "inf"
|
|
||||||
else:
|
|
||||||
var i = 0
|
|
||||||
while buf[i] != '\0':
|
|
||||||
result.add buf[i]
|
|
||||||
inc i
|
|
||||||
|
|
||||||
proc nimFloatToStr(f: float): string {.compilerproc.} =
|
|
||||||
result = newStringOfCap(8)
|
|
||||||
result.add f
|
|
||||||
|
|
||||||
proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
|
|
||||||
importc: "strtod", header: "<stdlib.h>", noSideEffect.}
|
|
||||||
|
|
||||||
const
|
|
||||||
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
|
||||||
powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
|
||||||
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
|
||||||
1e20, 1e21, 1e22]
|
|
||||||
|
|
||||||
proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
|
||||||
start = 0): int {.compilerProc.} =
|
|
||||||
# This routine attempt to parse float that can parsed quickly.
|
|
||||||
# ie whose integer part can fit inside a 53bits integer.
|
|
||||||
# their real exponent must also be <= 22. If the float doesn't follow
|
|
||||||
# these restrictions, transform the float into this form:
|
|
||||||
# INTEGER * 10 ^ exponent and leave the work to standard `strtod()`.
|
|
||||||
# This avoid the problems of decimal character portability.
|
|
||||||
# see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
|
||||||
var
|
|
||||||
i = start
|
|
||||||
sign = 1.0
|
|
||||||
kdigits, fdigits = 0
|
|
||||||
exponent: int
|
|
||||||
integer: uint64
|
|
||||||
frac_exponent = 0
|
|
||||||
exp_sign = 1
|
|
||||||
first_digit = -1
|
|
||||||
has_sign = false
|
|
||||||
|
|
||||||
# Sign?
|
|
||||||
if s[i] == '+' or s[i] == '-':
|
|
||||||
has_sign = true
|
|
||||||
if s[i] == '-':
|
|
||||||
sign = -1.0
|
|
||||||
inc(i)
|
|
||||||
|
|
||||||
# NaN?
|
|
||||||
if s[i] == 'N' or s[i] == 'n':
|
|
||||||
if s[i+1] == 'A' or s[i+1] == 'a':
|
|
||||||
if s[i+2] == 'N' or s[i+2] == 'n':
|
|
||||||
if s[i+3] notin IdentChars:
|
|
||||||
number = NaN
|
|
||||||
return i+3 - start
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# Inf?
|
|
||||||
if s[i] == 'I' or s[i] == 'i':
|
|
||||||
if s[i+1] == 'N' or s[i+1] == 'n':
|
|
||||||
if s[i+2] == 'F' or s[i+2] == 'f':
|
|
||||||
if s[i+3] notin IdentChars:
|
|
||||||
number = Inf*sign
|
|
||||||
return i+3 - start
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if s[i] in {'0'..'9'}:
|
|
||||||
first_digit = (s[i].ord - '0'.ord)
|
|
||||||
# Integer part?
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
inc(kdigits)
|
|
||||||
integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i)
|
|
||||||
|
|
||||||
# Fractional part?
|
|
||||||
if s[i] == '.':
|
|
||||||
inc(i)
|
|
||||||
# if no integer part, Skip leading zeros
|
|
||||||
if kdigits <= 0:
|
|
||||||
while s[i] == '0':
|
|
||||||
inc(frac_exponent)
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i)
|
|
||||||
|
|
||||||
if first_digit == -1 and s[i] in {'0'..'9'}:
|
|
||||||
first_digit = (s[i].ord - '0'.ord)
|
|
||||||
# get fractional part
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
inc(fdigits)
|
|
||||||
inc(frac_exponent)
|
|
||||||
integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i)
|
|
||||||
|
|
||||||
# if has no digits: return error
|
|
||||||
if kdigits + fdigits <= 0 and
|
|
||||||
(i == start or # no char consumed (empty string).
|
|
||||||
(i == start + 1 and has_sign)): # or only '+' or '-
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if s[i] in {'e', 'E'}:
|
|
||||||
inc(i)
|
|
||||||
if s[i] == '+' or s[i] == '-':
|
|
||||||
if s[i] == '-':
|
|
||||||
exp_sign = -1
|
|
||||||
|
|
||||||
inc(i)
|
|
||||||
if s[i] notin {'0'..'9'}:
|
|
||||||
return 0
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
exponent = exponent * 10 + (ord(s[i]) - ord('0'))
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
|
||||||
|
|
||||||
var real_exponent = exp_sign*exponent - frac_exponent
|
|
||||||
let exp_negative = real_exponent < 0
|
|
||||||
var abs_exponent = abs(real_exponent)
|
|
||||||
|
|
||||||
# if exponent greater than can be represented: +/- zero or infinity
|
|
||||||
if abs_exponent > 999:
|
|
||||||
if exp_negative:
|
|
||||||
number = 0.0*sign
|
|
||||||
else:
|
|
||||||
number = Inf*sign
|
|
||||||
return i - start
|
|
||||||
|
|
||||||
# if integer is representable in 53 bits: fast path
|
|
||||||
# max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits)
|
|
||||||
let digits = kdigits + fdigits
|
|
||||||
if digits <= 15 or (digits <= 16 and first_digit <= 8):
|
|
||||||
# max float power of ten with set bits above the 53th bit is 10^22
|
|
||||||
if abs_exponent <= 22:
|
|
||||||
if exp_negative:
|
|
||||||
number = sign * integer.float / powtens[abs_exponent]
|
|
||||||
else:
|
|
||||||
number = sign * integer.float * powtens[abs_exponent]
|
|
||||||
return i - start
|
|
||||||
|
|
||||||
# if exponent is greater try to fit extra exponent above 22 by multiplying
|
|
||||||
# integer part is there is space left.
|
|
||||||
let slop = 15 - kdigits - fdigits
|
|
||||||
if abs_exponent <= 22 + slop and not exp_negative:
|
|
||||||
number = sign * integer.float * powtens[slop] * powtens[abs_exponent-slop]
|
|
||||||
return i - start
|
|
||||||
|
|
||||||
# if failed: slow path with strtod.
|
|
||||||
var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
|
||||||
var ti = 0
|
|
||||||
let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
|
||||||
|
|
||||||
result = i - start
|
|
||||||
i = start
|
|
||||||
# re-parse without error checking, any error should be handled by the code above.
|
|
||||||
if s[i] == '.': i.inc
|
|
||||||
while s[i] in {'0'..'9','+','-'}:
|
|
||||||
if ti < maxlen:
|
|
||||||
t[ti] = s[i]; inc(ti)
|
|
||||||
inc(i)
|
|
||||||
while s[i] in {'.', '_'}: # skip underscore and decimal point
|
|
||||||
inc(i)
|
|
||||||
|
|
||||||
# insert exponent
|
|
||||||
t[ti] = 'E'; inc(ti)
|
|
||||||
t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
|
|
||||||
inc(ti, 3)
|
|
||||||
|
|
||||||
# insert adjusted exponent
|
|
||||||
t[ti-1] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
|
|
||||||
t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
|
|
||||||
t[ti-3] = ('0'.ord + abs_exponent mod 10).char
|
|
||||||
|
|
||||||
when defined(nimNoArrayToCstringConversion):
|
|
||||||
number = c_strtod(addr t, nil)
|
|
||||||
else:
|
|
||||||
number = c_strtod(t, nil)
|
|
||||||
|
|
||||||
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
|
|
||||||
result = newStringOfCap(sizeof(x)*4)
|
|
||||||
result.add x
|
|
||||||
|
|
||||||
proc nimBoolToStr(x: bool): string {.compilerRtl.} =
|
|
||||||
return if x: "true" else: "false"
|
|
||||||
|
|
||||||
proc nimCharToStr(x: char): string {.compilerRtl.} =
|
|
||||||
result = newString(1)
|
|
||||||
result[0] = x
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue