Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add overload add(a: var string, b: openArray[char]) #15951

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,10 @@ provided by the operating system.
dumping (on select signals) and notifying the parent process about the cause
of termination.

- `hashes.hash` now supports `object`, but can be overloaded.
- Added `std/strbasics` for high performance string operations.
Added `strip`, `setSlice`, `add(a: var string, b: openArray[char])`.

- Added `strip` and `setSlice` to `std/strbasics`.
- `hashes.hash` now supports `object`, but can be overloaded.

- Added to `wrapnils` an option-like API via `??.`, `isSome`, `get`.

Expand Down
16 changes: 16 additions & 0 deletions lib/std/strbasics.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,25 @@
#

## This module provides some high performance string operations.
##
## Experimental API, subject to change.

const whitespaces = {' ', '\t', '\v', '\r', '\l', '\f'}

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.
# Use `{.noalias.}` ?
let n = x.len
x.setLen n + y.len
# pending https://github.com/nim-lang/Nim/issues/14655#issuecomment-643671397
# use x.setLen(n + y.len, isInit = false)
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

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`.
runnableExamples:
Expand Down
15 changes: 8 additions & 7 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1069,15 +1069,16 @@ proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
## tmp.add('a')
## tmp.add('b')
## assert(tmp == "ab")
proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}

proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} =
## Concatenates `x` and `y` in place.
##
## .. code-block:: Nim
## var tmp = ""
## tmp.add("ab")
## tmp.add("cd")
## assert(tmp == "abcd")

## See also `strbasics.add`.
runnableExamples:
var tmp = ""
tmp.add("ab")
tmp.add("cd")
assert tmp == "abcd"

type
Endianness* = enum ## Type describing the endianness of a processor.
Expand Down
253 changes: 133 additions & 120 deletions tests/stdlib/tstrbasics.nim
Original file line number Diff line number Diff line change
@@ -1,126 +1,139 @@
discard """
targets: "c cpp js"
matrix: "--gc:refc; --gc:arc"
"""

import std/[strbasics, sugar]


proc teststrip() =
var a = " vhellov "
strip(a)
doAssert a == "vhellov"

a = " vhellov "
a.strip(leading = false)
doAssert a == " vhellov"

a = " vhellov "
a.strip(trailing = false)
doAssert a == "vhellov "

a.strip()
a.strip(chars = {'v'})
doAssert a == "hello"

a = " vhellov "
a.strip()
a.strip(leading = false, chars = {'v'})
doAssert a == "vhello"

var c = "blaXbla"
c.strip(chars = {'b', 'a'})
doAssert c == "laXbl"
c = "blaXbla"
c.strip(chars = {'b', 'a', 'l'})
doAssert c == "X"

block:
var a = "xxxxxx"
a.strip(chars={'x'})
doAssert a.len == 0

block:
var a = "x"
a.strip(chars={'x'})
doAssert a.len == 0

block:
var a = "x"
a.strip(chars={'1'})
doAssert a.len == 1

block:
var a = ""
a.strip(chars={'x'})
doAssert a.len == 0

block:
var a = "xxx xxx"
a.strip(chars={'x'})
doAssert a == " "

block:
var a = "xxx wind"
a.strip(chars={'x'})
doAssert a == " wind"

block:
var a = "xxx iii"
a.strip(chars={'i'})
doAssert a == "xxx "

block:
var a = "xxx iii"
doAssert a.dup(strip(chars = {'i'})) == "xxx "
doAssert a.dup(strip(chars = {' '})) == "xxx iii"
doAssert a.dup(strip(chars = {'x'})) == " iii"
doAssert a.dup(strip(chars = {'x', ' '})) == "iii"
doAssert a.dup(strip(chars = {'x', 'i'})) == " "
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block:
var a = "x i"
doAssert a.dup(strip(chars = {'i'})) == "x "
doAssert a.dup(strip(chars = {' '})) == "x i"
doAssert a.dup(strip(chars = {'x'})) == " i"
doAssert a.dup(strip(chars = {'x', ' '})) == "i"
doAssert a.dup(strip(chars = {'x', 'i'})) == " "
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block:
var a = ""
doAssert a.dup(strip(chars = {'i'})).len == 0
doAssert a.dup(strip(chars = {' '})).len == 0
doAssert a.dup(strip(chars = {'x'})).len == 0
doAssert a.dup(strip(chars = {'x', ' '})).len == 0
doAssert a.dup(strip(chars = {'x', 'i'})).len == 0
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block:
var a = " "
doAssert a.dup(strip(chars = {'i'})) == " "
doAssert a.dup(strip(chars = {' '})).len == 0
doAssert a.dup(strip(chars = {'x'})) == " "
doAssert a.dup(strip(chars = {'x', ' '})).len == 0
doAssert a.dup(strip(chars = {'x', 'i'})) == " "
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0


block:
var a = "Hello, Nim!"
doassert a.dup(setSlice(7 .. 9)) == "Nim"
doAssert a.dup(setSlice(0 .. 0)) == "H"
doAssert a.dup(setSlice(0 .. 1)) == "He"
doAssert a.dup(setSlice(0 .. 10)) == a
doAssert a.dup(setSlice(1 .. 0)).len == 0
doAssert a.dup(setSlice(20 .. -1)).len == 0


doAssertRaises(AssertionDefect):
discard a.dup(setSlice(-1 .. 1))

doAssertRaises(AssertionDefect):
discard a.dup(setSlice(1 .. 11))

static: teststrip()
teststrip()
proc main() =
when not defined(gcArc): # pending bug #17173
block: # strip
var a = " vhellov "
strip(a)
doAssert a == "vhellov"

a = " vhellov "
a.strip(leading = false)
doAssert a == " vhellov"

a = " vhellov "
a.strip(trailing = false)
doAssert a == "vhellov "

a.strip()
a.strip(chars = {'v'})
doAssert a == "hello"

a = " vhellov "
a.strip()
a.strip(leading = false, chars = {'v'})
doAssert a == "vhello"

var c = "blaXbla"
c.strip(chars = {'b', 'a'})
doAssert c == "laXbl"
c = "blaXbla"
c.strip(chars = {'b', 'a', 'l'})
doAssert c == "X"

block:
var a = "xxxxxx"
a.strip(chars={'x'})
doAssert a.len == 0

block:
var a = "x"
a.strip(chars={'x'})
doAssert a.len == 0

block:
var a = "x"
a.strip(chars={'1'})
doAssert a.len == 1

block:
var a = ""
a.strip(chars={'x'})
doAssert a.len == 0

block:
var a = "xxx xxx"
a.strip(chars={'x'})
doAssert a == " "

block:
var a = "xxx wind"
a.strip(chars={'x'})
doAssert a == " wind"

block:
var a = "xxx iii"
a.strip(chars={'i'})
doAssert a == "xxx "

block:
var a = "xxx iii"
doAssert a.dup(strip(chars = {'i'})) == "xxx "
doAssert a.dup(strip(chars = {' '})) == "xxx iii"
doAssert a.dup(strip(chars = {'x'})) == " iii"
doAssert a.dup(strip(chars = {'x', ' '})) == "iii"
doAssert a.dup(strip(chars = {'x', 'i'})) == " "
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block:
var a = "x i"
doAssert a.dup(strip(chars = {'i'})) == "x "
doAssert a.dup(strip(chars = {' '})) == "x i"
doAssert a.dup(strip(chars = {'x'})) == " i"
doAssert a.dup(strip(chars = {'x', ' '})) == "i"
doAssert a.dup(strip(chars = {'x', 'i'})) == " "
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block:
var a = ""
doAssert a.dup(strip(chars = {'i'})).len == 0
doAssert a.dup(strip(chars = {' '})).len == 0
doAssert a.dup(strip(chars = {'x'})).len == 0
doAssert a.dup(strip(chars = {'x', ' '})).len == 0
doAssert a.dup(strip(chars = {'x', 'i'})).len == 0
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block:
var a = " "
doAssert a.dup(strip(chars = {'i'})) == " "
doAssert a.dup(strip(chars = {' '})).len == 0
doAssert a.dup(strip(chars = {'x'})) == " "
doAssert a.dup(strip(chars = {'x', ' '})).len == 0
doAssert a.dup(strip(chars = {'x', 'i'})) == " "
doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0

block: # setSlice
var a = "Hello, Nim!"
doassert a.dup(setSlice(7 .. 9)) == "Nim"
doAssert a.dup(setSlice(0 .. 0)) == "H"
doAssert a.dup(setSlice(0 .. 1)) == "He"
doAssert a.dup(setSlice(0 .. 10)) == a
doAssert a.dup(setSlice(1 .. 0)).len == 0
doAssert a.dup(setSlice(20 .. -1)).len == 0

doAssertRaises(AssertionDefect):
discard a.dup(setSlice(-1 .. 1))

doAssertRaises(AssertionDefect):
discard a.dup(setSlice(1 .. 11))

block: # add
var a0 = "hi"
var b0 = "foobar"
when nimvm:
discard # pending bug #15952
else:
a0.add b0.toOpenArray(1,3)
doAssert a0 == "hioob"
proc fn(c: openArray[char]): string =
result.add c
doAssert fn("def") == "def"
doAssert fn(['d','\0', 'f'])[2] == 'f'

static: main()
main()
25 changes: 12 additions & 13 deletions tests/vm/tstring_openarray.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@ proc set_all[T](s: var openArray[T]; val: T) =
for i in 0..<s.len:
s[i] = val

proc test() =
var a0 = "hello_world"
var a1 = [1,2,3,4,5,6,7,8,9]
var a2 = @[1,2,3,4,5,6,7,8,9]
a0.set_all('i')
a1.set_all(4)
a2.set_all(4)
doAssert a0 == "iiiiiiiiiii"
doAssert a1 == [4,4,4,4,4,4,4,4,4]
doAssert a2 == @[4,4,4,4,4,4,4,4,4]
proc main() =
var a0 = "hello_world"
var a1 = [1,2,3,4,5,6,7,8,9]
var a2 = @[1,2,3,4,5,6,7,8,9]
a0.set_all('i')
a1.set_all(4)
a2.set_all(4)
doAssert a0 == "iiiiiiiiiii"
doAssert a1 == [4,4,4,4,4,4,4,4,4]
doAssert a2 == @[4,4,4,4,4,4,4,4,4]

const constval0 = "hello".map(proc(x: char): char = x)
const constval1 = [1,2,3,4].map(proc(x: int): int = x)

doAssert("hello".map(proc(x: char): char = x) == constval0)
doAssert([1,2,3,4].map(proc(x: int): int = x) == constval1)

test()
static:
test()
static: main()
main()