mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-12 18:15:30 +00:00
better beginStore API
This commit is contained in:
@@ -259,7 +259,7 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int =
|
||||
result = s.readDataStrImpl(s, buffer, slice)
|
||||
else:
|
||||
# fallback
|
||||
result = s.readData(beginStore(buffer, slice.b + 1 - slice.a, slice.a), slice.b + 1 - slice.a)
|
||||
result = s.readData(beginStore(buffer, slice.b + 1, slice.a), slice.b + 1 - slice.a)
|
||||
endStore(buffer)
|
||||
|
||||
template jsOrVmBlock(caseJsOrVm, caseElse: untyped): untyped =
|
||||
@@ -1226,7 +1226,7 @@ else: # after 1.3 or JS not defined
|
||||
jsOrVmBlock:
|
||||
buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
|
||||
do:
|
||||
copyMem(beginStore(buffer, result, slice.a), readRawData(s.data, s.pos), result)
|
||||
copyMem(beginStore(buffer, slice.a + result, slice.a), readRawData(s.data, s.pos), result)
|
||||
endStore(buffer)
|
||||
inc(s.pos, result)
|
||||
else:
|
||||
@@ -1267,16 +1267,16 @@ else: # after 1.3 or JS not defined
|
||||
var s = StringStream(s)
|
||||
if bufLen <= 0:
|
||||
return
|
||||
if s.pos + bufLen > s.data.len:
|
||||
setLen(s.data, s.pos + bufLen)
|
||||
when defined(js):
|
||||
if s.pos + bufLen > s.data.len:
|
||||
setLen(s.data, s.pos + bufLen)
|
||||
try:
|
||||
s.data[s.pos..<s.pos+bufLen] = cast[ptr string](buffer)[][0..<bufLen]
|
||||
except:
|
||||
raise newException(Defect, "could not write to string stream, " &
|
||||
"did you use a non-string buffer pointer?", getCurrentException())
|
||||
elif not defined(nimscript):
|
||||
copyMem(beginStore(s.data, bufLen, s.pos), buffer, bufLen)
|
||||
copyMem(beginStore(s.data, s.pos + bufLen, s.pos), buffer, bufLen)
|
||||
endStore(s.data)
|
||||
inc(s.pos, bufLen)
|
||||
|
||||
@@ -1346,7 +1346,7 @@ proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||
|
||||
proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int =
|
||||
let len = slice.b + 1 - slice.a
|
||||
result = readBuffer(FileStream(s).f, beginStore(buffer, len, slice.a), len)
|
||||
result = readBuffer(FileStream(s).f, beginStore(buffer, slice.b + 1, slice.a), len)
|
||||
endStore(buffer)
|
||||
|
||||
proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||
|
||||
@@ -18,12 +18,12 @@ proc addCstringN(result: var string, buf: cstring; buflen: int) =
|
||||
# no nimvm support needed, so it doesn't need to be fast here either
|
||||
let oldLen = result.len
|
||||
let newLen = oldLen + buflen
|
||||
result.setLen newLen
|
||||
{.cast(noSideEffect).}:
|
||||
when declared(completeStore):
|
||||
c_memcpy(beginStore(result, buflen, oldLen), buf, buflen.csize_t)
|
||||
when declared(beginStore):
|
||||
c_memcpy(beginStore(result, newLen, oldLen), buf, buflen.csize_t)
|
||||
endStore(result)
|
||||
else:
|
||||
result.setLen newLen
|
||||
discard c_memcpy(result[oldLen].addr, buf, buflen.csize_t)
|
||||
|
||||
import std/private/[dragonbox, schubfach]
|
||||
|
||||
@@ -84,7 +84,7 @@ func setSlice*(s: var string, slice: Slice[int]) =
|
||||
when not declared(moveMem):
|
||||
impl()
|
||||
else:
|
||||
let p = beginStore(s, last - first + 1)
|
||||
let p = beginStore(s, s.len)
|
||||
moveMem(p, addr p[first], last - first + 1)
|
||||
endStore(s)
|
||||
s.setLen(last - first + 1)
|
||||
|
||||
@@ -485,7 +485,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
|
||||
while true:
|
||||
# fixes #9634; this pattern may need to be abstracted as a template if reused;
|
||||
# likely other io procs need this for correctness.
|
||||
fgetsSuccess = c_fgets(cast[cstring](beginStore(line, sp, pos)), sp.cint, f) != nil
|
||||
fgetsSuccess = c_fgets(cast[cstring](beginStore(line, pos + sp, pos)), sp.cint, f) != nil
|
||||
endStore(line)
|
||||
if fgetsSuccess: break
|
||||
when not defined(nimscript):
|
||||
|
||||
@@ -1703,7 +1703,8 @@ when not (notJSnotNims and defined(nimSeqsV2)):
|
||||
# Needed so modules imported by system (e.g. syncio) can reference these without guards.
|
||||
when notJSnotNims:
|
||||
# mm:refc: string = ptr NimStringDesc with data: UncheckedArray[char]
|
||||
proc beginStore*(s: var string; ensuredLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
proc beginStore*(s: var string; newLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
{.cast(noSideEffect).}: s.setLen(newLen)
|
||||
let ns = cast[NimString](s)
|
||||
if ns == nil: nil
|
||||
else: cast[ptr UncheckedArray[char]](addr ns.data[start])
|
||||
@@ -1714,7 +1715,7 @@ when not (notJSnotNims and defined(nimSeqsV2)):
|
||||
else: cast[ptr UncheckedArray[char]](addr ns.data[start])
|
||||
else:
|
||||
# JS/nimscript: callers are guarded by whenNotVmJsNims/when not defined(js)
|
||||
proc beginStore*(s: var string; ensuredLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} = nil
|
||||
proc beginStore*(s: var string; newLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} = nil
|
||||
proc endStore*(s: var string) {.inline, noSideEffect, raises: [], tags: [].} = discard
|
||||
template readRawData*(s: string; start = 0): ptr UncheckedArray[char] = nil
|
||||
|
||||
|
||||
@@ -236,13 +236,17 @@ func capacity*(self: string): int {.inline.} =
|
||||
let str = cast[ptr NimStringV2](unsafeAddr self)
|
||||
result = if str.p != nil: str.p.cap and not strlitFlag else: 0
|
||||
|
||||
proc beginStore*(s: var string; ensuredLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
## Returns a writable pointer for bulk write of `ensuredLen` bytes starting at `start`.
|
||||
proc beginStore*(s: var string; newLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
## Sets s.len to `newLen` (new bytes are uninitialized), ensures unique
|
||||
## ownership, and returns a pointer to s[start] for bulk writing.
|
||||
## Call `endStore(s)` afterwards for portability.
|
||||
{.cast(noSideEffect).}: prepareMutation(s)
|
||||
let str = cast[ptr NimStringV2](unsafeAddr s)
|
||||
if str.p == nil: nil
|
||||
else: cast[ptr UncheckedArray[char]](addr str.p.data[start])
|
||||
## To keep the current length, pass `s.len`.
|
||||
{.cast(noSideEffect).}:
|
||||
let p = cast[ptr NimStringV2](addr s)
|
||||
setLengthStrV2Uninit(p[], newLen)
|
||||
prepareMutation(s)
|
||||
if p.p == nil: nil
|
||||
else: cast[ptr UncheckedArray[char]](addr p.p.data[start])
|
||||
|
||||
proc endStore*(s: var string) {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
## No-op for non-SSO strings; call after bulk writes via `beginStore`.
|
||||
|
||||
@@ -721,18 +721,37 @@ proc completeStore(s: var SmallString) {.compilerproc, inline.} =
|
||||
proc completeStore*(s: var string) {.inline.} =
|
||||
completeStore(cast[ptr SmallString](addr s)[])
|
||||
|
||||
proc beginStore*(s: var string; ensuredLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
## Prepares `s` for a bulk write of `ensuredLen` bytes starting at `start`.
|
||||
## The caller must ensure `s.len >= start + ensuredLen` (e.g. via `newString` or `setLen`).
|
||||
proc beginStore*(s: var string; newLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
## Sets s.len to `newLen` (new bytes are uninitialized), ensures unique
|
||||
## ownership, and returns a pointer to s[start] for bulk writing.
|
||||
## Call `endStore(s)` afterwards to sync the inline cache.
|
||||
## To keep the current length, pass `s.len`.
|
||||
{.cast(noSideEffect).}:
|
||||
let ss = cast[ptr SmallString](addr s)
|
||||
let slen = ssLen(ss[])
|
||||
if slen > PayloadSize:
|
||||
ensureUniqueLong(ss[], ss[].more.fullLen, ss[].more.fullLen)
|
||||
let curLen = if slen > PayloadSize: ss[].more.fullLen else: slen
|
||||
if newLen <= PayloadSize and slen <= PayloadSize:
|
||||
# Stay inline/medium.
|
||||
if newLen != curLen:
|
||||
setSSLen(ss[], newLen)
|
||||
result = cast[ptr UncheckedArray[char]](cast[uint](inlinePtr(ss[])) + uint(start))
|
||||
elif slen <= PayloadSize:
|
||||
# Inline/medium → long.
|
||||
let newCap = resize(newLen)
|
||||
let p = cast[ptr LongString](alloc(LongStringDataOffset + newCap + 1))
|
||||
p.rc = 1
|
||||
p.fullLen = newLen
|
||||
p.capImpl = newCap
|
||||
copyMem(addr p.data[0], inlinePtr(ss[]), curLen)
|
||||
p.data[newLen] = '\0'
|
||||
ss[].more = p
|
||||
setSSLen(ss[], HeapSlen)
|
||||
result = cast[ptr UncheckedArray[char]](addr ss[].more.data[start])
|
||||
else:
|
||||
result = cast[ptr UncheckedArray[char]](cast[uint](inlinePtr(ss[])) + uint(start))
|
||||
# Already long: resize within heap (no transition back to inline).
|
||||
ensureUniqueLong(ss[], curLen, newLen)
|
||||
ss[].more.data[newLen] = '\0'
|
||||
result = cast[ptr UncheckedArray[char]](addr ss[].more.data[start])
|
||||
|
||||
proc endStore*(s: var string) {.inline, noSideEffect, raises: [], tags: [].} =
|
||||
## Syncs the inline cache after bulk writes via `beginStore`. No-op for short/medium strings.
|
||||
|
||||
Reference in New Issue
Block a user