mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
120 lines
3.2 KiB
Nim
120 lines
3.2 KiB
Nim
#
|
|
#
|
|
# Nim's Runtime Library
|
|
# (c) Copyright 2021 Nim Contributors
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
## This module provides some high performance string operations.
|
|
##
|
|
## Experimental API, subject to change.
|
|
|
|
when defined(nimPreviewSlimSystem):
|
|
import std/assertions
|
|
|
|
|
|
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 #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
|
|
|
|
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:
|
|
assert stripSlice(" abc ") == 1 .. 3
|
|
var
|
|
first = 0
|
|
last = high(s)
|
|
if leading:
|
|
while first <= last and s[first] in chars: inc(first)
|
|
if trailing:
|
|
while last >= first and s[last] in chars: dec(last)
|
|
result = first .. last
|
|
|
|
func setSlice*(s: var string, slice: Slice[int]) =
|
|
## Inplace version of `substr`.
|
|
runnableExamples:
|
|
import std/sugar
|
|
|
|
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))
|
|
|
|
|
|
let first = slice.a
|
|
let last = slice.b
|
|
|
|
assert first >= 0
|
|
assert last <= s.high
|
|
|
|
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:
|
|
when defined(nimSeqsV2):
|
|
prepareMutation(s)
|
|
moveMem(addr s[0], addr s[first], last - first + 1)
|
|
s.setLen(last - first + 1)
|
|
|
|
func strip*(a: var string, leading = true, trailing = true, chars: set[char] = whitespaces) {.inline.} =
|
|
## Inplace version of `strip`. Strips leading or
|
|
## trailing `chars` (default: whitespace characters).
|
|
##
|
|
## If `leading` is true (default), leading `chars` are stripped.
|
|
## If `trailing` is true (default), trailing `chars` are stripped.
|
|
## If both are false, the string is unchanged.
|
|
runnableExamples:
|
|
var a = " vhellov "
|
|
strip(a)
|
|
assert a == "vhellov"
|
|
|
|
a = " vhellov "
|
|
a.strip(leading = false)
|
|
assert a == " vhellov"
|
|
|
|
a = " vhellov "
|
|
a.strip(trailing = false)
|
|
assert a == "vhellov "
|
|
|
|
var c = "blaXbla"
|
|
c.strip(chars = {'b', 'a'})
|
|
assert c == "laXbl"
|
|
c = "blaXbla"
|
|
c.strip(chars = {'b', 'a', 'l'})
|
|
assert c == "X"
|
|
|
|
setSlice(a, stripSlice(a, leading, trailing, chars))
|