Coverage Report

Created: 2026-10-15 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/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
623M
#define FAST_COUNT 0
25
207M
#define FAST_SEARCH 1
26
207M
#define FAST_RSEARCH 2
27
28
#if LONG_BIT >= 128
29
#define STRINGLIB_BLOOM_WIDTH 128
30
#elif LONG_BIT >= 64
31
4.15G
#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
1.86G
    ((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
40
#define STRINGLIB_BLOOM(mask, ch)     \
41
2.28G
    ((mask &  (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
42
43
#ifdef STRINGLIB_FAST_MEMCHR
44
25.6M
#  define MEMCHR_CUT_OFF 15
45
#else
46
35.8k
#  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
25.6M
{
52
25.6M
    const STRINGLIB_CHAR *p, *e;
53
54
25.6M
    p = s;
55
25.6M
    e = s + n;
56
25.6M
    if (n > MEMCHR_CUT_OFF) {
57
#ifdef STRINGLIB_FAST_MEMCHR
58
888k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
888k
        if (p != NULL)
60
853k
            return (p - s);
61
35.3k
        return -1;
62
#else
63
        /* use memchr if we can choose a needle without too many likely
64
           false positives */
65
        const STRINGLIB_CHAR *s1, *e1;
66
        unsigned char needle = ch & 0xff;
67
        /* If looking for a multiple of 256, we'd have too
68
           many false positives looking for the '\0' byte in UCS2
69
           and UCS4 representations. */
70
5.73k
        if (needle != 0) {
71
7.87k
            do {
72
7.87k
                const void *candidate = memchr(p, needle,
73
7.87k
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
7.87k
                if (candidate == NULL)
75
160
                    return -1;
76
7.71k
                s1 = p;
77
7.71k
                p = (const STRINGLIB_CHAR *)
78
7.71k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
7.71k
                if (*p == ch)
80
3.40k
                    return (p - s);
81
                /* False positive */
82
4.31k
                p++;
83
4.31k
                if (p - s1 > MEMCHR_CUT_OFF)
84
947
                    continue;
85
3.36k
                if (e - p <= MEMCHR_CUT_OFF)
86
520
                    break;
87
2.84k
                e1 = p + MEMCHR_CUT_OFF;
88
92.6k
                while (p != e1) {
89
90.8k
                    if (*p == ch)
90
1.09k
                        return (p - s);
91
89.7k
                    p++;
92
89.7k
                }
93
2.84k
            }
94
5.73k
            while (e - p > MEMCHR_CUT_OFF);
95
5.73k
        }
96
#endif
97
894k
    }
98
144M
    while (p < e) {
99
127M
        if (*p == ch)
100
7.85M
            return (p - s);
101
119M
        p++;
102
119M
    }
103
16.9M
    return -1;
104
24.8M
}
unicodeobject.c:ucs1lib_find_char
Line
Count
Source
51
25.0M
{
52
25.0M
    const STRINGLIB_CHAR *p, *e;
53
54
25.0M
    p = s;
55
25.0M
    e = s + n;
56
25.0M
    if (n > MEMCHR_CUT_OFF) {
57
275k
#ifdef STRINGLIB_FAST_MEMCHR
58
275k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
275k
        if (p != NULL)
60
274k
            return (p - s);
61
1.38k
        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
275k
    }
98
143M
    while (p < e) {
99
126M
        if (*p == ch)
100
7.84M
            return (p - s);
101
118M
        p++;
102
118M
    }
103
16.8M
    return -1;
104
24.7M
}
unicodeobject.c:ucs2lib_find_char
Line
Count
Source
51
22.6k
{
52
22.6k
    const STRINGLIB_CHAR *p, *e;
53
54
22.6k
    p = s;
55
22.6k
    e = s + n;
56
22.6k
    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
5.73k
        const STRINGLIB_CHAR *s1, *e1;
66
5.73k
        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
5.73k
        if (needle != 0) {
71
7.87k
            do {
72
7.87k
                const void *candidate = memchr(p, needle,
73
7.87k
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
7.87k
                if (candidate == NULL)
75
160
                    return -1;
76
7.71k
                s1 = p;
77
7.71k
                p = (const STRINGLIB_CHAR *)
78
7.71k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
7.71k
                if (*p == ch)
80
3.40k
                    return (p - s);
81
                /* False positive */
82
4.31k
                p++;
83
4.31k
                if (p - s1 > MEMCHR_CUT_OFF)
84
947
                    continue;
85
3.36k
                if (e - p <= MEMCHR_CUT_OFF)
86
520
                    break;
87
2.84k
                e1 = p + MEMCHR_CUT_OFF;
88
92.6k
                while (p != e1) {
89
90.8k
                    if (*p == ch)
90
1.09k
                        return (p - s);
91
89.7k
                    p++;
92
89.7k
                }
93
2.84k
            }
94
5.73k
            while (e - p > MEMCHR_CUT_OFF);
95
5.73k
        }
96
5.73k
#endif
97
5.73k
    }
98
229k
    while (p < e) {
99
214k
        if (*p == ch)
100
2.46k
            return (p - s);
101
211k
        p++;
102
211k
    }
103
15.4k
    return -1;
104
17.9k
}
unicodeobject.c:ucs4lib_find_char
Line
Count
Source
51
4.32k
{
52
4.32k
    const STRINGLIB_CHAR *p, *e;
53
54
4.32k
    p = s;
55
4.32k
    e = s + n;
56
4.32k
    if (n > MEMCHR_CUT_OFF) {
57
2.97k
#ifdef STRINGLIB_FAST_MEMCHR
58
2.97k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
2.97k
        if (p != NULL)
60
2.88k
            return (p - s);
61
93
        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
2.97k
    }
98
5.42k
    while (p < e) {
99
5.18k
        if (*p == ch)
100
1.11k
            return (p - s);
101
4.06k
        p++;
102
4.06k
    }
103
238
    return -1;
104
1.35k
}
unicodeobject.c:asciilib_find_char
Line
Count
Source
51
12.8k
{
52
12.8k
    const STRINGLIB_CHAR *p, *e;
53
54
12.8k
    p = s;
55
12.8k
    e = s + n;
56
12.8k
    if (n > MEMCHR_CUT_OFF) {
57
9.41k
#ifdef STRINGLIB_FAST_MEMCHR
58
9.41k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
9.41k
        if (p != NULL)
60
9.41k
            return (p - s);
61
0
        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
9.41k
    }
98
6.10k
    while (p < e) {
99
6.10k
        if (*p == ch)
100
3.41k
            return (p - s);
101
2.69k
        p++;
102
2.69k
    }
103
0
    return -1;
104
3.41k
}
bytes_methods.c:stringlib_find_char
Line
Count
Source
51
642k
{
52
642k
    const STRINGLIB_CHAR *p, *e;
53
54
642k
    p = s;
55
642k
    e = s + n;
56
642k
    if (n > MEMCHR_CUT_OFF) {
57
600k
#ifdef STRINGLIB_FAST_MEMCHR
58
600k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
600k
        if (p != NULL)
60
566k
            return (p - s);
61
33.8k
        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
600k
    }
98
630k
    while (p < e) {
99
591k
        if (*p == ch)
100
2.77k
            return (p - s);
101
588k
        p++;
102
588k
    }
103
39.4k
    return -1;
104
42.1k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_find_char
Unexecuted instantiation: bytesobject.c:stringlib_find_char
105
106
#undef MEMCHR_CUT_OFF
107
108
#if STRINGLIB_SIZEOF_CHAR == 1
109
30.7k
#  define MEMRCHR_CUT_OFF 15
110
#else
111
12.6k
#  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
32.9k
{
118
32.9k
    const STRINGLIB_CHAR *p;
119
32.9k
#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
32.9k
    if (n > MEMRCHR_CUT_OFF) {
126
#if STRINGLIB_SIZEOF_CHAR == 1
127
        p = memrchr(s, ch, n);
128
15.0k
        if (p != NULL)
129
6.68k
            return (p - s);
130
8.35k
        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
1.23k
        if (needle != 0) {
141
5.55k
            do {
142
5.55k
                void *candidate = memrchr(s, needle,
143
5.55k
                                          n * sizeof(STRINGLIB_CHAR));
144
5.55k
                if (candidate == NULL)
145
886
                    return -1;
146
4.67k
                n1 = n;
147
4.67k
                p = (const STRINGLIB_CHAR *)
148
4.67k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
4.67k
                n = p - s;
150
4.67k
                if (*p == ch)
151
244
                    return n;
152
                /* False positive */
153
4.42k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
3.53k
                    continue;
155
887
                if (n <= MEMRCHR_CUT_OFF)
156
28
                    break;
157
859
                s1 = p - MEMRCHR_CUT_OFF;
158
34.7k
                while (p > s1) {
159
33.9k
                    p--;
160
33.9k
                    if (*p == ch)
161
13
                        return (p - s);
162
33.9k
                }
163
846
                n = p - s;
164
846
            }
165
4.38k
            while (n > MEMRCHR_CUT_OFF);
166
1.23k
        }
167
#endif
168
16.2k
    }
169
16.7k
#endif  /* HAVE_MEMRCHR */
170
16.7k
    p = s + n;
171
138k
    while (p > s) {
172
125k
        p--;
173
125k
        if (*p == ch)
174
3.30k
            return (p - s);
175
125k
    }
176
13.4k
    return -1;
177
16.7k
}
unicodeobject.c:ucs1lib_rfind_char
Line
Count
Source
117
3.85k
{
118
3.85k
    const STRINGLIB_CHAR *p;
119
3.85k
#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
3.85k
    if (n > MEMRCHR_CUT_OFF) {
126
2.89k
#if STRINGLIB_SIZEOF_CHAR == 1
127
2.89k
        p = memrchr(s, ch, n);
128
2.89k
        if (p != NULL)
129
924
            return (p - s);
130
1.97k
        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
2.89k
    }
169
959
#endif  /* HAVE_MEMRCHR */
170
959
    p = s + n;
171
7.70k
    while (p > s) {
172
6.93k
        p--;
173
6.93k
        if (*p == ch)
174
189
            return (p - s);
175
6.93k
    }
176
770
    return -1;
177
959
}
unicodeobject.c:ucs2lib_rfind_char
Line
Count
Source
117
900
{
118
900
    const STRINGLIB_CHAR *p;
119
900
#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
900
    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
452
        const STRINGLIB_CHAR *s1;
135
452
        Py_ssize_t n1;
136
452
        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
452
        if (needle != 0) {
141
1.74k
            do {
142
1.74k
                void *candidate = memrchr(s, needle,
143
1.74k
                                          n * sizeof(STRINGLIB_CHAR));
144
1.74k
                if (candidate == NULL)
145
286
                    return -1;
146
1.45k
                n1 = n;
147
1.45k
                p = (const STRINGLIB_CHAR *)
148
1.45k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
1.45k
                n = p - s;
150
1.45k
                if (*p == ch)
151
105
                    return n;
152
                /* False positive */
153
1.35k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
827
                    continue;
155
526
                if (n <= MEMRCHR_CUT_OFF)
156
15
                    break;
157
511
                s1 = p - MEMRCHR_CUT_OFF;
158
20.7k
                while (p > s1) {
159
20.2k
                    p--;
160
20.2k
                    if (*p == ch)
161
7
                        return (p - s);
162
20.2k
                }
163
504
                n = p - s;
164
504
            }
165
1.33k
            while (n > MEMRCHR_CUT_OFF);
166
452
        }
167
452
#endif
168
452
    }
169
502
#endif  /* HAVE_MEMRCHR */
170
502
    p = s + n;
171
5.51k
    while (p > s) {
172
5.02k
        p--;
173
5.02k
        if (*p == ch)
174
14
            return (p - s);
175
5.02k
    }
176
488
    return -1;
177
502
}
unicodeobject.c:ucs4lib_rfind_char
Line
Count
Source
117
1.23k
{
118
1.23k
    const STRINGLIB_CHAR *p;
119
1.23k
#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
1.23k
    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
779
        const STRINGLIB_CHAR *s1;
135
779
        Py_ssize_t n1;
136
779
        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
779
        if (needle != 0) {
141
3.81k
            do {
142
3.81k
                void *candidate = memrchr(s, needle,
143
3.81k
                                          n * sizeof(STRINGLIB_CHAR));
144
3.81k
                if (candidate == NULL)
145
600
                    return -1;
146
3.21k
                n1 = n;
147
3.21k
                p = (const STRINGLIB_CHAR *)
148
3.21k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
3.21k
                n = p - s;
150
3.21k
                if (*p == ch)
151
139
                    return n;
152
                /* False positive */
153
3.07k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
2.71k
                    continue;
155
361
                if (n <= MEMRCHR_CUT_OFF)
156
13
                    break;
157
348
                s1 = p - MEMRCHR_CUT_OFF;
158
14.0k
                while (p > s1) {
159
13.7k
                    p--;
160
13.7k
                    if (*p == ch)
161
6
                        return (p - s);
162
13.7k
                }
163
342
                n = p - s;
164
342
            }
165
3.05k
            while (n > MEMRCHR_CUT_OFF);
166
779
        }
167
779
#endif
168
779
    }
169
487
#endif  /* HAVE_MEMRCHR */
170
487
    p = s + n;
171
5.68k
    while (p > s) {
172
5.21k
        p--;
173
5.21k
        if (*p == ch)
174
12
            return (p - s);
175
5.21k
    }
176
475
    return -1;
177
487
}
unicodeobject.c:asciilib_rfind_char
Line
Count
Source
117
4.74k
{
118
4.74k
    const STRINGLIB_CHAR *p;
119
4.74k
#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
4.74k
    if (n > MEMRCHR_CUT_OFF) {
126
1.27k
#if STRINGLIB_SIZEOF_CHAR == 1
127
1.27k
        p = memrchr(s, ch, n);
128
1.27k
        if (p != NULL)
129
1.16k
            return (p - s);
130
110
        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
1.27k
    }
169
3.47k
#endif  /* HAVE_MEMRCHR */
170
3.47k
    p = s + n;
171
23.6k
    while (p > s) {
172
21.8k
        p--;
173
21.8k
        if (*p == ch)
174
1.73k
            return (p - s);
175
21.8k
    }
176
1.74k
    return -1;
177
3.47k
}
bytes_methods.c:stringlib_rfind_char
Line
Count
Source
117
22.1k
{
118
22.1k
    const STRINGLIB_CHAR *p;
119
22.1k
#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
22.1k
    if (n > MEMRCHR_CUT_OFF) {
126
10.8k
#if STRINGLIB_SIZEOF_CHAR == 1
127
10.8k
        p = memrchr(s, ch, n);
128
10.8k
        if (p != NULL)
129
4.60k
            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
        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
10.8k
    }
169
11.2k
#endif  /* HAVE_MEMRCHR */
170
11.2k
    p = s + n;
171
96.0k
    while (p > s) {
172
86.1k
        p--;
173
86.1k
        if (*p == ch)
174
1.35k
            return (p - s);
175
86.1k
    }
176
9.94k
    return -1;
177
11.2k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_rfind_char
Unexecuted instantiation: bytesobject.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
0
{
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
0
    Py_ssize_t max_suffix = 0;
204
0
    Py_ssize_t candidate = 1;
205
0
    Py_ssize_t k = 0;
206
    // The period of the right half.
207
0
    Py_ssize_t period = 1;
208
209
0
    while (candidate + k < len_needle) {
210
        // each loop increases candidate + k + max_suffix
211
0
        STRINGLIB_CHAR a = needle[candidate + k];
212
0
        STRINGLIB_CHAR b = needle[max_suffix + k];
213
        // check if the suffix at candidate is better than max_suffix
214
0
        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
0
            candidate += k + 1;
219
0
            k = 0;
220
            // We've ruled out any period smaller than what's
221
            // been scanned since max_suffix.
222
0
            period = candidate - max_suffix;
223
0
        }
224
0
        else if (a == b) {
225
0
            if (k + 1 != period) {
226
                // Keep scanning the equal strings
227
0
                k++;
228
0
            }
229
0
            else {
230
                // Matched a whole period.
231
                // Start matching the next period.
232
0
                candidate += period;
233
0
                k = 0;
234
0
            }
235
0
        }
236
0
        else {
237
            // Did better than max_suffix, so replace it.
238
0
            max_suffix = candidate;
239
0
            candidate++;
240
0
            k = 0;
241
0
            period = 1;
242
0
        }
243
0
    }
244
0
    *return_period = period;
245
0
    return max_suffix;
246
0
}
Unexecuted instantiation: unicodeobject.c:asciilib__lex_search
Unexecuted instantiation: unicodeobject.c:ucs1lib__lex_search
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
Unexecuted instantiation: bytesobject.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
0
{
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
0
    Py_ssize_t cut1, period1, cut2, period2, cut, period;
286
0
    cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0);
287
0
    cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1);
288
289
    // Take the later cut.
290
0
    if (cut1 > cut2) {
291
0
        period = period1;
292
0
        cut = cut1;
293
0
    }
294
0
    else {
295
0
        period = period2;
296
0
        cut = cut2;
297
0
    }
298
299
0
    LOG("split: "); LOG_STRING(needle, cut);
300
0
    LOG(" + "); LOG_STRING(needle + cut, len_needle - cut);
301
0
    LOG("\n");
302
303
0
    *return_period = period;
304
0
    return cut;
305
0
}
Unexecuted instantiation: unicodeobject.c:asciilib__factorize
Unexecuted instantiation: unicodeobject.c:ucs1lib__factorize
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
Unexecuted instantiation: bytesobject.c:stringlib__factorize
306
307
308
0
#define SHIFT_TYPE uint8_t
309
#define MAX_SHIFT UINT8_MAX
310
311
0
#define TABLE_SIZE_BITS 6u
312
0
#define TABLE_SIZE (1U << TABLE_SIZE_BITS)
313
0
#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
0
{
330
0
    p->needle = needle;
331
0
    p->len_needle = len_needle;
332
0
    p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period));
333
0
    assert(p->period + p->cut <= len_needle);
334
0
    p->is_periodic = (0 == memcmp(needle,
335
0
                                  needle + p->period,
336
0
                                  p->cut * STRINGLIB_SIZEOF_CHAR));
337
0
    if (p->is_periodic) {
338
0
        assert(p->cut <= len_needle/2);
339
0
        assert(p->cut < p->period);
340
0
    }
341
0
    else {
342
        // A lower bound on the period
343
0
        p->period = Py_MAX(p->cut, len_needle - p->cut) + 1;
344
0
    }
345
    // The gap between the last character and the previous
346
    // occurrence of an equivalent character (modulo TABLE_SIZE)
347
0
    p->gap = len_needle;
348
0
    STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK;
349
0
    for (Py_ssize_t i = len_needle - 2; i >= 0; i--) {
350
0
        STRINGLIB_CHAR x = needle[i] & TABLE_MASK;
351
0
        if (x == last) {
352
0
            p->gap = len_needle - 1 - i;
353
0
            break;
354
0
        }
355
0
    }
356
    // Fill up a compressed Boyer-Moore "Bad Character" table
357
0
    Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT);
358
0
    for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) {
359
0
        p->table[i] = Py_SAFE_DOWNCAST(not_found_shift,
360
0
                                       Py_ssize_t, SHIFT_TYPE);
361
0
    }
362
0
    for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) {
363
0
        SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i,
364
0
                                            Py_ssize_t, SHIFT_TYPE);
365
0
        p->table[needle[i] & TABLE_MASK] = shift;
366
0
    }
367
0
}
Unexecuted instantiation: unicodeobject.c:asciilib__preprocess
Unexecuted instantiation: unicodeobject.c:ucs1lib__preprocess
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
Unexecuted instantiation: bytesobject.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
0
{
373
    // Crochemore and Perrin's (1991) Two-Way algorithm.
374
    // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260
375
0
    const Py_ssize_t len_needle = p->len_needle;
376
0
    const Py_ssize_t cut = p->cut;
377
0
    Py_ssize_t period = p->period;
378
0
    const STRINGLIB_CHAR *const needle = p->needle;
379
0
    const STRINGLIB_CHAR *window_last = haystack + len_needle - 1;
380
0
    const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack;
381
0
    SHIFT_TYPE *table = p->table;
382
0
    const STRINGLIB_CHAR *window;
383
0
    LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack);
384
385
0
    Py_ssize_t gap = p->gap;
386
0
    Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap);
387
0
    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
0
    else {
454
0
        period = Py_MAX(gap, period);
455
0
        LOG("Needle is not periodic.\n");
456
0
      windowloop:
457
0
        while (window_last < haystack_end) {
458
0
            for (;;) {
459
0
                LOG_LINEUP();
460
0
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
0
                window_last += shift;
462
0
                if (shift == 0) {
463
0
                    break;
464
0
                }
465
0
                if (window_last >= haystack_end) {
466
0
                    return -1;
467
0
                }
468
0
                LOG("Horspool skip\n");
469
0
            }
470
0
            window = window_last - len_needle + 1;
471
0
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
0
                   (needle[len_needle - 1] & TABLE_MASK));
473
0
            Py_ssize_t i = cut;
474
0
            for (; i < len_needle; i++) {
475
0
                if (needle[i] != window[i]) {
476
0
                    if (i < gap_jump_end) {
477
0
                        LOG("Early right half mismatch: jump by gap.\n");
478
0
                        assert(gap >= i - cut + 1);
479
0
                        window_last += gap;
480
0
                    }
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
0
                    goto windowloop;
487
0
                }
488
0
            }
489
0
            for (Py_ssize_t i = 0; i < cut; i++) {
490
0
                if (needle[i] != window[i]) {
491
0
                    LOG("Left half does not match.\n");
492
0
                    window_last += period;
493
0
                    goto windowloop;
494
0
                }
495
0
            }
496
0
            LOG("Found a match!\n");
497
0
            return window - haystack;
498
0
        }
499
0
    }
500
0
    LOG("Not found. Returning -1.\n");
501
0
    return -1;
502
0
}
Unexecuted instantiation: unicodeobject.c:asciilib__two_way
Unexecuted instantiation: unicodeobject.c:ucs1lib__two_way
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
Unexecuted instantiation: bytesobject.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
0
{
511
0
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
0
    STRINGLIB(prework) p;
513
0
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
0
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
0
}
Unexecuted instantiation: unicodeobject.c:asciilib__two_way_find
Unexecuted instantiation: unicodeobject.c:ucs1lib__two_way_find
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
Unexecuted instantiation: bytesobject.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: 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
Unexecuted instantiation: bytesobject.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
207M
{
561
207M
    const Py_ssize_t w = n - m;
562
207M
    Py_ssize_t mlast = m - 1, count = 0;
563
207M
    Py_ssize_t gap = mlast;
564
207M
    const STRINGLIB_CHAR last = p[mlast];
565
207M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
207M
    unsigned long mask = 0;
568
1.86G
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
1.65G
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
1.65G
        if (p[i] == last) {
571
154k
            gap = mlast - i - 1;
572
154k
        }
573
1.65G
    }
574
207M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
2.49G
    for (Py_ssize_t i = 0; i <= w; i++) {
577
2.28G
        if (ss[i] == last) {
578
            /* candidate match */
579
207M
            Py_ssize_t j;
580
207M
            for (j = 0; j < mlast; j++) {
581
207M
                if (s[i+j] != p[j]) {
582
207M
                    break;
583
207M
                }
584
207M
            }
585
207M
            if (j == mlast) {
586
                /* got a match! */
587
81.2k
                if (mode != FAST_COUNT) {
588
41.1k
                    return i;
589
41.1k
                }
590
40.0k
                count++;
591
40.0k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
40.0k
                i = i + mlast;
595
40.0k
                continue;
596
40.0k
            }
597
            /* miss: check if next character is part of pattern */
598
207M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.39k
                i = i + m;
600
1.39k
            }
601
207M
            else {
602
207M
                i = i + gap;
603
207M
            }
604
207M
        }
605
2.08G
        else {
606
            /* skip: check if next character is part of pattern */
607
2.08G
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
1.03G
                i = i + m;
609
1.03G
            }
610
2.08G
        }
611
2.28G
    }
612
207M
    return mode == FAST_COUNT ? count : -1;
613
207M
}
unicodeobject.c:asciilib_default_find
Line
Count
Source
560
17.3k
{
561
17.3k
    const Py_ssize_t w = n - m;
562
17.3k
    Py_ssize_t mlast = m - 1, count = 0;
563
17.3k
    Py_ssize_t gap = mlast;
564
17.3k
    const STRINGLIB_CHAR last = p[mlast];
565
17.3k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
17.3k
    unsigned long mask = 0;
568
37.5k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
20.1k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
20.1k
        if (p[i] == last) {
571
14.5k
            gap = mlast - i - 1;
572
14.5k
        }
573
20.1k
    }
574
17.3k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
32.7k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
32.7k
        if (ss[i] == last) {
578
            /* candidate match */
579
19.6k
            Py_ssize_t j;
580
39.8k
            for (j = 0; j < mlast; j++) {
581
22.4k
                if (s[i+j] != p[j]) {
582
2.24k
                    break;
583
2.24k
                }
584
22.4k
            }
585
19.6k
            if (j == mlast) {
586
                /* got a match! */
587
17.3k
                if (mode != FAST_COUNT) {
588
17.3k
                    return i;
589
17.3k
                }
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
2.24k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
0
                i = i + m;
600
0
            }
601
2.24k
            else {
602
2.24k
                i = i + gap;
603
2.24k
            }
604
2.24k
        }
605
13.1k
        else {
606
            /* skip: check if next character is part of pattern */
607
13.1k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
11.6k
                i = i + m;
609
11.6k
            }
610
13.1k
        }
611
32.7k
    }
612
0
    return mode == FAST_COUNT ? count : -1;
613
17.3k
}
unicodeobject.c:ucs1lib_default_find
Line
Count
Source
560
207M
{
561
207M
    const Py_ssize_t w = n - m;
562
207M
    Py_ssize_t mlast = m - 1, count = 0;
563
207M
    Py_ssize_t gap = mlast;
564
207M
    const STRINGLIB_CHAR last = p[mlast];
565
207M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
207M
    unsigned long mask = 0;
568
1.86G
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
1.65G
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
1.65G
        if (p[i] == last) {
571
120k
            gap = mlast - i - 1;
572
120k
        }
573
1.65G
    }
574
207M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
2.49G
    for (Py_ssize_t i = 0; i <= w; i++) {
577
2.28G
        if (ss[i] == last) {
578
            /* candidate match */
579
207M
            Py_ssize_t j;
580
207M
            for (j = 0; j < mlast; j++) {
581
207M
                if (s[i+j] != p[j]) {
582
207M
                    break;
583
207M
                }
584
207M
            }
585
207M
            if (j == mlast) {
586
                /* got a match! */
587
29.9k
                if (mode != FAST_COUNT) {
588
6.26k
                    return i;
589
6.26k
                }
590
23.6k
                count++;
591
23.6k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
23.6k
                i = i + mlast;
595
23.6k
                continue;
596
23.6k
            }
597
            /* miss: check if next character is part of pattern */
598
207M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
570
                i = i + m;
600
570
            }
601
207M
            else {
602
207M
                i = i + gap;
603
207M
            }
604
207M
        }
605
2.08G
        else {
606
            /* skip: check if next character is part of pattern */
607
2.08G
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
1.03G
                i = i + m;
609
1.03G
            }
610
2.08G
        }
611
2.28G
    }
612
207M
    return mode == FAST_COUNT ? count : -1;
613
207M
}
unicodeobject.c:ucs2lib_default_find
Line
Count
Source
560
4.81k
{
561
4.81k
    const Py_ssize_t w = n - m;
562
4.81k
    Py_ssize_t mlast = m - 1, count = 0;
563
4.81k
    Py_ssize_t gap = mlast;
564
4.81k
    const STRINGLIB_CHAR last = p[mlast];
565
4.81k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
4.81k
    unsigned long mask = 0;
568
9.62k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
4.81k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
4.81k
        if (p[i] == last) {
571
4.81k
            gap = mlast - i - 1;
572
4.81k
        }
573
4.81k
    }
574
4.81k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
33.0k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
32.6k
        if (ss[i] == last) {
578
            /* candidate match */
579
9.69k
            Py_ssize_t j;
580
18.4k
            for (j = 0; j < mlast; j++) {
581
9.69k
                if (s[i+j] != p[j]) {
582
950
                    break;
583
950
                }
584
9.69k
            }
585
9.69k
            if (j == mlast) {
586
                /* got a match! */
587
8.74k
                if (mode != FAST_COUNT) {
588
4.37k
                    return i;
589
4.37k
                }
590
4.37k
                count++;
591
4.37k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
4.37k
                i = i + mlast;
595
4.37k
                continue;
596
4.37k
            }
597
            /* miss: check if next character is part of pattern */
598
950
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
0
                i = i + m;
600
0
            }
601
950
            else {
602
950
                i = i + gap;
603
950
            }
604
950
        }
605
22.9k
        else {
606
            /* skip: check if next character is part of pattern */
607
22.9k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
21.2k
                i = i + m;
609
21.2k
            }
610
22.9k
        }
611
32.6k
    }
612
440
    return mode == FAST_COUNT ? count : -1;
613
4.81k
}
unicodeobject.c:ucs4lib_default_find
Line
Count
Source
560
13.3k
{
561
13.3k
    const Py_ssize_t w = n - m;
562
13.3k
    Py_ssize_t mlast = m - 1, count = 0;
563
13.3k
    Py_ssize_t gap = mlast;
564
13.3k
    const STRINGLIB_CHAR last = p[mlast];
565
13.3k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
13.3k
    unsigned long mask = 0;
568
26.6k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
13.3k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
13.3k
        if (p[i] == last) {
571
13.3k
            gap = mlast - i - 1;
572
13.3k
        }
573
13.3k
    }
574
13.3k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
56.1k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
54.9k
        if (ss[i] == last) {
578
            /* candidate match */
579
30.5k
            Py_ssize_t j;
580
54.5k
            for (j = 0; j < mlast; j++) {
581
30.5k
                if (s[i+j] != p[j]) {
582
6.41k
                    break;
583
6.41k
                }
584
30.5k
            }
585
30.5k
            if (j == mlast) {
586
                /* got a match! */
587
24.0k
                if (mode != FAST_COUNT) {
588
12.0k
                    return i;
589
12.0k
                }
590
12.0k
                count++;
591
12.0k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
12.0k
                i = i + mlast;
595
12.0k
                continue;
596
12.0k
            }
597
            /* miss: check if next character is part of pattern */
598
6.41k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
0
                i = i + m;
600
0
            }
601
6.41k
            else {
602
6.41k
                i = i + gap;
603
6.41k
            }
604
6.41k
        }
605
24.4k
        else {
606
            /* skip: check if next character is part of pattern */
607
24.4k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
20.5k
                i = i + m;
609
20.5k
            }
610
24.4k
        }
611
54.9k
    }
612
1.28k
    return mode == FAST_COUNT ? count : -1;
613
13.3k
}
bytes_methods.c:stringlib_default_find
Line
Count
Source
560
1.24k
{
561
1.24k
    const Py_ssize_t w = n - m;
562
1.24k
    Py_ssize_t mlast = m - 1, count = 0;
563
1.24k
    Py_ssize_t gap = mlast;
564
1.24k
    const STRINGLIB_CHAR last = p[mlast];
565
1.24k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
1.24k
    unsigned long mask = 0;
568
4.96k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.72k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.72k
        if (p[i] == last) {
571
1.24k
            gap = mlast - i - 1;
572
1.24k
        }
573
3.72k
    }
574
1.24k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
54.3k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
54.1k
        if (ss[i] == last) {
578
            /* candidate match */
579
3.83k
            Py_ssize_t j;
580
7.27k
            for (j = 0; j < mlast; j++) {
581
6.19k
                if (s[i+j] != p[j]) {
582
2.75k
                    break;
583
2.75k
                }
584
6.19k
            }
585
3.83k
            if (j == mlast) {
586
                /* got a match! */
587
1.07k
                if (mode != FAST_COUNT) {
588
1.07k
                    return i;
589
1.07k
                }
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
2.75k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
827
                i = i + m;
600
827
            }
601
1.92k
            else {
602
1.92k
                i = i + gap;
603
1.92k
            }
604
2.75k
        }
605
50.3k
        else {
606
            /* skip: check if next character is part of pattern */
607
50.3k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
37.6k
                i = i + m;
609
37.6k
            }
610
50.3k
        }
611
54.1k
    }
612
163
    return mode == FAST_COUNT ? count : -1;
613
1.24k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_default_find
Unexecuted instantiation: bytesobject.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: 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
Unexecuted instantiation: bytesobject.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
0
{
694
    /* create compressed boyer-moore delta 1 table */
695
0
    unsigned long mask = 0;
696
0
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
0
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
0
    for (i = mlast; i > 0; i--) {
702
0
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
0
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
0
    }
707
708
0
    for (i = w; i >= 0; i--) {
709
0
        if (s[i] == p[0]) {
710
            /* candidate match */
711
0
            for (j = mlast; j > 0; j--) {
712
0
                if (s[i+j] != p[j]) {
713
0
                    break;
714
0
                }
715
0
            }
716
0
            if (j == 0) {
717
                /* got a match! */
718
0
                return i;
719
0
            }
720
            /* miss: check if previous character is part of pattern */
721
0
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
0
                i = i - m;
723
0
            }
724
0
            else {
725
0
                i = i - skip;
726
0
            }
727
0
        }
728
0
        else {
729
            /* skip: check if previous character is part of pattern */
730
0
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
0
                i = i - m;
732
0
            }
733
0
        }
734
0
    }
735
0
    return -1;
736
0
}
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
Unexecuted instantiation: bytes_methods.c:stringlib_default_rfind
Unexecuted instantiation: bytearrayobject.c:stringlib_default_rfind
Unexecuted instantiation: bytesobject.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: 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
Unexecuted instantiation: bytesobject.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
63.7k
{
762
63.7k
    Py_ssize_t count = 0;
763
375M
    for (Py_ssize_t i = 0; i < n; i++) {
764
375M
        if (s[i] == p0) {
765
13.1M
            count++;
766
13.1M
        }
767
375M
    }
768
63.7k
    return count;
769
63.7k
}
Unexecuted instantiation: unicodeobject.c:asciilib_count_char_no_maxcount
unicodeobject.c:ucs1lib_count_char_no_maxcount
Line
Count
Source
761
55.7k
{
762
55.7k
    Py_ssize_t count = 0;
763
280M
    for (Py_ssize_t i = 0; i < n; i++) {
764
280M
        if (s[i] == p0) {
765
10.4M
            count++;
766
10.4M
        }
767
280M
    }
768
55.7k
    return count;
769
55.7k
}
unicodeobject.c:ucs2lib_count_char_no_maxcount
Line
Count
Source
761
3.28k
{
762
3.28k
    Py_ssize_t count = 0;
763
11.8M
    for (Py_ssize_t i = 0; i < n; i++) {
764
11.8M
        if (s[i] == p0) {
765
1.84M
            count++;
766
1.84M
        }
767
11.8M
    }
768
3.28k
    return count;
769
3.28k
}
unicodeobject.c:ucs4lib_count_char_no_maxcount
Line
Count
Source
761
2.79k
{
762
2.79k
    Py_ssize_t count = 0;
763
75.8M
    for (Py_ssize_t i = 0; i < n; i++) {
764
75.8M
        if (s[i] == p0) {
765
781k
            count++;
766
781k
        }
767
75.8M
    }
768
2.79k
    return count;
769
2.79k
}
bytes_methods.c:stringlib_count_char_no_maxcount
Line
Count
Source
761
1.85k
{
762
1.85k
    Py_ssize_t count = 0;
763
7.40M
    for (Py_ssize_t i = 0; i < n; i++) {
764
7.40M
        if (s[i] == p0) {
765
8.90k
            count++;
766
8.90k
        }
767
7.40M
    }
768
1.85k
    return count;
769
1.85k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_count_char_no_maxcount
Unexecuted instantiation: bytesobject.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
207M
{
777
207M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
229
        return -1;
779
229
    }
780
781
    /* look for special cases */
782
207M
    if (m <= 1) {
783
94.6k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
94.6k
        if (mode == FAST_SEARCH)
788
26.1k
            return STRINGLIB(find_char)(s, n, p[0]);
789
68.4k
        else if (mode == FAST_RSEARCH)
790
4.74k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
63.7k
        else {
792
63.7k
            if (maxcount == PY_SSIZE_T_MAX) {
793
63.7k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
63.7k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
63.7k
        }
797
94.6k
    }
798
799
207M
    if (mode != FAST_RSEARCH) {
800
207M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
207M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
207M
        }
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
207M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
207M
}
unicodeobject.c:asciilib_fastsearch
Line
Count
Source
776
34.9k
{
777
34.9k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
34.9k
    if (m <= 1) {
783
17.5k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
17.5k
        if (mode == FAST_SEARCH)
788
12.8k
            return STRINGLIB(find_char)(s, n, p[0]);
789
4.74k
        else if (mode == FAST_RSEARCH)
790
4.74k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
0
        else {
792
0
            if (maxcount == PY_SSIZE_T_MAX) {
793
0
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
0
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
0
        }
797
17.5k
    }
798
799
17.3k
    if (mode != FAST_RSEARCH) {
800
17.3k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
17.3k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
17.3k
        }
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
17.3k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
17.3k
}
unicodeobject.c:ucs1lib_fastsearch
Line
Count
Source
776
207M
{
777
207M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
207M
    if (m <= 1) {
783
59.6k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
59.6k
        if (mode == FAST_SEARCH)
788
3.83k
            return STRINGLIB(find_char)(s, n, p[0]);
789
55.7k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
55.7k
        else {
792
55.7k
            if (maxcount == PY_SSIZE_T_MAX) {
793
55.7k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
55.7k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
55.7k
        }
797
59.6k
    }
798
799
207M
    if (mode != FAST_RSEARCH) {
800
207M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
207M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
207M
        }
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
207M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
207M
}
unicodeobject.c:ucs2lib_fastsearch
Line
Count
Source
776
12.0k
{
777
12.0k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
12.0k
    if (m <= 1) {
783
7.27k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
7.27k
        if (mode == FAST_SEARCH)
788
3.99k
            return STRINGLIB(find_char)(s, n, p[0]);
789
3.28k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
3.28k
        else {
792
3.28k
            if (maxcount == PY_SSIZE_T_MAX) {
793
3.28k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
3.28k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
3.28k
        }
797
7.27k
    }
798
799
4.81k
    if (mode != FAST_RSEARCH) {
800
4.81k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
4.81k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
4.81k
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
4.81k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
4.81k
}
unicodeobject.c:ucs4lib_fastsearch
Line
Count
Source
776
19.5k
{
777
19.5k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
19.5k
    if (m <= 1) {
783
6.25k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
6.25k
        if (mode == FAST_SEARCH)
788
3.46k
            return STRINGLIB(find_char)(s, n, p[0]);
789
2.79k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
2.79k
        else {
792
2.79k
            if (maxcount == PY_SSIZE_T_MAX) {
793
2.79k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
2.79k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
2.79k
        }
797
6.25k
    }
798
799
13.3k
    if (mode != FAST_RSEARCH) {
800
13.3k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
13.3k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
13.3k
        }
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
13.3k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
13.3k
}
bytes_methods.c:fastsearch
Line
Count
Source
776
5.40k
{
777
5.40k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
229
        return -1;
779
229
    }
780
781
    /* look for special cases */
782
5.18k
    if (m <= 1) {
783
3.93k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
3.93k
        if (mode == FAST_SEARCH)
788
2.08k
            return STRINGLIB(find_char)(s, n, p[0]);
789
1.85k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
1.85k
        else {
792
1.85k
            if (maxcount == PY_SSIZE_T_MAX) {
793
1.85k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
1.85k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
1.85k
        }
797
3.93k
    }
798
799
1.24k
    if (mode != FAST_RSEARCH) {
800
1.24k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
1.24k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
1.24k
        }
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.24k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
1.24k
}
Unexecuted instantiation: bytearrayobject.c:fastsearch
Unexecuted instantiation: bytesobject.c:fastsearch
830