Coverage Report

Created: 2026-07-14 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Objects/stringlib/fastsearch.h
Line
Count
Source
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
245M
#define FAST_COUNT 0
25
104M
#define FAST_SEARCH 1
26
63.0M
#define FAST_RSEARCH 2
27
28
#if LONG_BIT >= 128
29
#define STRINGLIB_BLOOM_WIDTH 128
30
#elif LONG_BIT >= 64
31
912M
#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
137M
    ((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
40
#define STRINGLIB_BLOOM(mask, ch)     \
41
774M
    ((mask &  (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
42
43
#ifdef STRINGLIB_FAST_MEMCHR
44
251M
#  define MEMCHR_CUT_OFF 15
45
#else
46
9.12M
#  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
260M
{
52
260M
    const STRINGLIB_CHAR *p, *e;
53
54
260M
    p = s;
55
260M
    e = s + n;
56
260M
    if (n > MEMCHR_CUT_OFF) {
57
#ifdef STRINGLIB_FAST_MEMCHR
58
35.5M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
35.5M
        if (p != NULL)
60
34.1M
            return (p - s);
61
1.35M
        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
8.57M
        if (needle != 0) {
71
8.59M
            do {
72
8.59M
                const void *candidate = memchr(p, needle,
73
8.59M
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
8.59M
                if (candidate == NULL)
75
72.8k
                    return -1;
76
8.52M
                s1 = p;
77
8.52M
                p = (const STRINGLIB_CHAR *)
78
8.52M
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
8.52M
                if (*p == ch)
80
8.48M
                    return (p - s);
81
                /* False positive */
82
40.1k
                p++;
83
40.1k
                if (p - s1 > MEMCHR_CUT_OFF)
84
15.6k
                    continue;
85
24.5k
                if (e - p <= MEMCHR_CUT_OFF)
86
2.70k
                    break;
87
21.7k
                e1 = p + MEMCHR_CUT_OFF;
88
787k
                while (p != e1) {
89
768k
                    if (*p == ch)
90
3.14k
                        return (p - s);
91
765k
                    p++;
92
765k
                }
93
21.7k
            }
94
8.56M
            while (e - p > MEMCHR_CUT_OFF);
95
8.56M
        }
96
#endif
97
44.1M
    }
98
1.06G
    while (p < e) {
99
869M
        if (*p == ch)
100
18.8M
            return (p - s);
101
850M
        p++;
102
850M
    }
103
197M
    return -1;
104
216M
}
bytesobject.c:stringlib_find_char
Line
Count
Source
51
267k
{
52
267k
    const STRINGLIB_CHAR *p, *e;
53
54
267k
    p = s;
55
267k
    e = s + n;
56
267k
    if (n > MEMCHR_CUT_OFF) {
57
267k
#ifdef STRINGLIB_FAST_MEMCHR
58
267k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
267k
        if (p != NULL)
60
266k
            return (p - s);
61
1.47k
        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
                const 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
267k
    }
98
84
    while (p < e) {
99
84
        if (*p == ch)
100
14
            return (p - s);
101
70
        p++;
102
70
    }
103
0
    return -1;
104
14
}
unicodeobject.c:ucs1lib_find_char
Line
Count
Source
51
227M
{
52
227M
    const STRINGLIB_CHAR *p, *e;
53
54
227M
    p = s;
55
227M
    e = s + n;
56
227M
    if (n > MEMCHR_CUT_OFF) {
57
20.3M
#ifdef STRINGLIB_FAST_MEMCHR
58
20.3M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
20.3M
        if (p != NULL)
60
19.5M
            return (p - s);
61
832k
        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
                const 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
20.3M
    }
98
989M
    while (p < e) {
99
795M
        if (*p == ch)
100
13.3M
            return (p - s);
101
782M
        p++;
102
782M
    }
103
193M
    return -1;
104
206M
}
unicodeobject.c:ucs2lib_find_char
Line
Count
Source
51
9.00M
{
52
9.00M
    const STRINGLIB_CHAR *p, *e;
53
54
9.00M
    p = s;
55
9.00M
    e = s + n;
56
9.00M
    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
8.57M
        const STRINGLIB_CHAR *s1, *e1;
66
8.57M
        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
8.57M
        if (needle != 0) {
71
8.59M
            do {
72
8.59M
                const void *candidate = memchr(p, needle,
73
8.59M
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
8.59M
                if (candidate == NULL)
75
72.8k
                    return -1;
76
8.52M
                s1 = p;
77
8.52M
                p = (const STRINGLIB_CHAR *)
78
8.52M
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
8.52M
                if (*p == ch)
80
8.48M
                    return (p - s);
81
                /* False positive */
82
40.1k
                p++;
83
40.1k
                if (p - s1 > MEMCHR_CUT_OFF)
84
15.6k
                    continue;
85
24.5k
                if (e - p <= MEMCHR_CUT_OFF)
86
2.70k
                    break;
87
21.7k
                e1 = p + MEMCHR_CUT_OFF;
88
787k
                while (p != e1) {
89
768k
                    if (*p == ch)
90
3.14k
                        return (p - s);
91
765k
                    p++;
92
765k
                }
93
21.7k
            }
94
8.56M
            while (e - p > MEMCHR_CUT_OFF);
95
8.56M
        }
96
8.57M
#endif
97
8.57M
    }
98
6.03M
    while (p < e) {
99
5.77M
        if (*p == ch)
100
185k
            return (p - s);
101
5.59M
        p++;
102
5.59M
    }
103
258k
    return -1;
104
443k
}
unicodeobject.c:ucs4lib_find_char
Line
Count
Source
51
7.10M
{
52
7.10M
    const STRINGLIB_CHAR *p, *e;
53
54
7.10M
    p = s;
55
7.10M
    e = s + n;
56
7.10M
    if (n > MEMCHR_CUT_OFF) {
57
7.05M
#ifdef STRINGLIB_FAST_MEMCHR
58
7.05M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
7.05M
        if (p != NULL)
60
7.03M
            return (p - s);
61
15.0k
        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
                const 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
7.05M
    }
98
195k
    while (p < e) {
99
165k
        if (*p == ch)
100
20.6k
            return (p - s);
101
144k
        p++;
102
144k
    }
103
30.2k
    return -1;
104
50.8k
}
unicodeobject.c:asciilib_find_char
Line
Count
Source
51
5.60M
{
52
5.60M
    const STRINGLIB_CHAR *p, *e;
53
54
5.60M
    p = s;
55
5.60M
    e = s + n;
56
5.60M
    if (n > MEMCHR_CUT_OFF) {
57
4.62M
#ifdef STRINGLIB_FAST_MEMCHR
58
4.62M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
4.62M
        if (p != NULL)
60
4.19M
            return (p - s);
61
433k
        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
                const 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
4.62M
    }
98
3.15M
    while (p < e) {
99
3.08M
        if (*p == ch)
100
908k
            return (p - s);
101
2.17M
        p++;
102
2.17M
    }
103
68.9k
    return -1;
104
977k
}
bytes_methods.c:stringlib_find_char
Line
Count
Source
51
11.7M
{
52
11.7M
    const STRINGLIB_CHAR *p, *e;
53
54
11.7M
    p = s;
55
11.7M
    e = s + n;
56
11.7M
    if (n > MEMCHR_CUT_OFF) {
57
3.25M
#ifdef STRINGLIB_FAST_MEMCHR
58
3.25M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
3.25M
        if (p != NULL)
60
3.18M
            return (p - s);
61
71.7k
        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
                const 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
3.25M
    }
98
68.7M
    while (p < e) {
99
64.7M
        if (*p == ch)
100
4.42M
            return (p - s);
101
60.3M
        p++;
102
60.3M
    }
103
4.03M
    return -1;
104
8.45M
}
Unexecuted instantiation: bytearrayobject.c:stringlib_find_char
105
106
#undef MEMCHR_CUT_OFF
107
108
#if STRINGLIB_SIZEOF_CHAR == 1
109
381k
#  define MEMRCHR_CUT_OFF 15
110
#else
111
346k
#  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
686k
{
118
686k
    const STRINGLIB_CHAR *p;
119
686k
#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
686k
    if (n > MEMRCHR_CUT_OFF) {
126
#if STRINGLIB_SIZEOF_CHAR == 1
127
        p = memrchr(s, ch, n);
128
94.7k
        if (p != NULL)
129
88.4k
            return (p - s);
130
6.27k
        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
229k
        if (needle != 0) {
141
241k
            do {
142
241k
                void *candidate = memrchr(s, needle,
143
241k
                                          n * sizeof(STRINGLIB_CHAR));
144
241k
                if (candidate == NULL)
145
1.24k
                    return -1;
146
240k
                n1 = n;
147
240k
                p = (const STRINGLIB_CHAR *)
148
240k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
240k
                n = p - s;
150
240k
                if (*p == ch)
151
226k
                    return n;
152
                /* False positive */
153
14.1k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
6.42k
                    continue;
155
7.76k
                if (n <= MEMRCHR_CUT_OFF)
156
932
                    break;
157
6.83k
                s1 = p - MEMRCHR_CUT_OFF;
158
265k
                while (p > s1) {
159
259k
                    p--;
160
259k
                    if (*p == ch)
161
604
                        return (p - s);
162
259k
                }
163
6.23k
                n = p - s;
164
6.23k
            }
165
229k
            while (n > MEMRCHR_CUT_OFF);
166
229k
        }
167
#endif
168
324k
    }
169
363k
#endif  /* HAVE_MEMRCHR */
170
363k
    p = s + n;
171
2.37M
    while (p > s) {
172
2.18M
        p--;
173
2.18M
        if (*p == ch)
174
172k
            return (p - s);
175
2.18M
    }
176
190k
    return -1;
177
363k
}
Unexecuted instantiation: bytesobject.c:stringlib_rfind_char
unicodeobject.c:ucs1lib_rfind_char
Line
Count
Source
117
59.3k
{
118
59.3k
    const STRINGLIB_CHAR *p;
119
59.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
59.3k
    if (n > MEMRCHR_CUT_OFF) {
126
54.7k
#if STRINGLIB_SIZEOF_CHAR == 1
127
54.7k
        p = memrchr(s, ch, n);
128
54.7k
        if (p != NULL)
129
52.7k
            return (p - s);
130
1.93k
        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
54.7k
    }
169
4.67k
#endif  /* HAVE_MEMRCHR */
170
4.67k
    p = s + n;
171
19.6k
    while (p > s) {
172
17.9k
        p--;
173
17.9k
        if (*p == ch)
174
2.92k
            return (p - s);
175
17.9k
    }
176
1.75k
    return -1;
177
4.67k
}
unicodeobject.c:ucs2lib_rfind_char
Line
Count
Source
117
177k
{
118
177k
    const STRINGLIB_CHAR *p;
119
177k
#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
177k
    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
145k
        const STRINGLIB_CHAR *s1;
135
145k
        Py_ssize_t n1;
136
145k
        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
145k
        if (needle != 0) {
141
148k
            do {
142
148k
                void *candidate = memrchr(s, needle,
143
148k
                                          n * sizeof(STRINGLIB_CHAR));
144
148k
                if (candidate == NULL)
145
717
                    return -1;
146
147k
                n1 = n;
147
147k
                p = (const STRINGLIB_CHAR *)
148
147k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
147k
                n = p - s;
150
147k
                if (*p == ch)
151
143k
                    return n;
152
                /* False positive */
153
3.73k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
1.74k
                    continue;
155
1.99k
                if (n <= MEMRCHR_CUT_OFF)
156
563
                    break;
157
1.42k
                s1 = p - MEMRCHR_CUT_OFF;
158
52.5k
                while (p > s1) {
159
51.4k
                    p--;
160
51.4k
                    if (*p == ch)
161
240
                        return (p - s);
162
51.4k
                }
163
1.18k
                n = p - s;
164
1.18k
            }
165
145k
            while (n > MEMRCHR_CUT_OFF);
166
145k
        }
167
145k
#endif
168
145k
    }
169
32.5k
#endif  /* HAVE_MEMRCHR */
170
32.5k
    p = s + n;
171
118k
    while (p > s) {
172
116k
        p--;
173
116k
        if (*p == ch)
174
30.4k
            return (p - s);
175
116k
    }
176
2.19k
    return -1;
177
32.5k
}
unicodeobject.c:ucs4lib_rfind_char
Line
Count
Source
117
128k
{
118
128k
    const STRINGLIB_CHAR *p;
119
128k
#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
128k
    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
84.0k
        const STRINGLIB_CHAR *s1;
135
84.0k
        Py_ssize_t n1;
136
84.0k
        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
84.0k
        if (needle != 0) {
141
93.5k
            do {
142
93.5k
                void *candidate = memrchr(s, needle,
143
93.5k
                                          n * sizeof(STRINGLIB_CHAR));
144
93.5k
                if (candidate == NULL)
145
526
                    return -1;
146
92.9k
                n1 = n;
147
92.9k
                p = (const STRINGLIB_CHAR *)
148
92.9k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
92.9k
                n = p - s;
150
92.9k
                if (*p == ch)
151
82.5k
                    return n;
152
                /* False positive */
153
10.4k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
4.67k
                    continue;
155
5.77k
                if (n <= MEMRCHR_CUT_OFF)
156
369
                    break;
157
5.40k
                s1 = p - MEMRCHR_CUT_OFF;
158
212k
                while (p > s1) {
159
207k
                    p--;
160
207k
                    if (*p == ch)
161
364
                        return (p - s);
162
207k
                }
163
5.04k
                n = p - s;
164
5.04k
            }
165
84.0k
            while (n > MEMRCHR_CUT_OFF);
166
84.0k
        }
167
84.0k
#endif
168
84.0k
    }
169
44.6k
#endif  /* HAVE_MEMRCHR */
170
44.6k
    p = s + n;
171
281k
    while (p > s) {
172
279k
        p--;
173
279k
        if (*p == ch)
174
42.9k
            return (p - s);
175
279k
    }
176
1.70k
    return -1;
177
44.6k
}
unicodeobject.c:asciilib_rfind_char
Line
Count
Source
117
54.5k
{
118
54.5k
    const STRINGLIB_CHAR *p;
119
54.5k
#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
54.5k
    if (n > MEMRCHR_CUT_OFF) {
126
17.7k
#if STRINGLIB_SIZEOF_CHAR == 1
127
17.7k
        p = memrchr(s, ch, n);
128
17.7k
        if (p != NULL)
129
17.4k
            return (p - s);
130
292
        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
17.7k
    }
169
36.8k
#endif  /* HAVE_MEMRCHR */
170
36.8k
    p = s + n;
171
212k
    while (p > s) {
172
185k
        p--;
173
185k
        if (*p == ch)
174
10.1k
            return (p - s);
175
185k
    }
176
26.6k
    return -1;
177
36.8k
}
bytes_methods.c:stringlib_rfind_char
Line
Count
Source
117
267k
{
118
267k
    const STRINGLIB_CHAR *p;
119
267k
#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
267k
    if (n > MEMRCHR_CUT_OFF) {
126
22.2k
#if STRINGLIB_SIZEOF_CHAR == 1
127
22.2k
        p = memrchr(s, ch, n);
128
22.2k
        if (p != NULL)
129
18.2k
            return (p - s);
130
4.04k
        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
22.2k
    }
169
244k
#endif  /* HAVE_MEMRCHR */
170
244k
    p = s + n;
171
1.74M
    while (p > s) {
172
1.58M
        p--;
173
1.58M
        if (*p == ch)
174
86.5k
            return (p - s);
175
1.58M
    }
176
158k
    return -1;
177
244k
}
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
44
{
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
44
    Py_ssize_t max_suffix = 0;
204
44
    Py_ssize_t candidate = 1;
205
44
    Py_ssize_t k = 0;
206
    // The period of the right half.
207
44
    Py_ssize_t period = 1;
208
209
440
    while (candidate + k < len_needle) {
210
        // each loop increases candidate + k + max_suffix
211
396
        STRINGLIB_CHAR a = needle[candidate + k];
212
396
        STRINGLIB_CHAR b = needle[max_suffix + k];
213
        // check if the suffix at candidate is better than max_suffix
214
396
        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
286
            candidate += k + 1;
219
286
            k = 0;
220
            // We've ruled out any period smaller than what's
221
            // been scanned since max_suffix.
222
286
            period = candidate - max_suffix;
223
286
        }
224
110
        else if (a == b) {
225
22
            if (k + 1 != period) {
226
                // Keep scanning the equal strings
227
0
                k++;
228
0
            }
229
22
            else {
230
                // Matched a whole period.
231
                // Start matching the next period.
232
22
                candidate += period;
233
22
                k = 0;
234
22
            }
235
22
        }
236
88
        else {
237
            // Did better than max_suffix, so replace it.
238
88
            max_suffix = candidate;
239
88
            candidate++;
240
88
            k = 0;
241
88
            period = 1;
242
88
        }
243
396
    }
244
44
    *return_period = period;
245
44
    return max_suffix;
246
44
}
Unexecuted instantiation: bytesobject.c:stringlib__lex_search
Unexecuted instantiation: unicodeobject.c:asciilib__lex_search
unicodeobject.c:ucs1lib__lex_search
Line
Count
Source
199
44
{
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
44
    Py_ssize_t max_suffix = 0;
204
44
    Py_ssize_t candidate = 1;
205
44
    Py_ssize_t k = 0;
206
    // The period of the right half.
207
44
    Py_ssize_t period = 1;
208
209
440
    while (candidate + k < len_needle) {
210
        // each loop increases candidate + k + max_suffix
211
396
        STRINGLIB_CHAR a = needle[candidate + k];
212
396
        STRINGLIB_CHAR b = needle[max_suffix + k];
213
        // check if the suffix at candidate is better than max_suffix
214
396
        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
286
            candidate += k + 1;
219
286
            k = 0;
220
            // We've ruled out any period smaller than what's
221
            // been scanned since max_suffix.
222
286
            period = candidate - max_suffix;
223
286
        }
224
110
        else if (a == b) {
225
22
            if (k + 1 != period) {
226
                // Keep scanning the equal strings
227
0
                k++;
228
0
            }
229
22
            else {
230
                // Matched a whole period.
231
                // Start matching the next period.
232
22
                candidate += period;
233
22
                k = 0;
234
22
            }
235
22
        }
236
88
        else {
237
            // Did better than max_suffix, so replace it.
238
88
            max_suffix = candidate;
239
88
            candidate++;
240
88
            k = 0;
241
88
            period = 1;
242
88
        }
243
396
    }
244
44
    *return_period = period;
245
44
    return max_suffix;
246
44
}
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
22
{
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
22
    Py_ssize_t cut1, period1, cut2, period2, cut, period;
286
22
    cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0);
287
22
    cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1);
288
289
    // Take the later cut.
290
22
    if (cut1 > cut2) {
291
22
        period = period1;
292
22
        cut = cut1;
293
22
    }
294
0
    else {
295
0
        period = period2;
296
0
        cut = cut2;
297
0
    }
298
299
22
    LOG("split: "); LOG_STRING(needle, cut);
300
22
    LOG(" + "); LOG_STRING(needle + cut, len_needle - cut);
301
22
    LOG("\n");
302
303
22
    *return_period = period;
304
22
    return cut;
305
22
}
Unexecuted instantiation: bytesobject.c:stringlib__factorize
Unexecuted instantiation: unicodeobject.c:asciilib__factorize
unicodeobject.c:ucs1lib__factorize
Line
Count
Source
252
22
{
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
22
    Py_ssize_t cut1, period1, cut2, period2, cut, period;
286
22
    cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0);
287
22
    cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1);
288
289
    // Take the later cut.
290
22
    if (cut1 > cut2) {
291
22
        period = period1;
292
22
        cut = cut1;
293
22
    }
294
0
    else {
295
0
        period = period2;
296
0
        cut = cut2;
297
0
    }
298
299
22
    LOG("split: "); LOG_STRING(needle, cut);
300
22
    LOG(" + "); LOG_STRING(needle + cut, len_needle - cut);
301
22
    LOG("\n");
302
303
22
    *return_period = period;
304
22
    return cut;
305
22
}
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
242
#define SHIFT_TYPE uint8_t
309
#define MAX_SHIFT UINT8_MAX
310
311
81.4k
#define TABLE_SIZE_BITS 6u
312
81.4k
#define TABLE_SIZE (1U << TABLE_SIZE_BITS)
313
79.9k
#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
22
{
330
22
    p->needle = needle;
331
22
    p->len_needle = len_needle;
332
22
    p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period));
333
22
    assert(p->period + p->cut <= len_needle);
334
22
    p->is_periodic = (0 == memcmp(needle,
335
22
                                  needle + p->period,
336
22
                                  p->cut * STRINGLIB_SIZEOF_CHAR));
337
22
    if (p->is_periodic) {
338
0
        assert(p->cut <= len_needle/2);
339
0
        assert(p->cut < p->period);
340
0
    }
341
22
    else {
342
        // A lower bound on the period
343
22
        p->period = Py_MAX(p->cut, len_needle - p->cut) + 1;
344
22
    }
345
    // The gap between the last character and the previous
346
    // occurrence of an equivalent character (modulo TABLE_SIZE)
347
22
    p->gap = len_needle;
348
22
    STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK;
349
154
    for (Py_ssize_t i = len_needle - 2; i >= 0; i--) {
350
154
        STRINGLIB_CHAR x = needle[i] & TABLE_MASK;
351
154
        if (x == last) {
352
22
            p->gap = len_needle - 1 - i;
353
22
            break;
354
22
        }
355
154
    }
356
    // Fill up a compressed Boyer-Moore "Bad Character" table
357
22
    Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT);
358
1.43k
    for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) {
359
1.40k
        p->table[i] = Py_SAFE_DOWNCAST(not_found_shift,
360
1.40k
                                       Py_ssize_t, SHIFT_TYPE);
361
1.40k
    }
362
242
    for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) {
363
220
        SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i,
364
220
                                            Py_ssize_t, SHIFT_TYPE);
365
220
        p->table[needle[i] & TABLE_MASK] = shift;
366
220
    }
367
22
}
Unexecuted instantiation: bytesobject.c:stringlib__preprocess
Unexecuted instantiation: unicodeobject.c:asciilib__preprocess
unicodeobject.c:ucs1lib__preprocess
Line
Count
Source
329
22
{
330
22
    p->needle = needle;
331
22
    p->len_needle = len_needle;
332
22
    p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period));
333
22
    assert(p->period + p->cut <= len_needle);
334
22
    p->is_periodic = (0 == memcmp(needle,
335
22
                                  needle + p->period,
336
22
                                  p->cut * STRINGLIB_SIZEOF_CHAR));
337
22
    if (p->is_periodic) {
338
0
        assert(p->cut <= len_needle/2);
339
0
        assert(p->cut < p->period);
340
0
    }
341
22
    else {
342
        // A lower bound on the period
343
22
        p->period = Py_MAX(p->cut, len_needle - p->cut) + 1;
344
22
    }
345
    // The gap between the last character and the previous
346
    // occurrence of an equivalent character (modulo TABLE_SIZE)
347
22
    p->gap = len_needle;
348
22
    STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK;
349
154
    for (Py_ssize_t i = len_needle - 2; i >= 0; i--) {
350
154
        STRINGLIB_CHAR x = needle[i] & TABLE_MASK;
351
154
        if (x == last) {
352
22
            p->gap = len_needle - 1 - i;
353
22
            break;
354
22
        }
355
154
    }
356
    // Fill up a compressed Boyer-Moore "Bad Character" table
357
22
    Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT);
358
1.43k
    for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) {
359
1.40k
        p->table[i] = Py_SAFE_DOWNCAST(not_found_shift,
360
1.40k
                                       Py_ssize_t, SHIFT_TYPE);
361
1.40k
    }
362
242
    for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) {
363
220
        SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i,
364
220
                                            Py_ssize_t, SHIFT_TYPE);
365
220
        p->table[needle[i] & TABLE_MASK] = shift;
366
220
    }
367
22
}
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
22
{
373
    // Crochemore and Perrin's (1991) Two-Way algorithm.
374
    // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260
375
22
    const Py_ssize_t len_needle = p->len_needle;
376
22
    const Py_ssize_t cut = p->cut;
377
22
    Py_ssize_t period = p->period;
378
22
    const STRINGLIB_CHAR *const needle = p->needle;
379
22
    const STRINGLIB_CHAR *window_last = haystack + len_needle - 1;
380
22
    const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack;
381
22
    SHIFT_TYPE *table = p->table;
382
22
    const STRINGLIB_CHAR *window;
383
22
    LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack);
384
385
22
    Py_ssize_t gap = p->gap;
386
22
    Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap);
387
22
    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
22
    else {
454
22
        period = Py_MAX(gap, period);
455
22
        LOG("Needle is not periodic.\n");
456
15.1k
      windowloop:
457
15.1k
        while (window_last < haystack_end) {
458
79.5k
            for (;;) {
459
79.5k
                LOG_LINEUP();
460
79.5k
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
79.5k
                window_last += shift;
462
79.5k
                if (shift == 0) {
463
15.1k
                    break;
464
15.1k
                }
465
64.4k
                if (window_last >= haystack_end) {
466
17
                    return -1;
467
17
                }
468
64.4k
                LOG("Horspool skip\n");
469
64.4k
            }
470
15.1k
            window = window_last - len_needle + 1;
471
15.1k
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
15.1k
                   (needle[len_needle - 1] & TABLE_MASK));
473
15.1k
            Py_ssize_t i = cut;
474
15.3k
            for (; i < len_needle; i++) {
475
15.2k
                if (needle[i] != window[i]) {
476
15.0k
                    if (i < gap_jump_end) {
477
15.0k
                        LOG("Early right half mismatch: jump by gap.\n");
478
15.0k
                        assert(gap >= i - cut + 1);
479
15.0k
                        window_last += gap;
480
15.0k
                    }
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
15.0k
                    goto windowloop;
487
15.0k
                }
488
15.2k
            }
489
199
            for (Py_ssize_t i = 0; i < cut; i++) {
490
196
                if (needle[i] != window[i]) {
491
92
                    LOG("Left half does not match.\n");
492
92
                    window_last += period;
493
92
                    goto windowloop;
494
92
                }
495
196
            }
496
3
            LOG("Found a match!\n");
497
3
            return window - haystack;
498
95
        }
499
15.1k
    }
500
2
    LOG("Not found. Returning -1.\n");
501
2
    return -1;
502
22
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way
Unexecuted instantiation: unicodeobject.c:asciilib__two_way
unicodeobject.c:ucs1lib__two_way
Line
Count
Source
372
22
{
373
    // Crochemore and Perrin's (1991) Two-Way algorithm.
374
    // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260
375
22
    const Py_ssize_t len_needle = p->len_needle;
376
22
    const Py_ssize_t cut = p->cut;
377
22
    Py_ssize_t period = p->period;
378
22
    const STRINGLIB_CHAR *const needle = p->needle;
379
22
    const STRINGLIB_CHAR *window_last = haystack + len_needle - 1;
380
22
    const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack;
381
22
    SHIFT_TYPE *table = p->table;
382
22
    const STRINGLIB_CHAR *window;
383
22
    LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack);
384
385
22
    Py_ssize_t gap = p->gap;
386
22
    Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap);
387
22
    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
22
    else {
454
22
        period = Py_MAX(gap, period);
455
22
        LOG("Needle is not periodic.\n");
456
15.1k
      windowloop:
457
15.1k
        while (window_last < haystack_end) {
458
79.5k
            for (;;) {
459
79.5k
                LOG_LINEUP();
460
79.5k
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
79.5k
                window_last += shift;
462
79.5k
                if (shift == 0) {
463
15.1k
                    break;
464
15.1k
                }
465
64.4k
                if (window_last >= haystack_end) {
466
17
                    return -1;
467
17
                }
468
64.4k
                LOG("Horspool skip\n");
469
64.4k
            }
470
15.1k
            window = window_last - len_needle + 1;
471
15.1k
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
15.1k
                   (needle[len_needle - 1] & TABLE_MASK));
473
15.1k
            Py_ssize_t i = cut;
474
15.3k
            for (; i < len_needle; i++) {
475
15.2k
                if (needle[i] != window[i]) {
476
15.0k
                    if (i < gap_jump_end) {
477
15.0k
                        LOG("Early right half mismatch: jump by gap.\n");
478
15.0k
                        assert(gap >= i - cut + 1);
479
15.0k
                        window_last += gap;
480
15.0k
                    }
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
15.0k
                    goto windowloop;
487
15.0k
                }
488
15.2k
            }
489
199
            for (Py_ssize_t i = 0; i < cut; i++) {
490
196
                if (needle[i] != window[i]) {
491
92
                    LOG("Left half does not match.\n");
492
92
                    window_last += period;
493
92
                    goto windowloop;
494
92
                }
495
196
            }
496
3
            LOG("Found a match!\n");
497
3
            return window - haystack;
498
95
        }
499
15.1k
    }
500
2
    LOG("Not found. Returning -1.\n");
501
2
    return -1;
502
22
}
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
22
{
511
22
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
22
    STRINGLIB(prework) p;
513
22
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
22
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
22
}
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
22
{
511
22
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
22
    STRINGLIB(prework) p;
513
22
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
22
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
22
}
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
27.6M
{
561
27.6M
    const Py_ssize_t w = n - m;
562
27.6M
    Py_ssize_t mlast = m - 1, count = 0;
563
27.6M
    Py_ssize_t gap = mlast;
564
27.6M
    const STRINGLIB_CHAR last = p[mlast];
565
27.6M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
27.6M
    unsigned long mask = 0;
568
137M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
110M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
110M
        if (p[i] == last) {
571
1.67M
            gap = mlast - i - 1;
572
1.67M
        }
573
110M
    }
574
27.6M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
810M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
792M
        if (ss[i] == last) {
578
            /* candidate match */
579
31.4M
            Py_ssize_t j;
580
49.4M
            for (j = 0; j < mlast; j++) {
581
32.6M
                if (s[i+j] != p[j]) {
582
14.6M
                    break;
583
14.6M
                }
584
32.6M
            }
585
31.4M
            if (j == mlast) {
586
                /* got a match! */
587
16.8M
                if (mode != FAST_COUNT) {
588
8.92M
                    return i;
589
8.92M
                }
590
7.88M
                count++;
591
7.88M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
7.88M
                i = i + mlast;
595
7.88M
                continue;
596
7.88M
            }
597
            /* miss: check if next character is part of pattern */
598
14.6M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
5.21M
                i = i + m;
600
5.21M
            }
601
9.42M
            else {
602
9.42M
                i = i + gap;
603
9.42M
            }
604
14.6M
        }
605
760M
        else {
606
            /* skip: check if next character is part of pattern */
607
760M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
675M
                i = i + m;
609
675M
            }
610
760M
        }
611
792M
    }
612
18.7M
    return mode == FAST_COUNT ? count : -1;
613
27.6M
}
Unexecuted instantiation: bytesobject.c:stringlib_default_find
unicodeobject.c:asciilib_default_find
Line
Count
Source
560
1.74M
{
561
1.74M
    const Py_ssize_t w = n - m;
562
1.74M
    Py_ssize_t mlast = m - 1, count = 0;
563
1.74M
    Py_ssize_t gap = mlast;
564
1.74M
    const STRINGLIB_CHAR last = p[mlast];
565
1.74M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
1.74M
    unsigned long mask = 0;
568
3.90M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
2.15M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
2.15M
        if (p[i] == last) {
571
34.4k
            gap = mlast - i - 1;
572
34.4k
        }
573
2.15M
    }
574
1.74M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
42.6M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
42.6M
        if (ss[i] == last) {
578
            /* candidate match */
579
3.32M
            Py_ssize_t j;
580
5.41M
            for (j = 0; j < mlast; j++) {
581
3.71M
                if (s[i+j] != p[j]) {
582
1.62M
                    break;
583
1.62M
                }
584
3.71M
            }
585
3.32M
            if (j == mlast) {
586
                /* got a match! */
587
1.69M
                if (mode != FAST_COUNT) {
588
1.69M
                    return i;
589
1.69M
                }
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.62M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
96.9k
                i = i + m;
600
96.9k
            }
601
1.52M
            else {
602
1.52M
                i = i + gap;
603
1.52M
            }
604
1.62M
        }
605
39.2M
        else {
606
            /* skip: check if next character is part of pattern */
607
39.2M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
35.8M
                i = i + m;
609
35.8M
            }
610
39.2M
        }
611
42.6M
    }
612
47.3k
    return mode == FAST_COUNT ? count : -1;
613
1.74M
}
unicodeobject.c:ucs1lib_default_find
Line
Count
Source
560
20.6M
{
561
20.6M
    const Py_ssize_t w = n - m;
562
20.6M
    Py_ssize_t mlast = m - 1, count = 0;
563
20.6M
    Py_ssize_t gap = mlast;
564
20.6M
    const STRINGLIB_CHAR last = p[mlast];
565
20.6M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
20.6M
    unsigned long mask = 0;
568
123M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
102M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
102M
        if (p[i] == last) {
571
1.58M
            gap = mlast - i - 1;
572
1.58M
        }
573
102M
    }
574
20.6M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
317M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
299M
        if (ss[i] == last) {
578
            /* candidate match */
579
11.3M
            Py_ssize_t j;
580
17.0M
            for (j = 0; j < mlast; j++) {
581
11.9M
                if (s[i+j] != p[j]) {
582
6.17M
                    break;
583
6.17M
                }
584
11.9M
            }
585
11.3M
            if (j == mlast) {
586
                /* got a match! */
587
5.18M
                if (mode != FAST_COUNT) {
588
2.10M
                    return i;
589
2.10M
                }
590
3.07M
                count++;
591
3.07M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
3.07M
                i = i + mlast;
595
3.07M
                continue;
596
3.07M
            }
597
            /* miss: check if next character is part of pattern */
598
6.17M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.92M
                i = i + m;
600
1.92M
            }
601
4.25M
            else {
602
4.25M
                i = i + gap;
603
4.25M
            }
604
6.17M
        }
605
287M
        else {
606
            /* skip: check if next character is part of pattern */
607
287M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
217M
                i = i + m;
609
217M
            }
610
287M
        }
611
299M
    }
612
18.5M
    return mode == FAST_COUNT ? count : -1;
613
20.6M
}
unicodeobject.c:ucs2lib_default_find
Line
Count
Source
560
1.89M
{
561
1.89M
    const Py_ssize_t w = n - m;
562
1.89M
    Py_ssize_t mlast = m - 1, count = 0;
563
1.89M
    Py_ssize_t gap = mlast;
564
1.89M
    const STRINGLIB_CHAR last = p[mlast];
565
1.89M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
1.89M
    unsigned long mask = 0;
568
3.87M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
1.98M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
1.98M
        if (p[i] == last) {
571
35.4k
            gap = mlast - i - 1;
572
35.4k
        }
573
1.98M
    }
574
1.89M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
222M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
222M
        if (ss[i] == last) {
578
            /* candidate match */
579
6.74M
            Py_ssize_t j;
580
10.2M
            for (j = 0; j < mlast; j++) {
581
6.84M
                if (s[i+j] != p[j]) {
582
3.31M
                    break;
583
3.31M
                }
584
6.84M
            }
585
6.74M
            if (j == mlast) {
586
                /* got a match! */
587
3.43M
                if (mode != FAST_COUNT) {
588
1.80M
                    return i;
589
1.80M
                }
590
1.63M
                count++;
591
1.63M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
1.63M
                i = i + mlast;
595
1.63M
                continue;
596
1.63M
            }
597
            /* miss: check if next character is part of pattern */
598
3.31M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.27M
                i = i + m;
600
1.27M
            }
601
2.04M
            else {
602
2.04M
                i = i + gap;
603
2.04M
            }
604
3.31M
        }
605
216M
        else {
606
            /* skip: check if next character is part of pattern */
607
216M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
209M
                i = i + m;
609
209M
            }
610
216M
        }
611
222M
    }
612
95.3k
    return mode == FAST_COUNT ? count : -1;
613
1.89M
}
unicodeobject.c:ucs4lib_default_find
Line
Count
Source
560
3.34M
{
561
3.34M
    const Py_ssize_t w = n - m;
562
3.34M
    Py_ssize_t mlast = m - 1, count = 0;
563
3.34M
    Py_ssize_t gap = mlast;
564
3.34M
    const STRINGLIB_CHAR last = p[mlast];
565
3.34M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
3.34M
    unsigned long mask = 0;
568
6.82M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.47M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.47M
        if (p[i] == last) {
571
20.5k
            gap = mlast - i - 1;
572
20.5k
        }
573
3.47M
    }
574
3.34M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
226M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
226M
        if (ss[i] == last) {
578
            /* candidate match */
579
9.99M
            Py_ssize_t j;
580
16.6M
            for (j = 0; j < mlast; j++) {
581
10.1M
                if (s[i+j] != p[j]) {
582
3.49M
                    break;
583
3.49M
                }
584
10.1M
            }
585
9.99M
            if (j == mlast) {
586
                /* got a match! */
587
6.50M
                if (mode != FAST_COUNT) {
588
3.31M
                    return i;
589
3.31M
                }
590
3.18M
                count++;
591
3.18M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
3.18M
                i = i + mlast;
595
3.18M
                continue;
596
3.18M
            }
597
            /* miss: check if next character is part of pattern */
598
3.49M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.89M
                i = i + m;
600
1.89M
            }
601
1.60M
            else {
602
1.60M
                i = i + gap;
603
1.60M
            }
604
3.49M
        }
605
216M
        else {
606
            /* skip: check if next character is part of pattern */
607
216M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
211M
                i = i + m;
609
211M
            }
610
216M
        }
611
226M
    }
612
30.3k
    return mode == FAST_COUNT ? count : -1;
613
3.34M
}
bytes_methods.c:stringlib_default_find
Line
Count
Source
560
3.02k
{
561
3.02k
    const Py_ssize_t w = n - m;
562
3.02k
    Py_ssize_t mlast = m - 1, count = 0;
563
3.02k
    Py_ssize_t gap = mlast;
564
3.02k
    const STRINGLIB_CHAR last = p[mlast];
565
3.02k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
3.02k
    unsigned long mask = 0;
568
12.1k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
9.08k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
9.08k
        if (p[i] == last) {
571
3.02k
            gap = mlast - i - 1;
572
3.02k
        }
573
9.08k
    }
574
3.02k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
1.42M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
1.42M
        if (ss[i] == last) {
578
            /* candidate match */
579
35.3k
            Py_ssize_t j;
580
44.6k
            for (j = 0; j < mlast; j++) {
581
41.8k
                if (s[i+j] != p[j]) {
582
32.5k
                    break;
583
32.5k
                }
584
41.8k
            }
585
35.3k
            if (j == mlast) {
586
                /* got a match! */
587
2.81k
                if (mode != FAST_COUNT) {
588
2.81k
                    return i;
589
2.81k
                }
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
32.5k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
27.0k
                i = i + m;
600
27.0k
            }
601
5.51k
            else {
602
5.51k
                i = i + gap;
603
5.51k
            }
604
32.5k
        }
605
1.39M
        else {
606
            /* skip: check if next character is part of pattern */
607
1.39M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
1.05M
                i = i + m;
609
1.05M
            }
610
1.39M
        }
611
1.42M
    }
612
218
    return mode == FAST_COUNT ? count : -1;
613
3.02k
}
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 (i + 1 <= w && !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 (i + 1 <= w && !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
7.30k
{
694
    /* create compressed boyer-moore delta 1 table */
695
7.30k
    unsigned long mask = 0;
696
7.30k
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
7.30k
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
29.2k
    for (i = mlast; i > 0; i--) {
702
21.9k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
21.9k
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
21.9k
    }
707
708
1.83M
    for (i = w; i >= 0; i--) {
709
1.83M
        if (s[i] == p[0]) {
710
            /* candidate match */
711
87.3k
            for (j = mlast; j > 0; j--) {
712
80.1k
                if (s[i+j] != p[j]) {
713
57.8k
                    break;
714
57.8k
                }
715
80.1k
            }
716
65.0k
            if (j == 0) {
717
                /* got a match! */
718
7.21k
                return i;
719
7.21k
            }
720
            /* miss: check if previous character is part of pattern */
721
57.8k
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
56.5k
                i = i - m;
723
56.5k
            }
724
1.23k
            else {
725
1.23k
                i = i - skip;
726
1.23k
            }
727
57.8k
        }
728
1.76M
        else {
729
            /* skip: check if previous character is part of pattern */
730
1.76M
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
1.49M
                i = i - m;
732
1.49M
            }
733
1.76M
        }
734
1.83M
    }
735
89
    return -1;
736
7.30k
}
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
7.30k
{
694
    /* create compressed boyer-moore delta 1 table */
695
7.30k
    unsigned long mask = 0;
696
7.30k
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
7.30k
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
29.2k
    for (i = mlast; i > 0; i--) {
702
21.9k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
21.9k
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
21.9k
    }
707
708
1.83M
    for (i = w; i >= 0; i--) {
709
1.83M
        if (s[i] == p[0]) {
710
            /* candidate match */
711
87.3k
            for (j = mlast; j > 0; j--) {
712
80.1k
                if (s[i+j] != p[j]) {
713
57.8k
                    break;
714
57.8k
                }
715
80.1k
            }
716
65.0k
            if (j == 0) {
717
                /* got a match! */
718
7.21k
                return i;
719
7.21k
            }
720
            /* miss: check if previous character is part of pattern */
721
57.8k
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
56.5k
                i = i - m;
723
56.5k
            }
724
1.23k
            else {
725
1.23k
                i = i - skip;
726
1.23k
            }
727
57.8k
        }
728
1.76M
        else {
729
            /* skip: check if previous character is part of pattern */
730
1.76M
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
1.49M
                i = i - m;
732
1.49M
            }
733
1.76M
        }
734
1.83M
    }
735
89
    return -1;
736
7.30k
}
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
35.3M
{
762
35.3M
    Py_ssize_t count = 0;
763
4.59G
    for (Py_ssize_t i = 0; i < n; i++) {
764
4.56G
        if (s[i] == p0) {
765
652M
            count++;
766
652M
        }
767
4.56G
    }
768
35.3M
    return count;
769
35.3M
}
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
22.9M
{
762
22.9M
    Py_ssize_t count = 0;
763
627M
    for (Py_ssize_t i = 0; i < n; i++) {
764
604M
        if (s[i] == p0) {
765
30.5M
            count++;
766
30.5M
        }
767
604M
    }
768
22.9M
    return count;
769
22.9M
}
unicodeobject.c:ucs2lib_count_char_no_maxcount
Line
Count
Source
761
4.32M
{
762
4.32M
    Py_ssize_t count = 0;
763
575M
    for (Py_ssize_t i = 0; i < n; i++) {
764
571M
        if (s[i] == p0) {
765
16.9M
            count++;
766
16.9M
        }
767
571M
    }
768
4.32M
    return count;
769
4.32M
}
unicodeobject.c:ucs4lib_count_char_no_maxcount
Line
Count
Source
761
2.41M
{
762
2.41M
    Py_ssize_t count = 0;
763
497M
    for (Py_ssize_t i = 0; i < n; i++) {
764
495M
        if (s[i] == p0) {
765
15.1M
            count++;
766
15.1M
        }
767
495M
    }
768
2.41M
    return count;
769
2.41M
}
bytes_methods.c:stringlib_count_char_no_maxcount
Line
Count
Source
761
5.64M
{
762
5.64M
    Py_ssize_t count = 0;
763
2.89G
    for (Py_ssize_t i = 0; i < n; i++) {
764
2.88G
        if (s[i] == p0) {
765
590M
            count++;
766
590M
        }
767
2.88G
    }
768
5.64M
    return count;
769
5.64M
}
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
85.5M
{
777
85.5M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
632
        return -1;
779
632
    }
780
781
    /* look for special cases */
782
85.5M
    if (m <= 1) {
783
57.9M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
57.9M
        if (mode == FAST_SEARCH)
788
22.5M
            return STRINGLIB(find_char)(s, n, p[0]);
789
35.3M
        else if (mode == FAST_RSEARCH)
790
54.5k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
35.3M
        else {
792
35.3M
            if (maxcount == PY_SSIZE_T_MAX) {
793
35.3M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
35.3M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
35.3M
        }
797
57.9M
    }
798
799
27.6M
    if (mode != FAST_RSEARCH) {
800
27.6M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
27.6M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
27.6M
        }
803
22
        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
22
            if (mode == FAST_SEARCH) {
810
22
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
22
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
22
        }
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
27.6M
    }
825
7.30k
    else {
826
        /* FAST_RSEARCH */
827
7.30k
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
7.30k
    }
829
27.6M
}
bytesobject.c:fastsearch
Line
Count
Source
776
267k
{
777
267k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
267k
    if (m <= 1) {
783
267k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
267k
        if (mode == FAST_SEARCH)
788
267k
            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
267k
    }
798
799
0
    if (mode != FAST_RSEARCH) {
800
0
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
0
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
0
        }
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
0
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
0
}
unicodeobject.c:asciilib_fastsearch
Line
Count
Source
776
7.40M
{
777
7.40M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
7.40M
    if (m <= 1) {
783
5.65M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
5.65M
        if (mode == FAST_SEARCH)
788
5.60M
            return STRINGLIB(find_char)(s, n, p[0]);
789
54.5k
        else if (mode == FAST_RSEARCH)
790
54.5k
            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
5.65M
    }
798
799
1.74M
    if (mode != FAST_RSEARCH) {
800
1.74M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
1.74M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
1.74M
        }
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.74M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
1.74M
}
unicodeobject.c:ucs1lib_fastsearch
Line
Count
Source
776
51.8M
{
777
51.8M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
51.8M
    if (m <= 1) {
783
31.2M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
31.2M
        if (mode == FAST_SEARCH)
788
8.28M
            return STRINGLIB(find_char)(s, n, p[0]);
789
22.9M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
22.9M
        else {
792
22.9M
            if (maxcount == PY_SSIZE_T_MAX) {
793
22.9M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
22.9M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
22.9M
        }
797
31.2M
    }
798
799
20.6M
    if (mode != FAST_RSEARCH) {
800
20.6M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
20.6M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
20.6M
        }
803
22
        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
22
            if (mode == FAST_SEARCH) {
810
22
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
22
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
22
        }
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
20.6M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
20.6M
}
unicodeobject.c:ucs2lib_fastsearch
Line
Count
Source
776
10.1M
{
777
10.1M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
618
        return -1;
779
618
    }
780
781
    /* look for special cases */
782
10.1M
    if (m <= 1) {
783
8.28M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
8.28M
        if (mode == FAST_SEARCH)
788
3.95M
            return STRINGLIB(find_char)(s, n, p[0]);
789
4.32M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
4.32M
        else {
792
4.32M
            if (maxcount == PY_SSIZE_T_MAX) {
793
4.32M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
4.32M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
4.32M
        }
797
8.28M
    }
798
799
1.89M
    if (mode != FAST_RSEARCH) {
800
1.89M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
1.89M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
1.89M
        }
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.89M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
1.89M
}
unicodeobject.c:ucs4lib_fastsearch
Line
Count
Source
776
10.1M
{
777
10.1M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
10.1M
    if (m <= 1) {
783
6.81M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
6.81M
        if (mode == FAST_SEARCH)
788
4.39M
            return STRINGLIB(find_char)(s, n, p[0]);
789
2.41M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
2.41M
        else {
792
2.41M
            if (maxcount == PY_SSIZE_T_MAX) {
793
2.41M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
2.41M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
2.41M
        }
797
6.81M
    }
798
799
3.34M
    if (mode != FAST_RSEARCH) {
800
3.34M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
3.34M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
3.34M
        }
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
3.34M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
3.34M
}
bytes_methods.c:fastsearch
Line
Count
Source
776
5.65M
{
777
5.65M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
14
        return -1;
779
14
    }
780
781
    /* look for special cases */
782
5.65M
    if (m <= 1) {
783
5.64M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
5.64M
        if (mode == FAST_SEARCH)
788
0
            return STRINGLIB(find_char)(s, n, p[0]);
789
5.64M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
5.64M
        else {
792
5.64M
            if (maxcount == PY_SSIZE_T_MAX) {
793
5.64M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
5.64M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
5.64M
        }
797
5.64M
    }
798
799
10.3k
    if (mode != FAST_RSEARCH) {
800
3.02k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
3.02k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
3.02k
        }
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
3.02k
    }
825
7.30k
    else {
826
        /* FAST_RSEARCH */
827
7.30k
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
7.30k
    }
829
10.3k
}
Unexecuted instantiation: bytearrayobject.c:fastsearch
830