use strstr for a faster find implementation (#17672)

* use strstr for a faster find implementation
* stress the -d:release and -d:danger switches
This commit is contained in:
Andreas Rumpf 2021-04-08 00:54:47 +02:00 • committed by GitHub
commit 643dbc743b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 4 deletions

View file

@ -67,6 +67,11 @@ aiming for your debugging pleasure. With `-d:release` some checks are
`turned off and optimizations are turned on `turned off and optimizations are turned on
<nimc.html#compiler-usage-compileminustime-symbols>`_. <nimc.html#compiler-usage-compileminustime-symbols>`_.
For benchmarking or production code, use the `-d:release` switch.
For comparing the performance with unsafe languages like C, use the `-d:danger` switch
in order to get meaningful, comparable results. Otherwise Nim might be handicapped
by checks that are **not even available** for C.
Though it should be pretty obvious what the program does, I will explain the Though it should be pretty obvious what the program does, I will explain the
syntax: statements which are not indented are executed when the program syntax: statements which are not indented are executed when the program
starts. Indentation is Nim's way of grouping statements. Indentation is starts. Indentation is Nim's way of grouping statements. Indentation is

View file

@ -1826,6 +1826,9 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {.
when not (defined(js) or defined(nimdoc) or defined(nimscript)): when not (defined(js) or defined(nimdoc) or defined(nimscript)):
func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {.
importc: "memchr", header: "<string.h>".} importc: "memchr", header: "<string.h>".}
func c_strstr(haystack, needle: cstring): cstring {.
importc: "strstr", header: "<string.h>".}
const hasCStringBuiltin = true const hasCStringBuiltin = true
else: else:
const hasCStringBuiltin = false const hasCStringBuiltin = false
@ -1889,10 +1892,30 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl,
## * `replace func<#replace,string,string,string>`_ ## * `replace func<#replace,string,string,string>`_
if sub.len > s.len: return -1 if sub.len > s.len: return -1
if sub.len == 1: return find(s, sub[0], start, last) if sub.len == 1: return find(s, sub[0], start, last)
template useSkipTable {.dirty.} =
var a {.noinit.}: SkipTable var a {.noinit.}: SkipTable
initSkipTable(a, sub) initSkipTable(a, sub)
result = find(a, s, sub, start, last) result = find(a, s, sub, start, last)
when not hasCStringBuiltin:
useSkipTable()
else:
when nimvm:
useSkipTable()
else:
when hasCStringBuiltin:
if last == 0 and s.len > start:
let found = c_strstr(s[start].unsafeAddr, sub)
if not found.isNil:
result = cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
else:
result = -1
else:
useSkipTable()
else:
useSkipTable()
func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl, func rfind*(s: string, sub: char, start: Natural = 0, last = -1): int {.rtl,
extern: "nsuRFindChar".} = extern: "nsuRFindChar".} =
## Searches for `sub` in `s` inside range `start..last` (both ends included) ## Searches for `sub` in `s` inside range `start..last` (both ends included)