diff --git a/lib/system.nim b/lib/system.nim index ffdc59661d..28a0415a12 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1703,19 +1703,19 @@ 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, tags: [].} = + proc beginStore*(s: var string; ensuredLen: int; start = 0): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} = let ns = cast[NimString](s) if ns == nil: nil else: cast[ptr UncheckedArray[char]](addr ns.data[start]) - proc endStore*(s: var string) {.inline, noSideEffect, tags: [].} = discard + proc endStore*(s: var string) {.inline, noSideEffect, raises: [], tags: [].} = discard template readRawData*(s: string; start = 0): ptr UncheckedArray[char] = let ns = cast[NimString](s) if ns == nil: nil 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, tags: [].} = nil - proc endStore*(s: var string) {.inline, noSideEffect, tags: [].} = discard + proc beginStore*(s: var string; ensuredLen: 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 when not defined(js): diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index b99b433257..6942b69a6d 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -176,18 +176,18 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = a.len = b.len copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1) -proc nimPrepareStrMutationImpl(s: var NimStringV2) = +proc nimPrepareStrMutationImpl(s: var NimStringV2) {.raises: [], tags: [].} = let oldP = s.p # can't mutate a literal, so we need a fresh copy here: s.p = allocPayload(s.len) s.p.cap = s.len copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) -proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inl.} = +proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inl, raises: [], tags: [].} = if s.p != nil and (s.p.cap and strlitFlag) == strlitFlag: nimPrepareStrMutationImpl(s) -proc prepareMutation*(s: var string) {.inline, tags: [].} = +proc prepareMutation*(s: var string) {.inline, raises: [], tags: [].} = # string literals are "copy on write", so you need to call # `prepareMutation` before modifying the strings via `addr`. {.cast(noSideEffect).}: @@ -216,21 +216,25 @@ 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, tags: [].} = +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`. ## Call `endStore(s)` afterwards for portability. {.cast(noSideEffect).}: prepareMutation(s) - if s.len == 0: nil - else: cast[ptr UncheckedArray[char]](addr s[start]) + let str = cast[ptr NimStringV2](unsafeAddr s) + if str.p == nil: nil + else: cast[ptr UncheckedArray[char]](addr str.p.data[start]) -proc endStore*(s: var string) {.inline, noSideEffect, tags: [].} = +proc endStore*(s: var string) {.inline, noSideEffect, raises: [], tags: [].} = ## No-op for non-SSO strings; call after bulk writes via `beginStore`. discard +proc rawDataImpl(str: ptr NimStringV2; start: int): ptr UncheckedArray[char] {.inline, noSideEffect, raises: [], tags: [].} = + if str.p == nil: nil + else: cast[ptr UncheckedArray[char]](addr str.p.data[start]) + template readRawData*(s: string; start = 0): ptr UncheckedArray[char] = ## Returns a pointer to `s[start]` for read-only raw access. ## Template ensures no copy of `s`; ptr is valid while `s` is alive. - let str = cast[ptr NimStringV2](unsafeAddr s) - if str.p == nil: nil else: cast[ptr UncheckedArray[char]](addr str.p.data[start]) + rawDataImpl(cast[ptr NimStringV2](unsafeAddr s), start) {.pop.} diff --git a/lib/system/strs_v3.nim b/lib/system/strs_v3.nim index b4e426908c..ff22e24ecc 100644 --- a/lib/system/strs_v3.nim +++ b/lib/system/strs_v3.nim @@ -675,7 +675,7 @@ 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, tags: [].} = +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`). ## Call `endStore(s)` afterwards to sync the inline cache. @@ -688,7 +688,7 @@ proc beginStore*(s: var string; ensuredLen: int; start = 0): ptr UncheckedArray[ else: result = cast[ptr UncheckedArray[char]](cast[uint](inlinePtr(ss[])) + uint(start)) -proc endStore*(s: var string) {.inline, noSideEffect, tags: [].} = +proc endStore*(s: var string) {.inline, noSideEffect, raises: [], tags: [].} = ## Syncs the inline cache after bulk writes via `beginStore`. No-op for short/medium strings. {.cast(noSideEffect).}: completeStore(cast[ptr SmallString](addr s)[])