follow up #19714; add memmem optimizations for find on Linux, Macos and BSDs (#20556)

* fixes tests

* add memmem optimization for find

* fixes

* ty[o

* fixes `"abc".find("") == 0 doesn't work on macOS

Co-authored-by: xflywind <43030857+xflywind@users.noreply.github.com>
This commit is contained in:
ringabout 2022-10-14 05:58:59 +08:00 • committed by GitHub
commit be18f4e513
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1936,6 +1936,14 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = -1): int {.
if s[i] in chars: if s[i] in chars:
return i return i
when defined(linux):
proc memmem(haystack: pointer, haystacklen: csize_t,
needle: pointer, needlelen: csize_t): pointer {.importc, header: """#define _GNU_SOURCE
#include <string.h>""".}
elif defined(bsd) or (defined(macosx) and not defined(ios)):
proc memmem(haystack: pointer, haystacklen: csize_t,
needle: pointer, needlelen: csize_t): pointer {.importc, header: "#include <string.h>".}
func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl, func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl,
extern: "nsuFindStr".} = extern: "nsuFindStr".} =
## Searches for `sub` in `s` inside range `start..last` (both ends included). ## Searches for `sub` in `s` inside range `start..last` (both ends included).
@ -1951,8 +1959,25 @@ func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl,
if sub.len > s.len - start: return -1 if sub.len > s.len - start: 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 =
result = find(initSkipTable(sub), s, sub, start, last) result = find(initSkipTable(sub), s, sub, start, last)
when nimvm:
useSkipTable()
else:
when declared(memmem):
let subLen = sub.len
if last < 0 and start < s.len and subLen != 0:
let found = memmem(s[start].unsafeAddr, csize_t(s.len - start), sub.cstring, csize_t(subLen))
result = if not found.isNil:
cast[ByteAddress](found) -% cast[ByteAddress](s.cstring)
else:
-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)