summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2022-10-14 05:58:59 +0800
committerGitHub <noreply@github.com>2022-10-13 23:58:59 +0200
commitbe18f4e513799de186e6de53f32c9488b19f1ec7 (patch)
treea259966faef2cb66f5c070b06e5b396284993d35 /lib
parent6082b9ea5d4907e7ad8dfb66289d164a7cbdab42 (diff)
downloadNim-be18f4e513799de186e6de53f32c9488b19f1ec7.tar.gz
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>
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/strutils.nim27
1 files changed, 26 insertions, 1 deletions
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index abdeed5b4..2e408f438 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1936,6 +1936,14 @@ func find*(s: string, chars: set[char], start: Natural = 0, last = -1): int {.
     if s[i] in chars:
       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,
     extern: "nsuFindStr".} =
   ## Searches for `sub` in `s` inside range `start..last` (both ends included).
@@ -1951,7 +1959,24 @@ func find*(s, sub: string, start: Natural = 0, last = -1): int {.rtl,
   if sub.len > s.len - start: return -1
   if sub.len == 1: return find(s, sub[0], start, last)
 
-  result = find(initSkipTable(sub), s, sub, start, last)
+  template useSkipTable =
+    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,
     extern: "nsuRFindChar".} =