mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-18 21:40:32 +00:00
progress
This commit is contained in:
@@ -962,7 +962,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
putIntoDest(p, d, e, cDeref(rdLoc(a)), a.storage)
|
||||
|
||||
proc cowBracket(p: BProc; n: PNode) =
|
||||
if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions:
|
||||
if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions and
|
||||
not p.config.isDefined("nimsso"):
|
||||
let strCandidate = n[0]
|
||||
if strCandidate.typ.skipTypes(abstractInst).kind == tyString:
|
||||
var a: TLoc = initLocExpr(p, strCandidate)
|
||||
@@ -987,6 +988,14 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||
expr(p, e[0], d)
|
||||
# bug #19497
|
||||
d.lode = e
|
||||
elif p.config.isDefined("nimsso") and e[0].kind == nkBracketExpr and
|
||||
e[0][0].typ.skipTypes(abstractVar).kind == tyString:
|
||||
# addr s[i] for nimsso: nimStrAtMutV3 returns char* directly — no extra & needed
|
||||
var base = initLocExpr(p, e[0][0])
|
||||
var idx = initLocExpr(p, e[0][1])
|
||||
putIntoDest(p, d, e,
|
||||
cCall(cgsymValue(p.module, "nimStrAtMutV3"), byRefLoc(p, base), rdLoc(idx)),
|
||||
base.storage)
|
||||
else:
|
||||
var a: TLoc = initLocExpr(p, e[0])
|
||||
if e[0].kind in {nkHiddenStdConv, nkHiddenSubConv, nkConv} and not ignoreConv(e[0]):
|
||||
@@ -1315,16 +1324,21 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
a.snippet = cDeref(a.snippet)
|
||||
|
||||
if lfPrepareForMutation in d.flags and ty.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"),
|
||||
bra)
|
||||
if p.config.isDefined("nimsso") and ty.kind == tyString:
|
||||
# direct writes (s[i] = c) are intercepted in genAsgn via nimStrPutV3
|
||||
let bra = byRefLoc(p, a)
|
||||
putIntoDest(p, d, n,
|
||||
subscript(cCall(cgsymValue(p.module, "nimStrData"), bra), rcb), a.storage)
|
||||
if lfPrepareForMutation in d.flags:
|
||||
# s[i] passed as `var char`: return *(nimStrAtMutV3(&s, i)) — a valid C lvalue
|
||||
putIntoDest(p, d, n,
|
||||
cDeref(cCall(cgsymValue(p.module, "nimStrAtMutV3"), bra, rcb)), a.storage)
|
||||
else:
|
||||
putIntoDest(p, d, n,
|
||||
cCall(cgsymValue(p.module, "nimStrAtV3"), bra, rcb), a.storage)
|
||||
else:
|
||||
if lfPrepareForMutation in d.flags and ty.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
let bra = byRefLoc(p, a)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"), bra)
|
||||
let ra = rdLoc(a)
|
||||
putIntoDest(p, d, n, subscript(dataField(p, ra), rcb), a.storage)
|
||||
|
||||
|
||||
@@ -1940,6 +1940,15 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
elif optFieldCheck in p.options and isDiscriminantField(e[0]):
|
||||
genLineDir(p, e)
|
||||
asgnFieldDiscriminant(p, e)
|
||||
elif p.config.isDefined("nimsso") and e[0].kind == nkBracketExpr and
|
||||
e[0][0].typ.skipTypes(abstractVar).kind == tyString:
|
||||
# nimsso: s[i] = c → nimStrPutV3(&s, i, c) (handles COW internally)
|
||||
genLineDir(p, e)
|
||||
var base = initLocExpr(p, e[0][0])
|
||||
var idx = initLocExpr(p, e[0][1])
|
||||
var rhs = initLocExpr(p, e[1])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimStrPutV3"),
|
||||
byRefLoc(p, base), rdLoc(idx), rdCharLoc(rhs))
|
||||
else:
|
||||
let le = e[0]
|
||||
let ri = e[1]
|
||||
|
||||
@@ -74,7 +74,7 @@ template guts(s: SmallString): (int, ptr UncheckedArray[char]) =
|
||||
else:
|
||||
(slen, cast[ptr UncheckedArray[char]](addr s.payload[0]))
|
||||
|
||||
proc `[]`(s: SmallString; i: int): char {.inline.} =
|
||||
proc nimStrAtV3*(s: var SmallString; i: int): char {.compilerproc, inline.} =
|
||||
let slen = int s.slen
|
||||
if slen <= PayloadSize:
|
||||
# unchecked: when i >= 7 we store into the `more` overlay
|
||||
@@ -84,7 +84,7 @@ proc `[]`(s: SmallString; i: int): char {.inline.} =
|
||||
else:
|
||||
result = s.more.data[i]
|
||||
|
||||
proc `[]=`(s: var SmallString; i: int; c: char) =
|
||||
proc nimStrPutV3*(s: var SmallString; i: int; c: char) {.compilerproc, inline.} =
|
||||
let slen = int s.slen
|
||||
if slen <= PayloadSize:
|
||||
# unchecked: when i >= 7 we store into the `more` overlay
|
||||
@@ -96,7 +96,7 @@ proc `[]=`(s: var SmallString; i: int; c: char) =
|
||||
if i < AlwaysAvail:
|
||||
s.payload[i] = c
|
||||
|
||||
proc cmp*(a, b: SmallString): int =
|
||||
proc cmp(a, b: SmallString): int =
|
||||
# Use slen directly for prefix length: for short/medium it is the real length,
|
||||
# for long it is the sentinel (> AlwaysAvail), so min(..., AlwaysAvail) still gives 7.
|
||||
# This avoids dereferencing `more` before the prefix comparison.
|
||||
@@ -116,7 +116,7 @@ proc cmp*(a, b: SmallString): int =
|
||||
if result == 0:
|
||||
result = la - lb
|
||||
|
||||
proc `==`*(a, b: SmallString): bool =
|
||||
proc `==`(a, b: SmallString): bool =
|
||||
if a.slen != b.slen: return false
|
||||
# slen equal: for short/medium this means equal lengths; for long (both sentinel) we still need fullLen.
|
||||
let slen = int(a.slen)
|
||||
@@ -133,7 +133,7 @@ proc `==`*(a, b: SmallString): bool =
|
||||
if la != b.more.fullLen: return false
|
||||
cmpMem(addr a.more.data[pfxLen], addr b.more.data[pfxLen], la - pfxLen) == 0
|
||||
|
||||
proc `<=`*(a, b: SmallString): bool {.inline.} = cmp(a, b) <= 0
|
||||
proc `<=`(a, b: SmallString): bool {.inline.} = cmp(a, b) <= 0
|
||||
|
||||
proc continuesWith*(s, sub: SmallString; start: int): bool =
|
||||
if start < 0: return false
|
||||
@@ -158,7 +158,7 @@ proc startsWith*(s, sub: SmallString): bool {.inline.} = continuesWith(s, sub, 0
|
||||
proc endsWith*(s, sub: SmallString): bool {.inline.} = continuesWith(s, sub, s.len - sub.len)
|
||||
|
||||
|
||||
proc add*(s: var SmallString; c: char) =
|
||||
proc add(s: var SmallString; c: char) =
|
||||
let slen = int(s.slen)
|
||||
if slen <= PayloadSize:
|
||||
let newLen = slen + 1
|
||||
@@ -187,7 +187,7 @@ proc add*(s: var SmallString; c: char) =
|
||||
s.more.data[l + 1] = '\0'
|
||||
# l >= PayloadSize > AlwaysAvail, so prefix is unaffected
|
||||
|
||||
proc add*(s: var SmallString; t: SmallString) =
|
||||
proc add(s: var SmallString; t: SmallString) =
|
||||
let slen = int(s.slen)
|
||||
let (tl, tp) = t.guts # fetch t's guts before any mutation (aliasing safety)
|
||||
if tl == 0: return
|
||||
@@ -223,11 +223,6 @@ proc add*(s: var SmallString; t: SmallString) =
|
||||
s.more.data[newLen] = '\0'
|
||||
# sl >= PayloadSize > AlwaysAvail, so prefix is unaffected
|
||||
|
||||
proc `&`*(a, b: SmallString): SmallString =
|
||||
result = a
|
||||
result.add(b)
|
||||
|
||||
|
||||
{.push overflowChecks: off, rangeChecks: off.}
|
||||
|
||||
proc prepareAddLong(s: var SmallString; newLen: int) =
|
||||
@@ -428,13 +423,18 @@ proc prepareMutation*(s: var string) {.inline.} =
|
||||
{.cast(noSideEffect).}:
|
||||
nimPrepareStrMutationV2(cast[ptr SmallString](addr s)[])
|
||||
|
||||
proc nimStrAtMutV3*(s: var SmallString; i: int): var char {.compilerproc, inline.} =
|
||||
## Returns a mutable reference to the i-th char. Handles COW for long strings.
|
||||
## Used by the codegen when s[i] is passed as a `var char` argument.
|
||||
if int(s.slen) > PayloadSize:
|
||||
nimPrepareStrMutationV2(s) # COW: ensure unique heap block before exposing ref
|
||||
result = s.more.data[i]
|
||||
else:
|
||||
result = (cast[ptr UncheckedArray[char]](addr s.payload[0]))[i]
|
||||
|
||||
proc nimAddStrV1(s: var SmallString; src: SmallString) {.compilerRtl, inline.} =
|
||||
s.add(src)
|
||||
|
||||
proc nimStrAtLe(s: SmallString; idx: int; ch: char): bool {.compilerRtl, inline.} =
|
||||
let l = s.len
|
||||
result = idx < l and s[idx] <= ch
|
||||
|
||||
func capacity*(self: SmallString): int {.inline.} =
|
||||
## Returns the current capacity of the string.
|
||||
let slen = int(self.slen)
|
||||
|
||||
Reference in New Issue
Block a user