|
17 | 17 | │ PERFORMANCE OF THIS SOFTWARE. │
|
18 | 18 | ╚─────────────────────────────────────────────────────────────────────────────*/
|
19 | 19 | #include "libc/str/str.h"
|
20 |
| -#include "libc/dce.h" |
| 20 | +#include "libc/mem/alloca.h" |
| 21 | +#include "libc/runtime/stack.h" |
21 | 22 | #include "libc/str/tab.h"
|
22 | 23 |
|
23 |
| -typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); |
| 24 | +static void computeLPS(const char *pattern, long M, long *lps) { |
| 25 | + long len = 0; |
| 26 | + lps[0] = 0; |
| 27 | + long i = 1; |
| 28 | + while (i < M) { |
| 29 | + if (kToLower[pattern[i] & 255] == kToLower[pattern[len] & 255]) { |
| 30 | + len++; |
| 31 | + lps[i] = len; |
| 32 | + i++; |
| 33 | + } else { |
| 34 | + if (len != 0) { |
| 35 | + len = lps[len - 1]; |
| 36 | + } else { |
| 37 | + lps[i] = 0; |
| 38 | + i++; |
| 39 | + } |
| 40 | + } |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +static char *kmp(const char *s, size_t n, const char *ss, size_t m) { |
| 45 | + if (!m) |
| 46 | + return (char *)s; |
| 47 | + if (n < m) |
| 48 | + return NULL; |
| 49 | +#pragma GCC push_options |
| 50 | +#pragma GCC diagnostic ignored "-Walloca-larger-than=" |
| 51 | +#pragma GCC diagnostic ignored "-Wanalyzer-out-of-bounds" |
| 52 | + long need = sizeof(long) * m; |
| 53 | + long *lps = (long *)alloca(need); |
| 54 | + CheckLargeStackAllocation(lps, need); |
| 55 | +#pragma GCC pop_options |
| 56 | + computeLPS(ss, m, lps); |
| 57 | + long i = 0; |
| 58 | + long j = 0; |
| 59 | + while (i < n) { |
| 60 | + if (kToLower[ss[j] & 255] == kToLower[s[i] & 255]) { |
| 61 | + i++; |
| 62 | + j++; |
| 63 | + } |
| 64 | + if (j == m) { |
| 65 | + return (char *)(s + i - j); |
| 66 | + } else if (i < n && kToLower[ss[j] & 255] != kToLower[s[i] & 255]) { |
| 67 | + if (j != 0) { |
| 68 | + j = lps[j - 1]; |
| 69 | + } else { |
| 70 | + i++; |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + return NULL; |
| 75 | +} |
24 | 76 |
|
25 | 77 | /**
|
26 | 78 | * Searches for substring case-insensitively.
|
27 | 79 | *
|
28 | 80 | * @param haystack is the search area, as a NUL-terminated string
|
29 | 81 | * @param needle is the desired substring, also NUL-terminated
|
30 | 82 | * @return pointer to first substring within haystack, or NULL
|
31 |
| - * @note this implementation goes fast in practice but isn't hardened |
32 |
| - * against pathological cases, and therefore shouldn't be used on |
33 |
| - * untrustworthy data |
34 | 83 | * @asyncsignalsafe
|
35 | 84 | * @see strstr()
|
36 | 85 | */
|
37 |
| -__vex char *strcasestr(const char *haystack, const char *needle) { |
38 |
| -#if defined(__x86_64__) && !defined(__chibicc__) |
39 |
| - char c; |
40 |
| - size_t i; |
41 |
| - unsigned k, m; |
42 |
| - const xmm_t *p; |
43 |
| - xmm_t v, n1, n2, z = {0}; |
44 |
| - if (haystack == needle || !*needle) |
45 |
| - return (char *)haystack; |
46 |
| - c = *needle; |
47 |
| - n1 = (xmm_t){c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; |
48 |
| - c = kToLower[c & 255]; |
49 |
| - n2 = (xmm_t){c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c}; |
50 |
| - for (;;) { |
51 |
| - k = (uintptr_t)haystack & 15; |
52 |
| - p = (const xmm_t *)((uintptr_t)haystack & -16); |
53 |
| - v = *p; |
54 |
| - m = __builtin_ia32_pmovmskb128((v == z) | (v == n1) | (v == n2)); |
55 |
| - m >>= k; |
56 |
| - m <<= k; |
57 |
| - while (!m) { |
58 |
| - v = *++p; |
59 |
| - m = __builtin_ia32_pmovmskb128((v == z) | (v == n1) | (v == n2)); |
60 |
| - } |
61 |
| - haystack = (const char *)p + __builtin_ctzl(m); |
62 |
| - for (i = 0;; ++i) { |
63 |
| - if (!needle[i]) |
64 |
| - return (/*unconst*/ char *)haystack; |
65 |
| - if (!haystack[i]) |
66 |
| - break; |
67 |
| - if (kToLower[needle[i] & 255] != kToLower[haystack[i] & 255]) |
68 |
| - break; |
69 |
| - } |
70 |
| - if (!*haystack++) |
71 |
| - break; |
72 |
| - } |
73 |
| - return 0; |
74 |
| -#else |
75 |
| - size_t i; |
76 |
| - if (haystack == needle || !*needle) |
77 |
| - return (void *)haystack; |
78 |
| - for (;;) { |
79 |
| - for (i = 0;; ++i) { |
80 |
| - if (!needle[i]) |
81 |
| - return (/*unconst*/ char *)haystack; |
82 |
| - if (!haystack[i]) |
83 |
| - break; |
84 |
| - if (kToLower[needle[i] & 255] != kToLower[haystack[i] & 255]) |
85 |
| - break; |
86 |
| - } |
87 |
| - if (!*haystack++) |
88 |
| - break; |
89 |
| - } |
90 |
| - return 0; |
91 |
| -#endif |
| 86 | +char *strcasestr(const char *haystack, const char *needle) { |
| 87 | + return kmp(haystack, strlen(haystack), needle, strlen(needle)); |
92 | 88 | }
|
0 commit comments