Skip to content

Commit

Permalink
use strstr for a faster find implementation (nim-lang#17672)
Browse files Browse the repository at this point in the history
* use strstr for a faster find implementation
* stress the -d:release and -d:danger switches
  • Loading branch information
Araq authored and PMunch committed Mar 28, 2022
1 parent 4a33c73 commit 874c380
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 4 deletions.
7 changes: 6 additions & 1 deletion doc/tut1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ aiming for your debugging pleasure. With `-d:release` some checks are
`turned off and optimizations are turned on
<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
syntax: statements which are not indented are executed when the program
starts. Indentation is Nim's way of grouping statements. Indentation is
Expand Down Expand Up @@ -626,7 +631,7 @@ Some terminology: in the example `question` is called a (formal) *parameter*,
Result variable
---------------
A procedure that returns a value has an implicit `result` variable declared
that represents the return value. A `return` statement with no expression is
that represents the return value. A `return` statement with no expression is
shorthand for `return result`. The `result` value is always returned
automatically at the end of a procedure if there is no `return` statement at
the exit.
Expand Down
29 changes: 26 additions & 3 deletions lib/pure/strutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)):
func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {.
importc: "memchr", header: "<string.h>".}
func c_strstr(haystack, needle: cstring): cstring {.
importc: "strstr", header: "<string.h>".}

const hasCStringBuiltin = true
else:
const hasCStringBuiltin = false
Expand Down Expand Up @@ -1889,9 +1892,29 @@ func find*(s, sub: string, start: Natural = 0, last = 0): int {.rtl,
## * `replace func<#replace,string,string,string>`_
if sub.len > s.len: return -1
if sub.len == 1: return find(s, sub[0], start, last)
var a {.noinit.}: SkipTable
initSkipTable(a, sub)
result = find(a, s, sub, start, last)

template useSkipTable {.dirty.} =
var a {.noinit.}: SkipTable
initSkipTable(a, sub)
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,
extern: "nsuRFindChar".} =
Expand Down

0 comments on commit 874c380

Please sign in to comment.