/src/cpython/Objects/stringlib/fastsearch.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* stringlib: fastsearch implementation */ |
2 | | |
3 | | #define STRINGLIB_FASTSEARCH_H |
4 | | |
5 | | /* fast search/count implementation, based on a mix between boyer- |
6 | | moore and horspool, with a few more bells and whistles on the top. |
7 | | for some more background, see: |
8 | | https://web.archive.org/web/20201107074620/http://effbot.org/zone/stringlib.htm */ |
9 | | |
10 | | /* note: fastsearch may access s[n], which isn't a problem when using |
11 | | Python's ordinary string types, but may cause problems if you're |
12 | | using this code in other contexts. also, the count mode returns -1 |
13 | | if there cannot possibly be a match in the target string, and 0 if |
14 | | it has actually checked for matches, but didn't find any. callers |
15 | | beware! */ |
16 | | |
17 | | /* If the strings are long enough, use Crochemore and Perrin's Two-Way |
18 | | algorithm, which has worst-case O(n) runtime and best-case O(n/k). |
19 | | Also compute a table of shifts to achieve O(n/k) in more cases, |
20 | | and often (data dependent) deduce larger shifts than pure C&P can |
21 | | deduce. See stringlib_find_two_way_notes.txt in this folder for a |
22 | | detailed explanation. */ |
23 | | |
24 | 580M | #define FAST_COUNT 0 |
25 | 390M | #define FAST_SEARCH 1 |
26 | 84.7M | #define FAST_RSEARCH 2 |
27 | | |
28 | | #if LONG_BIT >= 128 |
29 | | #define STRINGLIB_BLOOM_WIDTH 128 |
30 | | #elif LONG_BIT >= 64 |
31 | 5.84G | #define STRINGLIB_BLOOM_WIDTH 64 |
32 | | #elif LONG_BIT >= 32 |
33 | | #define STRINGLIB_BLOOM_WIDTH 32 |
34 | | #else |
35 | | #error "LONG_BIT is smaller than 32" |
36 | | #endif |
37 | | |
38 | | #define STRINGLIB_BLOOM_ADD(mask, ch) \ |
39 | 32.5M | ((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1))))) |
40 | | #define STRINGLIB_BLOOM(mask, ch) \ |
41 | 5.80G | ((mask & (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1))))) |
42 | | |
43 | | #ifdef STRINGLIB_FAST_MEMCHR |
44 | 206M | # define MEMCHR_CUT_OFF 15 |
45 | | #else |
46 | 57.6M | # define MEMCHR_CUT_OFF 40 |
47 | | #endif |
48 | | |
49 | | Py_LOCAL_INLINE(Py_ssize_t) |
50 | | STRINGLIB(find_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch) |
51 | 263M | { |
52 | 263M | const STRINGLIB_CHAR *p, *e; |
53 | | |
54 | 263M | p = s; |
55 | 263M | e = s + n; |
56 | 263M | if (n > MEMCHR_CUT_OFF) { |
57 | | #ifdef STRINGLIB_FAST_MEMCHR |
58 | 110M | p = STRINGLIB_FAST_MEMCHR(s, ch, n); |
59 | 110M | if (p != NULL) |
60 | 109M | return (p - s); |
61 | 1.50M | return -1; |
62 | | #else |
63 | | /* use memchr if we can choose a needle without too many likely |
64 | | false positives */ |
65 | | const STRINGLIB_CHAR *s1, *e1; |
66 | | unsigned char needle = ch & 0xff; |
67 | | /* If looking for a multiple of 256, we'd have too |
68 | | many false positives looking for the '\0' byte in UCS2 |
69 | | and UCS4 representations. */ |
70 | 49.8M | if (needle != 0) { |
71 | 49.4M | do { |
72 | 49.4M | void *candidate = memchr(p, needle, |
73 | 49.4M | (e - p) * sizeof(STRINGLIB_CHAR)); |
74 | 49.4M | if (candidate == NULL) |
75 | 506k | return -1; |
76 | 48.9M | s1 = p; |
77 | 48.9M | p = (const STRINGLIB_CHAR *) |
78 | 48.9M | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); |
79 | 48.9M | if (*p == ch) |
80 | 48.9M | return (p - s); |
81 | | /* False positive */ |
82 | 59.0k | p++; |
83 | 59.0k | if (p - s1 > MEMCHR_CUT_OFF) |
84 | 28.2k | continue; |
85 | 30.7k | if (e - p <= MEMCHR_CUT_OFF) |
86 | 3.31k | break; |
87 | 27.4k | e1 = p + MEMCHR_CUT_OFF; |
88 | 917k | while (p != e1) { |
89 | 897k | if (*p == ch) |
90 | 7.40k | return (p - s); |
91 | 890k | p++; |
92 | 890k | } |
93 | 27.4k | } |
94 | 49.4M | while (e - p > MEMCHR_CUT_OFF); |
95 | 49.4M | } |
96 | | #endif |
97 | 160M | } |
98 | 399M | while (p < e) { |
99 | 310M | if (*p == ch) |
100 | 15.1M | return (p - s); |
101 | 295M | p++; |
102 | 295M | } |
103 | 88.4M | return -1; |
104 | 103M | } Unexecuted instantiation: bytesobject.c:stringlib_find_char unicodeobject.c:ucs1lib_find_char Line | Count | Source | 51 | 107M | { | 52 | 107M | const STRINGLIB_CHAR *p, *e; | 53 | | | 54 | 107M | p = s; | 55 | 107M | e = s + n; | 56 | 107M | if (n > MEMCHR_CUT_OFF) { | 57 | 17.9M | #ifdef STRINGLIB_FAST_MEMCHR | 58 | 17.9M | p = STRINGLIB_FAST_MEMCHR(s, ch, n); | 59 | 17.9M | if (p != NULL) | 60 | 17.1M | return (p - s); | 61 | 792k | return -1; | 62 | | #else | 63 | | /* use memchr if we can choose a needle without too many likely | 64 | | false positives */ | 65 | | const STRINGLIB_CHAR *s1, *e1; | 66 | | unsigned char needle = ch & 0xff; | 67 | | /* If looking for a multiple of 256, we'd have too | 68 | | many false positives looking for the '\0' byte in UCS2 | 69 | | and UCS4 representations. */ | 70 | | if (needle != 0) { | 71 | | do { | 72 | | void *candidate = memchr(p, needle, | 73 | | (e - p) * sizeof(STRINGLIB_CHAR)); | 74 | | if (candidate == NULL) | 75 | | return -1; | 76 | | s1 = p; | 77 | | p = (const STRINGLIB_CHAR *) | 78 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 79 | | if (*p == ch) | 80 | | return (p - s); | 81 | | /* False positive */ | 82 | | p++; | 83 | | if (p - s1 > MEMCHR_CUT_OFF) | 84 | | continue; | 85 | | if (e - p <= MEMCHR_CUT_OFF) | 86 | | break; | 87 | | e1 = p + MEMCHR_CUT_OFF; | 88 | | while (p != e1) { | 89 | | if (*p == ch) | 90 | | return (p - s); | 91 | | p++; | 92 | | } | 93 | | } | 94 | | while (e - p > MEMCHR_CUT_OFF); | 95 | | } | 96 | | #endif | 97 | 17.9M | } | 98 | 253M | while (p < e) { | 99 | 167M | if (*p == ch) | 100 | 3.95M | return (p - s); | 101 | 163M | p++; | 102 | 163M | } | 103 | 85.8M | return -1; | 104 | 89.8M | } |
unicodeobject.c:ucs2lib_find_char Line | Count | Source | 51 | 57.4M | { | 52 | 57.4M | const STRINGLIB_CHAR *p, *e; | 53 | | | 54 | 57.4M | p = s; | 55 | 57.4M | e = s + n; | 56 | 57.4M | if (n > MEMCHR_CUT_OFF) { | 57 | | #ifdef STRINGLIB_FAST_MEMCHR | 58 | | p = STRINGLIB_FAST_MEMCHR(s, ch, n); | 59 | | if (p != NULL) | 60 | | return (p - s); | 61 | | return -1; | 62 | | #else | 63 | | /* use memchr if we can choose a needle without too many likely | 64 | | false positives */ | 65 | 49.8M | const STRINGLIB_CHAR *s1, *e1; | 66 | 49.8M | unsigned char needle = ch & 0xff; | 67 | | /* If looking for a multiple of 256, we'd have too | 68 | | many false positives looking for the '\0' byte in UCS2 | 69 | | and UCS4 representations. */ | 70 | 49.8M | if (needle != 0) { | 71 | 49.4M | do { | 72 | 49.4M | void *candidate = memchr(p, needle, | 73 | 49.4M | (e - p) * sizeof(STRINGLIB_CHAR)); | 74 | 49.4M | if (candidate == NULL) | 75 | 506k | return -1; | 76 | 48.9M | s1 = p; | 77 | 48.9M | p = (const STRINGLIB_CHAR *) | 78 | 48.9M | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 79 | 48.9M | if (*p == ch) | 80 | 48.9M | return (p - s); | 81 | | /* False positive */ | 82 | 59.0k | p++; | 83 | 59.0k | if (p - s1 > MEMCHR_CUT_OFF) | 84 | 28.2k | continue; | 85 | 30.7k | if (e - p <= MEMCHR_CUT_OFF) | 86 | 3.31k | break; | 87 | 27.4k | e1 = p + MEMCHR_CUT_OFF; | 88 | 917k | while (p != e1) { | 89 | 897k | if (*p == ch) | 90 | 7.40k | return (p - s); | 91 | 890k | p++; | 92 | 890k | } | 93 | 27.4k | } | 94 | 49.4M | while (e - p > MEMCHR_CUT_OFF); | 95 | 49.4M | } | 96 | 49.8M | #endif | 97 | 49.8M | } | 98 | 128M | while (p < e) { | 99 | 126M | if (*p == ch) | 100 | 5.59M | return (p - s); | 101 | 120M | p++; | 102 | 120M | } | 103 | 2.47M | return -1; | 104 | 8.06M | } |
unicodeobject.c:ucs4lib_find_char Line | Count | Source | 51 | 80.6M | { | 52 | 80.6M | const STRINGLIB_CHAR *p, *e; | 53 | | | 54 | 80.6M | p = s; | 55 | 80.6M | e = s + n; | 56 | 80.6M | if (n > MEMCHR_CUT_OFF) { | 57 | 80.5M | #ifdef STRINGLIB_FAST_MEMCHR | 58 | 80.5M | p = STRINGLIB_FAST_MEMCHR(s, ch, n); | 59 | 80.5M | if (p != NULL) | 60 | 80.5M | return (p - s); | 61 | 31.3k | return -1; | 62 | | #else | 63 | | /* use memchr if we can choose a needle without too many likely | 64 | | false positives */ | 65 | | const STRINGLIB_CHAR *s1, *e1; | 66 | | unsigned char needle = ch & 0xff; | 67 | | /* If looking for a multiple of 256, we'd have too | 68 | | many false positives looking for the '\0' byte in UCS2 | 69 | | and UCS4 representations. */ | 70 | | if (needle != 0) { | 71 | | do { | 72 | | void *candidate = memchr(p, needle, | 73 | | (e - p) * sizeof(STRINGLIB_CHAR)); | 74 | | if (candidate == NULL) | 75 | | return -1; | 76 | | s1 = p; | 77 | | p = (const STRINGLIB_CHAR *) | 78 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 79 | | if (*p == ch) | 80 | | return (p - s); | 81 | | /* False positive */ | 82 | | p++; | 83 | | if (p - s1 > MEMCHR_CUT_OFF) | 84 | | continue; | 85 | | if (e - p <= MEMCHR_CUT_OFF) | 86 | | break; | 87 | | e1 = p + MEMCHR_CUT_OFF; | 88 | | while (p != e1) { | 89 | | if (*p == ch) | 90 | | return (p - s); | 91 | | p++; | 92 | | } | 93 | | } | 94 | | while (e - p > MEMCHR_CUT_OFF); | 95 | | } | 96 | | #endif | 97 | 80.5M | } | 98 | 262k | while (p < e) { | 99 | 229k | if (*p == ch) | 100 | 26.7k | return (p - s); | 101 | 202k | p++; | 102 | 202k | } | 103 | 33.1k | return -1; | 104 | 59.8k | } |
unicodeobject.c:asciilib_find_char Line | Count | Source | 51 | 17.8M | { | 52 | 17.8M | const STRINGLIB_CHAR *p, *e; | 53 | | | 54 | 17.8M | p = s; | 55 | 17.8M | e = s + n; | 56 | 17.8M | if (n > MEMCHR_CUT_OFF) { | 57 | 12.2M | #ifdef STRINGLIB_FAST_MEMCHR | 58 | 12.2M | p = STRINGLIB_FAST_MEMCHR(s, ch, n); | 59 | 12.2M | if (p != NULL) | 60 | 11.5M | return (p - s); | 61 | 682k | return -1; | 62 | | #else | 63 | | /* use memchr if we can choose a needle without too many likely | 64 | | false positives */ | 65 | | const STRINGLIB_CHAR *s1, *e1; | 66 | | unsigned char needle = ch & 0xff; | 67 | | /* If looking for a multiple of 256, we'd have too | 68 | | many false positives looking for the '\0' byte in UCS2 | 69 | | and UCS4 representations. */ | 70 | | if (needle != 0) { | 71 | | do { | 72 | | void *candidate = memchr(p, needle, | 73 | | (e - p) * sizeof(STRINGLIB_CHAR)); | 74 | | if (candidate == NULL) | 75 | | return -1; | 76 | | s1 = p; | 77 | | p = (const STRINGLIB_CHAR *) | 78 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 79 | | if (*p == ch) | 80 | | return (p - s); | 81 | | /* False positive */ | 82 | | p++; | 83 | | if (p - s1 > MEMCHR_CUT_OFF) | 84 | | continue; | 85 | | if (e - p <= MEMCHR_CUT_OFF) | 86 | | break; | 87 | | e1 = p + MEMCHR_CUT_OFF; | 88 | | while (p != e1) { | 89 | | if (*p == ch) | 90 | | return (p - s); | 91 | | p++; | 92 | | } | 93 | | } | 94 | | while (e - p > MEMCHR_CUT_OFF); | 95 | | } | 96 | | #endif | 97 | 12.2M | } | 98 | 16.4M | while (p < e) { | 99 | 16.4M | if (*p == ch) | 100 | 5.55M | return (p - s); | 101 | 10.8M | p++; | 102 | 10.8M | } | 103 | 48.3k | return -1; | 104 | 5.60M | } |
bytes_methods.c:stringlib_find_char Line | Count | Source | 51 | 1.59k | { | 52 | 1.59k | const STRINGLIB_CHAR *p, *e; | 53 | | | 54 | 1.59k | p = s; | 55 | 1.59k | e = s + n; | 56 | 1.59k | if (n > MEMCHR_CUT_OFF) { | 57 | 1.59k | #ifdef STRINGLIB_FAST_MEMCHR | 58 | 1.59k | p = STRINGLIB_FAST_MEMCHR(s, ch, n); | 59 | 1.59k | if (p != NULL) | 60 | 1.35k | return (p - s); | 61 | 242 | return -1; | 62 | | #else | 63 | | /* use memchr if we can choose a needle without too many likely | 64 | | false positives */ | 65 | | const STRINGLIB_CHAR *s1, *e1; | 66 | | unsigned char needle = ch & 0xff; | 67 | | /* If looking for a multiple of 256, we'd have too | 68 | | many false positives looking for the '\0' byte in UCS2 | 69 | | and UCS4 representations. */ | 70 | | if (needle != 0) { | 71 | | do { | 72 | | void *candidate = memchr(p, needle, | 73 | | (e - p) * sizeof(STRINGLIB_CHAR)); | 74 | | if (candidate == NULL) | 75 | | return -1; | 76 | | s1 = p; | 77 | | p = (const STRINGLIB_CHAR *) | 78 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 79 | | if (*p == ch) | 80 | | return (p - s); | 81 | | /* False positive */ | 82 | | p++; | 83 | | if (p - s1 > MEMCHR_CUT_OFF) | 84 | | continue; | 85 | | if (e - p <= MEMCHR_CUT_OFF) | 86 | | break; | 87 | | e1 = p + MEMCHR_CUT_OFF; | 88 | | while (p != e1) { | 89 | | if (*p == ch) | 90 | | return (p - s); | 91 | | p++; | 92 | | } | 93 | | } | 94 | | while (e - p > MEMCHR_CUT_OFF); | 95 | | } | 96 | | #endif | 97 | 1.59k | } | 98 | 0 | while (p < e) { | 99 | 0 | if (*p == ch) | 100 | 0 | return (p - s); | 101 | 0 | p++; | 102 | 0 | } | 103 | 0 | return -1; | 104 | 0 | } |
Unexecuted instantiation: bytearrayobject.c:stringlib_find_char |
105 | | |
106 | | #undef MEMCHR_CUT_OFF |
107 | | |
108 | | #if STRINGLIB_SIZEOF_CHAR == 1 |
109 | 37.4k | # define MEMRCHR_CUT_OFF 15 |
110 | | #else |
111 | 309k | # define MEMRCHR_CUT_OFF 40 |
112 | | #endif |
113 | | |
114 | | |
115 | | Py_LOCAL_INLINE(Py_ssize_t) |
116 | | STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch) |
117 | 308k | { |
118 | 308k | const STRINGLIB_CHAR *p; |
119 | 308k | #ifdef HAVE_MEMRCHR |
120 | | /* memrchr() is a GNU extension, available since glibc 2.1.91. it |
121 | | doesn't seem as optimized as memchr(), but is still quite |
122 | | faster than our hand-written loop below. There is no wmemrchr |
123 | | for 4-byte chars. */ |
124 | | |
125 | 308k | if (n > MEMRCHR_CUT_OFF) { |
126 | | #if STRINGLIB_SIZEOF_CHAR == 1 |
127 | | p = memrchr(s, ch, n); |
128 | 10.6k | if (p != NULL) |
129 | 7.27k | return (p - s); |
130 | 3.36k | return -1; |
131 | | #else |
132 | | /* use memrchr if we can choose a needle without too many likely |
133 | | false positives */ |
134 | | const STRINGLIB_CHAR *s1; |
135 | | Py_ssize_t n1; |
136 | | unsigned char needle = ch & 0xff; |
137 | | /* If looking for a multiple of 256, we'd have too |
138 | | many false positives looking for the '\0' byte in UCS2 |
139 | | and UCS4 representations. */ |
140 | 127k | if (needle != 0) { |
141 | 137k | do { |
142 | 137k | void *candidate = memrchr(s, needle, |
143 | 137k | n * sizeof(STRINGLIB_CHAR)); |
144 | 137k | if (candidate == NULL) |
145 | 635 | return -1; |
146 | 136k | n1 = n; |
147 | 136k | p = (const STRINGLIB_CHAR *) |
148 | 136k | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); |
149 | 136k | n = p - s; |
150 | 136k | if (*p == ch) |
151 | 123k | return n; |
152 | | /* False positive */ |
153 | 13.3k | if (n1 - n > MEMRCHR_CUT_OFF) |
154 | 6.05k | continue; |
155 | 7.26k | if (n <= MEMRCHR_CUT_OFF) |
156 | 847 | break; |
157 | 6.42k | s1 = p - MEMRCHR_CUT_OFF; |
158 | 243k | while (p > s1) { |
159 | 237k | p--; |
160 | 237k | if (*p == ch) |
161 | 905 | return (p - s); |
162 | 237k | } |
163 | 5.51k | n = p - s; |
164 | 5.51k | } |
165 | 127k | while (n > MEMRCHR_CUT_OFF); |
166 | 127k | } |
167 | | #endif |
168 | 138k | } |
169 | 173k | #endif /* HAVE_MEMRCHR */ |
170 | 173k | p = s + n; |
171 | 650k | while (p > s) { |
172 | 634k | p--; |
173 | 634k | if (*p == ch) |
174 | 156k | return (p - s); |
175 | 634k | } |
176 | 16.3k | return -1; |
177 | 173k | } Unexecuted instantiation: bytesobject.c:stringlib_rfind_char unicodeobject.c:ucs1lib_rfind_char Line | Count | Source | 117 | 9.14k | { | 118 | 9.14k | const STRINGLIB_CHAR *p; | 119 | 9.14k | #ifdef HAVE_MEMRCHR | 120 | | /* memrchr() is a GNU extension, available since glibc 2.1.91. it | 121 | | doesn't seem as optimized as memchr(), but is still quite | 122 | | faster than our hand-written loop below. There is no wmemrchr | 123 | | for 4-byte chars. */ | 124 | | | 125 | 9.14k | if (n > MEMRCHR_CUT_OFF) { | 126 | 3.91k | #if STRINGLIB_SIZEOF_CHAR == 1 | 127 | 3.91k | p = memrchr(s, ch, n); | 128 | 3.91k | if (p != NULL) | 129 | 2.97k | return (p - s); | 130 | 944 | return -1; | 131 | | #else | 132 | | /* use memrchr if we can choose a needle without too many likely | 133 | | false positives */ | 134 | | const STRINGLIB_CHAR *s1; | 135 | | Py_ssize_t n1; | 136 | | unsigned char needle = ch & 0xff; | 137 | | /* If looking for a multiple of 256, we'd have too | 138 | | many false positives looking for the '\0' byte in UCS2 | 139 | | and UCS4 representations. */ | 140 | | if (needle != 0) { | 141 | | do { | 142 | | void *candidate = memrchr(s, needle, | 143 | | n * sizeof(STRINGLIB_CHAR)); | 144 | | if (candidate == NULL) | 145 | | return -1; | 146 | | n1 = n; | 147 | | p = (const STRINGLIB_CHAR *) | 148 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 149 | | n = p - s; | 150 | | if (*p == ch) | 151 | | return n; | 152 | | /* False positive */ | 153 | | if (n1 - n > MEMRCHR_CUT_OFF) | 154 | | continue; | 155 | | if (n <= MEMRCHR_CUT_OFF) | 156 | | break; | 157 | | s1 = p - MEMRCHR_CUT_OFF; | 158 | | while (p > s1) { | 159 | | p--; | 160 | | if (*p == ch) | 161 | | return (p - s); | 162 | | } | 163 | | n = p - s; | 164 | | } | 165 | | while (n > MEMRCHR_CUT_OFF); | 166 | | } | 167 | | #endif | 168 | 3.91k | } | 169 | 5.22k | #endif /* HAVE_MEMRCHR */ | 170 | 5.22k | p = s + n; | 171 | 14.9k | while (p > s) { | 172 | 14.2k | p--; | 173 | 14.2k | if (*p == ch) | 174 | 4.49k | return (p - s); | 175 | 14.2k | } | 176 | 733 | return -1; | 177 | 5.22k | } |
unicodeobject.c:ucs2lib_rfind_char Line | Count | Source | 117 | 28.7k | { | 118 | 28.7k | const STRINGLIB_CHAR *p; | 119 | 28.7k | #ifdef HAVE_MEMRCHR | 120 | | /* memrchr() is a GNU extension, available since glibc 2.1.91. it | 121 | | doesn't seem as optimized as memchr(), but is still quite | 122 | | faster than our hand-written loop below. There is no wmemrchr | 123 | | for 4-byte chars. */ | 124 | | | 125 | 28.7k | if (n > MEMRCHR_CUT_OFF) { | 126 | | #if STRINGLIB_SIZEOF_CHAR == 1 | 127 | | p = memrchr(s, ch, n); | 128 | | if (p != NULL) | 129 | | return (p - s); | 130 | | return -1; | 131 | | #else | 132 | | /* use memrchr if we can choose a needle without too many likely | 133 | | false positives */ | 134 | 12.3k | const STRINGLIB_CHAR *s1; | 135 | 12.3k | Py_ssize_t n1; | 136 | 12.3k | unsigned char needle = ch & 0xff; | 137 | | /* If looking for a multiple of 256, we'd have too | 138 | | many false positives looking for the '\0' byte in UCS2 | 139 | | and UCS4 representations. */ | 140 | 12.3k | if (needle != 0) { | 141 | 14.2k | do { | 142 | 14.2k | void *candidate = memrchr(s, needle, | 143 | 14.2k | n * sizeof(STRINGLIB_CHAR)); | 144 | 14.2k | if (candidate == NULL) | 145 | 372 | return -1; | 146 | 13.9k | n1 = n; | 147 | 13.9k | p = (const STRINGLIB_CHAR *) | 148 | 13.9k | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 149 | 13.9k | n = p - s; | 150 | 13.9k | if (*p == ch) | 151 | 10.4k | return n; | 152 | | /* False positive */ | 153 | 3.50k | if (n1 - n > MEMRCHR_CUT_OFF) | 154 | 1.29k | continue; | 155 | 2.20k | if (n <= MEMRCHR_CUT_OFF) | 156 | 399 | break; | 157 | 1.80k | s1 = p - MEMRCHR_CUT_OFF; | 158 | 67.9k | while (p > s1) { | 159 | 66.3k | p--; | 160 | 66.3k | if (*p == ch) | 161 | 223 | return (p - s); | 162 | 66.3k | } | 163 | 1.58k | n = p - s; | 164 | 1.58k | } | 165 | 12.3k | while (n > MEMRCHR_CUT_OFF); | 166 | 12.3k | } | 167 | 12.3k | #endif | 168 | 12.3k | } | 169 | 17.7k | #endif /* HAVE_MEMRCHR */ | 170 | 17.7k | p = s + n; | 171 | 99.9k | while (p > s) { | 172 | 98.1k | p--; | 173 | 98.1k | if (*p == ch) | 174 | 15.9k | return (p - s); | 175 | 98.1k | } | 176 | 1.78k | return -1; | 177 | 17.7k | } |
unicodeobject.c:ucs4lib_rfind_char Line | Count | Source | 117 | 242k | { | 118 | 242k | const STRINGLIB_CHAR *p; | 119 | 242k | #ifdef HAVE_MEMRCHR | 120 | | /* memrchr() is a GNU extension, available since glibc 2.1.91. it | 121 | | doesn't seem as optimized as memchr(), but is still quite | 122 | | faster than our hand-written loop below. There is no wmemrchr | 123 | | for 4-byte chars. */ | 124 | | | 125 | 242k | if (n > MEMRCHR_CUT_OFF) { | 126 | | #if STRINGLIB_SIZEOF_CHAR == 1 | 127 | | p = memrchr(s, ch, n); | 128 | | if (p != NULL) | 129 | | return (p - s); | 130 | | return -1; | 131 | | #else | 132 | | /* use memrchr if we can choose a needle without too many likely | 133 | | false positives */ | 134 | 115k | const STRINGLIB_CHAR *s1; | 135 | 115k | Py_ssize_t n1; | 136 | 115k | unsigned char needle = ch & 0xff; | 137 | | /* If looking for a multiple of 256, we'd have too | 138 | | many false positives looking for the '\0' byte in UCS2 | 139 | | and UCS4 representations. */ | 140 | 115k | if (needle != 0) { | 141 | 123k | do { | 142 | 123k | void *candidate = memrchr(s, needle, | 143 | 123k | n * sizeof(STRINGLIB_CHAR)); | 144 | 123k | if (candidate == NULL) | 145 | 263 | return -1; | 146 | 122k | n1 = n; | 147 | 122k | p = (const STRINGLIB_CHAR *) | 148 | 122k | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 149 | 122k | n = p - s; | 150 | 122k | if (*p == ch) | 151 | 113k | return n; | 152 | | /* False positive */ | 153 | 9.82k | if (n1 - n > MEMRCHR_CUT_OFF) | 154 | 4.76k | continue; | 155 | 5.06k | if (n <= MEMRCHR_CUT_OFF) | 156 | 448 | break; | 157 | 4.61k | s1 = p - MEMRCHR_CUT_OFF; | 158 | 175k | while (p > s1) { | 159 | 171k | p--; | 160 | 171k | if (*p == ch) | 161 | 682 | return (p - s); | 162 | 171k | } | 163 | 3.93k | n = p - s; | 164 | 3.93k | } | 165 | 115k | while (n > MEMRCHR_CUT_OFF); | 166 | 115k | } | 167 | 115k | #endif | 168 | 115k | } | 169 | 128k | #endif /* HAVE_MEMRCHR */ | 170 | 128k | p = s + n; | 171 | 416k | while (p > s) { | 172 | 414k | p--; | 173 | 414k | if (*p == ch) | 174 | 127k | return (p - s); | 175 | 414k | } | 176 | 1.38k | return -1; | 177 | 128k | } |
unicodeobject.c:asciilib_rfind_char Line | Count | Source | 117 | 9.92k | { | 118 | 9.92k | const STRINGLIB_CHAR *p; | 119 | 9.92k | #ifdef HAVE_MEMRCHR | 120 | | /* memrchr() is a GNU extension, available since glibc 2.1.91. it | 121 | | doesn't seem as optimized as memchr(), but is still quite | 122 | | faster than our hand-written loop below. There is no wmemrchr | 123 | | for 4-byte chars. */ | 124 | | | 125 | 9.92k | if (n > MEMRCHR_CUT_OFF) { | 126 | 3.51k | #if STRINGLIB_SIZEOF_CHAR == 1 | 127 | 3.51k | p = memrchr(s, ch, n); | 128 | 3.51k | if (p != NULL) | 129 | 3.43k | return (p - s); | 130 | 80 | return -1; | 131 | | #else | 132 | | /* use memrchr if we can choose a needle without too many likely | 133 | | false positives */ | 134 | | const STRINGLIB_CHAR *s1; | 135 | | Py_ssize_t n1; | 136 | | unsigned char needle = ch & 0xff; | 137 | | /* If looking for a multiple of 256, we'd have too | 138 | | many false positives looking for the '\0' byte in UCS2 | 139 | | and UCS4 representations. */ | 140 | | if (needle != 0) { | 141 | | do { | 142 | | void *candidate = memrchr(s, needle, | 143 | | n * sizeof(STRINGLIB_CHAR)); | 144 | | if (candidate == NULL) | 145 | | return -1; | 146 | | n1 = n; | 147 | | p = (const STRINGLIB_CHAR *) | 148 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 149 | | n = p - s; | 150 | | if (*p == ch) | 151 | | return n; | 152 | | /* False positive */ | 153 | | if (n1 - n > MEMRCHR_CUT_OFF) | 154 | | continue; | 155 | | if (n <= MEMRCHR_CUT_OFF) | 156 | | break; | 157 | | s1 = p - MEMRCHR_CUT_OFF; | 158 | | while (p > s1) { | 159 | | p--; | 160 | | if (*p == ch) | 161 | | return (p - s); | 162 | | } | 163 | | n = p - s; | 164 | | } | 165 | | while (n > MEMRCHR_CUT_OFF); | 166 | | } | 167 | | #endif | 168 | 3.51k | } | 169 | 6.40k | #endif /* HAVE_MEMRCHR */ | 170 | 6.40k | p = s + n; | 171 | 35.5k | while (p > s) { | 172 | 33.5k | p--; | 173 | 33.5k | if (*p == ch) | 174 | 4.40k | return (p - s); | 175 | 33.5k | } | 176 | 2.00k | return -1; | 177 | 6.40k | } |
bytes_methods.c:stringlib_rfind_char Line | Count | Source | 117 | 18.3k | { | 118 | 18.3k | const STRINGLIB_CHAR *p; | 119 | 18.3k | #ifdef HAVE_MEMRCHR | 120 | | /* memrchr() is a GNU extension, available since glibc 2.1.91. it | 121 | | doesn't seem as optimized as memchr(), but is still quite | 122 | | faster than our hand-written loop below. There is no wmemrchr | 123 | | for 4-byte chars. */ | 124 | | | 125 | 18.3k | if (n > MEMRCHR_CUT_OFF) { | 126 | 3.20k | #if STRINGLIB_SIZEOF_CHAR == 1 | 127 | 3.20k | p = memrchr(s, ch, n); | 128 | 3.20k | if (p != NULL) | 129 | 864 | return (p - s); | 130 | 2.33k | return -1; | 131 | | #else | 132 | | /* use memrchr if we can choose a needle without too many likely | 133 | | false positives */ | 134 | | const STRINGLIB_CHAR *s1; | 135 | | Py_ssize_t n1; | 136 | | unsigned char needle = ch & 0xff; | 137 | | /* If looking for a multiple of 256, we'd have too | 138 | | many false positives looking for the '\0' byte in UCS2 | 139 | | and UCS4 representations. */ | 140 | | if (needle != 0) { | 141 | | do { | 142 | | void *candidate = memrchr(s, needle, | 143 | | n * sizeof(STRINGLIB_CHAR)); | 144 | | if (candidate == NULL) | 145 | | return -1; | 146 | | n1 = n; | 147 | | p = (const STRINGLIB_CHAR *) | 148 | | _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR)); | 149 | | n = p - s; | 150 | | if (*p == ch) | 151 | | return n; | 152 | | /* False positive */ | 153 | | if (n1 - n > MEMRCHR_CUT_OFF) | 154 | | continue; | 155 | | if (n <= MEMRCHR_CUT_OFF) | 156 | | break; | 157 | | s1 = p - MEMRCHR_CUT_OFF; | 158 | | while (p > s1) { | 159 | | p--; | 160 | | if (*p == ch) | 161 | | return (p - s); | 162 | | } | 163 | | n = p - s; | 164 | | } | 165 | | while (n > MEMRCHR_CUT_OFF); | 166 | | } | 167 | | #endif | 168 | 3.20k | } | 169 | 15.1k | #endif /* HAVE_MEMRCHR */ | 170 | 15.1k | p = s + n; | 171 | 84.3k | while (p > s) { | 172 | 73.9k | p--; | 173 | 73.9k | if (*p == ch) | 174 | 4.74k | return (p - s); | 175 | 73.9k | } | 176 | 10.3k | return -1; | 177 | 15.1k | } |
Unexecuted instantiation: bytearrayobject.c:stringlib_rfind_char |
178 | | |
179 | | #undef MEMRCHR_CUT_OFF |
180 | | |
181 | | /* Change to a 1 to see logging comments walk through the algorithm. */ |
182 | | #if 0 && STRINGLIB_SIZEOF_CHAR == 1 |
183 | | # define LOG(...) printf(__VA_ARGS__) |
184 | | # define LOG_STRING(s, n) printf("\"%.*s\"", (int)(n), s) |
185 | | # define LOG_LINEUP() do { \ |
186 | | LOG("> "); LOG_STRING(haystack, len_haystack); LOG("\n> "); \ |
187 | | LOG("%*s",(int)(window_last - haystack + 1 - len_needle), ""); \ |
188 | | LOG_STRING(needle, len_needle); LOG("\n"); \ |
189 | | } while(0) |
190 | | #else |
191 | | # define LOG(...) |
192 | | # define LOG_STRING(s, n) |
193 | | # define LOG_LINEUP() |
194 | | #endif |
195 | | |
196 | | Py_LOCAL_INLINE(Py_ssize_t) |
197 | | STRINGLIB(_lex_search)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle, |
198 | | Py_ssize_t *return_period, int invert_alphabet) |
199 | 38 | { |
200 | | /* Do a lexicographic search. Essentially this: |
201 | | >>> max(needle[i:] for i in range(len(needle)+1)) |
202 | | Also find the period of the right half. */ |
203 | 38 | Py_ssize_t max_suffix = 0; |
204 | 38 | Py_ssize_t candidate = 1; |
205 | 38 | Py_ssize_t k = 0; |
206 | | // The period of the right half. |
207 | 38 | Py_ssize_t period = 1; |
208 | | |
209 | 380 | while (candidate + k < len_needle) { |
210 | | // each loop increases candidate + k + max_suffix |
211 | 342 | STRINGLIB_CHAR a = needle[candidate + k]; |
212 | 342 | STRINGLIB_CHAR b = needle[max_suffix + k]; |
213 | | // check if the suffix at candidate is better than max_suffix |
214 | 342 | if (invert_alphabet ? (b < a) : (a < b)) { |
215 | | // Fell short of max_suffix. |
216 | | // The next k + 1 characters are non-increasing |
217 | | // from candidate, so they won't start a maximal suffix. |
218 | 247 | candidate += k + 1; |
219 | 247 | k = 0; |
220 | | // We've ruled out any period smaller than what's |
221 | | // been scanned since max_suffix. |
222 | 247 | period = candidate - max_suffix; |
223 | 247 | } |
224 | 95 | else if (a == b) { |
225 | 19 | if (k + 1 != period) { |
226 | | // Keep scanning the equal strings |
227 | 0 | k++; |
228 | 0 | } |
229 | 19 | else { |
230 | | // Matched a whole period. |
231 | | // Start matching the next period. |
232 | 19 | candidate += period; |
233 | 19 | k = 0; |
234 | 19 | } |
235 | 19 | } |
236 | 76 | else { |
237 | | // Did better than max_suffix, so replace it. |
238 | 76 | max_suffix = candidate; |
239 | 76 | candidate++; |
240 | 76 | k = 0; |
241 | 76 | period = 1; |
242 | 76 | } |
243 | 342 | } |
244 | 38 | *return_period = period; |
245 | 38 | return max_suffix; |
246 | 38 | } Unexecuted instantiation: bytesobject.c:stringlib__lex_search Unexecuted instantiation: unicodeobject.c:asciilib__lex_search unicodeobject.c:ucs1lib__lex_search Line | Count | Source | 199 | 38 | { | 200 | | /* Do a lexicographic search. Essentially this: | 201 | | >>> max(needle[i:] for i in range(len(needle)+1)) | 202 | | Also find the period of the right half. */ | 203 | 38 | Py_ssize_t max_suffix = 0; | 204 | 38 | Py_ssize_t candidate = 1; | 205 | 38 | Py_ssize_t k = 0; | 206 | | // The period of the right half. | 207 | 38 | Py_ssize_t period = 1; | 208 | | | 209 | 380 | while (candidate + k < len_needle) { | 210 | | // each loop increases candidate + k + max_suffix | 211 | 342 | STRINGLIB_CHAR a = needle[candidate + k]; | 212 | 342 | STRINGLIB_CHAR b = needle[max_suffix + k]; | 213 | | // check if the suffix at candidate is better than max_suffix | 214 | 342 | if (invert_alphabet ? (b < a) : (a < b)) { | 215 | | // Fell short of max_suffix. | 216 | | // The next k + 1 characters are non-increasing | 217 | | // from candidate, so they won't start a maximal suffix. | 218 | 247 | candidate += k + 1; | 219 | 247 | k = 0; | 220 | | // We've ruled out any period smaller than what's | 221 | | // been scanned since max_suffix. | 222 | 247 | period = candidate - max_suffix; | 223 | 247 | } | 224 | 95 | else if (a == b) { | 225 | 19 | if (k + 1 != period) { | 226 | | // Keep scanning the equal strings | 227 | 0 | k++; | 228 | 0 | } | 229 | 19 | else { | 230 | | // Matched a whole period. | 231 | | // Start matching the next period. | 232 | 19 | candidate += period; | 233 | 19 | k = 0; | 234 | 19 | } | 235 | 19 | } | 236 | 76 | else { | 237 | | // Did better than max_suffix, so replace it. | 238 | 76 | max_suffix = candidate; | 239 | 76 | candidate++; | 240 | 76 | k = 0; | 241 | 76 | period = 1; | 242 | 76 | } | 243 | 342 | } | 244 | 38 | *return_period = period; | 245 | 38 | return max_suffix; | 246 | 38 | } |
Unexecuted instantiation: unicodeobject.c:ucs2lib__lex_search Unexecuted instantiation: unicodeobject.c:ucs4lib__lex_search Unexecuted instantiation: bytes_methods.c:stringlib__lex_search Unexecuted instantiation: bytearrayobject.c:stringlib__lex_search |
247 | | |
248 | | Py_LOCAL_INLINE(Py_ssize_t) |
249 | | STRINGLIB(_factorize)(const STRINGLIB_CHAR *needle, |
250 | | Py_ssize_t len_needle, |
251 | | Py_ssize_t *return_period) |
252 | 19 | { |
253 | | /* Do a "critical factorization", making it so that: |
254 | | >>> needle = (left := needle[:cut]) + (right := needle[cut:]) |
255 | | where the "local period" of the cut is maximal. |
256 | | |
257 | | The local period of the cut is the minimal length of a string w |
258 | | such that (left endswith w or w endswith left) |
259 | | and (right startswith w or w startswith right). |
260 | | |
261 | | The Critical Factorization Theorem says that this maximal local |
262 | | period is the global period of the string. |
263 | | |
264 | | Crochemore and Perrin (1991) show that this cut can be computed |
265 | | as the later of two cuts: one that gives a lexicographically |
266 | | maximal right half, and one that gives the same with the |
267 | | with respect to a reversed alphabet-ordering. |
268 | | |
269 | | This is what we want to happen: |
270 | | >>> x = "GCAGAGAG" |
271 | | >>> cut, period = factorize(x) |
272 | | >>> x[:cut], (right := x[cut:]) |
273 | | ('GC', 'AGAGAG') |
274 | | >>> period # right half period |
275 | | 2 |
276 | | >>> right[period:] == right[:-period] |
277 | | True |
278 | | |
279 | | This is how the local period lines up in the above example: |
280 | | GC | AGAGAG |
281 | | AGAGAGC = AGAGAGC |
282 | | The length of this minimal repetition is 7, which is indeed the |
283 | | period of the original string. */ |
284 | | |
285 | 19 | Py_ssize_t cut1, period1, cut2, period2, cut, period; |
286 | 19 | cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0); |
287 | 19 | cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1); |
288 | | |
289 | | // Take the later cut. |
290 | 19 | if (cut1 > cut2) { |
291 | 19 | period = period1; |
292 | 19 | cut = cut1; |
293 | 19 | } |
294 | 0 | else { |
295 | 0 | period = period2; |
296 | 0 | cut = cut2; |
297 | 0 | } |
298 | | |
299 | 19 | LOG("split: "); LOG_STRING(needle, cut); |
300 | 19 | LOG(" + "); LOG_STRING(needle + cut, len_needle - cut); |
301 | 19 | LOG("\n"); |
302 | | |
303 | 19 | *return_period = period; |
304 | 19 | return cut; |
305 | 19 | } Unexecuted instantiation: bytesobject.c:stringlib__factorize Unexecuted instantiation: unicodeobject.c:asciilib__factorize unicodeobject.c:ucs1lib__factorize Line | Count | Source | 252 | 19 | { | 253 | | /* Do a "critical factorization", making it so that: | 254 | | >>> needle = (left := needle[:cut]) + (right := needle[cut:]) | 255 | | where the "local period" of the cut is maximal. | 256 | | | 257 | | The local period of the cut is the minimal length of a string w | 258 | | such that (left endswith w or w endswith left) | 259 | | and (right startswith w or w startswith right). | 260 | | | 261 | | The Critical Factorization Theorem says that this maximal local | 262 | | period is the global period of the string. | 263 | | | 264 | | Crochemore and Perrin (1991) show that this cut can be computed | 265 | | as the later of two cuts: one that gives a lexicographically | 266 | | maximal right half, and one that gives the same with the | 267 | | with respect to a reversed alphabet-ordering. | 268 | | | 269 | | This is what we want to happen: | 270 | | >>> x = "GCAGAGAG" | 271 | | >>> cut, period = factorize(x) | 272 | | >>> x[:cut], (right := x[cut:]) | 273 | | ('GC', 'AGAGAG') | 274 | | >>> period # right half period | 275 | | 2 | 276 | | >>> right[period:] == right[:-period] | 277 | | True | 278 | | | 279 | | This is how the local period lines up in the above example: | 280 | | GC | AGAGAG | 281 | | AGAGAGC = AGAGAGC | 282 | | The length of this minimal repetition is 7, which is indeed the | 283 | | period of the original string. */ | 284 | | | 285 | 19 | Py_ssize_t cut1, period1, cut2, period2, cut, period; | 286 | 19 | cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0); | 287 | 19 | cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1); | 288 | | | 289 | | // Take the later cut. | 290 | 19 | if (cut1 > cut2) { | 291 | 19 | period = period1; | 292 | 19 | cut = cut1; | 293 | 19 | } | 294 | 0 | else { | 295 | 0 | period = period2; | 296 | 0 | cut = cut2; | 297 | 0 | } | 298 | | | 299 | 19 | LOG("split: "); LOG_STRING(needle, cut); | 300 | 19 | LOG(" + "); LOG_STRING(needle + cut, len_needle - cut); | 301 | 19 | LOG("\n"); | 302 | | | 303 | 19 | *return_period = period; | 304 | 19 | return cut; | 305 | 19 | } |
Unexecuted instantiation: unicodeobject.c:ucs2lib__factorize Unexecuted instantiation: unicodeobject.c:ucs4lib__factorize Unexecuted instantiation: bytes_methods.c:stringlib__factorize Unexecuted instantiation: bytearrayobject.c:stringlib__factorize |
306 | | |
307 | | |
308 | 209 | #define SHIFT_TYPE uint8_t |
309 | | #define MAX_SHIFT UINT8_MAX |
310 | | |
311 | 68.4k | #define TABLE_SIZE_BITS 6u |
312 | 68.4k | #define TABLE_SIZE (1U << TABLE_SIZE_BITS) |
313 | 67.1k | #define TABLE_MASK (TABLE_SIZE - 1U) |
314 | | |
315 | | typedef struct STRINGLIB(_pre) { |
316 | | const STRINGLIB_CHAR *needle; |
317 | | Py_ssize_t len_needle; |
318 | | Py_ssize_t cut; |
319 | | Py_ssize_t period; |
320 | | Py_ssize_t gap; |
321 | | int is_periodic; |
322 | | SHIFT_TYPE table[TABLE_SIZE]; |
323 | | } STRINGLIB(prework); |
324 | | |
325 | | |
326 | | static void |
327 | | STRINGLIB(_preprocess)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle, |
328 | | STRINGLIB(prework) *p) |
329 | 19 | { |
330 | 19 | p->needle = needle; |
331 | 19 | p->len_needle = len_needle; |
332 | 19 | p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period)); |
333 | 19 | assert(p->period + p->cut <= len_needle); |
334 | 19 | p->is_periodic = (0 == memcmp(needle, |
335 | 19 | needle + p->period, |
336 | 19 | p->cut * STRINGLIB_SIZEOF_CHAR)); |
337 | 19 | if (p->is_periodic) { |
338 | 0 | assert(p->cut <= len_needle/2); |
339 | 0 | assert(p->cut < p->period); |
340 | 0 | } |
341 | 19 | else { |
342 | | // A lower bound on the period |
343 | 19 | p->period = Py_MAX(p->cut, len_needle - p->cut) + 1; |
344 | 19 | } |
345 | | // The gap between the last character and the previous |
346 | | // occurrence of an equivalent character (modulo TABLE_SIZE) |
347 | 19 | p->gap = len_needle; |
348 | 19 | STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK; |
349 | 133 | for (Py_ssize_t i = len_needle - 2; i >= 0; i--) { |
350 | 133 | STRINGLIB_CHAR x = needle[i] & TABLE_MASK; |
351 | 133 | if (x == last) { |
352 | 19 | p->gap = len_needle - 1 - i; |
353 | 19 | break; |
354 | 19 | } |
355 | 133 | } |
356 | | // Fill up a compressed Boyer-Moore "Bad Character" table |
357 | 19 | Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT); |
358 | 1.23k | for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) { |
359 | 1.21k | p->table[i] = Py_SAFE_DOWNCAST(not_found_shift, |
360 | 1.21k | Py_ssize_t, SHIFT_TYPE); |
361 | 1.21k | } |
362 | 209 | for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) { |
363 | 190 | SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i, |
364 | 190 | Py_ssize_t, SHIFT_TYPE); |
365 | 190 | p->table[needle[i] & TABLE_MASK] = shift; |
366 | 190 | } |
367 | 19 | } Unexecuted instantiation: bytesobject.c:stringlib__preprocess Unexecuted instantiation: unicodeobject.c:asciilib__preprocess unicodeobject.c:ucs1lib__preprocess Line | Count | Source | 329 | 19 | { | 330 | 19 | p->needle = needle; | 331 | 19 | p->len_needle = len_needle; | 332 | 19 | p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period)); | 333 | 19 | assert(p->period + p->cut <= len_needle); | 334 | 19 | p->is_periodic = (0 == memcmp(needle, | 335 | 19 | needle + p->period, | 336 | 19 | p->cut * STRINGLIB_SIZEOF_CHAR)); | 337 | 19 | if (p->is_periodic) { | 338 | 0 | assert(p->cut <= len_needle/2); | 339 | 0 | assert(p->cut < p->period); | 340 | 0 | } | 341 | 19 | else { | 342 | | // A lower bound on the period | 343 | 19 | p->period = Py_MAX(p->cut, len_needle - p->cut) + 1; | 344 | 19 | } | 345 | | // The gap between the last character and the previous | 346 | | // occurrence of an equivalent character (modulo TABLE_SIZE) | 347 | 19 | p->gap = len_needle; | 348 | 19 | STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK; | 349 | 133 | for (Py_ssize_t i = len_needle - 2; i >= 0; i--) { | 350 | 133 | STRINGLIB_CHAR x = needle[i] & TABLE_MASK; | 351 | 133 | if (x == last) { | 352 | 19 | p->gap = len_needle - 1 - i; | 353 | 19 | break; | 354 | 19 | } | 355 | 133 | } | 356 | | // Fill up a compressed Boyer-Moore "Bad Character" table | 357 | 19 | Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT); | 358 | 1.23k | for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) { | 359 | 1.21k | p->table[i] = Py_SAFE_DOWNCAST(not_found_shift, | 360 | 1.21k | Py_ssize_t, SHIFT_TYPE); | 361 | 1.21k | } | 362 | 209 | for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) { | 363 | 190 | SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i, | 364 | 190 | Py_ssize_t, SHIFT_TYPE); | 365 | 190 | p->table[needle[i] & TABLE_MASK] = shift; | 366 | 190 | } | 367 | 19 | } |
Unexecuted instantiation: unicodeobject.c:ucs2lib__preprocess Unexecuted instantiation: unicodeobject.c:ucs4lib__preprocess Unexecuted instantiation: bytes_methods.c:stringlib__preprocess Unexecuted instantiation: bytearrayobject.c:stringlib__preprocess |
368 | | |
369 | | static Py_ssize_t |
370 | | STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack, |
371 | | STRINGLIB(prework) *p) |
372 | 19 | { |
373 | | // Crochemore and Perrin's (1991) Two-Way algorithm. |
374 | | // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 |
375 | 19 | const Py_ssize_t len_needle = p->len_needle; |
376 | 19 | const Py_ssize_t cut = p->cut; |
377 | 19 | Py_ssize_t period = p->period; |
378 | 19 | const STRINGLIB_CHAR *const needle = p->needle; |
379 | 19 | const STRINGLIB_CHAR *window_last = haystack + len_needle - 1; |
380 | 19 | const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack; |
381 | 19 | SHIFT_TYPE *table = p->table; |
382 | 19 | const STRINGLIB_CHAR *window; |
383 | 19 | LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack); |
384 | | |
385 | 19 | Py_ssize_t gap = p->gap; |
386 | 19 | Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap); |
387 | 19 | if (p->is_periodic) { |
388 | 0 | LOG("Needle is periodic.\n"); |
389 | 0 | Py_ssize_t memory = 0; |
390 | 0 | periodicwindowloop: |
391 | 0 | while (window_last < haystack_end) { |
392 | 0 | assert(memory == 0); |
393 | 0 | for (;;) { |
394 | 0 | LOG_LINEUP(); |
395 | 0 | Py_ssize_t shift = table[(*window_last) & TABLE_MASK]; |
396 | 0 | window_last += shift; |
397 | 0 | if (shift == 0) { |
398 | 0 | break; |
399 | 0 | } |
400 | 0 | if (window_last >= haystack_end) { |
401 | 0 | return -1; |
402 | 0 | } |
403 | 0 | LOG("Horspool skip\n"); |
404 | 0 | } |
405 | 0 | no_shift: |
406 | 0 | window = window_last - len_needle + 1; |
407 | 0 | assert((window[len_needle - 1] & TABLE_MASK) == |
408 | 0 | (needle[len_needle - 1] & TABLE_MASK)); |
409 | 0 | Py_ssize_t i = Py_MAX(cut, memory); |
410 | 0 | for (; i < len_needle; i++) { |
411 | 0 | if (needle[i] != window[i]) { |
412 | 0 | if (i < gap_jump_end) { |
413 | 0 | LOG("Early right half mismatch: jump by gap.\n"); |
414 | 0 | assert(gap >= i - cut + 1); |
415 | 0 | window_last += gap; |
416 | 0 | } |
417 | 0 | else { |
418 | 0 | LOG("Late right half mismatch: jump by n (>gap)\n"); |
419 | 0 | assert(i - cut + 1 > gap); |
420 | 0 | window_last += i - cut + 1; |
421 | 0 | } |
422 | 0 | memory = 0; |
423 | 0 | goto periodicwindowloop; |
424 | 0 | } |
425 | 0 | } |
426 | 0 | for (i = memory; i < cut; i++) { |
427 | 0 | if (needle[i] != window[i]) { |
428 | 0 | LOG("Left half does not match.\n"); |
429 | 0 | window_last += period; |
430 | 0 | memory = len_needle - period; |
431 | 0 | if (window_last >= haystack_end) { |
432 | 0 | return -1; |
433 | 0 | } |
434 | 0 | Py_ssize_t shift = table[(*window_last) & TABLE_MASK]; |
435 | 0 | if (shift) { |
436 | | // A mismatch has been identified to the right |
437 | | // of where i will next start, so we can jump |
438 | | // at least as far as if the mismatch occurred |
439 | | // on the first comparison. |
440 | 0 | Py_ssize_t mem_jump = Py_MAX(cut, memory) - cut + 1; |
441 | 0 | LOG("Skip with Memory.\n"); |
442 | 0 | memory = 0; |
443 | 0 | window_last += Py_MAX(shift, mem_jump); |
444 | 0 | goto periodicwindowloop; |
445 | 0 | } |
446 | 0 | goto no_shift; |
447 | 0 | } |
448 | 0 | } |
449 | 0 | LOG("Found a match!\n"); |
450 | 0 | return window - haystack; |
451 | 0 | } |
452 | 0 | } |
453 | 19 | else { |
454 | 19 | period = Py_MAX(gap, period); |
455 | 19 | LOG("Needle is not periodic.\n"); |
456 | 12.2k | windowloop: |
457 | 12.2k | while (window_last < haystack_end) { |
458 | 66.8k | for (;;) { |
459 | 66.8k | LOG_LINEUP(); |
460 | 66.8k | Py_ssize_t shift = table[(*window_last) & TABLE_MASK]; |
461 | 66.8k | window_last += shift; |
462 | 66.8k | if (shift == 0) { |
463 | 12.1k | break; |
464 | 12.1k | } |
465 | 54.6k | if (window_last >= haystack_end) { |
466 | 16 | return -1; |
467 | 16 | } |
468 | 54.6k | LOG("Horspool skip\n"); |
469 | 54.6k | } |
470 | 12.1k | window = window_last - len_needle + 1; |
471 | 12.1k | assert((window[len_needle - 1] & TABLE_MASK) == |
472 | 12.1k | (needle[len_needle - 1] & TABLE_MASK)); |
473 | 12.1k | Py_ssize_t i = cut; |
474 | 12.3k | for (; i < len_needle; i++) { |
475 | 12.2k | if (needle[i] != window[i]) { |
476 | 12.1k | if (i < gap_jump_end) { |
477 | 12.1k | LOG("Early right half mismatch: jump by gap.\n"); |
478 | 12.1k | assert(gap >= i - cut + 1); |
479 | 12.1k | window_last += gap; |
480 | 12.1k | } |
481 | 0 | else { |
482 | 0 | LOG("Late right half mismatch: jump by n (>gap)\n"); |
483 | 0 | assert(i - cut + 1 > gap); |
484 | 0 | window_last += i - cut + 1; |
485 | 0 | } |
486 | 12.1k | goto windowloop; |
487 | 12.1k | } |
488 | 12.2k | } |
489 | 98 | for (Py_ssize_t i = 0; i < cut; i++) { |
490 | 96 | if (needle[i] != window[i]) { |
491 | 80 | LOG("Left half does not match.\n"); |
492 | 80 | window_last += period; |
493 | 80 | goto windowloop; |
494 | 80 | } |
495 | 96 | } |
496 | 2 | LOG("Found a match!\n"); |
497 | 2 | return window - haystack; |
498 | 82 | } |
499 | 12.2k | } |
500 | 1 | LOG("Not found. Returning -1.\n"); |
501 | 1 | return -1; |
502 | 19 | } Unexecuted instantiation: bytesobject.c:stringlib__two_way Unexecuted instantiation: unicodeobject.c:asciilib__two_way unicodeobject.c:ucs1lib__two_way Line | Count | Source | 372 | 19 | { | 373 | | // Crochemore and Perrin's (1991) Two-Way algorithm. | 374 | | // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 | 375 | 19 | const Py_ssize_t len_needle = p->len_needle; | 376 | 19 | const Py_ssize_t cut = p->cut; | 377 | 19 | Py_ssize_t period = p->period; | 378 | 19 | const STRINGLIB_CHAR *const needle = p->needle; | 379 | 19 | const STRINGLIB_CHAR *window_last = haystack + len_needle - 1; | 380 | 19 | const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack; | 381 | 19 | SHIFT_TYPE *table = p->table; | 382 | 19 | const STRINGLIB_CHAR *window; | 383 | 19 | LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack); | 384 | | | 385 | 19 | Py_ssize_t gap = p->gap; | 386 | 19 | Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap); | 387 | 19 | if (p->is_periodic) { | 388 | 0 | LOG("Needle is periodic.\n"); | 389 | 0 | Py_ssize_t memory = 0; | 390 | 0 | periodicwindowloop: | 391 | 0 | while (window_last < haystack_end) { | 392 | 0 | assert(memory == 0); | 393 | 0 | for (;;) { | 394 | 0 | LOG_LINEUP(); | 395 | 0 | Py_ssize_t shift = table[(*window_last) & TABLE_MASK]; | 396 | 0 | window_last += shift; | 397 | 0 | if (shift == 0) { | 398 | 0 | break; | 399 | 0 | } | 400 | 0 | if (window_last >= haystack_end) { | 401 | 0 | return -1; | 402 | 0 | } | 403 | 0 | LOG("Horspool skip\n"); | 404 | 0 | } | 405 | 0 | no_shift: | 406 | 0 | window = window_last - len_needle + 1; | 407 | 0 | assert((window[len_needle - 1] & TABLE_MASK) == | 408 | 0 | (needle[len_needle - 1] & TABLE_MASK)); | 409 | 0 | Py_ssize_t i = Py_MAX(cut, memory); | 410 | 0 | for (; i < len_needle; i++) { | 411 | 0 | if (needle[i] != window[i]) { | 412 | 0 | if (i < gap_jump_end) { | 413 | 0 | LOG("Early right half mismatch: jump by gap.\n"); | 414 | 0 | assert(gap >= i - cut + 1); | 415 | 0 | window_last += gap; | 416 | 0 | } | 417 | 0 | else { | 418 | 0 | LOG("Late right half mismatch: jump by n (>gap)\n"); | 419 | 0 | assert(i - cut + 1 > gap); | 420 | 0 | window_last += i - cut + 1; | 421 | 0 | } | 422 | 0 | memory = 0; | 423 | 0 | goto periodicwindowloop; | 424 | 0 | } | 425 | 0 | } | 426 | 0 | for (i = memory; i < cut; i++) { | 427 | 0 | if (needle[i] != window[i]) { | 428 | 0 | LOG("Left half does not match.\n"); | 429 | 0 | window_last += period; | 430 | 0 | memory = len_needle - period; | 431 | 0 | if (window_last >= haystack_end) { | 432 | 0 | return -1; | 433 | 0 | } | 434 | 0 | Py_ssize_t shift = table[(*window_last) & TABLE_MASK]; | 435 | 0 | if (shift) { | 436 | | // A mismatch has been identified to the right | 437 | | // of where i will next start, so we can jump | 438 | | // at least as far as if the mismatch occurred | 439 | | // on the first comparison. | 440 | 0 | Py_ssize_t mem_jump = Py_MAX(cut, memory) - cut + 1; | 441 | 0 | LOG("Skip with Memory.\n"); | 442 | 0 | memory = 0; | 443 | 0 | window_last += Py_MAX(shift, mem_jump); | 444 | 0 | goto periodicwindowloop; | 445 | 0 | } | 446 | 0 | goto no_shift; | 447 | 0 | } | 448 | 0 | } | 449 | 0 | LOG("Found a match!\n"); | 450 | 0 | return window - haystack; | 451 | 0 | } | 452 | 0 | } | 453 | 19 | else { | 454 | 19 | period = Py_MAX(gap, period); | 455 | 19 | LOG("Needle is not periodic.\n"); | 456 | 12.2k | windowloop: | 457 | 12.2k | while (window_last < haystack_end) { | 458 | 66.8k | for (;;) { | 459 | 66.8k | LOG_LINEUP(); | 460 | 66.8k | Py_ssize_t shift = table[(*window_last) & TABLE_MASK]; | 461 | 66.8k | window_last += shift; | 462 | 66.8k | if (shift == 0) { | 463 | 12.1k | break; | 464 | 12.1k | } | 465 | 54.6k | if (window_last >= haystack_end) { | 466 | 16 | return -1; | 467 | 16 | } | 468 | 54.6k | LOG("Horspool skip\n"); | 469 | 54.6k | } | 470 | 12.1k | window = window_last - len_needle + 1; | 471 | 12.1k | assert((window[len_needle - 1] & TABLE_MASK) == | 472 | 12.1k | (needle[len_needle - 1] & TABLE_MASK)); | 473 | 12.1k | Py_ssize_t i = cut; | 474 | 12.3k | for (; i < len_needle; i++) { | 475 | 12.2k | if (needle[i] != window[i]) { | 476 | 12.1k | if (i < gap_jump_end) { | 477 | 12.1k | LOG("Early right half mismatch: jump by gap.\n"); | 478 | 12.1k | assert(gap >= i - cut + 1); | 479 | 12.1k | window_last += gap; | 480 | 12.1k | } | 481 | 0 | else { | 482 | 0 | LOG("Late right half mismatch: jump by n (>gap)\n"); | 483 | 0 | assert(i - cut + 1 > gap); | 484 | 0 | window_last += i - cut + 1; | 485 | 0 | } | 486 | 12.1k | goto windowloop; | 487 | 12.1k | } | 488 | 12.2k | } | 489 | 98 | for (Py_ssize_t i = 0; i < cut; i++) { | 490 | 96 | if (needle[i] != window[i]) { | 491 | 80 | LOG("Left half does not match.\n"); | 492 | 80 | window_last += period; | 493 | 80 | goto windowloop; | 494 | 80 | } | 495 | 96 | } | 496 | 2 | LOG("Found a match!\n"); | 497 | 2 | return window - haystack; | 498 | 82 | } | 499 | 12.2k | } | 500 | 1 | LOG("Not found. Returning -1.\n"); | 501 | 1 | return -1; | 502 | 19 | } |
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way Unexecuted instantiation: bytes_methods.c:stringlib__two_way Unexecuted instantiation: bytearrayobject.c:stringlib__two_way |
503 | | |
504 | | |
505 | | static Py_ssize_t |
506 | | STRINGLIB(_two_way_find)(const STRINGLIB_CHAR *haystack, |
507 | | Py_ssize_t len_haystack, |
508 | | const STRINGLIB_CHAR *needle, |
509 | | Py_ssize_t len_needle) |
510 | 19 | { |
511 | 19 | LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack); |
512 | 19 | STRINGLIB(prework) p; |
513 | 19 | STRINGLIB(_preprocess)(needle, len_needle, &p); |
514 | 19 | return STRINGLIB(_two_way)(haystack, len_haystack, &p); |
515 | 19 | } Unexecuted instantiation: bytesobject.c:stringlib__two_way_find Unexecuted instantiation: unicodeobject.c:asciilib__two_way_find unicodeobject.c:ucs1lib__two_way_find Line | Count | Source | 510 | 19 | { | 511 | 19 | LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack); | 512 | 19 | STRINGLIB(prework) p; | 513 | 19 | STRINGLIB(_preprocess)(needle, len_needle, &p); | 514 | 19 | return STRINGLIB(_two_way)(haystack, len_haystack, &p); | 515 | 19 | } |
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way_find Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way_find Unexecuted instantiation: bytes_methods.c:stringlib__two_way_find Unexecuted instantiation: bytearrayobject.c:stringlib__two_way_find |
516 | | |
517 | | |
518 | | static Py_ssize_t |
519 | | STRINGLIB(_two_way_count)(const STRINGLIB_CHAR *haystack, |
520 | | Py_ssize_t len_haystack, |
521 | | const STRINGLIB_CHAR *needle, |
522 | | Py_ssize_t len_needle, |
523 | | Py_ssize_t maxcount) |
524 | 0 | { |
525 | 0 | LOG("###### Counting \"%s\" in \"%s\".\n", needle, haystack); |
526 | 0 | STRINGLIB(prework) p; |
527 | 0 | STRINGLIB(_preprocess)(needle, len_needle, &p); |
528 | 0 | Py_ssize_t index = 0, count = 0; |
529 | 0 | while (1) { |
530 | 0 | Py_ssize_t result; |
531 | 0 | result = STRINGLIB(_two_way)(haystack + index, |
532 | 0 | len_haystack - index, &p); |
533 | 0 | if (result == -1) { |
534 | 0 | return count; |
535 | 0 | } |
536 | 0 | count++; |
537 | 0 | if (count == maxcount) { |
538 | 0 | return maxcount; |
539 | 0 | } |
540 | 0 | index += result + len_needle; |
541 | 0 | } |
542 | 0 | return count; |
543 | 0 | } Unexecuted instantiation: bytesobject.c:stringlib__two_way_count Unexecuted instantiation: unicodeobject.c:asciilib__two_way_count Unexecuted instantiation: unicodeobject.c:ucs1lib__two_way_count Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way_count Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way_count Unexecuted instantiation: bytes_methods.c:stringlib__two_way_count Unexecuted instantiation: bytearrayobject.c:stringlib__two_way_count |
544 | | |
545 | | #undef SHIFT_TYPE |
546 | | #undef NOT_FOUND |
547 | | #undef SHIFT_OVERFLOW |
548 | | #undef TABLE_SIZE_BITS |
549 | | #undef TABLE_SIZE |
550 | | #undef TABLE_MASK |
551 | | |
552 | | #undef LOG |
553 | | #undef LOG_STRING |
554 | | #undef LOG_LINEUP |
555 | | |
556 | | static inline Py_ssize_t |
557 | | STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n, |
558 | | const STRINGLIB_CHAR* p, Py_ssize_t m, |
559 | | Py_ssize_t maxcount, int mode) |
560 | 16.2M | { |
561 | 16.2M | const Py_ssize_t w = n - m; |
562 | 16.2M | Py_ssize_t mlast = m - 1, count = 0; |
563 | 16.2M | Py_ssize_t gap = mlast; |
564 | 16.2M | const STRINGLIB_CHAR last = p[mlast]; |
565 | 16.2M | const STRINGLIB_CHAR *const ss = &s[mlast]; |
566 | | |
567 | 16.2M | unsigned long mask = 0; |
568 | 32.5M | for (Py_ssize_t i = 0; i < mlast; i++) { |
569 | 16.3M | STRINGLIB_BLOOM_ADD(mask, p[i]); |
570 | 16.3M | if (p[i] == last) { |
571 | 338k | gap = mlast - i - 1; |
572 | 338k | } |
573 | 16.3M | } |
574 | 16.2M | STRINGLIB_BLOOM_ADD(mask, last); |
575 | | |
576 | 5.83G | for (Py_ssize_t i = 0; i <= w; i++) { |
577 | 5.83G | if (ss[i] == last) { |
578 | | /* candidate match */ |
579 | 67.1M | Py_ssize_t j; |
580 | 90.9M | for (j = 0; j < mlast; j++) { |
581 | 67.1M | if (s[i+j] != p[j]) { |
582 | 43.4M | break; |
583 | 43.4M | } |
584 | 67.1M | } |
585 | 67.1M | if (j == mlast) { |
586 | | /* got a match! */ |
587 | 23.7M | if (mode != FAST_COUNT) { |
588 | 11.9M | return i; |
589 | 11.9M | } |
590 | 11.8M | count++; |
591 | 11.8M | if (count == maxcount) { |
592 | 0 | return maxcount; |
593 | 0 | } |
594 | 11.8M | i = i + mlast; |
595 | 11.8M | continue; |
596 | 11.8M | } |
597 | | /* miss: check if next character is part of pattern */ |
598 | 43.4M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { |
599 | 8.21M | i = i + m; |
600 | 8.21M | } |
601 | 35.1M | else { |
602 | 35.1M | i = i + gap; |
603 | 35.1M | } |
604 | 43.4M | } |
605 | 5.76G | else { |
606 | | /* skip: check if next character is part of pattern */ |
607 | 5.76G | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { |
608 | 5.70G | i = i + m; |
609 | 5.70G | } |
610 | 5.76G | } |
611 | 5.83G | } |
612 | 4.33M | return mode == FAST_COUNT ? count : -1; |
613 | 16.2M | } Unexecuted instantiation: bytesobject.c:stringlib_default_find unicodeobject.c:asciilib_default_find Line | Count | Source | 560 | 1.92M | { | 561 | 1.92M | const Py_ssize_t w = n - m; | 562 | 1.92M | Py_ssize_t mlast = m - 1, count = 0; | 563 | 1.92M | Py_ssize_t gap = mlast; | 564 | 1.92M | const STRINGLIB_CHAR last = p[mlast]; | 565 | 1.92M | const STRINGLIB_CHAR *const ss = &s[mlast]; | 566 | | | 567 | 1.92M | unsigned long mask = 0; | 568 | 3.85M | for (Py_ssize_t i = 0; i < mlast; i++) { | 569 | 1.92M | STRINGLIB_BLOOM_ADD(mask, p[i]); | 570 | 1.92M | if (p[i] == last) { | 571 | 3.87k | gap = mlast - i - 1; | 572 | 3.87k | } | 573 | 1.92M | } | 574 | 1.92M | STRINGLIB_BLOOM_ADD(mask, last); | 575 | | | 576 | 172M | for (Py_ssize_t i = 0; i <= w; i++) { | 577 | 172M | if (ss[i] == last) { | 578 | | /* candidate match */ | 579 | 3.81M | Py_ssize_t j; | 580 | 5.71M | for (j = 0; j < mlast; j++) { | 581 | 3.81M | if (s[i+j] != p[j]) { | 582 | 1.91M | break; | 583 | 1.91M | } | 584 | 3.81M | } | 585 | 3.81M | if (j == mlast) { | 586 | | /* got a match! */ | 587 | 1.90M | if (mode != FAST_COUNT) { | 588 | 1.90M | return i; | 589 | 1.90M | } | 590 | 0 | count++; | 591 | 0 | if (count == maxcount) { | 592 | 0 | return maxcount; | 593 | 0 | } | 594 | 0 | i = i + mlast; | 595 | 0 | continue; | 596 | 0 | } | 597 | | /* miss: check if next character is part of pattern */ | 598 | 1.91M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 599 | 23.0k | i = i + m; | 600 | 23.0k | } | 601 | 1.89M | else { | 602 | 1.89M | i = i + gap; | 603 | 1.89M | } | 604 | 1.91M | } | 605 | 168M | else { | 606 | | /* skip: check if next character is part of pattern */ | 607 | 168M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 608 | 162M | i = i + m; | 609 | 162M | } | 610 | 168M | } | 611 | 172M | } | 612 | 26.4k | return mode == FAST_COUNT ? count : -1; | 613 | 1.92M | } |
unicodeobject.c:ucs1lib_default_find Line | Count | Source | 560 | 5.57M | { | 561 | 5.57M | const Py_ssize_t w = n - m; | 562 | 5.57M | Py_ssize_t mlast = m - 1, count = 0; | 563 | 5.57M | Py_ssize_t gap = mlast; | 564 | 5.57M | const STRINGLIB_CHAR last = p[mlast]; | 565 | 5.57M | const STRINGLIB_CHAR *const ss = &s[mlast]; | 566 | | | 567 | 5.57M | unsigned long mask = 0; | 568 | 11.2M | for (Py_ssize_t i = 0; i < mlast; i++) { | 569 | 5.62M | STRINGLIB_BLOOM_ADD(mask, p[i]); | 570 | 5.62M | if (p[i] == last) { | 571 | 274k | gap = mlast - i - 1; | 572 | 274k | } | 573 | 5.62M | } | 574 | 5.57M | STRINGLIB_BLOOM_ADD(mask, last); | 575 | | | 576 | 2.94G | for (Py_ssize_t i = 0; i <= w; i++) { | 577 | 2.93G | if (ss[i] == last) { | 578 | | /* candidate match */ | 579 | 21.4M | Py_ssize_t j; | 580 | 26.2M | for (j = 0; j < mlast; j++) { | 581 | 21.4M | if (s[i+j] != p[j]) { | 582 | 16.7M | break; | 583 | 16.7M | } | 584 | 21.4M | } | 585 | 21.4M | if (j == mlast) { | 586 | | /* got a match! */ | 587 | 4.76M | if (mode != FAST_COUNT) { | 588 | 1.41M | return i; | 589 | 1.41M | } | 590 | 3.34M | count++; | 591 | 3.34M | if (count == maxcount) { | 592 | 0 | return maxcount; | 593 | 0 | } | 594 | 3.34M | i = i + mlast; | 595 | 3.34M | continue; | 596 | 3.34M | } | 597 | | /* miss: check if next character is part of pattern */ | 598 | 16.7M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 599 | 3.89M | i = i + m; | 600 | 3.89M | } | 601 | 12.8M | else { | 602 | 12.8M | i = i + gap; | 603 | 12.8M | } | 604 | 16.7M | } | 605 | 2.91G | else { | 606 | | /* skip: check if next character is part of pattern */ | 607 | 2.91G | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 608 | 2.90G | i = i + m; | 609 | 2.90G | } | 610 | 2.91G | } | 611 | 2.93G | } | 612 | 4.15M | return mode == FAST_COUNT ? count : -1; | 613 | 5.57M | } |
unicodeobject.c:ucs2lib_default_find Line | Count | Source | 560 | 4.01M | { | 561 | 4.01M | const Py_ssize_t w = n - m; | 562 | 4.01M | Py_ssize_t mlast = m - 1, count = 0; | 563 | 4.01M | Py_ssize_t gap = mlast; | 564 | 4.01M | const STRINGLIB_CHAR last = p[mlast]; | 565 | 4.01M | const STRINGLIB_CHAR *const ss = &s[mlast]; | 566 | | | 567 | 4.01M | unsigned long mask = 0; | 568 | 8.03M | for (Py_ssize_t i = 0; i < mlast; i++) { | 569 | 4.02M | STRINGLIB_BLOOM_ADD(mask, p[i]); | 570 | 4.02M | if (p[i] == last) { | 571 | 36.5k | gap = mlast - i - 1; | 572 | 36.5k | } | 573 | 4.02M | } | 574 | 4.01M | STRINGLIB_BLOOM_ADD(mask, last); | 575 | | | 576 | 1.30G | for (Py_ssize_t i = 0; i <= w; i++) { | 577 | 1.30G | if (ss[i] == last) { | 578 | | /* candidate match */ | 579 | 14.2M | Py_ssize_t j; | 580 | 21.9M | for (j = 0; j < mlast; j++) { | 581 | 14.2M | if (s[i+j] != p[j]) { | 582 | 6.48M | break; | 583 | 6.48M | } | 584 | 14.2M | } | 585 | 14.2M | if (j == mlast) { | 586 | | /* got a match! */ | 587 | 7.74M | if (mode != FAST_COUNT) { | 588 | 3.90M | return i; | 589 | 3.90M | } | 590 | 3.84M | count++; | 591 | 3.84M | if (count == maxcount) { | 592 | 0 | return maxcount; | 593 | 0 | } | 594 | 3.84M | i = i + mlast; | 595 | 3.84M | continue; | 596 | 3.84M | } | 597 | | /* miss: check if next character is part of pattern */ | 598 | 6.48M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 599 | 1.59M | i = i + m; | 600 | 1.59M | } | 601 | 4.88M | else { | 602 | 4.88M | i = i + gap; | 603 | 4.88M | } | 604 | 6.48M | } | 605 | 1.29G | else { | 606 | | /* skip: check if next character is part of pattern */ | 607 | 1.29G | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 608 | 1.28G | i = i + m; | 609 | 1.28G | } | 610 | 1.29G | } | 611 | 1.30G | } | 612 | 108k | return mode == FAST_COUNT ? count : -1; | 613 | 4.01M | } |
unicodeobject.c:ucs4lib_default_find Line | Count | Source | 560 | 4.72M | { | 561 | 4.72M | const Py_ssize_t w = n - m; | 562 | 4.72M | Py_ssize_t mlast = m - 1, count = 0; | 563 | 4.72M | Py_ssize_t gap = mlast; | 564 | 4.72M | const STRINGLIB_CHAR last = p[mlast]; | 565 | 4.72M | const STRINGLIB_CHAR *const ss = &s[mlast]; | 566 | | | 567 | 4.72M | unsigned long mask = 0; | 568 | 9.44M | for (Py_ssize_t i = 0; i < mlast; i++) { | 569 | 4.72M | STRINGLIB_BLOOM_ADD(mask, p[i]); | 570 | 4.72M | if (p[i] == last) { | 571 | 20.9k | gap = mlast - i - 1; | 572 | 20.9k | } | 573 | 4.72M | } | 574 | 4.72M | STRINGLIB_BLOOM_ADD(mask, last); | 575 | | | 576 | 1.41G | for (Py_ssize_t i = 0; i <= w; i++) { | 577 | 1.41G | if (ss[i] == last) { | 578 | | /* candidate match */ | 579 | 27.6M | Py_ssize_t j; | 580 | 36.9M | for (j = 0; j < mlast; j++) { | 581 | 27.6M | if (s[i+j] != p[j]) { | 582 | 18.2M | break; | 583 | 18.2M | } | 584 | 27.6M | } | 585 | 27.6M | if (j == mlast) { | 586 | | /* got a match! */ | 587 | 9.34M | if (mode != FAST_COUNT) { | 588 | 4.68M | return i; | 589 | 4.68M | } | 590 | 4.66M | count++; | 591 | 4.66M | if (count == maxcount) { | 592 | 0 | return maxcount; | 593 | 0 | } | 594 | 4.66M | i = i + mlast; | 595 | 4.66M | continue; | 596 | 4.66M | } | 597 | | /* miss: check if next character is part of pattern */ | 598 | 18.2M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 599 | 2.70M | i = i + m; | 600 | 2.70M | } | 601 | 15.5M | else { | 602 | 15.5M | i = i + gap; | 603 | 15.5M | } | 604 | 18.2M | } | 605 | 1.38G | else { | 606 | | /* skip: check if next character is part of pattern */ | 607 | 1.38G | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 608 | 1.36G | i = i + m; | 609 | 1.36G | } | 610 | 1.38G | } | 611 | 1.41G | } | 612 | 41.9k | return mode == FAST_COUNT ? count : -1; | 613 | 4.72M | } |
bytes_methods.c:stringlib_default_find Line | Count | Source | 560 | 2.93k | { | 561 | 2.93k | const Py_ssize_t w = n - m; | 562 | 2.93k | Py_ssize_t mlast = m - 1, count = 0; | 563 | 2.93k | Py_ssize_t gap = mlast; | 564 | 2.93k | const STRINGLIB_CHAR last = p[mlast]; | 565 | 2.93k | const STRINGLIB_CHAR *const ss = &s[mlast]; | 566 | | | 567 | 2.93k | unsigned long mask = 0; | 568 | 11.7k | for (Py_ssize_t i = 0; i < mlast; i++) { | 569 | 8.79k | STRINGLIB_BLOOM_ADD(mask, p[i]); | 570 | 8.79k | if (p[i] == last) { | 571 | 2.93k | gap = mlast - i - 1; | 572 | 2.93k | } | 573 | 8.79k | } | 574 | 2.93k | STRINGLIB_BLOOM_ADD(mask, last); | 575 | | | 576 | 1.39M | for (Py_ssize_t i = 0; i <= w; i++) { | 577 | 1.39M | if (ss[i] == last) { | 578 | | /* candidate match */ | 579 | 8.63k | Py_ssize_t j; | 580 | 17.0k | for (j = 0; j < mlast; j++) { | 581 | 14.3k | if (s[i+j] != p[j]) { | 582 | 5.91k | break; | 583 | 5.91k | } | 584 | 14.3k | } | 585 | 8.63k | if (j == mlast) { | 586 | | /* got a match! */ | 587 | 2.71k | if (mode != FAST_COUNT) { | 588 | 2.71k | return i; | 589 | 2.71k | } | 590 | 0 | count++; | 591 | 0 | if (count == maxcount) { | 592 | 0 | return maxcount; | 593 | 0 | } | 594 | 0 | i = i + mlast; | 595 | 0 | continue; | 596 | 0 | } | 597 | | /* miss: check if next character is part of pattern */ | 598 | 5.91k | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 599 | 638 | i = i + m; | 600 | 638 | } | 601 | 5.27k | else { | 602 | 5.27k | i = i + gap; | 603 | 5.27k | } | 604 | 5.91k | } | 605 | 1.38M | else { | 606 | | /* skip: check if next character is part of pattern */ | 607 | 1.38M | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { | 608 | 120k | i = i + m; | 609 | 120k | } | 610 | 1.38M | } | 611 | 1.39M | } | 612 | 219 | return mode == FAST_COUNT ? count : -1; | 613 | 2.93k | } |
Unexecuted instantiation: bytearrayobject.c:stringlib_default_find |
614 | | |
615 | | |
616 | | static Py_ssize_t |
617 | | STRINGLIB(adaptive_find)(const STRINGLIB_CHAR* s, Py_ssize_t n, |
618 | | const STRINGLIB_CHAR* p, Py_ssize_t m, |
619 | | Py_ssize_t maxcount, int mode) |
620 | 0 | { |
621 | 0 | const Py_ssize_t w = n - m; |
622 | 0 | Py_ssize_t mlast = m - 1, count = 0; |
623 | 0 | Py_ssize_t gap = mlast; |
624 | 0 | Py_ssize_t hits = 0, res; |
625 | 0 | const STRINGLIB_CHAR last = p[mlast]; |
626 | 0 | const STRINGLIB_CHAR *const ss = &s[mlast]; |
627 | |
|
628 | 0 | unsigned long mask = 0; |
629 | 0 | for (Py_ssize_t i = 0; i < mlast; i++) { |
630 | 0 | STRINGLIB_BLOOM_ADD(mask, p[i]); |
631 | 0 | if (p[i] == last) { |
632 | 0 | gap = mlast - i - 1; |
633 | 0 | } |
634 | 0 | } |
635 | 0 | STRINGLIB_BLOOM_ADD(mask, last); |
636 | |
|
637 | 0 | for (Py_ssize_t i = 0; i <= w; i++) { |
638 | 0 | if (ss[i] == last) { |
639 | | /* candidate match */ |
640 | 0 | Py_ssize_t j; |
641 | 0 | for (j = 0; j < mlast; j++) { |
642 | 0 | if (s[i+j] != p[j]) { |
643 | 0 | break; |
644 | 0 | } |
645 | 0 | } |
646 | 0 | if (j == mlast) { |
647 | | /* got a match! */ |
648 | 0 | if (mode != FAST_COUNT) { |
649 | 0 | return i; |
650 | 0 | } |
651 | 0 | count++; |
652 | 0 | if (count == maxcount) { |
653 | 0 | return maxcount; |
654 | 0 | } |
655 | 0 | i = i + mlast; |
656 | 0 | continue; |
657 | 0 | } |
658 | 0 | hits += j + 1; |
659 | 0 | if (hits > m / 4 && w - i > 2000) { |
660 | 0 | if (mode == FAST_SEARCH) { |
661 | 0 | res = STRINGLIB(_two_way_find)(s + i, n - i, p, m); |
662 | 0 | return res == -1 ? -1 : res + i; |
663 | 0 | } |
664 | 0 | else { |
665 | 0 | res = STRINGLIB(_two_way_count)(s + i, n - i, p, m, |
666 | 0 | maxcount - count); |
667 | 0 | return res + count; |
668 | 0 | } |
669 | 0 | } |
670 | | /* miss: check if next character is part of pattern */ |
671 | 0 | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { |
672 | 0 | i = i + m; |
673 | 0 | } |
674 | 0 | else { |
675 | 0 | i = i + gap; |
676 | 0 | } |
677 | 0 | } |
678 | 0 | else { |
679 | | /* skip: check if next character is part of pattern */ |
680 | 0 | if (!STRINGLIB_BLOOM(mask, ss[i+1])) { |
681 | 0 | i = i + m; |
682 | 0 | } |
683 | 0 | } |
684 | 0 | } |
685 | 0 | return mode == FAST_COUNT ? count : -1; |
686 | 0 | } Unexecuted instantiation: bytesobject.c:stringlib_adaptive_find Unexecuted instantiation: unicodeobject.c:asciilib_adaptive_find Unexecuted instantiation: unicodeobject.c:ucs1lib_adaptive_find Unexecuted instantiation: unicodeobject.c:ucs2lib_adaptive_find Unexecuted instantiation: unicodeobject.c:ucs4lib_adaptive_find Unexecuted instantiation: bytes_methods.c:stringlib_adaptive_find Unexecuted instantiation: bytearrayobject.c:stringlib_adaptive_find |
687 | | |
688 | | |
689 | | static Py_ssize_t |
690 | | STRINGLIB(default_rfind)(const STRINGLIB_CHAR* s, Py_ssize_t n, |
691 | | const STRINGLIB_CHAR* p, Py_ssize_t m, |
692 | | Py_ssize_t maxcount, int mode) |
693 | 4 | { |
694 | | /* create compressed boyer-moore delta 1 table */ |
695 | 4 | unsigned long mask = 0; |
696 | 4 | Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m; |
697 | | |
698 | | /* process pattern[0] outside the loop */ |
699 | 4 | STRINGLIB_BLOOM_ADD(mask, p[0]); |
700 | | /* process pattern[:0:-1] */ |
701 | 16 | for (i = mlast; i > 0; i--) { |
702 | 12 | STRINGLIB_BLOOM_ADD(mask, p[i]); |
703 | 12 | if (p[i] == p[0]) { |
704 | 0 | skip = i - 1; |
705 | 0 | } |
706 | 12 | } |
707 | | |
708 | 356 | for (i = w; i >= 0; i--) { |
709 | 352 | if (s[i] == p[0]) { |
710 | | /* candidate match */ |
711 | 8 | for (j = mlast; j > 0; j--) { |
712 | 8 | if (s[i+j] != p[j]) { |
713 | 8 | break; |
714 | 8 | } |
715 | 8 | } |
716 | 8 | if (j == 0) { |
717 | | /* got a match! */ |
718 | 0 | return i; |
719 | 0 | } |
720 | | /* miss: check if previous character is part of pattern */ |
721 | 8 | if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) { |
722 | 8 | i = i - m; |
723 | 8 | } |
724 | 0 | else { |
725 | 0 | i = i - skip; |
726 | 0 | } |
727 | 8 | } |
728 | 344 | else { |
729 | | /* skip: check if previous character is part of pattern */ |
730 | 344 | if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) { |
731 | 336 | i = i - m; |
732 | 336 | } |
733 | 344 | } |
734 | 352 | } |
735 | 4 | return -1; |
736 | 4 | } Unexecuted instantiation: bytesobject.c:stringlib_default_rfind Unexecuted instantiation: unicodeobject.c:asciilib_default_rfind Unexecuted instantiation: unicodeobject.c:ucs1lib_default_rfind Unexecuted instantiation: unicodeobject.c:ucs2lib_default_rfind Unexecuted instantiation: unicodeobject.c:ucs4lib_default_rfind bytes_methods.c:stringlib_default_rfind Line | Count | Source | 693 | 4 | { | 694 | | /* create compressed boyer-moore delta 1 table */ | 695 | 4 | unsigned long mask = 0; | 696 | 4 | Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m; | 697 | | | 698 | | /* process pattern[0] outside the loop */ | 699 | 4 | STRINGLIB_BLOOM_ADD(mask, p[0]); | 700 | | /* process pattern[:0:-1] */ | 701 | 16 | for (i = mlast; i > 0; i--) { | 702 | 12 | STRINGLIB_BLOOM_ADD(mask, p[i]); | 703 | 12 | if (p[i] == p[0]) { | 704 | 0 | skip = i - 1; | 705 | 0 | } | 706 | 12 | } | 707 | | | 708 | 356 | for (i = w; i >= 0; i--) { | 709 | 352 | if (s[i] == p[0]) { | 710 | | /* candidate match */ | 711 | 8 | for (j = mlast; j > 0; j--) { | 712 | 8 | if (s[i+j] != p[j]) { | 713 | 8 | break; | 714 | 8 | } | 715 | 8 | } | 716 | 8 | if (j == 0) { | 717 | | /* got a match! */ | 718 | 0 | return i; | 719 | 0 | } | 720 | | /* miss: check if previous character is part of pattern */ | 721 | 8 | if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) { | 722 | 8 | i = i - m; | 723 | 8 | } | 724 | 0 | else { | 725 | 0 | i = i - skip; | 726 | 0 | } | 727 | 8 | } | 728 | 344 | else { | 729 | | /* skip: check if previous character is part of pattern */ | 730 | 344 | if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) { | 731 | 336 | i = i - m; | 732 | 336 | } | 733 | 344 | } | 734 | 352 | } | 735 | 4 | return -1; | 736 | 4 | } |
Unexecuted instantiation: bytearrayobject.c:stringlib_default_rfind |
737 | | |
738 | | |
739 | | static inline Py_ssize_t |
740 | | STRINGLIB(count_char)(const STRINGLIB_CHAR *s, Py_ssize_t n, |
741 | | const STRINGLIB_CHAR p0, Py_ssize_t maxcount) |
742 | 0 | { |
743 | 0 | Py_ssize_t i, count = 0; |
744 | 0 | for (i = 0; i < n; i++) { |
745 | 0 | if (s[i] == p0) { |
746 | 0 | count++; |
747 | 0 | if (count == maxcount) { |
748 | 0 | return maxcount; |
749 | 0 | } |
750 | 0 | } |
751 | 0 | } |
752 | 0 | return count; |
753 | 0 | } Unexecuted instantiation: bytesobject.c:stringlib_count_char Unexecuted instantiation: unicodeobject.c:asciilib_count_char Unexecuted instantiation: unicodeobject.c:ucs1lib_count_char Unexecuted instantiation: unicodeobject.c:ucs2lib_count_char Unexecuted instantiation: unicodeobject.c:ucs4lib_count_char Unexecuted instantiation: bytes_methods.c:stringlib_count_char Unexecuted instantiation: bytearrayobject.c:stringlib_count_char |
754 | | |
755 | | |
756 | | static inline Py_ssize_t |
757 | | STRINGLIB(count_char_no_maxcount)(const STRINGLIB_CHAR *s, Py_ssize_t n, |
758 | | const STRINGLIB_CHAR p0) |
759 | | /* A specialized function of count_char that does not cut off at a maximum. |
760 | | As a result, the compiler is able to vectorize the loop. */ |
761 | 68.5M | { |
762 | 68.5M | Py_ssize_t count = 0; |
763 | 13.7G | for (Py_ssize_t i = 0; i < n; i++) { |
764 | 13.6G | if (s[i] == p0) { |
765 | 259M | count++; |
766 | 259M | } |
767 | 13.6G | } |
768 | 68.5M | return count; |
769 | 68.5M | } Unexecuted instantiation: bytesobject.c:stringlib_count_char_no_maxcount Unexecuted instantiation: unicodeobject.c:asciilib_count_char_no_maxcount unicodeobject.c:ucs1lib_count_char_no_maxcount Line | Count | Source | 761 | 59.6M | { | 762 | 59.6M | Py_ssize_t count = 0; | 763 | 8.95G | for (Py_ssize_t i = 0; i < n; i++) { | 764 | 8.89G | if (s[i] == p0) { | 765 | 60.8M | count++; | 766 | 60.8M | } | 767 | 8.89G | } | 768 | 59.6M | return count; | 769 | 59.6M | } |
unicodeobject.c:ucs2lib_count_char_no_maxcount Line | Count | Source | 761 | 7.79M | { | 762 | 7.79M | Py_ssize_t count = 0; | 763 | 2.56G | for (Py_ssize_t i = 0; i < n; i++) { | 764 | 2.55G | if (s[i] == p0) { | 765 | 64.4M | count++; | 766 | 64.4M | } | 767 | 2.55G | } | 768 | 7.79M | return count; | 769 | 7.79M | } |
unicodeobject.c:ucs4lib_count_char_no_maxcount Line | Count | Source | 761 | 1.06M | { | 762 | 1.06M | Py_ssize_t count = 0; | 763 | 2.24G | for (Py_ssize_t i = 0; i < n; i++) { | 764 | 2.24G | if (s[i] == p0) { | 765 | 133M | count++; | 766 | 133M | } | 767 | 2.24G | } | 768 | 1.06M | return count; | 769 | 1.06M | } |
Unexecuted instantiation: bytes_methods.c:stringlib_count_char_no_maxcount Unexecuted instantiation: bytearrayobject.c:stringlib_count_char_no_maxcount |
770 | | |
771 | | |
772 | | Py_LOCAL_INLINE(Py_ssize_t) |
773 | | FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, |
774 | | const STRINGLIB_CHAR* p, Py_ssize_t m, |
775 | | Py_ssize_t maxcount, int mode) |
776 | 239M | { |
777 | 239M | if (n < m || (mode == FAST_COUNT && maxcount == 0)) { |
778 | 11.1k | return -1; |
779 | 11.1k | } |
780 | | |
781 | | /* look for special cases */ |
782 | 239M | if (m <= 1) { |
783 | 223M | if (m <= 0) { |
784 | 0 | return -1; |
785 | 0 | } |
786 | | /* use special case for 1-character strings */ |
787 | 223M | if (mode == FAST_SEARCH) |
788 | 155M | return STRINGLIB(find_char)(s, n, p[0]); |
789 | 68.5M | else if (mode == FAST_RSEARCH) |
790 | 9.92k | return STRINGLIB(rfind_char)(s, n, p[0]); |
791 | 68.5M | else { |
792 | 68.5M | if (maxcount == PY_SSIZE_T_MAX) { |
793 | 68.5M | return STRINGLIB(count_char_no_maxcount)(s, n, p[0]); |
794 | 68.5M | } |
795 | 0 | return STRINGLIB(count_char)(s, n, p[0], maxcount); |
796 | 68.5M | } |
797 | 223M | } |
798 | | |
799 | 16.2M | if (mode != FAST_RSEARCH) { |
800 | 16.2M | if (n < 2500 || (m < 100 && n < 30000) || m < 6) { |
801 | 16.2M | return STRINGLIB(default_find)(s, n, p, m, maxcount, mode); |
802 | 16.2M | } |
803 | 19 | else if ((m >> 2) * 3 < (n >> 2)) { |
804 | | /* 33% threshold, but don't overflow. */ |
805 | | /* For larger problems where the needle isn't a huge |
806 | | percentage of the size of the haystack, the relatively |
807 | | expensive O(m) startup cost of the two-way algorithm |
808 | | will surely pay off. */ |
809 | 19 | if (mode == FAST_SEARCH) { |
810 | 19 | return STRINGLIB(_two_way_find)(s, n, p, m); |
811 | 19 | } |
812 | 0 | else { |
813 | 0 | return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); |
814 | 0 | } |
815 | 19 | } |
816 | 0 | else { |
817 | | /* To ensure that we have good worst-case behavior, |
818 | | here's an adaptive version of the algorithm, where if |
819 | | we match O(m) characters without any matches of the |
820 | | entire needle, then we predict that the startup cost of |
821 | | the two-way algorithm will probably be worth it. */ |
822 | 0 | return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode); |
823 | 0 | } |
824 | 16.2M | } |
825 | 4 | else { |
826 | | /* FAST_RSEARCH */ |
827 | 4 | return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode); |
828 | 4 | } |
829 | 16.2M | } Unexecuted instantiation: bytesobject.c:fastsearch unicodeobject.c:asciilib_fastsearch Line | Count | Source | 776 | 19.7M | { | 777 | 19.7M | if (n < m || (mode == FAST_COUNT && maxcount == 0)) { | 778 | 0 | return -1; | 779 | 0 | } | 780 | | | 781 | | /* look for special cases */ | 782 | 19.7M | if (m <= 1) { | 783 | 17.8M | if (m <= 0) { | 784 | 0 | return -1; | 785 | 0 | } | 786 | | /* use special case for 1-character strings */ | 787 | 17.8M | if (mode == FAST_SEARCH) | 788 | 17.8M | return STRINGLIB(find_char)(s, n, p[0]); | 789 | 9.92k | else if (mode == FAST_RSEARCH) | 790 | 9.92k | return STRINGLIB(rfind_char)(s, n, p[0]); | 791 | 0 | else { | 792 | 0 | if (maxcount == PY_SSIZE_T_MAX) { | 793 | 0 | return STRINGLIB(count_char_no_maxcount)(s, n, p[0]); | 794 | 0 | } | 795 | 0 | return STRINGLIB(count_char)(s, n, p[0], maxcount); | 796 | 0 | } | 797 | 17.8M | } | 798 | | | 799 | 1.92M | if (mode != FAST_RSEARCH) { | 800 | 1.92M | if (n < 2500 || (m < 100 && n < 30000) || m < 6) { | 801 | 1.92M | return STRINGLIB(default_find)(s, n, p, m, maxcount, mode); | 802 | 1.92M | } | 803 | 0 | else if ((m >> 2) * 3 < (n >> 2)) { | 804 | | /* 33% threshold, but don't overflow. */ | 805 | | /* For larger problems where the needle isn't a huge | 806 | | percentage of the size of the haystack, the relatively | 807 | | expensive O(m) startup cost of the two-way algorithm | 808 | | will surely pay off. */ | 809 | 0 | if (mode == FAST_SEARCH) { | 810 | 0 | return STRINGLIB(_two_way_find)(s, n, p, m); | 811 | 0 | } | 812 | 0 | else { | 813 | 0 | return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); | 814 | 0 | } | 815 | 0 | } | 816 | 0 | else { | 817 | | /* To ensure that we have good worst-case behavior, | 818 | | here's an adaptive version of the algorithm, where if | 819 | | we match O(m) characters without any matches of the | 820 | | entire needle, then we predict that the startup cost of | 821 | | the two-way algorithm will probably be worth it. */ | 822 | 0 | return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode); | 823 | 0 | } | 824 | 1.92M | } | 825 | 0 | else { | 826 | | /* FAST_RSEARCH */ | 827 | 0 | return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode); | 828 | 0 | } | 829 | 1.92M | } |
unicodeobject.c:ucs1lib_fastsearch Line | Count | Source | 776 | 71.8M | { | 777 | 71.8M | if (n < m || (mode == FAST_COUNT && maxcount == 0)) { | 778 | 0 | return -1; | 779 | 0 | } | 780 | | | 781 | | /* look for special cases */ | 782 | 71.8M | if (m <= 1) { | 783 | 66.3M | if (m <= 0) { | 784 | 0 | return -1; | 785 | 0 | } | 786 | | /* use special case for 1-character strings */ | 787 | 66.3M | if (mode == FAST_SEARCH) | 788 | 6.66M | return STRINGLIB(find_char)(s, n, p[0]); | 789 | 59.6M | else if (mode == FAST_RSEARCH) | 790 | 0 | return STRINGLIB(rfind_char)(s, n, p[0]); | 791 | 59.6M | else { | 792 | 59.6M | if (maxcount == PY_SSIZE_T_MAX) { | 793 | 59.6M | return STRINGLIB(count_char_no_maxcount)(s, n, p[0]); | 794 | 59.6M | } | 795 | 0 | return STRINGLIB(count_char)(s, n, p[0], maxcount); | 796 | 59.6M | } | 797 | 66.3M | } | 798 | | | 799 | 5.57M | if (mode != FAST_RSEARCH) { | 800 | 5.57M | if (n < 2500 || (m < 100 && n < 30000) || m < 6) { | 801 | 5.57M | return STRINGLIB(default_find)(s, n, p, m, maxcount, mode); | 802 | 5.57M | } | 803 | 19 | else if ((m >> 2) * 3 < (n >> 2)) { | 804 | | /* 33% threshold, but don't overflow. */ | 805 | | /* For larger problems where the needle isn't a huge | 806 | | percentage of the size of the haystack, the relatively | 807 | | expensive O(m) startup cost of the two-way algorithm | 808 | | will surely pay off. */ | 809 | 19 | if (mode == FAST_SEARCH) { | 810 | 19 | return STRINGLIB(_two_way_find)(s, n, p, m); | 811 | 19 | } | 812 | 0 | else { | 813 | 0 | return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); | 814 | 0 | } | 815 | 19 | } | 816 | 0 | else { | 817 | | /* To ensure that we have good worst-case behavior, | 818 | | here's an adaptive version of the algorithm, where if | 819 | | we match O(m) characters without any matches of the | 820 | | entire needle, then we predict that the startup cost of | 821 | | the two-way algorithm will probably be worth it. */ | 822 | 0 | return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode); | 823 | 0 | } | 824 | 5.57M | } | 825 | 0 | else { | 826 | | /* FAST_RSEARCH */ | 827 | 0 | return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode); | 828 | 0 | } | 829 | 5.57M | } |
unicodeobject.c:ucs2lib_fastsearch Line | Count | Source | 776 | 62.5M | { | 777 | 62.5M | if (n < m || (mode == FAST_COUNT && maxcount == 0)) { | 778 | 11.1k | return -1; | 779 | 11.1k | } | 780 | | | 781 | | /* look for special cases */ | 782 | 62.5M | if (m <= 1) { | 783 | 58.5M | if (m <= 0) { | 784 | 0 | return -1; | 785 | 0 | } | 786 | | /* use special case for 1-character strings */ | 787 | 58.5M | if (mode == FAST_SEARCH) | 788 | 50.7M | return STRINGLIB(find_char)(s, n, p[0]); | 789 | 7.79M | else if (mode == FAST_RSEARCH) | 790 | 0 | return STRINGLIB(rfind_char)(s, n, p[0]); | 791 | 7.79M | else { | 792 | 7.79M | if (maxcount == PY_SSIZE_T_MAX) { | 793 | 7.79M | return STRINGLIB(count_char_no_maxcount)(s, n, p[0]); | 794 | 7.79M | } | 795 | 0 | return STRINGLIB(count_char)(s, n, p[0], maxcount); | 796 | 7.79M | } | 797 | 58.5M | } | 798 | | | 799 | 4.01M | if (mode != FAST_RSEARCH) { | 800 | 4.01M | if (n < 2500 || (m < 100 && n < 30000) || m < 6) { | 801 | 4.01M | return STRINGLIB(default_find)(s, n, p, m, maxcount, mode); | 802 | 4.01M | } | 803 | 0 | else if ((m >> 2) * 3 < (n >> 2)) { | 804 | | /* 33% threshold, but don't overflow. */ | 805 | | /* For larger problems where the needle isn't a huge | 806 | | percentage of the size of the haystack, the relatively | 807 | | expensive O(m) startup cost of the two-way algorithm | 808 | | will surely pay off. */ | 809 | 0 | if (mode == FAST_SEARCH) { | 810 | 0 | return STRINGLIB(_two_way_find)(s, n, p, m); | 811 | 0 | } | 812 | 0 | else { | 813 | 0 | return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); | 814 | 0 | } | 815 | 0 | } | 816 | 0 | else { | 817 | | /* To ensure that we have good worst-case behavior, | 818 | | here's an adaptive version of the algorithm, where if | 819 | | we match O(m) characters without any matches of the | 820 | | entire needle, then we predict that the startup cost of | 821 | | the two-way algorithm will probably be worth it. */ | 822 | 0 | return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode); | 823 | 0 | } | 824 | 4.01M | } | 825 | 0 | else { | 826 | | /* FAST_RSEARCH */ | 827 | 0 | return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode); | 828 | 0 | } | 829 | 4.01M | } |
unicodeobject.c:ucs4lib_fastsearch Line | Count | Source | 776 | 85.6M | { | 777 | 85.6M | if (n < m || (mode == FAST_COUNT && maxcount == 0)) { | 778 | 0 | return -1; | 779 | 0 | } | 780 | | | 781 | | /* look for special cases */ | 782 | 85.6M | if (m <= 1) { | 783 | 80.8M | if (m <= 0) { | 784 | 0 | return -1; | 785 | 0 | } | 786 | | /* use special case for 1-character strings */ | 787 | 80.8M | if (mode == FAST_SEARCH) | 788 | 79.8M | return STRINGLIB(find_char)(s, n, p[0]); | 789 | 1.06M | else if (mode == FAST_RSEARCH) | 790 | 0 | return STRINGLIB(rfind_char)(s, n, p[0]); | 791 | 1.06M | else { | 792 | 1.06M | if (maxcount == PY_SSIZE_T_MAX) { | 793 | 1.06M | return STRINGLIB(count_char_no_maxcount)(s, n, p[0]); | 794 | 1.06M | } | 795 | 0 | return STRINGLIB(count_char)(s, n, p[0], maxcount); | 796 | 1.06M | } | 797 | 80.8M | } | 798 | | | 799 | 4.72M | if (mode != FAST_RSEARCH) { | 800 | 4.72M | if (n < 2500 || (m < 100 && n < 30000) || m < 6) { | 801 | 4.72M | return STRINGLIB(default_find)(s, n, p, m, maxcount, mode); | 802 | 4.72M | } | 803 | 0 | else if ((m >> 2) * 3 < (n >> 2)) { | 804 | | /* 33% threshold, but don't overflow. */ | 805 | | /* For larger problems where the needle isn't a huge | 806 | | percentage of the size of the haystack, the relatively | 807 | | expensive O(m) startup cost of the two-way algorithm | 808 | | will surely pay off. */ | 809 | 0 | if (mode == FAST_SEARCH) { | 810 | 0 | return STRINGLIB(_two_way_find)(s, n, p, m); | 811 | 0 | } | 812 | 0 | else { | 813 | 0 | return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); | 814 | 0 | } | 815 | 0 | } | 816 | 0 | else { | 817 | | /* To ensure that we have good worst-case behavior, | 818 | | here's an adaptive version of the algorithm, where if | 819 | | we match O(m) characters without any matches of the | 820 | | entire needle, then we predict that the startup cost of | 821 | | the two-way algorithm will probably be worth it. */ | 822 | 0 | return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode); | 823 | 0 | } | 824 | 4.72M | } | 825 | 0 | else { | 826 | | /* FAST_RSEARCH */ | 827 | 0 | return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode); | 828 | 0 | } | 829 | 4.72M | } |
bytes_methods.c:fastsearch Line | Count | Source | 776 | 2.94k | { | 777 | 2.94k | if (n < m || (mode == FAST_COUNT && maxcount == 0)) { | 778 | 9 | return -1; | 779 | 9 | } | 780 | | | 781 | | /* look for special cases */ | 782 | 2.93k | if (m <= 1) { | 783 | 0 | if (m <= 0) { | 784 | 0 | return -1; | 785 | 0 | } | 786 | | /* use special case for 1-character strings */ | 787 | 0 | if (mode == FAST_SEARCH) | 788 | 0 | return STRINGLIB(find_char)(s, n, p[0]); | 789 | 0 | else if (mode == FAST_RSEARCH) | 790 | 0 | return STRINGLIB(rfind_char)(s, n, p[0]); | 791 | 0 | else { | 792 | 0 | if (maxcount == PY_SSIZE_T_MAX) { | 793 | 0 | return STRINGLIB(count_char_no_maxcount)(s, n, p[0]); | 794 | 0 | } | 795 | 0 | return STRINGLIB(count_char)(s, n, p[0], maxcount); | 796 | 0 | } | 797 | 0 | } | 798 | | | 799 | 2.93k | if (mode != FAST_RSEARCH) { | 800 | 2.93k | if (n < 2500 || (m < 100 && n < 30000) || m < 6) { | 801 | 2.93k | return STRINGLIB(default_find)(s, n, p, m, maxcount, mode); | 802 | 2.93k | } | 803 | 0 | else if ((m >> 2) * 3 < (n >> 2)) { | 804 | | /* 33% threshold, but don't overflow. */ | 805 | | /* For larger problems where the needle isn't a huge | 806 | | percentage of the size of the haystack, the relatively | 807 | | expensive O(m) startup cost of the two-way algorithm | 808 | | will surely pay off. */ | 809 | 0 | if (mode == FAST_SEARCH) { | 810 | 0 | return STRINGLIB(_two_way_find)(s, n, p, m); | 811 | 0 | } | 812 | 0 | else { | 813 | 0 | return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); | 814 | 0 | } | 815 | 0 | } | 816 | 0 | else { | 817 | | /* To ensure that we have good worst-case behavior, | 818 | | here's an adaptive version of the algorithm, where if | 819 | | we match O(m) characters without any matches of the | 820 | | entire needle, then we predict that the startup cost of | 821 | | the two-way algorithm will probably be worth it. */ | 822 | 0 | return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode); | 823 | 0 | } | 824 | 2.93k | } | 825 | 4 | else { | 826 | | /* FAST_RSEARCH */ | 827 | 4 | return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode); | 828 | 4 | } | 829 | 2.93k | } |
Unexecuted instantiation: bytearrayobject.c:fastsearch |
830 | | |