--gc:destructors: next steps; WIP
This commit is contained in:
parent
4389409e26
commit
f485ebe162
8 changed files with 108 additions and 64 deletions
|
|
@ -256,8 +256,8 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
# (for objects, etc.):
|
# (for objects, etc.):
|
||||||
if p.config.selectedGC == gcDestructors:
|
if p.config.selectedGC == gcDestructors:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
"$1.len = $2.len; $1.p = $2.p;$n",
|
||||||
addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest))
|
rdLoc(dest), rdLoc(src))
|
||||||
elif needToCopy notin flags or
|
elif needToCopy notin flags or
|
||||||
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
||||||
if dest.storage == OnStack or not usesWriteBarrier(p.config):
|
if dest.storage == OnStack or not usesWriteBarrier(p.config):
|
||||||
|
|
@ -1512,28 +1512,19 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
|
if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
|
||||||
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
|
else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
|
||||||
of tyString:
|
of tyString:
|
||||||
if not p.module.compileToCpp:
|
var a: TLoc
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
|
initLocExpr(p, e.sons[1], a)
|
||||||
else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
|
var x = lenExpr(p, a)
|
||||||
else:
|
if op == mHigh: x = "($1-1)" % [x]
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
|
putIntoDest(p, d, e, x)
|
||||||
else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
|
|
||||||
of tySequence:
|
of tySequence:
|
||||||
|
# we go through a temporary here because people write bullshit code.
|
||||||
var a, tmp: TLoc
|
var a, tmp: TLoc
|
||||||
initLocExpr(p, e[1], a)
|
initLocExpr(p, e[1], a)
|
||||||
getIntTemp(p, tmp)
|
getIntTemp(p, tmp)
|
||||||
var frmt: FormatStr
|
var x = lenExpr(p, a)
|
||||||
if not p.module.compileToCpp:
|
if op == mHigh: x = "($1-1)" % [x]
|
||||||
if op == mHigh:
|
lineCg(p, cpsStmts, "$1 = $2;$n", tmp.r, x)
|
||||||
frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n"
|
|
||||||
else:
|
|
||||||
frmt = "$1 = ($2 ? $2->Sup.len : 0);$n"
|
|
||||||
else:
|
|
||||||
if op == mHigh:
|
|
||||||
frmt = "$1 = ($2 ? ($2->len-1) : -1);$n"
|
|
||||||
else:
|
|
||||||
frmt = "$1 = ($2 ? $2->len : 0);$n"
|
|
||||||
lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
|
|
||||||
putIntoDest(p, d, e, tmp.r)
|
putIntoDest(p, d, e, tmp.r)
|
||||||
of tyArray:
|
of tyArray:
|
||||||
# YYY: length(sideeffect) is optimized away incorrectly?
|
# YYY: length(sideeffect) is optimized away incorrectly?
|
||||||
|
|
@ -1889,7 +1880,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
else:
|
else:
|
||||||
binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
|
binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
|
||||||
of mAppendStrStr: genStrAppend(p, e, d)
|
of mAppendStrStr: genStrAppend(p, e, d)
|
||||||
of mAppendSeqElem: genSeqElemAppend(p, e, d)
|
of mAppendSeqElem:
|
||||||
|
if p.config.selectedGc == gcDestructors:
|
||||||
|
genCall(p, e, d)
|
||||||
|
else:
|
||||||
|
genSeqElemAppend(p, e, d)
|
||||||
of mEqStr: genStrEquals(p, e, d)
|
of mEqStr: genStrEquals(p, e, d)
|
||||||
of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
|
of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
|
||||||
of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
|
of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
|
||||||
|
|
@ -2537,6 +2532,13 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
|
||||||
result = genConstSimpleList(p, n)
|
result = genConstSimpleList(p, n)
|
||||||
of nkObjConstr:
|
of nkObjConstr:
|
||||||
result = genConstObjConstr(p, n)
|
result = genConstObjConstr(p, n)
|
||||||
|
of nkStrLit..nkTripleStrLit:
|
||||||
|
if p.config.selectedGc == gcDestructors:
|
||||||
|
result = genStringLiteralV2Const(p.module, n)
|
||||||
|
else:
|
||||||
|
var d: TLoc
|
||||||
|
initLocExpr(p, n, d)
|
||||||
|
result = rdLoc(d)
|
||||||
else:
|
else:
|
||||||
var d: TLoc
|
var d: TLoc
|
||||||
initLocExpr(p, n, d)
|
initLocExpr(p, n, d)
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =
|
||||||
proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
|
proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
|
||||||
result = getTempName(m)
|
result = getTempName(m)
|
||||||
addf(m.s[cfsData], "static const struct {$n" &
|
addf(m.s[cfsData], "static const struct {$n" &
|
||||||
" NI cap; void* allocator; NIM_CHAR[$2] data;$n" &
|
" NI cap; void* allocator; NIM_CHAR data[$2];$n" &
|
||||||
"} $1 = { $2, NIM_NIL, $3 };$n",
|
"} $1 = { $2, NIM_NIL, $3 };$n",
|
||||||
[result, rope(len(s)+1), makeCString(s)])
|
[result, rope(len(s)), makeCString(s)])
|
||||||
|
|
||||||
proc genStringLiteralV2(m: BModule; n: PNode): Rope =
|
proc genStringLiteralV2(m: BModule; n: PNode): Rope =
|
||||||
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||||
|
|
@ -67,10 +67,22 @@ proc genStringLiteralV2(m: BModule; n: PNode): Rope =
|
||||||
let pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
|
let pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
|
||||||
result = getTempName(m)
|
result = getTempName(m)
|
||||||
addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
|
addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
|
||||||
[result, rope(len(n.strVal)+1), pureLit])
|
[result, rope(len(n.strVal)), pureLit])
|
||||||
else:
|
else:
|
||||||
result = m.tmpBase & rope(id)
|
result = m.tmpBase & rope(id)
|
||||||
|
|
||||||
|
proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
|
||||||
|
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||||
|
var pureLit: Rope
|
||||||
|
if id == m.labels:
|
||||||
|
discard cgsym(m, "NimStrPayload")
|
||||||
|
discard cgsym(m, "NimStringV2")
|
||||||
|
# string literal not found in the cache:
|
||||||
|
pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
|
||||||
|
else:
|
||||||
|
pureLit = m.tmpBase & rope(id)
|
||||||
|
result = "{$1, (NimStrPayload*)&$2}" % [rope(len(n.strVal)), pureLit]
|
||||||
|
|
||||||
# ------ Version selector ---------------------------------------------------
|
# ------ Version selector ---------------------------------------------------
|
||||||
|
|
||||||
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
|
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## Generates traversal procs for the C backend. Traversal procs are only an
|
## Generates traversal procs for the C backend.
|
||||||
## optimization; the GC works without them too.
|
|
||||||
|
|
||||||
# included from cgen.nim
|
# included from cgen.nim
|
||||||
|
|
||||||
|
|
@ -61,6 +60,7 @@ proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
|
||||||
else:
|
else:
|
||||||
result = accessor
|
result = accessor
|
||||||
|
|
||||||
|
proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType)
|
||||||
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||||
if typ == nil: return
|
if typ == nil: return
|
||||||
|
|
||||||
|
|
@ -93,8 +93,18 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
|
||||||
let typ = getUniqueType(typ)
|
let typ = getUniqueType(typ)
|
||||||
for i in countup(0, sonsLen(typ) - 1):
|
for i in countup(0, sonsLen(typ) - 1):
|
||||||
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
|
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
|
||||||
of tyRef, tyString, tySequence:
|
of tyRef:
|
||||||
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
|
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
|
||||||
|
of tySequence:
|
||||||
|
if tfHasAsgn notin typ.flags:
|
||||||
|
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
|
||||||
|
elif containsGarbageCollectedRef(typ.lastSon):
|
||||||
|
# destructor based seqs are themselves not traced but their data is, if
|
||||||
|
# they contain a GC'ed type:
|
||||||
|
genTraverseProcSeq(c, accessor, typ)
|
||||||
|
of tyString:
|
||||||
|
if tfHasAsgn notin typ.flags:
|
||||||
|
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if typ.callConv == ccClosure:
|
if typ.callConv == ccClosure:
|
||||||
lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor))
|
lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor))
|
||||||
|
|
|
||||||
|
|
@ -359,8 +359,11 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||||
result = getTypeForward(m, t, hashType(t))
|
result = getTypeForward(m, t, hashType(t))
|
||||||
pushType(m, t)
|
pushType(m, t)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
result = getTypeForward(m, t, hashType(t)) & seqStar(m)
|
if m.config.selectedGC == gcDestructors:
|
||||||
pushType(m, t)
|
result = getTypeDescAux(m, t, check)
|
||||||
|
else:
|
||||||
|
result = getTypeForward(m, t, hashType(t)) & seqStar(m)
|
||||||
|
pushType(m, t)
|
||||||
else:
|
else:
|
||||||
result = getTypeDescAux(m, t, check)
|
result = getTypeDescAux(m, t, check)
|
||||||
|
|
||||||
|
|
@ -491,7 +494,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||||
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||||
elif fieldType.kind == tySequence:
|
elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
|
||||||
# we need to use a weak dependency here for trecursive_table.
|
# we need to use a weak dependency here for trecursive_table.
|
||||||
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
||||||
elif field.bitsize != 0:
|
elif field.bitsize != 0:
|
||||||
|
|
@ -606,12 +609,13 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
|
||||||
else: result.elemType
|
else: result.elemType
|
||||||
|
|
||||||
proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
proc getSeqPayloadType(m: BModule; t: PType): Rope =
|
||||||
var check = initIntSet()
|
result = getTypeForward(m, t, hashType(t)) & "_Content"
|
||||||
result = getTypeForward(m, t, hashType(t))
|
when false:
|
||||||
# XXX remove this duplication:
|
var check = initIntSet()
|
||||||
appcg(m, m.s[cfsSeqTypes],
|
# XXX remove this duplication:
|
||||||
"struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE];$n } ",
|
appcg(m, m.s[cfsSeqTypes],
|
||||||
[getTypeDescAux(m, t.sons[0], check), result])
|
"struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE]; };$n",
|
||||||
|
[getTypeDescAux(m, t.sons[0], check), result])
|
||||||
|
|
||||||
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
# returns only the type's name
|
# returns only the type's name
|
||||||
|
|
@ -725,11 +729,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
cSeq = "struct $2 {$n" &
|
cSeq = "struct $2 {$n" &
|
||||||
" #TGenericSeq Sup;$n"
|
" #TGenericSeq Sup;$n"
|
||||||
if m.config.selectedGC == gcDestructors:
|
if m.config.selectedGC == gcDestructors:
|
||||||
appcg(m, m.s[cfsSeqTypes],
|
appcg(m, m.s[cfsTypes],
|
||||||
"struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE];$n } " &
|
"typedef struct{ NI cap;void* allocator;$1 data[SEQ_DECL_SIZE];}$2_Content;$n" &
|
||||||
"struct $2 {$n" &
|
"struct $2 {$n" &
|
||||||
" NI len; $2_Content* p;$n" &
|
" NI len; $2_Content* p;$n" &
|
||||||
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||||
else:
|
else:
|
||||||
appcg(m, m.s[cfsSeqTypes],
|
appcg(m, m.s[cfsSeqTypes],
|
||||||
(if m.compileToCpp: cppSeq else: cSeq) &
|
(if m.compileToCpp: cppSeq else: cSeq) &
|
||||||
|
|
@ -1198,7 +1202,13 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||||
else:
|
else:
|
||||||
let x = fakeClosureType(m, t.owner)
|
let x = fakeClosureType(m, t.owner)
|
||||||
genTupleInfo(m, x, x, result, info)
|
genTupleInfo(m, x, x, result, info)
|
||||||
of tySequence, tyRef, tyOptAsRef:
|
of tySequence:
|
||||||
|
if tfHasAsgn notin t.flags:
|
||||||
|
genTypeInfoAux(m, t, t, result, info)
|
||||||
|
if m.config.selectedGC >= gcMarkAndSweep:
|
||||||
|
let markerProc = genTraverseProc(m, origType, sig)
|
||||||
|
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
|
||||||
|
of tyRef, tyOptAsRef:
|
||||||
genTypeInfoAux(m, t, t, result, info)
|
genTypeInfoAux(m, t, t, result, info)
|
||||||
if m.config.selectedGC >= gcMarkAndSweep:
|
if m.config.selectedGC >= gcMarkAndSweep:
|
||||||
let markerProc = genTraverseProc(m, origType, sig)
|
let markerProc = genTraverseProc(m, origType, sig)
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,9 @@ proc resetLoc(p: BProc, loc: var TLoc) =
|
||||||
|
|
||||||
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
|
proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
|
||||||
let typ = loc.t
|
let typ = loc.t
|
||||||
if not isComplexValueType(typ):
|
if p.config.selectedGc == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
|
||||||
|
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", rdLoc(loc))
|
||||||
|
elif not isComplexValueType(typ):
|
||||||
linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
|
linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
|
||||||
getTypeDesc(p.module, typ))
|
getTypeDesc(p.module, typ))
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1519,7 +1519,13 @@ when not defined(JS) and not defined(nimscript) and hostOS != "standalone":
|
||||||
when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(gcDestructors):
|
when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(gcDestructors):
|
||||||
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
|
proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
|
||||||
|
|
||||||
proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
when defined(gcDestructors):
|
||||||
|
proc add*[T](x: var seq[T], y: sink T) {.magic: "AppendSeqElem", noSideEffect.} =
|
||||||
|
let xl = x.len
|
||||||
|
setLen(x, xl + 1)
|
||||||
|
x[xl] = y
|
||||||
|
else:
|
||||||
|
proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
|
||||||
proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
proc add*[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
||||||
## Generic proc for adding a data item `y` to a container `x`.
|
## Generic proc for adding a data item `y` to a container `x`.
|
||||||
## For containers that have an order, `add` means *append*. New generic
|
## For containers that have an order, `add` means *append*. New generic
|
||||||
|
|
@ -3856,7 +3862,7 @@ proc shallow*(s: var string) {.noSideEffect, inline.} =
|
||||||
## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
## perform deep copies of `s`. This is only useful for optimization
|
## perform deep copies of `s`. This is only useful for optimization
|
||||||
## purposes.
|
## purposes.
|
||||||
when not defined(JS) and not defined(nimscript):
|
when not defined(JS) and not defined(nimscript) and not defined(gcDestructors):
|
||||||
var s = cast[PGenericSeq](s)
|
var s = cast[PGenericSeq](s)
|
||||||
# string literals cannot become 'shallow':
|
# string literals cannot become 'shallow':
|
||||||
if (s.reserved and strlitFlag) == 0:
|
if (s.reserved and strlitFlag) == 0:
|
||||||
|
|
@ -4031,7 +4037,9 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
|
||||||
## # -> B is 1
|
## # -> B is 1
|
||||||
discard
|
discard
|
||||||
|
|
||||||
when hasAlloc and not defined(nimscript) and not defined(JS):
|
when hasAlloc and not defined(nimscript) and not defined(JS) and
|
||||||
|
not defined(gcDestructors):
|
||||||
|
# XXX how to implement 'deepCopy' is an open problem.
|
||||||
proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
|
proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
|
||||||
## performs a deep copy of `y` and copies it into `x`.
|
## performs a deep copy of `y` and copies it into `x`.
|
||||||
## This is also used by the code generator
|
## This is also used by the code generator
|
||||||
|
|
|
||||||
|
|
@ -25,24 +25,6 @@ proc reprPointer(x: pointer): string {.compilerproc.} =
|
||||||
discard c_sprintf(buf, "%p", x)
|
discard c_sprintf(buf, "%p", x)
|
||||||
return $buf
|
return $buf
|
||||||
|
|
||||||
proc `$`(x: uint64): string =
|
|
||||||
if x == 0:
|
|
||||||
result = "0"
|
|
||||||
else:
|
|
||||||
result = newString(60)
|
|
||||||
var i = 0
|
|
||||||
var n = x
|
|
||||||
while n != 0:
|
|
||||||
let nn = n div 10'u64
|
|
||||||
result[i] = char(n - 10'u64 * nn + ord('0'))
|
|
||||||
inc i
|
|
||||||
n = nn
|
|
||||||
result.setLen i
|
|
||||||
|
|
||||||
let half = i div 2
|
|
||||||
# Reverse
|
|
||||||
for t in 0 .. half-1: swap(result[t], result[i-t-1])
|
|
||||||
|
|
||||||
proc reprStrAux(result: var string, s: cstring; len: int) =
|
proc reprStrAux(result: var string, s: cstring; len: int) =
|
||||||
if cast[pointer](s) == nil:
|
if cast[pointer](s) == nil:
|
||||||
add result, "nil"
|
add result, "nil"
|
||||||
|
|
|
||||||
|
|
@ -278,3 +278,21 @@ proc nimBoolToStr(x: bool): string {.compilerRtl.} =
|
||||||
proc nimCharToStr(x: char): string {.compilerRtl.} =
|
proc nimCharToStr(x: char): string {.compilerRtl.} =
|
||||||
result = newString(1)
|
result = newString(1)
|
||||||
result[0] = x
|
result[0] = x
|
||||||
|
|
||||||
|
proc `$`(x: uint64): string =
|
||||||
|
if x == 0:
|
||||||
|
result = "0"
|
||||||
|
else:
|
||||||
|
result = newString(60)
|
||||||
|
var i = 0
|
||||||
|
var n = x
|
||||||
|
while n != 0:
|
||||||
|
let nn = n div 10'u64
|
||||||
|
result[i] = char(n - 10'u64 * nn + ord('0'))
|
||||||
|
inc i
|
||||||
|
n = nn
|
||||||
|
result.setLen i
|
||||||
|
|
||||||
|
let half = i div 2
|
||||||
|
# Reverse
|
||||||
|
for t in 0 .. half-1: swap(result[t], result[i-t-1])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue