mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Remove some unnecessary initialization in string operations (#22579)
* `prepareAdd`
* `toNimStr`
* `setLengthStrV2`
* `NimAsgnStrV2`
* `prepareMutation`
* Some cleanups
(cherry picked from commit a4df44d9fb)
This commit is contained in:
committed by
narimiran
parent
79a1990774
commit
d7dfbf026b
@@ -34,53 +34,72 @@ template frees(s) =
|
||||
else:
|
||||
dealloc(s.p)
|
||||
|
||||
template allocPayload(newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](allocShared(contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](alloc(contentSize(newLen)))
|
||||
|
||||
template allocPayload0(newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](allocShared0(contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](alloc0(contentSize(newLen)))
|
||||
|
||||
template reallocPayload(p: pointer, newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](reallocShared(p, contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](realloc(p, contentSize(newLen)))
|
||||
|
||||
template reallocPayload0(p: pointer; oldLen, newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](reallocShared0(p, contentSize(oldLen), contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](realloc0(p, contentSize(oldLen), contentSize(newLen)))
|
||||
|
||||
proc resize(old: int): int {.inline.} =
|
||||
if old <= 0: result = 4
|
||||
elif old < 65536: result = old * 2
|
||||
else: result = old * 3 div 2 # for large arrays * 3/2 is better
|
||||
|
||||
proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
|
||||
let newLen = s.len + addlen
|
||||
proc prepareAdd(s: var NimStringV2; addLen: int) {.compilerRtl.} =
|
||||
let newLen = s.len + addLen
|
||||
if isLiteral(s):
|
||||
let oldP = s.p
|
||||
# can't mutate a literal, so we need a fresh copy here:
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(newLen)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](alloc0(contentSize(newLen)))
|
||||
s.p = allocPayload(newLen)
|
||||
s.p.cap = newLen
|
||||
if s.len > 0:
|
||||
# we are about to append, so there is no need to copy the \0 terminator:
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen))
|
||||
elif oldP == nil:
|
||||
# In the case of `newString(0) & ""`, since `src.len == 0`, `appendString`
|
||||
# will not set the `\0` terminator, so we set it here.
|
||||
s.p.data[0] = '\0'
|
||||
else:
|
||||
let oldCap = s.p.cap and not strlitFlag
|
||||
if newLen > oldCap:
|
||||
let newCap = max(newLen, resize(oldCap))
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](realloc0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||
s.p = reallocPayload(s.p, newCap)
|
||||
s.p.cap = newCap
|
||||
if newLen < newCap:
|
||||
zeroMem(cast[pointer](addr s.p.data[newLen+1]), newCap - newLen)
|
||||
|
||||
proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inline.} =
|
||||
#if (s.p == nil) or (s.len+1 > s.p.cap and not strlitFlag):
|
||||
prepareAdd(s, 1)
|
||||
s.p.data[s.len] = c
|
||||
s.p.data[s.len+1] = '\0'
|
||||
inc s.len
|
||||
s.p.data[s.len] = '\0'
|
||||
|
||||
proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} =
|
||||
if len <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(len)))
|
||||
var p = allocPayload(len)
|
||||
p.cap = len
|
||||
if len > 0:
|
||||
# we are about to append, so there is no need to copy the \0 terminator:
|
||||
copyMem(unsafeAddr p.data[0], str, len)
|
||||
copyMem(unsafeAddr p.data[0], str, len+1)
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
proc cstrToNimstr(str: cstring): NimStringV2 {.compilerRtl.} =
|
||||
@@ -99,18 +118,15 @@ proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inlin
|
||||
|
||||
proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
|
||||
dest.p.data[dest.len] = c
|
||||
dest.p.data[dest.len+1] = '\0'
|
||||
inc dest.len
|
||||
dest.p.data[dest.len] = '\0'
|
||||
|
||||
proc rawNewString(space: int): NimStringV2 {.compilerproc.} =
|
||||
# this is also 'system.newStringOfCap'.
|
||||
if space <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared(contentSize(space)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc(contentSize(space)))
|
||||
var p = allocPayload(space)
|
||||
p.cap = space
|
||||
p.data[0] = '\0'
|
||||
result = NimStringV2(len: 0, p: p)
|
||||
@@ -119,10 +135,7 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} =
|
||||
if len <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(len)))
|
||||
var p = allocPayload0(len)
|
||||
p.cap = len
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
@@ -130,8 +143,25 @@ proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
|
||||
if newLen == 0:
|
||||
discard "do not free the buffer here, pattern 's.setLen 0' is common for avoiding allocations"
|
||||
else:
|
||||
if newLen > s.len or isLiteral(s):
|
||||
prepareAdd(s, newLen - s.len)
|
||||
if isLiteral(s):
|
||||
let oldP = s.p
|
||||
s.p = allocPayload(newLen)
|
||||
s.p.cap = newLen
|
||||
if s.len > 0:
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen))
|
||||
if newLen > s.len:
|
||||
zeroMem(cast[pointer](addr s.p.data[s.len]), newLen - s.len + 1)
|
||||
else:
|
||||
s.p.data[newLen] = '\0'
|
||||
else:
|
||||
zeroMem(cast[pointer](addr s.p.data[0]), newLen + 1)
|
||||
elif newLen > s.len:
|
||||
let oldCap = s.p.cap and not strlitFlag
|
||||
if newLen > oldCap:
|
||||
let newCap = max(newLen, resize(oldCap))
|
||||
s.p = reallocPayload0(s.p, oldCap, newCap)
|
||||
s.p.cap = newCap
|
||||
|
||||
s.p.data[newLen] = '\0'
|
||||
s.len = newLen
|
||||
|
||||
@@ -148,10 +178,7 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||
# 'let y = newStringOfCap(); var x = y'
|
||||
# on the other hand... These get turned into moves now.
|
||||
frees(a)
|
||||
when compileOption("threads"):
|
||||
a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len)))
|
||||
else:
|
||||
a.p = cast[ptr NimStrPayload](alloc0(contentSize(b.len)))
|
||||
a.p = allocPayload(b.len)
|
||||
a.p.cap = b.len
|
||||
a.len = b.len
|
||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
||||
@@ -159,10 +186,7 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||
proc nimPrepareStrMutationImpl(s: var NimStringV2) =
|
||||
let oldP = s.p
|
||||
# can't mutate a literal, so we need a fresh copy here:
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len)))
|
||||
s.p = allocPayload(s.len)
|
||||
s.p.cap = s.len
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user