now with newStringUninit for SSO

This commit is contained in:
araq
2026-03-08 20:26:41 +01:00
parent e199944855
commit 3c7a97674b
2 changed files with 45 additions and 13 deletions

View File

@@ -1747,16 +1747,21 @@ when not defined(js):
else:
{.error: "The type T cannot contain managed memory or have destructors".}
when not defined(nimsso):
proc newStringUninit*(len: Natural): string {.noSideEffect.} =
## Returns a new string of length `len` but with uninitialized
## content. One needs to fill the string character after character
## with the index operator `s[i]`.
##
## This procedure exists only for optimization purposes;
## the same effect can be achieved with the `&` operator or with `add`.
when nimvm:
result = newString(len)
when defined(nimsso) and not declared(newStringUninitWasDeclared):
proc newStringUninitImpl(len: Natural): string {.noSideEffect, inline.}
proc newStringUninit*(len: Natural): string {.noSideEffect.} =
## Returns a new string of length `len` but with uninitialized
## content. One needs to fill the string character after character
## with the index operator `s[i]`.
##
## This procedure exists only for optimization purposes;
## the same effect can be achieved with the `&` operator or with `add`.
when nimvm:
result = newString(len)
else:
when defined(nimsso):
result = newStringUninitImpl(len)
else:
result = newStringOfCap(len)
{.cast(noSideEffect).}:
@@ -1769,9 +1774,6 @@ when not defined(js):
let s = cast[NimString](result)
s.len = len
s.data[len] = '\0'
else:
proc newStringUninit*(len: Natural): string {.
magic: "NewString", importc: "mnewString", noSideEffect.}
{.pop.}
@@ -3176,3 +3178,6 @@ when hostOS == "standalone":
# ssymbols being duplicated.
proc nimPanic(s: string) {.exportc, noreturn.} = panic(s)
proc nimRawoutput(s: string) {.exportc.} = rawoutput(s)
when not declared(newStringUninitWasDeclared):
proc newStringUninitImpl(len: Natural): string {.noSideEffect, inline.} = discard

View File

@@ -509,6 +509,33 @@ proc nimStrData(s: var SmallString): ptr UncheckedArray[char] {.compilerproc, in
if slen > PayloadSize: cast[ptr UncheckedArray[char]](addr s.more.data[0])
else: cast[ptr UncheckedArray[char]](addr s.payload[0])
const
newStringUninitWasDeclared = true
proc newStringUninitImpl(len: Natural): string {.noSideEffect, inline.} =
## Returns a new string of length `len` but with uninitialized content.
## One needs to fill the string character after character
## with the index operator `s[i]`.
##
## This procedure exists only for optimization purposes;
## the same effect can be achieved with the `&` operator or with `add`.
when nimvm:
result = newString(len)
else:
result = newStringOfCap(len) # rawNewString: alloc (not alloc0) for long strings
{.cast(noSideEffect).}:
if len > 0:
let s = cast[ptr SmallString](addr result)
if len <= PayloadSize:
s.slen = byte(len)
# Null-terminate; bytes [0..len-1] left uninitialized for caller to fill.
cast[ptr UncheckedArray[char]](addr s.payload[0])[len] = '\0'
else:
# rawNewString allocated with alloc (not alloc0), so data[0..len-1] is
# intentionally uninitialized. Caller fills it and calls completeStore.
s.more.fullLen = len
s.more.data[len] = '\0'
proc completeStore(s: var SmallString) {.compilerproc, inline.} =
## Must be called after bulk data has been written directly into the string buffer
## via a raw pointer obtained from `nimStrData`/`nimStrAtMutV3` (e.g. `readBuffer`,