Coverage Report

Created: 2026-08-13 06:33

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
544M
#define FAST_COUNT 0
25
181M
#define FAST_SEARCH 1
26
181M
#define FAST_RSEARCH 2
27
28
#if LONG_BIT >= 128
29
#define STRINGLIB_BLOOM_WIDTH 128
30
#elif LONG_BIT >= 64
31
3.62G
#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.62G
    ((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
40
#define STRINGLIB_BLOOM(mask, ch)     \
41
1.99G
    ((mask &  (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
42
43
#ifdef STRINGLIB_FAST_MEMCHR
44
28.7M
#  define MEMCHR_CUT_OFF 15
45
#else
46
45.3k
#  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
28.7M
{
52
28.7M
    const STRINGLIB_CHAR *p, *e;
53
54
28.7M
    p = s;
55
28.7M
    e = s + n;
56
28.7M
    if (n > MEMCHR_CUT_OFF) {
57
#ifdef STRINGLIB_FAST_MEMCHR
58
1.00M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
1.00M
        if (p != NULL)
60
977k
            return (p - s);
61
22.5k
        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
7.38k
        if (needle != 0) {
71
9.52k
            do {
72
9.52k
                const void *candidate = memchr(p, needle,
73
9.52k
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
9.52k
                if (candidate == NULL)
75
147
                    return -1;
76
9.37k
                s1 = p;
77
9.37k
                p = (const STRINGLIB_CHAR *)
78
9.37k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
9.37k
                if (*p == ch)
80
4.15k
                    return (p - s);
81
                /* False positive */
82
5.22k
                p++;
83
5.22k
                if (p - s1 > MEMCHR_CUT_OFF)
84
519
                    continue;
85
4.70k
                if (e - p <= MEMCHR_CUT_OFF)
86
938
                    break;
87
3.77k
                e1 = p + MEMCHR_CUT_OFF;
88
107k
                while (p != e1) {
89
105k
                    if (*p == ch)
90
1.83k
                        return (p - s);
91
103k
                    p++;
92
103k
                }
93
3.77k
            }
94
7.38k
            while (e - p > MEMCHR_CUT_OFF);
95
7.38k
        }
96
#endif
97
1.00M
    }
98
156M
    while (p < e) {
99
138M
        if (*p == ch)
100
10.0M
            return (p - s);
101
128M
        p++;
102
128M
    }
103
17.7M
    return -1;
104
27.7M
}
unicodeobject.c:ucs1lib_find_char
Line
Count
Source
51
28.0M
{
52
28.0M
    const STRINGLIB_CHAR *p, *e;
53
54
28.0M
    p = s;
55
28.0M
    e = s + n;
56
28.0M
    if (n > MEMCHR_CUT_OFF) {
57
353k
#ifdef STRINGLIB_FAST_MEMCHR
58
353k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
353k
        if (p != NULL)
60
352k
            return (p - s);
61
1.35k
        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
353k
    }
98
154M
    while (p < e) {
99
137M
        if (*p == ch)
100
10.0M
            return (p - s);
101
127M
        p++;
102
127M
    }
103
17.6M
    return -1;
104
27.6M
}
unicodeobject.c:ucs2lib_find_char
Line
Count
Source
51
29.2k
{
52
29.2k
    const STRINGLIB_CHAR *p, *e;
53
54
29.2k
    p = s;
55
29.2k
    e = s + n;
56
29.2k
    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
7.38k
        const STRINGLIB_CHAR *s1, *e1;
66
7.38k
        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
7.38k
        if (needle != 0) {
71
9.52k
            do {
72
9.52k
                const void *candidate = memchr(p, needle,
73
9.52k
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
9.52k
                if (candidate == NULL)
75
147
                    return -1;
76
9.37k
                s1 = p;
77
9.37k
                p = (const STRINGLIB_CHAR *)
78
9.37k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
9.37k
                if (*p == ch)
80
4.15k
                    return (p - s);
81
                /* False positive */
82
5.22k
                p++;
83
5.22k
                if (p - s1 > MEMCHR_CUT_OFF)
84
519
                    continue;
85
4.70k
                if (e - p <= MEMCHR_CUT_OFF)
86
938
                    break;
87
3.77k
                e1 = p + MEMCHR_CUT_OFF;
88
107k
                while (p != e1) {
89
105k
                    if (*p == ch)
90
1.83k
                        return (p - s);
91
103k
                    p++;
92
103k
                }
93
3.77k
            }
94
7.38k
            while (e - p > MEMCHR_CUT_OFF);
95
7.38k
        }
96
7.38k
#endif
97
7.38k
    }
98
281k
    while (p < e) {
99
264k
        if (*p == ch)
100
6.01k
            return (p - s);
101
258k
        p++;
102
258k
    }
103
17.0k
    return -1;
104
23.0k
}
unicodeobject.c:ucs4lib_find_char
Line
Count
Source
51
6.27k
{
52
6.27k
    const STRINGLIB_CHAR *p, *e;
53
54
6.27k
    p = s;
55
6.27k
    e = s + n;
56
6.27k
    if (n > MEMCHR_CUT_OFF) {
57
4.70k
#ifdef STRINGLIB_FAST_MEMCHR
58
4.70k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
4.70k
        if (p != NULL)
60
4.66k
            return (p - s);
61
31
        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.70k
    }
98
5.12k
    while (p < e) {
99
4.97k
        if (*p == ch)
100
1.42k
            return (p - s);
101
3.54k
        p++;
102
3.54k
    }
103
153
    return -1;
104
1.57k
}
unicodeobject.c:asciilib_find_char
Line
Count
Source
51
9.94k
{
52
9.94k
    const STRINGLIB_CHAR *p, *e;
53
54
9.94k
    p = s;
55
9.94k
    e = s + n;
56
9.94k
    if (n > MEMCHR_CUT_OFF) {
57
7.04k
#ifdef STRINGLIB_FAST_MEMCHR
58
7.04k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
7.04k
        if (p != NULL)
60
7.04k
            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
7.04k
    }
98
4.53k
    while (p < e) {
99
4.53k
        if (*p == ch)
100
2.90k
            return (p - s);
101
1.63k
        p++;
102
1.63k
    }
103
0
    return -1;
104
2.90k
}
bytes_methods.c:stringlib_find_char
Line
Count
Source
51
695k
{
52
695k
    const STRINGLIB_CHAR *p, *e;
53
54
695k
    p = s;
55
695k
    e = s + n;
56
695k
    if (n > MEMCHR_CUT_OFF) {
57
635k
#ifdef STRINGLIB_FAST_MEMCHR
58
635k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
635k
        if (p != NULL)
60
614k
            return (p - s);
61
21.1k
        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
635k
    }
98
940k
    while (p < e) {
99
881k
        if (*p == ch)
100
699
            return (p - s);
101
880k
        p++;
102
880k
    }
103
59.1k
    return -1;
104
59.8k
}
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
26.4k
#  define MEMRCHR_CUT_OFF 15
110
#else
111
13.5k
#  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
28.7k
{
118
28.7k
    const STRINGLIB_CHAR *p;
119
28.7k
#ifdef HAVE_MEMRCHR
120
    /* memrchr() is a GNU extension, available since glibc 2.1.91.  it
121
       doesn't seem as optimized as memchr(), but is still quite
122
       faster than our hand-written loop below. There is no wmemrchr
123
       for 4-byte chars. */
124
125
28.7k
    if (n > MEMRCHR_CUT_OFF) {
126
#if STRINGLIB_SIZEOF_CHAR == 1
127
        p = memrchr(s, ch, n);
128
10.8k
        if (p != NULL)
129
4.00k
            return (p - s);
130
6.87k
        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.29k
        if (needle != 0) {
141
5.80k
            do {
142
5.80k
                void *candidate = memrchr(s, needle,
143
5.80k
                                          n * sizeof(STRINGLIB_CHAR));
144
5.80k
                if (candidate == NULL)
145
894
                    return -1;
146
4.90k
                n1 = n;
147
4.90k
                p = (const STRINGLIB_CHAR *)
148
4.90k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
4.90k
                n = p - s;
150
4.90k
                if (*p == ch)
151
301
                    return n;
152
                /* False positive */
153
4.60k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
3.56k
                    continue;
155
1.04k
                if (n <= MEMRCHR_CUT_OFF)
156
32
                    break;
157
1.01k
                s1 = p - MEMRCHR_CUT_OFF;
158
40.9k
                while (p > s1) {
159
39.9k
                    p--;
160
39.9k
                    if (*p == ch)
161
13
                        return (p - s);
162
39.9k
                }
163
997
                n = p - s;
164
997
            }
165
4.56k
            while (n > MEMRCHR_CUT_OFF);
166
1.29k
        }
167
#endif
168
12.1k
    }
169
16.6k
#endif  /* HAVE_MEMRCHR */
170
16.6k
    p = s + n;
171
142k
    while (p > s) {
172
127k
        p--;
173
127k
        if (*p == ch)
174
2.49k
            return (p - s);
175
127k
    }
176
14.1k
    return -1;
177
16.6k
}
unicodeobject.c:ucs1lib_rfind_char
Line
Count
Source
117
3.40k
{
118
3.40k
    const STRINGLIB_CHAR *p;
119
3.40k
#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.40k
    if (n > MEMRCHR_CUT_OFF) {
126
2.62k
#if STRINGLIB_SIZEOF_CHAR == 1
127
2.62k
        p = memrchr(s, ch, n);
128
2.62k
        if (p != NULL)
129
695
            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
2.62k
    }
169
777
#endif  /* HAVE_MEMRCHR */
170
777
    p = s + n;
171
6.06k
    while (p > s) {
172
5.40k
        p--;
173
5.40k
        if (*p == ch)
174
111
            return (p - s);
175
5.40k
    }
176
666
    return -1;
177
777
}
unicodeobject.c:ucs2lib_rfind_char
Line
Count
Source
117
942
{
118
942
    const STRINGLIB_CHAR *p;
119
942
#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
942
    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
457
        const STRINGLIB_CHAR *s1;
135
457
        Py_ssize_t n1;
136
457
        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
457
        if (needle != 0) {
141
1.75k
            do {
142
1.75k
                void *candidate = memrchr(s, needle,
143
1.75k
                                          n * sizeof(STRINGLIB_CHAR));
144
1.75k
                if (candidate == NULL)
145
292
                    return -1;
146
1.46k
                n1 = n;
147
1.46k
                p = (const STRINGLIB_CHAR *)
148
1.46k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
1.46k
                n = p - s;
150
1.46k
                if (*p == ch)
151
107
                    return n;
152
                /* False positive */
153
1.35k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
850
                    continue;
155
503
                if (n <= MEMRCHR_CUT_OFF)
156
18
                    break;
157
485
                s1 = p - MEMRCHR_CUT_OFF;
158
19.6k
                while (p > s1) {
159
19.2k
                    p--;
160
19.2k
                    if (*p == ch)
161
6
                        return (p - s);
162
19.2k
                }
163
479
                n = p - s;
164
479
            }
165
1.32k
            while (n > MEMRCHR_CUT_OFF);
166
457
        }
167
457
#endif
168
457
    }
169
537
#endif  /* HAVE_MEMRCHR */
170
537
    p = s + n;
171
5.50k
    while (p > s) {
172
4.98k
        p--;
173
4.98k
        if (*p == ch)
174
15
            return (p - s);
175
4.98k
    }
176
522
    return -1;
177
537
}
unicodeobject.c:ucs4lib_rfind_char
Line
Count
Source
117
1.35k
{
118
1.35k
    const STRINGLIB_CHAR *p;
119
1.35k
#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.35k
    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
840
        const STRINGLIB_CHAR *s1;
135
840
        Py_ssize_t n1;
136
840
        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
840
        if (needle != 0) {
141
4.05k
            do {
142
4.05k
                void *candidate = memrchr(s, needle,
143
4.05k
                                          n * sizeof(STRINGLIB_CHAR));
144
4.05k
                if (candidate == NULL)
145
602
                    return -1;
146
3.44k
                n1 = n;
147
3.44k
                p = (const STRINGLIB_CHAR *)
148
3.44k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
3.44k
                n = p - s;
150
3.44k
                if (*p == ch)
151
194
                    return n;
152
                /* False positive */
153
3.25k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
2.71k
                    continue;
155
539
                if (n <= MEMRCHR_CUT_OFF)
156
14
                    break;
157
525
                s1 = p - MEMRCHR_CUT_OFF;
158
21.2k
                while (p > s1) {
159
20.7k
                    p--;
160
20.7k
                    if (*p == ch)
161
7
                        return (p - s);
162
20.7k
                }
163
518
                n = p - s;
164
518
            }
165
3.23k
            while (n > MEMRCHR_CUT_OFF);
166
840
        }
167
840
#endif
168
840
    }
169
550
#endif  /* HAVE_MEMRCHR */
170
550
    p = s + n;
171
6.23k
    while (p > s) {
172
5.70k
        p--;
173
5.70k
        if (*p == ch)
174
15
            return (p - s);
175
5.70k
    }
176
535
    return -1;
177
550
}
unicodeobject.c:asciilib_rfind_char
Line
Count
Source
117
2.98k
{
118
2.98k
    const STRINGLIB_CHAR *p;
119
2.98k
#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
2.98k
    if (n > MEMRCHR_CUT_OFF) {
126
601
#if STRINGLIB_SIZEOF_CHAR == 1
127
601
        p = memrchr(s, ch, n);
128
601
        if (p != NULL)
129
496
            return (p - s);
130
105
        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
601
    }
169
2.38k
#endif  /* HAVE_MEMRCHR */
170
2.38k
    p = s + n;
171
17.4k
    while (p > s) {
172
15.9k
        p--;
173
15.9k
        if (*p == ch)
174
855
            return (p - s);
175
15.9k
    }
176
1.53k
    return -1;
177
2.38k
}
bytes_methods.c:stringlib_rfind_char
Line
Count
Source
117
20.0k
{
118
20.0k
    const STRINGLIB_CHAR *p;
119
20.0k
#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
20.0k
    if (n > MEMRCHR_CUT_OFF) {
126
7.64k
#if STRINGLIB_SIZEOF_CHAR == 1
127
7.64k
        p = memrchr(s, ch, n);
128
7.64k
        if (p != NULL)
129
2.81k
            return (p - s);
130
4.83k
        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
7.64k
    }
169
12.4k
#endif  /* HAVE_MEMRCHR */
170
12.4k
    p = s + n;
171
106k
    while (p > s) {
172
95.8k
        p--;
173
95.8k
        if (*p == ch)
174
1.49k
            return (p - s);
175
95.8k
    }
176
10.9k
    return -1;
177
12.4k
}
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
181M
{
561
181M
    const Py_ssize_t w = n - m;
562
181M
    Py_ssize_t mlast = m - 1, count = 0;
563
181M
    Py_ssize_t gap = mlast;
564
181M
    const STRINGLIB_CHAR last = p[mlast];
565
181M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
181M
    unsigned long mask = 0;
568
1.62G
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
1.44G
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
1.44G
        if (p[i] == last) {
571
100k
            gap = mlast - i - 1;
572
100k
        }
573
1.44G
    }
574
181M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
2.17G
    for (Py_ssize_t i = 0; i <= w; i++) {
577
1.99G
        if (ss[i] == last) {
578
            /* candidate match */
579
180M
            Py_ssize_t j;
580
181M
            for (j = 0; j < mlast; j++) {
581
180M
                if (s[i+j] != p[j]) {
582
180M
                    break;
583
180M
                }
584
180M
            }
585
180M
            if (j == mlast) {
586
                /* got a match! */
587
83.1k
                if (mode != FAST_COUNT) {
588
42.1k
                    return i;
589
42.1k
                }
590
40.9k
                count++;
591
40.9k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
40.9k
                i = i + mlast;
595
40.9k
                continue;
596
40.9k
            }
597
            /* miss: check if next character is part of pattern */
598
180M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
10.6k
                i = i + m;
600
10.6k
            }
601
180M
            else {
602
180M
                i = i + gap;
603
180M
            }
604
180M
        }
605
1.81G
        else {
606
            /* skip: check if next character is part of pattern */
607
1.81G
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
904M
                i = i + m;
609
904M
            }
610
1.81G
        }
611
1.99G
    }
612
181M
    return mode == FAST_COUNT ? count : -1;
613
181M
}
unicodeobject.c:asciilib_default_find
Line
Count
Source
560
19.4k
{
561
19.4k
    const Py_ssize_t w = n - m;
562
19.4k
    Py_ssize_t mlast = m - 1, count = 0;
563
19.4k
    Py_ssize_t gap = mlast;
564
19.4k
    const STRINGLIB_CHAR last = p[mlast];
565
19.4k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
19.4k
    unsigned long mask = 0;
568
42.0k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
22.6k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
22.6k
        if (p[i] == last) {
571
16.3k
            gap = mlast - i - 1;
572
16.3k
        }
573
22.6k
    }
574
19.4k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
39.2k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
39.2k
        if (ss[i] == last) {
578
            /* candidate match */
579
22.3k
            Py_ssize_t j;
580
44.9k
            for (j = 0; j < mlast; j++) {
581
25.4k
                if (s[i+j] != p[j]) {
582
2.83k
                    break;
583
2.83k
                }
584
25.4k
            }
585
22.3k
            if (j == mlast) {
586
                /* got a match! */
587
19.4k
                if (mode != FAST_COUNT) {
588
19.4k
                    return i;
589
19.4k
                }
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.83k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
0
                i = i + m;
600
0
            }
601
2.83k
            else {
602
2.83k
                i = i + gap;
603
2.83k
            }
604
2.83k
        }
605
16.9k
        else {
606
            /* skip: check if next character is part of pattern */
607
16.9k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
14.9k
                i = i + m;
609
14.9k
            }
610
16.9k
        }
611
39.2k
    }
612
0
    return mode == FAST_COUNT ? count : -1;
613
19.4k
}
unicodeobject.c:ucs1lib_default_find
Line
Count
Source
560
181M
{
561
181M
    const Py_ssize_t w = n - m;
562
181M
    Py_ssize_t mlast = m - 1, count = 0;
563
181M
    Py_ssize_t gap = mlast;
564
181M
    const STRINGLIB_CHAR last = p[mlast];
565
181M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
181M
    unsigned long mask = 0;
568
1.62G
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
1.44G
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
1.44G
        if (p[i] == last) {
571
65.9k
            gap = mlast - i - 1;
572
65.9k
        }
573
1.44G
    }
574
181M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
2.17G
    for (Py_ssize_t i = 0; i <= w; i++) {
577
1.99G
        if (ss[i] == last) {
578
            /* candidate match */
579
180M
            Py_ssize_t j;
580
180M
            for (j = 0; j < mlast; j++) {
581
180M
                if (s[i+j] != p[j]) {
582
180M
                    break;
583
180M
                }
584
180M
            }
585
180M
            if (j == mlast) {
586
                /* got a match! */
587
30.9k
                if (mode != FAST_COUNT) {
588
5.73k
                    return i;
589
5.73k
                }
590
25.2k
                count++;
591
25.2k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
25.2k
                i = i + mlast;
595
25.2k
                continue;
596
25.2k
            }
597
            /* miss: check if next character is part of pattern */
598
180M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
9.32k
                i = i + m;
600
9.32k
            }
601
180M
            else {
602
180M
                i = i + gap;
603
180M
            }
604
180M
        }
605
1.81G
        else {
606
            /* skip: check if next character is part of pattern */
607
1.81G
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
904M
                i = i + m;
609
904M
            }
610
1.81G
        }
611
1.99G
    }
612
181M
    return mode == FAST_COUNT ? count : -1;
613
181M
}
unicodeobject.c:ucs2lib_default_find
Line
Count
Source
560
5.08k
{
561
5.08k
    const Py_ssize_t w = n - m;
562
5.08k
    Py_ssize_t mlast = m - 1, count = 0;
563
5.08k
    Py_ssize_t gap = mlast;
564
5.08k
    const STRINGLIB_CHAR last = p[mlast];
565
5.08k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
5.08k
    unsigned long mask = 0;
568
10.1k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
5.08k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
5.08k
        if (p[i] == last) {
571
5.08k
            gap = mlast - i - 1;
572
5.08k
        }
573
5.08k
    }
574
5.08k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
98.0k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
97.7k
        if (ss[i] == last) {
578
            /* candidate match */
579
11.8k
            Py_ssize_t j;
580
21.4k
            for (j = 0; j < mlast; j++) {
581
11.8k
                if (s[i+j] != p[j]) {
582
2.26k
                    break;
583
2.26k
                }
584
11.8k
            }
585
11.8k
            if (j == mlast) {
586
                /* got a match! */
587
9.58k
                if (mode != FAST_COUNT) {
588
4.79k
                    return i;
589
4.79k
                }
590
4.79k
                count++;
591
4.79k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
4.79k
                i = i + mlast;
595
4.79k
                continue;
596
4.79k
            }
597
            /* miss: check if next character is part of pattern */
598
2.26k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
0
                i = i + m;
600
0
            }
601
2.26k
            else {
602
2.26k
                i = i + gap;
603
2.26k
            }
604
2.26k
        }
605
85.8k
        else {
606
            /* skip: check if next character is part of pattern */
607
85.8k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
83.2k
                i = i + m;
609
83.2k
            }
610
85.8k
        }
611
97.7k
    }
612
296
    return mode == FAST_COUNT ? count : -1;
613
5.08k
}
unicodeobject.c:ucs4lib_default_find
Line
Count
Source
560
12.1k
{
561
12.1k
    const Py_ssize_t w = n - m;
562
12.1k
    Py_ssize_t mlast = m - 1, count = 0;
563
12.1k
    Py_ssize_t gap = mlast;
564
12.1k
    const STRINGLIB_CHAR last = p[mlast];
565
12.1k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
12.1k
    unsigned long mask = 0;
568
24.2k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
12.1k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
12.1k
        if (p[i] == last) {
571
12.1k
            gap = mlast - i - 1;
572
12.1k
        }
573
12.1k
    }
574
12.1k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
59.4k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
58.3k
        if (ss[i] == last) {
578
            /* candidate match */
579
27.7k
            Py_ssize_t j;
580
49.7k
            for (j = 0; j < mlast; j++) {
581
27.7k
                if (s[i+j] != p[j]) {
582
5.71k
                    break;
583
5.71k
                }
584
27.7k
            }
585
27.7k
            if (j == mlast) {
586
                /* got a match! */
587
22.0k
                if (mode != FAST_COUNT) {
588
11.0k
                    return i;
589
11.0k
                }
590
11.0k
                count++;
591
11.0k
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
11.0k
                i = i + mlast;
595
11.0k
                continue;
596
11.0k
            }
597
            /* miss: check if next character is part of pattern */
598
5.71k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
0
                i = i + m;
600
0
            }
601
5.71k
            else {
602
5.71k
                i = i + gap;
603
5.71k
            }
604
5.71k
        }
605
30.6k
        else {
606
            /* skip: check if next character is part of pattern */
607
30.6k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
27.1k
                i = i + m;
609
27.1k
            }
610
30.6k
        }
611
58.3k
    }
612
1.12k
    return mode == FAST_COUNT ? count : -1;
613
12.1k
}
bytes_methods.c:stringlib_default_find
Line
Count
Source
560
1.32k
{
561
1.32k
    const Py_ssize_t w = n - m;
562
1.32k
    Py_ssize_t mlast = m - 1, count = 0;
563
1.32k
    Py_ssize_t gap = mlast;
564
1.32k
    const STRINGLIB_CHAR last = p[mlast];
565
1.32k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
1.32k
    unsigned long mask = 0;
568
5.30k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.98k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.98k
        if (p[i] == last) {
571
1.32k
            gap = mlast - i - 1;
572
1.32k
        }
573
3.98k
    }
574
1.32k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
74.0k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
73.9k
        if (ss[i] == last) {
578
            /* candidate match */
579
4.52k
            Py_ssize_t j;
580
8.70k
            for (j = 0; j < mlast; j++) {
581
7.51k
                if (s[i+j] != p[j]) {
582
3.32k
                    break;
583
3.32k
                }
584
7.51k
            }
585
4.52k
            if (j == mlast) {
586
                /* got a match! */
587
1.19k
                if (mode != FAST_COUNT) {
588
1.19k
                    return i;
589
1.19k
                }
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
3.32k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.36k
                i = i + m;
600
1.36k
            }
601
1.96k
            else {
602
1.96k
                i = i + gap;
603
1.96k
            }
604
3.32k
        }
605
69.4k
        else {
606
            /* skip: check if next character is part of pattern */
607
69.4k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
37.6k
                i = i + m;
609
37.6k
            }
610
69.4k
        }
611
73.9k
    }
612
133
    return mode == FAST_COUNT ? count : -1;
613
1.32k
}
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
47.8k
{
762
47.8k
    Py_ssize_t count = 0;
763
297M
    for (Py_ssize_t i = 0; i < n; i++) {
764
297M
        if (s[i] == p0) {
765
12.3M
            count++;
766
12.3M
        }
767
297M
    }
768
47.8k
    return count;
769
47.8k
}
Unexecuted instantiation: unicodeobject.c:asciilib_count_char_no_maxcount
unicodeobject.c:ucs1lib_count_char_no_maxcount
Line
Count
Source
761
41.4k
{
762
41.4k
    Py_ssize_t count = 0;
763
199M
    for (Py_ssize_t i = 0; i < n; i++) {
764
199M
        if (s[i] == p0) {
765
10.0M
            count++;
766
10.0M
        }
767
199M
    }
768
41.4k
    return count;
769
41.4k
}
unicodeobject.c:ucs2lib_count_char_no_maxcount
Line
Count
Source
761
2.11k
{
762
2.11k
    Py_ssize_t count = 0;
763
10.1M
    for (Py_ssize_t i = 0; i < n; i++) {
764
10.1M
        if (s[i] == p0) {
765
1.68M
            count++;
766
1.68M
        }
767
10.1M
    }
768
2.11k
    return count;
769
2.11k
}
unicodeobject.c:ucs4lib_count_char_no_maxcount
Line
Count
Source
761
2.43k
{
762
2.43k
    Py_ssize_t count = 0;
763
80.1M
    for (Py_ssize_t i = 0; i < n; i++) {
764
80.1M
        if (s[i] == p0) {
765
609k
            count++;
766
609k
        }
767
80.1M
    }
768
2.43k
    return count;
769
2.43k
}
bytes_methods.c:stringlib_count_char_no_maxcount
Line
Count
Source
761
1.91k
{
762
1.91k
    Py_ssize_t count = 0;
763
8.05M
    for (Py_ssize_t i = 0; i < n; i++) {
764
8.05M
        if (s[i] == p0) {
765
9.93k
            count++;
766
9.93k
        }
767
8.05M
    }
768
1.91k
    return count;
769
1.91k
}
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
181M
{
777
181M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
194
        return -1;
779
194
    }
780
781
    /* look for special cases */
782
181M
    if (m <= 1) {
783
77.2k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
77.2k
        if (mode == FAST_SEARCH)
788
26.4k
            return STRINGLIB(find_char)(s, n, p[0]);
789
50.8k
        else if (mode == FAST_RSEARCH)
790
2.98k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
47.8k
        else {
792
47.8k
            if (maxcount == PY_SSIZE_T_MAX) {
793
47.8k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
47.8k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
47.8k
        }
797
77.2k
    }
798
799
181M
    if (mode != FAST_RSEARCH) {
800
181M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
181M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
181M
        }
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
181M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
181M
}
unicodeobject.c:asciilib_fastsearch
Line
Count
Source
776
32.3k
{
777
32.3k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
32.3k
    if (m <= 1) {
783
12.9k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
12.9k
        if (mode == FAST_SEARCH)
788
9.94k
            return STRINGLIB(find_char)(s, n, p[0]);
789
2.98k
        else if (mode == FAST_RSEARCH)
790
2.98k
            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
12.9k
    }
798
799
19.4k
    if (mode != FAST_RSEARCH) {
800
19.4k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
19.4k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
19.4k
        }
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
19.4k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
19.4k
}
unicodeobject.c:ucs1lib_fastsearch
Line
Count
Source
776
181M
{
777
181M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
181M
    if (m <= 1) {
783
45.4k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
45.4k
        if (mode == FAST_SEARCH)
788
4.08k
            return STRINGLIB(find_char)(s, n, p[0]);
789
41.4k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
41.4k
        else {
792
41.4k
            if (maxcount == PY_SSIZE_T_MAX) {
793
41.4k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
41.4k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
41.4k
        }
797
45.4k
    }
798
799
181M
    if (mode != FAST_RSEARCH) {
800
181M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
181M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
181M
        }
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
181M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
181M
}
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
6.92k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
6.92k
        if (mode == FAST_SEARCH)
788
4.80k
            return STRINGLIB(find_char)(s, n, p[0]);
789
2.11k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
2.11k
        else {
792
2.11k
            if (maxcount == PY_SSIZE_T_MAX) {
793
2.11k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
2.11k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
2.11k
        }
797
6.92k
    }
798
799
5.08k
    if (mode != FAST_RSEARCH) {
800
5.08k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
5.08k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
5.08k
        }
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
5.08k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
5.08k
}
unicodeobject.c:ucs4lib_fastsearch
Line
Count
Source
776
20.0k
{
777
20.0k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
20.0k
    if (m <= 1) {
783
7.91k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
7.91k
        if (mode == FAST_SEARCH)
788
5.48k
            return STRINGLIB(find_char)(s, n, p[0]);
789
2.43k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
2.43k
        else {
792
2.43k
            if (maxcount == PY_SSIZE_T_MAX) {
793
2.43k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
2.43k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
2.43k
        }
797
7.91k
    }
798
799
12.1k
    if (mode != FAST_RSEARCH) {
800
12.1k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
12.1k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
12.1k
        }
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
12.1k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
12.1k
}
bytes_methods.c:fastsearch
Line
Count
Source
776
5.55k
{
777
5.55k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
194
        return -1;
779
194
    }
780
781
    /* look for special cases */
782
5.35k
    if (m <= 1) {
783
4.03k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
4.03k
        if (mode == FAST_SEARCH)
788
2.11k
            return STRINGLIB(find_char)(s, n, p[0]);
789
1.91k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
1.91k
        else {
792
1.91k
            if (maxcount == PY_SSIZE_T_MAX) {
793
1.91k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
1.91k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
1.91k
        }
797
4.03k
    }
798
799
1.32k
    if (mode != FAST_RSEARCH) {
800
1.32k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
1.32k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
1.32k
        }
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.32k
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
1.32k
}
Unexecuted instantiation: bytearrayobject.c:fastsearch
Unexecuted instantiation: bytesobject.c:fastsearch
830