From 1c37d9a50e6ac92f4fc640f2d442943b5f714b67 Mon Sep 17 00:00:00 2001 From: Zoom Date: Mon, 3 Aug 2026 22:46:37 +0400 Subject: [PATCH] std: `strbasics.add` uses copymem when available (#25768) `strbasics.add` uses `copymem` when available. CT conditional scaffolding mirrors the same from system. Follow-up to #15951 Compile-time test for `strbasics.add` undiscarded and passes, though pending bug #15952 is still open. --- lib/std/strbasics.nim | 52 +++++++++++++++++++++---------------- tests/stdlib/tstrbasics.nim | 3 ++- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/std/strbasics.nim b/lib/std/strbasics.nim index beaf9d89a3..63a66cc182 100644 --- a/lib/std/strbasics.nim +++ b/lib/std/strbasics.nim @@ -17,19 +17,30 @@ when defined(nimPreviewSlimSystem): const whitespaces = {' ', '\t', '\v', '\r', '\l', '\f'} +const notJSnotNims = not defined(js) and not defined(nimscript) +template whenNotVmJsNims(normalBody, restrictedBody: untyped) = + ## hack, see: #12517 #12518; Edit together with identical in `system` + when nimvm: + restrictedBody + else: + when notJSnotNims: + normalBody + else: + restrictedBody + proc add*(x: var string, y: openArray[char]) = - ## Concatenates `x` and `y` in place. `y` must not overlap with `x` to - ## allow future `memcpy` optimizations. + ## Concatenates `x` and `y` in place. `y` must not overlap with `x` # Use `{.noalias.}` ? - let n = x.len - x.setLen n + y.len - # pending #19727 - # setLen unnecessarily zeros memory - var i = 0 - while i < y.len: - x[n + i] = y[i] - i.inc - # xxx use `nimCopyMem(x[n].addr, y[0].addr, y.len)` after some refactoring + if y.len == 0: return + let oldLen = x.len + x.setLenUninit(oldLen + y.len) + whenNotVmJsNims(): + {.cast(noSideEffect).}: + copyMem(beginStore(x, oldLen + y.len, oldLen), addr(y[0]), y.len) + endStore(x) + do: + for i, ch in y: + x[oldLen + i] = ch func stripSlice(s: openArray[char], leading = true, trailing = true, chars: set[char] = whitespaces): Slice[int] = ## Returns the slice range of `s` which is stripped `chars`. @@ -74,19 +85,14 @@ func setSlice*(s: var string, slice: Slice[int]) = if first > last: s.setLen(0) return - template impl = - for index in first .. last: - s[index - first] = s[index] if first > 0: - when nimvm: impl() - else: - # not JS and not Nimscript - when not declared(moveMem): - impl() - else: - let p = beginStore(s, s.len) - moveMem(p, addr p[first], last - first + 1) - endStore(s) + whenNotVmJsNims(): + let p = beginStore(s, s.len) + moveMem(p, addr p[first], last - first + 1) + endStore(s) + do: + for index in first .. last: + s[index - first] = s[index] s.setLen(last - first + 1) func strip*(a: var string, leading = true, trailing = true, chars: set[char] = whitespaces) {.inline.} = diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim index bfae55fde9..e812e20ee4 100644 --- a/tests/stdlib/tstrbasics.nim +++ b/tests/stdlib/tstrbasics.nim @@ -90,7 +90,8 @@ proc main() = var a0 = "hi" var b0 = "foobar" when nimvm: - discard # pending bug #15952 + a0.add b0.toOpenArray(1,3) + doAssert a0 == "hioob" else: a0.add b0.toOpenArray(1,3) doAssert a0 == "hioob"